109 lines
3.4 KiB
Vue
109 lines
3.4 KiB
Vue
<template>
|
|
<div
|
|
class="flex min-h-full items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8"
|
|
>
|
|
<div class="w-full max-w-md space-y-8">
|
|
<div>
|
|
<h2
|
|
class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900"
|
|
>
|
|
Sign in to your account
|
|
</h2>
|
|
</div>
|
|
<Transition
|
|
enter-active-class="transition-height ease-out duration-500 origin-bottom overflow-hidden"
|
|
enter-from-class="h-0"
|
|
enter-to-class="h-10"
|
|
>
|
|
<div class="mb-4 rounded" v-if="errorMessage">
|
|
<div
|
|
class="rounded bg-red-100 px-4 py-2 text-center font-bold text-red-700"
|
|
role="alert"
|
|
aria-live="assertive"
|
|
>
|
|
{{ errorMessage }}
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
<form
|
|
@submit.prevent="doLogin"
|
|
class="mt-8 overflow-hidden shadow sm:rounded-md"
|
|
>
|
|
<div class="bg-white px-4 py-5 sm:p-6">
|
|
<div class="space-y-5">
|
|
<div class="space-y-1">
|
|
<label for="email" class="block text-sm font-medium text-gray-700"
|
|
>Email address</label
|
|
>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
id="email"
|
|
required
|
|
autofocus
|
|
autocomplete="email"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
|
|
v-model="loginForm.email"
|
|
/>
|
|
</div>
|
|
<div class="space-y-1">
|
|
<label
|
|
for="password"
|
|
class="block text-sm font-medium text-gray-700"
|
|
>Password</label
|
|
>
|
|
<input
|
|
type="password"
|
|
name="password"
|
|
id="password"
|
|
required
|
|
autocomplete="current-password"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
|
|
v-model="loginForm.password"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-50 px-4 py-3 text-right sm:px-6">
|
|
<button
|
|
type="submit"
|
|
class="inline-flex justify-center rounded-md border border-transparent bg-green-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
|
>
|
|
Sign in
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useUserStore } from '../store/user.store';
|
|
import { JFetchError } from '../utils/jfetch';
|
|
|
|
const userStore = useUserStore();
|
|
const router = useRouter();
|
|
const errorMessage = ref<string>('');
|
|
const loginForm = ref<{
|
|
email: string;
|
|
password: string;
|
|
}>({
|
|
email: '',
|
|
password: '',
|
|
});
|
|
|
|
const doLogin = async () => {
|
|
errorMessage.value = '';
|
|
try {
|
|
const { email, password } = loginForm.value;
|
|
await userStore.login({ email, password });
|
|
router.replace({ name: 'dashboard' });
|
|
} catch (e) {
|
|
const error = e as JFetchError;
|
|
errorMessage.value = error?.data?.message || (e as Error).message;
|
|
}
|
|
};
|
|
</script>
|