refactor(auth): cleanup auth module and streamline the registration flow
This commit is contained in:
257
frontend/src/views/auth/RegisterView.vue
Normal file
257
frontend/src/views/auth/RegisterView.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<div class="flex min-h-full w-full items-center justify-center p-20">
|
||||
<!-- Show verification message on success -->
|
||||
<div
|
||||
v-if="registrationSuccess"
|
||||
class="card justify-items-center"
|
||||
>
|
||||
<img
|
||||
:alt="t('alt')"
|
||||
src="/images/hutopymedia/loginpage/hutopylogin.svg"
|
||||
/>
|
||||
<div class="flex flex-col gap-10 text-center">
|
||||
<h1 class="login-text text-2xl font-bold text-green-600">
|
||||
{{ t('success.title') }}
|
||||
</h1>
|
||||
<div class="text-hOnSurface">
|
||||
<p>{{ t('success.message') }}</p>
|
||||
<p class="mt-2 font-medium">{{ userEmail }}</p>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-col gap-2">
|
||||
<router-link
|
||||
class="text-blue-500 hover:underline"
|
||||
to="/login"
|
||||
>
|
||||
{{ t('success.backToLogin') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="text-blue-500 hover:underline"
|
||||
:to="{ path: '/verify-email', query: { email: userEmail } }"
|
||||
>
|
||||
{{ t('success.resendVerification') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Show registration form -->
|
||||
<div
|
||||
v-else
|
||||
class="card justify-items-center"
|
||||
>
|
||||
<img
|
||||
:alt="t('alt')"
|
||||
src="/images/hutopymedia/loginpage/hutopylogin.svg"
|
||||
/>
|
||||
<div class="flex flex-col gap-10">
|
||||
<h1 class="login-text text-center text-2xl font-bold">
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
|
||||
<v-form @submit.prevent="handleRegister">
|
||||
<div class="flex flex-col gap-4">
|
||||
<v-text-field
|
||||
v-model="name"
|
||||
:label="t('name')"
|
||||
required
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="email"
|
||||
:label="t('email')"
|
||||
required
|
||||
type="email"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
:hint="t('passwordRequirements')"
|
||||
: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-text-field
|
||||
v-model="confirmPassword"
|
||||
:label="t('confirmPassword')"
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
required
|
||||
>
|
||||
<template v-slot:append-inner>
|
||||
<v-icon
|
||||
:icon="showConfirmPassword ? mdiEyeOff : mdiEye"
|
||||
class="visibility-toggle"
|
||||
size="small"
|
||||
@click="showConfirmPassword = !showConfirmPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<v-btn
|
||||
:loading="isLoading"
|
||||
block
|
||||
color="primary"
|
||||
type="submit"
|
||||
>
|
||||
{{ t('register') }}
|
||||
</v-btn>
|
||||
|
||||
<!-- Error message displayed as block text below submit button -->
|
||||
<div
|
||||
v-if="errorMessage"
|
||||
class="mt-2 p-3 bg-red-50 border border-red-200 rounded text-red-700 text-sm"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
{{ t('alreadyHaveAccount') }}
|
||||
<router-link
|
||||
class="text-blue-500"
|
||||
to="/login"
|
||||
>
|
||||
{{ t('signIn') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</v-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { mdiEye, mdiEyeOff } from '@mdi/js';
|
||||
|
||||
const { t } = useI18n();
|
||||
const clientApi = useClient();
|
||||
|
||||
const name = ref('');
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
const confirmPassword = ref('');
|
||||
const isLoading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const showPassword = ref(false);
|
||||
const showConfirmPassword = ref(false);
|
||||
const registrationSuccess = ref(false);
|
||||
const userEmail = ref('');
|
||||
|
||||
async function handleRegister() {
|
||||
if (password.value !== confirmPassword.value) {
|
||||
errorMessage.value = t('passwordsDoNotMatch');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
await clientApi.post('api/users/register', {
|
||||
name: name.value,
|
||||
email: email.value.trim(),
|
||||
password: password.value,
|
||||
});
|
||||
|
||||
// On success, show verification message
|
||||
userEmail.value = email.value.trim();
|
||||
registrationSuccess.value = true;
|
||||
} catch (error) {
|
||||
console.error('Registration failed:', error);
|
||||
errorMessage.value = error.response?.data?.message || t('registrationFailed');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.visibility-toggle {
|
||||
@apply cursor-pointer;
|
||||
@apply transition-opacity duration-300;
|
||||
@apply opacity-60 hover:opacity-100;
|
||||
@apply z-10;
|
||||
}
|
||||
|
||||
/* Override Vuetify's default padding to accommodate our icon */
|
||||
:deep(.v-field__append-inner) {
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Create your account",
|
||||
"alt": "Hutopy Registration",
|
||||
"name": "Full Name",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"passwordRequirements": "Password must be at least 8 characters",
|
||||
"register": "Register",
|
||||
"alreadyHaveAccount": "Already have an account?",
|
||||
"signIn": "Sign in",
|
||||
"passwordsDoNotMatch": "Passwords do not match",
|
||||
"registrationFailed": "Registration failed. Please try again.",
|
||||
"success": {
|
||||
"title": "Registration Successful!",
|
||||
"message": "Please check your email to verify your account. We've sent a verification link to:",
|
||||
"backToLogin": "Back to Login",
|
||||
"resendVerification": "Didn't receive the email? Resend verification"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"title": "Créer votre compte",
|
||||
"alt": "Inscription Hutopy",
|
||||
"name": "Nom complet",
|
||||
"email": "Email",
|
||||
"password": "Mot de passe",
|
||||
"confirmPassword": "Confirmer le mot de passe",
|
||||
"passwordRequirements": "Le mot de passe doit comporter au moins 8 caractères",
|
||||
"register": "S'inscrire",
|
||||
"alreadyHaveAccount": "Vous avez déjà un compte?",
|
||||
"signIn": "Se connecter",
|
||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
|
||||
"registrationFailed": "L'inscription a échoué. Veuillez réessayer.",
|
||||
"success": {
|
||||
"title": "Inscription réussie!",
|
||||
"message": "Veuillez vérifier votre email pour activer votre compte. Nous avons envoyé un lien de vérification à:",
|
||||
"backToLogin": "Retour à la connexion",
|
||||
"resendVerification": "Vous n'avez pas reçu l'email? Renvoyer la vérification"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"title": "Crea tu cuenta",
|
||||
"alt": "Registro de Hutopy",
|
||||
"name": "Nombre completo",
|
||||
"email": "Correo electrónico",
|
||||
"password": "Contraseña",
|
||||
"confirmPassword": "Confirmar contraseña",
|
||||
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres",
|
||||
"register": "Registrarse",
|
||||
"alreadyHaveAccount": "¿Ya tienes una cuenta?",
|
||||
"signIn": "Iniciar sesión",
|
||||
"passwordsDoNotMatch": "Las contraseñas no coinciden",
|
||||
"registrationFailed": "El registro falló. Por favor, inténtelo de nuevo.",
|
||||
"success": {
|
||||
"title": "¡Registro exitoso!",
|
||||
"message": "Por favor revisa tu correo electrónico para verificar tu cuenta. Hemos enviado un enlace de verificación a:",
|
||||
"backToLogin": "Volver al inicio de sesión",
|
||||
"resendVerification": "¿No recibiste el correo? Reenviar verificación"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
Reference in New Issue
Block a user