obsidian-visualiser/pages/user/login.vue

86 lines
2.3 KiB
Vue

<template>
<Head>
<Title>Connexion</Title>
</Head>
<div class="flex flex-1 flex-col justify-center items-center">
<ProseH4>Connexion</ProseH4>
<form @submit="() => submit()" class="flex flex-1 flex-col justify-center items-stretch">
<TextInput type="text" label="Utilisateur ou email" autocomplete="username" v-model="state.usernameOrEmail"/>
<TextInput type="password" label="Mot de passe" autocomplete="current-password" v-model="state.password"/>
<Button class="border border-light-35 dark:border-dark-35 self-center" :loading="status === 'pending'">Se connecter</Button>
<NuxtLink class="mt-4 text-center block text-sm font-semibold tracking-wide hover:text-accent-blue" :to="{ path: `/user/register`, force: true }">Pas de compte ?</NuxtLink>
</form>
<Toast :closeable="false" :content="toastMessage" :duration="10000" timer />
</div>
</template>
<script setup lang="ts">
import type { ZodError } from 'zod';
import { schema, type Login } from '~/schemas/login';
definePageMeta({
layout: 'login',
});
const state = reactive<Login>({
usernameOrEmail: '',
password: ''
});
const { data: result, status, error, refresh } = await useFetch('/api/auth/login', {
body: state,
immediate: false,
method: 'POST',
watch: false,
ignoreResponseError: true,
})
const toastMessage = ref('');
async function submit()
{
if(state.password === "")
return;
const data = schema.safeParse(state);
if(data.success)
{
await refresh();
const login = result.value;
if(!login || !login.success)
{
handleErrors(login?.error ?? error.value!);
}
else if(status.value === 'success' && login.success)
{
await navigateTo('/user/profile');
}
}
else
{
handleErrors(data.error);
}
}
function handleErrors(error: Error | ZodError)
{
if(!error)
return;
status.value = 'error';
if(error.hasOwnProperty('issues'))
{
for(const err of (error as ZodError).issues)
{
toastMessage.value = err.message;
break;
}
}
else
{
toastMessage.value = error?.message ?? 'Erreur inconnue.';
}
}
</script>