feat: add public site pages and social login
This commit is contained in:
@@ -1,94 +1,116 @@
|
||||
<template>
|
||||
<div class="flex min-h-full w-full items-center justify-center p-4">
|
||||
<div class="flex w-full max-w-[512px] flex-col gap-10">
|
||||
<h1 class="login-text text-center text-2xl font-bold">
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
<div class="login-page">
|
||||
<div class="login-wrap">
|
||||
<router-link
|
||||
class="login-brand"
|
||||
to="/"
|
||||
>
|
||||
<span class="login-brand-mark">S</span>
|
||||
<span class="login-brand-text">Socialize</span>
|
||||
</router-link>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<google-login
|
||||
:callback="googleCallback"
|
||||
popup-type="TOKEN"
|
||||
>
|
||||
<button class="secondary">
|
||||
<section class="login-card">
|
||||
<h1 class="login-text text-center text-2xl font-bold">
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<google-login
|
||||
:callback="googleCallback"
|
||||
popup-type="TOKEN"
|
||||
>
|
||||
<button class="secondary">
|
||||
<v-icon
|
||||
:icon="mdiGoogle"
|
||||
class="mr-2"
|
||||
/>
|
||||
{{ t('continueWithGoogle') }}
|
||||
</button>
|
||||
</google-login>
|
||||
|
||||
<button
|
||||
class="secondary"
|
||||
type="button"
|
||||
@click="handleFacebookLogin"
|
||||
>
|
||||
<v-icon
|
||||
:icon="mdiGoogle"
|
||||
:icon="mdiFacebook"
|
||||
class="mr-2"
|
||||
/>
|
||||
{{ t('continueWithGoogle') }}
|
||||
{{ t('continueWithFacebook') }}
|
||||
</button>
|
||||
</google-login>
|
||||
</div>
|
||||
|
||||
<div class="my-4 flex items-center">
|
||||
<div class="h-px grow bg-gray-200"></div>
|
||||
<span class="px-3 text-sm font-semibold uppercase text-gray-300">{{ t('orContinueWith') }}</span>
|
||||
<div class="h-px grow bg-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<!-- Add email/password form -->
|
||||
<v-form @submit.prevent="handleLocalLogin">
|
||||
<div class="flex flex-col gap-4">
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
:label="t('email')"
|
||||
required
|
||||
type="email"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
:label="t('password')"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
required
|
||||
>
|
||||
<template v-slot:append-inner>
|
||||
<v-icon
|
||||
:icon="showPassword ? mdiEyeOff : mdiEye"
|
||||
class="visibility-toggle"
|
||||
size="small"
|
||||
@click="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
type="submit"
|
||||
>
|
||||
{{ t('signIn') }}
|
||||
</v-btn>
|
||||
|
||||
<div class="text-center">
|
||||
<a
|
||||
class="cursor-pointer text-sm text-blue-500"
|
||||
@click="forgotPassword"
|
||||
>
|
||||
{{ t('forgotPassword') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 text-center">
|
||||
<a
|
||||
class="cursor-pointer text-sm text-blue-500"
|
||||
@click="resendVerification"
|
||||
>
|
||||
{{ t('resendVerification') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
{{ t('noAccount') }}
|
||||
<router-link
|
||||
class="text-blue-500"
|
||||
to="/register"
|
||||
>
|
||||
{{ t('register') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</v-form>
|
||||
|
||||
<div class="my-4 flex items-center">
|
||||
<div class="h-px grow bg-gray-200"></div>
|
||||
<span class="px-3 text-sm font-semibold uppercase text-gray-300">{{ t('orContinueWith') }}</span>
|
||||
<div class="h-px grow bg-gray-200"></div>
|
||||
</div>
|
||||
|
||||
<!-- Add email/password form -->
|
||||
<v-form @submit.prevent="handleLocalLogin">
|
||||
<div class="flex flex-col gap-4">
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
:label="t('email')"
|
||||
required
|
||||
type="email"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
:label="t('password')"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
required
|
||||
>
|
||||
<template v-slot:append-inner>
|
||||
<v-icon
|
||||
:icon="showPassword ? mdiEyeOff : mdiEye"
|
||||
class="visibility-toggle"
|
||||
size="small"
|
||||
@click="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
type="submit"
|
||||
>
|
||||
{{ t('signIn') }}
|
||||
</v-btn>
|
||||
|
||||
<div class="text-center">
|
||||
<a
|
||||
class="cursor-pointer text-sm text-blue-500"
|
||||
@click="forgotPassword"
|
||||
>
|
||||
{{ t('forgotPassword') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 text-center">
|
||||
<a
|
||||
class="cursor-pointer text-sm text-blue-500"
|
||||
@click="resendVerification"
|
||||
>
|
||||
{{ t('resendVerification') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
{{ t('noAccount') }}
|
||||
<router-link
|
||||
class="text-blue-500"
|
||||
to="/register"
|
||||
>
|
||||
{{ t('register') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</v-form>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Error notification -->
|
||||
@@ -105,13 +127,15 @@
|
||||
import { ref } from 'vue';
|
||||
import { GoogleLogin } from 'vue3-google-login';
|
||||
import { useAuthStore } from '@/features/auth/stores/authStore.js';
|
||||
import { useFacebookLogin } from '@/features/auth/composables/useFacebookLogin.js';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { mdiEye, mdiEyeOff, mdiGoogle } from '@mdi/js';
|
||||
import { mdiEye, mdiEyeOff, mdiFacebook, mdiGoogle } from '@mdi/js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const { loginWithFacebook } = useFacebookLogin();
|
||||
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
@@ -149,6 +173,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFacebookLogin() {
|
||||
try {
|
||||
const response = await loginWithFacebook();
|
||||
if (response === true) {
|
||||
await router.push(props.returnUrl);
|
||||
} else {
|
||||
errorSnackBar.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Facebook login failed:', error);
|
||||
errorSnackBar.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function forgotPassword() {
|
||||
router.push('/forgot-password');
|
||||
}
|
||||
@@ -159,6 +197,41 @@
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-page {
|
||||
@apply flex min-h-screen w-full items-stretch justify-center sm:items-center sm:p-4;
|
||||
}
|
||||
|
||||
.login-wrap {
|
||||
@apply flex min-h-screen w-full max-w-[512px] flex-col gap-6 sm:min-h-0;
|
||||
}
|
||||
|
||||
.login-brand {
|
||||
@apply mx-auto flex items-center gap-3 px-4 pt-6 no-underline sm:px-0 sm:pt-0;
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.login-brand-mark {
|
||||
@apply flex h-11 w-11 items-center justify-center rounded-2xl text-lg font-black;
|
||||
background: linear-gradient(135deg, #ff8a3d 0%, #ef4444 100%);
|
||||
color: #fffaf2;
|
||||
}
|
||||
|
||||
.login-brand-text {
|
||||
@apply text-lg font-black uppercase tracking-[0.18em];
|
||||
}
|
||||
|
||||
.login-card {
|
||||
@apply flex min-h-0 w-full flex-1 flex-col justify-center gap-10 bg-white/80 px-5 py-8 sm:flex-none sm:rounded-[1.5rem] sm:border sm:p-8;
|
||||
border-color: rgba(23, 32, 51, 0.08);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.login-card {
|
||||
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.visibility-toggle {
|
||||
@apply cursor-pointer;
|
||||
@apply transition-opacity duration-300;
|
||||
@@ -194,7 +267,8 @@
|
||||
"noAccount": "Don't have an account?",
|
||||
"register": "Register",
|
||||
"loginFailed": "Login failed. Please check your credentials.",
|
||||
"continueWithGoogle": "Continue with Google"
|
||||
"continueWithGoogle": "Continue with Google",
|
||||
"continueWithFacebook": "Continue with Facebook"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Se connecter",
|
||||
@@ -208,7 +282,8 @@
|
||||
"noAccount": "Vous n'avez pas de compte?",
|
||||
"register": "S'inscrire",
|
||||
"loginFailed": "Échec de la connexion. Veuillez vérifier vos identifiants.",
|
||||
"continueWithGoogle": "Continuer avec Google"
|
||||
"continueWithGoogle": "Continuer avec Google",
|
||||
"continueWithFacebook": "Continuer avec Facebook"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
Reference in New Issue
Block a user