feat: add sign in page

This commit is contained in:
Sergey Krylov 2025-02-13 05:21:49 +03:00
parent 240e2f97fb
commit 55d67cf118
4 changed files with 104 additions and 37 deletions

46
src/pages/SignIn.vue Normal file
View File

@ -0,0 +1,46 @@
<script setup>
import { Button, InputText, Message } from 'primevue';
import { ref } from 'vue';
import { useAuthStore } from '@/store/auth';
import Loader from '@/components/Loader.vue';
const authStore = useAuthStore()
const email = ref('')
const password = ref('')
const signin = async () => {
await authStore.auth('signIn',{ email: email.value, password: password.value })
}
</script>
<template>
<h2>Sign In</h2>
<form class="flex flex-column gap-3" @submit.prevent="signin">
<transition-group name="p-message" tag="div" class="flex flex-col">
<Message v-if="authStore.error" closable icon="pi pi-times-circle" class="flex-1" severity="error">{{authStore.error}}</Message>
</transition-group>
<div class="p-inputgroup flex align-items-center gap-4">
<span class="p-inputgroup-addon">
<i class="pi pi-user"></i>
</span>
<InputText type="email" class="flex-1" v-model="email" placeholder="Your Email" />
</div>
<div class="p-inputgroup flex align-items-center gap-4">
<span class="p-inputgroup-addon">
<i class="pi pi-at"></i>
</span>
<InputText type="password" class="flex-1" v-model="password" placeholder="Password" />
</div>
<div class="flex flex-column gap-3">
<Loader v-if="authStore.loading" />
<Button v-else label="Signin" type="submit" />
<span>Are you not registered yet? <router-link to="/sign-up">Sign up</router-link></span>
</div>
</form>
</template>

View File

@ -10,7 +10,7 @@
const password = ref('') const password = ref('')
const signup = async () => { const signup = async () => {
await authStore.signUp({ email: email.value, password: password.value }) await authStore.auth('signUp', { email: email.value, password: password.value })
} }
</script> </script>
@ -19,7 +19,7 @@
<h2>Sign Up</h2> <h2>Sign Up</h2>
<form class="flex flex-column gap-3" @submit.prevent="signup"> <form class="flex flex-column gap-3" @submit.prevent="signup">
<transition-group name="p-message" tag="div" class="flex flex-col"> <transition-group name="p-message" tag="div" class="flex flex-col">
<Message v-if="authStore.error" closable icon="pi pi-times-circle" severity="error">{{authStore.error}}</Message> <Message v-if="authStore.error" closable icon="pi pi-times-circle" class="flex-1" severity="error">{{authStore.error}}</Message>
</transition-group> </transition-group>
<div class="p-inputgroup flex align-items-center gap-4"> <div class="p-inputgroup flex align-items-center gap-4">
@ -38,9 +38,9 @@
<div class="flex flex-column gap-3"> <div class="flex flex-column gap-3">
<Loader v-if="authStore.loading" /> <Loader v-if="authStore.loading" />
<Button v-else label="Signup" @click="signup"/> <Button v-else label="Signup" type="submit" />
<span>Are you already registered? <router-link to="/signin">Sign in</router-link></span> <span>Are you already registered? <router-link to="/sign-in">Sign in</router-link></span>
</div> </div>
</form> </form>
</template> </template>

View File

@ -8,6 +8,11 @@ const router = createRouter({
path: '/sign-up', path: '/sign-up',
name: 'SignUp', name: 'SignUp',
component: () => import('../pages/SignUp.vue') component: () => import('../pages/SignUp.vue')
},
{
path: '/sign-in',
name: 'SignIn',
component: () => import('../pages/SignIn.vue')
} }
] ]
}) })

View File

@ -13,11 +13,13 @@ export const useAuthStore = defineStore('auth', () => {
const loading = ref(false); const loading = ref(false);
const error = ref(''); const error = ref('');
const signUp = async (payload: {email: string; password: string}) => { const auth = async <T extends 'signUp' | 'signIn'>(type: T, payload: {email: string; password: string}) => {
error.value = ''; error.value = '';
const url = `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${process.env.FIREBASE_API_KEY}` const url = type === 'signUp'
? `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${process.env.FIREBASE_API_KEY}`
: `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${process.env.FIREBASE_API_KEY}`;
type AuthResponse = { type SignUpResponse = {
kind: string kind: string
idToken: string idToken: string
email: string; email: string;
@ -25,9 +27,19 @@ export const useAuthStore = defineStore('auth', () => {
expiresIn: string; expiresIn: string;
localId: string; localId: string;
} }
type SignInResponse = {
kind: string;
localId: string;
email: string;
displayName: string;
idToken: string;
registered: boolean;
refreshToken: string;
expiresIn: string;
}
try { try {
loading.value = true; loading.value = true;
const { data } = await axios.post<AuthResponse>(url, { const { data } = await axios.post<SignUpResponse | SignInResponse>(url, {
...payload, ...payload,
returnSecureToken: true returnSecureToken: true
}) })
@ -40,43 +52,47 @@ export const useAuthStore = defineStore('auth', () => {
token: data.idToken, token: data.idToken,
} }
} catch (e) { } catch (e) {
if (e instanceof AxiosError) { if (!(e instanceof AxiosError)){
switch (e?.response?.data?.error?.message) { error.value = 'Something went wrong';
case 'EMAIL_EXISTS': return;
error.value = 'Email already exists';
break;
case 'OPERATION_NOT_ALLOWED':
error.value = 'Operation not allowed';
break;
case 'TOO_MANY_ATTEMPTS_TRY_LATER':
error.value = 'Too many attempts';
break;
case 'EMAIL_NOT_FOUND':
error.value = 'Email not found';
break;
case 'INVALID_PASSWORD':
error.value = 'Invalid password';
break;
case 'WEAK_PASSWORD':
error.value = 'Password is weak';
break;
case 'USER_DISABLED':
error.value = 'User disabled';
break;
default:
error.value = 'Something went wrong';
return;
}
} }
error.value = 'Something went wrong'; switch (e?.response?.data?.error?.message) {
case 'EMAIL_EXISTS':
error.value = 'Email already exists';
return;
case 'OPERATION_NOT_ALLOWED':
error.value = 'Operation not allowed';
return;
case 'TOO_MANY_ATTEMPTS_TRY_LATER':
error.value = 'Too many attempts';
return;
case 'EMAIL_NOT_FOUND':
error.value = 'Email not found';
return;
case 'INVALID_LOGIN_CREDENTIALS':
error.value = 'Invalid credentials';
return;
case 'INVALID_PASSWORD':
error.value = 'Invalid password';
return;
case 'WEAK_PASSWORD':
error.value = 'Password is weak';
return;
case 'USER_DISABLED':
error.value = 'User disabled';
return;
default:
error.value = 'Something went wrong';
return;
}
} finally { } finally {
loading.value = false; loading.value = false;
} }
}; };
return { return {
signUp, auth,
userInfo, userInfo,
error, error,
loading, loading,