From 189dcfc7268dcd57dfb66dc226e0a19c75954a77 Mon Sep 17 00:00:00 2001 From: Hyko Date: Wed, 22 Apr 2026 20:39:05 -0400 Subject: [PATCH] style(auth): replace inline card styles with Card component and clean up comments in ConfirmEmailPage --- .../auth/pages/ConfirmEmailPage.client.js | 147 +++---- .../auth/pages/ForgotPasswordPage.client.js | 217 ++++------ src/features/auth/pages/LoginPage.client.js | 272 +++++------- src/features/auth/pages/LogoutPage.client.js | 69 +-- .../auth/pages/RegisterPage.client.js | 401 +++++++----------- .../auth/pages/ResetPasswordPage.client.js | 257 ++++------- 6 files changed, 523 insertions(+), 840 deletions(-) diff --git a/src/features/auth/pages/ConfirmEmailPage.client.js b/src/features/auth/pages/ConfirmEmailPage.client.js index 46fbccf..3659b90 100644 --- a/src/features/auth/pages/ConfirmEmailPage.client.js +++ b/src/features/auth/pages/ConfirmEmailPage.client.js @@ -1,10 +1,7 @@ 'use client'; -/** - * Confirm Email Page Component - */ - import { useState, useEffect, useRef } from 'react'; +import { Card } from '@zen/core/shared/components'; export default function ConfirmEmailPage({ onSubmit, onNavigate, email, token }) { const [error, setError] = useState(''); @@ -15,26 +12,20 @@ export default function ConfirmEmailPage({ onSubmit, onNavigate, email, token }) useEffect(() => { console.log('ConfirmEmailPage useEffect triggered', { email, token, hasVerified }); - - // Check for persisted success message on mount + const persistedSuccess = sessionStorage.getItem('emailVerificationSuccess'); console.log('Persisted success message:', persistedSuccess); - + if (persistedSuccess) { console.log('Restoring persisted success message'); setSuccess(persistedSuccess); setIsLoading(false); - setHasVerified(true); // Mark as verified to prevent re-verification - // Clear the persisted message after showing it + setHasVerified(true); sessionStorage.removeItem('emailVerificationSuccess'); - // Redirect after showing the message - setTimeout(() => { - onNavigate('login'); - }, 3000); + setTimeout(() => onNavigate('login'), 3000); return; } - // Auto-verify on mount, but only once if (email && token && !hasVerified && !isVerifyingRef.current) { console.log('Starting email verification'); verifyEmail(); @@ -46,22 +37,18 @@ export default function ConfirmEmailPage({ onSubmit, onNavigate, email, token }) }, [email, token, hasVerified, onNavigate]); async function verifyEmail() { - // Prevent multiple calls if (hasVerified || isVerifyingRef.current) { console.log('Email verification already attempted or in progress'); return; } - - // Set flags IMMEDIATELY to prevent multiple calls + isVerifyingRef.current = true; setHasVerified(true); - - // Clear any existing states at the start setError(''); setSuccess(''); - + console.log('Starting email verification for:', email); - + const formData = new FormData(); formData.set('email', email); formData.set('token', token); @@ -69,20 +56,14 @@ export default function ConfirmEmailPage({ onSubmit, onNavigate, email, token }) try { const result = await onSubmit(formData); console.log('Verification result:', result); - + if (result.success) { console.log('Verification successful'); const successMessage = result.message || 'E-mail vérifié avec succès. Vous pouvez maintenant vous connecter.'; - - // Persist success message in sessionStorage sessionStorage.setItem('emailVerificationSuccess', successMessage); - setSuccess(successMessage); setIsLoading(false); - // Redirect to login after 3 seconds - setTimeout(() => { - onNavigate('login'); - }, 3000); + setTimeout(() => onNavigate('login'), 3000); } else { console.log('Verification failed:', result.error); setError(result.error || 'Échec de la vérification de l\'e-mail'); @@ -98,65 +79,55 @@ export default function ConfirmEmailPage({ onSubmit, onNavigate, email, token }) console.log('ConfirmEmailPage render', { success, error, isLoading, hasVerified }); return ( -
- {/* Header */} -
-

- Vérification de l'e-mail -

-

- Nous vérifions votre adresse e-mail... -

-
- - {isLoading && ( -
-
-

Vérification de votre e-mail en cours...

-
- )} - - {/* Success Message - Only show if success and no error */} - {success && !error && ( -
-
-
- {success} -
-
- )} - - {/* Error Message - Only show if error and no success */} - {error && !success && ( -
-
-
-
- {error} -
-
-
- { - e.preventDefault(); - onNavigate('login'); - }} - className="text-sm text-neutral-900 hover:text-neutral-600 font-medium transition-colors duration-200 dark:text-white dark:hover:text-neutral-300" - > - ← Retour à la connexion - -
-
- )} - - {/* Redirect message - Only show if success and no error */} - {success && !error && ( -

Redirection vers la connexion...

- )} + +
+

+ Vérification de l'e-mail +

+

+ Nous vérifions votre adresse e-mail... +

+ + {isLoading && ( +
+
+

Vérification de votre e-mail en cours...

+
+ )} + + {success && !error && ( +
+
+
+ {success} +
+
+ )} + + {error && !success && ( +
+
+
+
+ {error} +
+
+
+ { e.preventDefault(); onNavigate('login'); }} + className="text-sm text-neutral-900 hover:text-neutral-600 font-medium transition-colors duration-200 dark:text-white dark:hover:text-neutral-300" + > + ← Retour à la connexion + +
+
+ )} + + {success && !error && ( +

Redirection vers la connexion...

+ )} +
); } - - - diff --git a/src/features/auth/pages/ForgotPasswordPage.client.js b/src/features/auth/pages/ForgotPasswordPage.client.js index a7c0e12..afe7126 100644 --- a/src/features/auth/pages/ForgotPasswordPage.client.js +++ b/src/features/auth/pages/ForgotPasswordPage.client.js @@ -1,18 +1,13 @@ 'use client'; -/** - * Forgot Password Page Component - */ - import { useState, useEffect } from 'react'; +import { Card, Input, Button } from '@zen/core/shared/components'; export default function ForgotPasswordPage({ onSubmit, onNavigate, currentUser = null }) { const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const [success, setSuccess] = useState(''); - const [formData, setFormData] = useState({ - email: '' - }); + const [email, setEmail] = useState(''); const [honeypot, setHoneypot] = useState(''); const [formLoadedAt, setFormLoadedAt] = useState(0); @@ -20,14 +15,6 @@ export default function ForgotPasswordPage({ onSubmit, onNavigate, currentUser = setFormLoadedAt(Date.now()); }, []); - const handleChange = (e) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; - async function handleSubmit(e) { e.preventDefault(); setError(''); @@ -35,13 +22,13 @@ export default function ForgotPasswordPage({ onSubmit, onNavigate, currentUser = setIsLoading(true); const submitData = new FormData(); - submitData.append('email', formData.email); + submitData.append('email', email); submitData.append('_hp', honeypot); submitData.append('_t', String(formLoadedAt)); try { const result = await onSubmit(submitData); - + if (result.success) { setSuccess(result.message); setIsLoading(false); @@ -56,119 +43,91 @@ export default function ForgotPasswordPage({ onSubmit, onNavigate, currentUser = } } - const inputClasses = 'w-full px-3 py-2.5 rounded-lg text-sm focus:outline-none transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20'; - return ( -
- {/* Header */} -
-

- Mot de passe oublié -

-

- Entrez votre adresse e-mail et nous vous enverrons un lien pour réinitialiser votre mot de passe. -

-
- - {/* Already Connected Message */} - {currentUser && ( -
-
-
-
- - Vous êtes connecté en tant que {currentUser.name}.{' '} - - Se déconnecter ? - - -
-
-
- )} - - {/* Error Message */} - {error && ( -
-
-
- {error} -
-
- )} - - {/* Success Message */} - {success && ( -
-
-
- {success} -
-
- )} - - {/* Forgot Password Form */} -
- {/* Honeypot — invisible to humans, filled by bots */} - -
- - -
- - -
- - {/* Back to Login Link */} -
- { - e.preventDefault(); - if (!currentUser) { - onNavigate('login'); - } - }} - className="text-sm text-neutral-900 hover:text-neutral-600 font-medium transition-colors duration-200 dark:text-white dark:hover:text-neutral-300" - > - ← Retour à la connexion - -
+ +
+

+ Mot de passe oublié +

+

+ Entrez votre adresse e-mail et nous vous enverrons un lien pour réinitialiser votre mot de passe. +

+ + {currentUser && ( +
+
+
+ + Vous êtes connecté en tant que {currentUser.name}.{' '} + + Se déconnecter ? + + +
+
+ )} + + {error && ( +
+
+
+ {error} +
+
+ )} + + {success && ( +
+
+
+ {success} +
+
+ )} + +
+ + + + + +
+ +
+ { + e.preventDefault(); + if (!currentUser) onNavigate('login'); + }} + className="text-sm text-neutral-900 hover:text-neutral-600 font-medium transition-colors duration-200 dark:text-white dark:hover:text-neutral-300" + > + ← Retour à la connexion + +
+
); } - - - diff --git a/src/features/auth/pages/LoginPage.client.js b/src/features/auth/pages/LoginPage.client.js index b419441..6e4fef3 100644 --- a/src/features/auth/pages/LoginPage.client.js +++ b/src/features/auth/pages/LoginPage.client.js @@ -1,20 +1,14 @@ 'use client'; -/** - * Login Page Component - */ - import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; +import { Card, Input, Button } from '@zen/core/shared/components'; export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, redirectAfterLogin = '/', currentUser = null }) { const [error, setError] = useState(''); const [success, setSuccess] = useState(''); const [isLoading, setIsLoading] = useState(false); - const [formData, setFormData] = useState({ - email: '', - password: '' - }); + const [formData, setFormData] = useState({ email: '', password: '' }); const [honeypot, setHoneypot] = useState(''); const [formLoadedAt, setFormLoadedAt] = useState(0); const router = useRouter(); @@ -23,21 +17,12 @@ export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, re setFormLoadedAt(Date.now()); }, []); - // If already logged in, redirect to redirectAfterLogin useEffect(() => { if (currentUser) { router.replace(redirectAfterLogin); } }, [currentUser, redirectAfterLogin, router]); - const handleChange = (e) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; - const handleKeyPress = (e) => { if (e.key === 'Enter' && !isLoading && !success) { handleSubmit(); @@ -57,21 +42,16 @@ export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, re try { const result = await onSubmit(submitData); - + if (result.success) { const successMsg = result.message || 'Connexion réussie ! Redirection...'; - - // Display success message immediately (no page refresh because we didn't set cookie yet) setSuccess(successMsg); setIsLoading(false); - - // Wait for user to see the success message + setTimeout(async () => { - // Now set the session cookie (this might cause a refresh, but we're redirecting anyway) if (result.sessionToken && onSetSessionCookie) { await onSetSessionCookie(result.sessionToken); } - // Then navigate router.push(redirectAfterLogin); }, 1500); } else { @@ -85,144 +65,114 @@ export default function LoginPage({ onSubmit, onNavigate, onSetSessionCookie, re } }; - const inputClasses = 'w-full px-[10px] py-[7px] rounded text-[13px] focus:outline-none transition-all duration-[120ms] ease-out disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20'; - return ( -
- {/* Header */} -
-

- Connexion -

-

- Veuillez vous connecter pour continuer. -

-
- - {/* Already logged in: redirecting (brief message while redirect runs) */} - {currentUser && ( -
-
-
- Redirection... -
-
- )} - - {/* Success Message */} - {success && ( -
-
-
- {success} -
-
- )} - - {/* Error Message */} - {error && ( -
-
-
- {error} -
-
- )} - - {/* Login Form */} -
- {/* Honeypot — invisible to humans, filled by bots */} - -
- - -
- - - - -
- - {/* Register Link */} -
- - { - e.preventDefault(); - if (!currentUser) { - onNavigate('register'); - } - }} - className="group flex items-center justify-center gap-2" - > - Pas de compte ? - S'inscrire - -
+ +
+

+ Connexion +

+

+ Veuillez vous connecter pour continuer. +

+ + {currentUser && ( +
+
+
+ Redirection... +
+
+ )} + + {success && ( +
+
+
+ {success} +
+
+ )} + + {error && ( +
+
+
+ {error} +
+
+ )} + +
+ + + setFormData(prev => ({ ...prev, email: value }))} + onKeyDown={handleKeyPress} + placeholder="your@email.com" + disabled={!!success || !!currentUser} + required + /> + +
+ + setFormData(prev => ({ ...prev, password: value }))} + onKeyDown={handleKeyPress} + placeholder="••••••••" + disabled={!!success || !!currentUser} + /> +
+ + +
+ + +
); } - - - diff --git a/src/features/auth/pages/LogoutPage.client.js b/src/features/auth/pages/LogoutPage.client.js index 6e383f5..59f7c56 100644 --- a/src/features/auth/pages/LogoutPage.client.js +++ b/src/features/auth/pages/LogoutPage.client.js @@ -1,11 +1,8 @@ 'use client'; -/** - * Logout Page Component - */ - import { useState } from 'react'; import { useRouter } from 'next/navigation'; +import { Card, Button } from '@zen/core/shared/components'; export default function LogoutPage({ onLogout, onSetSessionCookie }) { const [error, setError] = useState(''); @@ -19,10 +16,8 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) { setIsLoading(true); try { - // Call the logout action if provided if (onLogout) { const result = await onLogout(); - if (result && !result.success) { setError(result.error || 'Échec de la déconnexion'); setIsLoading(false); @@ -30,20 +25,14 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) { } } - // Clear session cookie if provided if (onSetSessionCookie) { await onSetSessionCookie('', { expires: new Date(0) }); } - // Show success message setSuccess('Vous avez été déconnecté. Redirection...'); setIsLoading(false); - - // Wait for user to see the success message, then redirect - setTimeout(() => { - router.push('/'); - }, 100); - + + setTimeout(() => router.push('/'), 100); } catch (err) { console.error('Logout error:', err); setError('Une erreur inattendue s\'est produite lors de la déconnexion'); @@ -52,8 +41,7 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) { }; return ( -
- {/* Header */} +

Prêt à vous déconnecter ? @@ -63,7 +51,6 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) {

- {/* Success Message */} {success && (
@@ -73,7 +60,6 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) {
)} - {/* Error Message */} {error && (
@@ -83,35 +69,26 @@ export default function LogoutPage({ onLogout, onSetSessionCookie }) {
)} - {/* Logout Button */} -
- -
+ - {/* Cancel Link */}
- Vous avez changé d'avis ? - - Retour - -
-
+ Vous avez changé d'avis ? + + Retour + +
+
); } diff --git a/src/features/auth/pages/RegisterPage.client.js b/src/features/auth/pages/RegisterPage.client.js index f0f3fb9..878301c 100644 --- a/src/features/auth/pages/RegisterPage.client.js +++ b/src/features/auth/pages/RegisterPage.client.js @@ -1,11 +1,7 @@ 'use client'; -/** - * Register Page Component - */ - import { useState, useEffect } from 'react'; -import { PasswordStrengthIndicator } from '@zen/core/shared/components'; +import { Card, Input, Button, PasswordStrengthIndicator } from '@zen/core/shared/components'; export default function RegisterPage({ onSubmit, onNavigate, currentUser = null }) { const [error, setError] = useState(''); @@ -24,107 +20,50 @@ export default function RegisterPage({ onSubmit, onNavigate, currentUser = null setFormLoadedAt(Date.now()); }, []); - // Validation functions const validateEmail = (email) => { const errors = []; - - if (email.length > 254) { - errors.push('L\'e-mail doit contenir 254 caractères ou moins'); - } - + if (email.length > 254) errors.push('L\'e-mail doit contenir 254 caractères ou moins'); return errors; }; const validatePassword = (password) => { const errors = []; - - if (password.length < 8) { - errors.push('Le mot de passe doit contenir au moins 8 caractères'); - } - - if (password.length > 128) { - errors.push('Le mot de passe doit contenir 128 caractères ou moins'); - } - - if (!/[A-Z]/.test(password)) { - errors.push('Le mot de passe doit contenir au moins une majuscule'); - } - - if (!/[a-z]/.test(password)) { - errors.push('Le mot de passe doit contenir au moins une minuscule'); - } - - if (!/\d/.test(password)) { - errors.push('Le mot de passe doit contenir au moins un chiffre'); - } - + if (password.length < 8) errors.push('Le mot de passe doit contenir au moins 8 caractères'); + if (password.length > 128) errors.push('Le mot de passe doit contenir 128 caractères ou moins'); + if (!/[A-Z]/.test(password)) errors.push('Le mot de passe doit contenir au moins une majuscule'); + if (!/[a-z]/.test(password)) errors.push('Le mot de passe doit contenir au moins une minuscule'); + if (!/\d/.test(password)) errors.push('Le mot de passe doit contenir au moins un chiffre'); return errors; }; const validateName = (name) => { const errors = []; - - if (name.trim().length === 0) { - errors.push('Le nom ne peut pas être vide'); - } - - if (name.length > 100) { - errors.push('Le nom doit contenir 100 caractères ou moins'); - } - + if (name.trim().length === 0) errors.push('Le nom ne peut pas être vide'); + if (name.length > 100) errors.push('Le nom doit contenir 100 caractères ou moins'); return errors; }; const isFormValid = () => { - const emailErrors = validateEmail(formData.email); - const passwordErrors = validatePassword(formData.password); - const nameErrors = validateName(formData.name); - - return emailErrors.length === 0 && - passwordErrors.length === 0 && - nameErrors.length === 0 && + return validateEmail(formData.email).length === 0 && + validatePassword(formData.password).length === 0 && + validateName(formData.name).length === 0 && formData.password === formData.confirmPassword && formData.email.trim().length > 0; }; - const handleChange = (e) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; - async function handleSubmit(e) { e.preventDefault(); setError(''); setSuccess(''); setIsLoading(true); - // Frontend validation const emailErrors = validateEmail(formData.email); const passwordErrors = validatePassword(formData.password); const nameErrors = validateName(formData.name); - - if (emailErrors.length > 0) { - setError(emailErrors[0]); // Show first error - setIsLoading(false); - return; - } - - if (passwordErrors.length > 0) { - setError(passwordErrors[0]); // Show first error - setIsLoading(false); - return; - } - - if (nameErrors.length > 0) { - setError(nameErrors[0]); // Show first error - setIsLoading(false); - return; - } - // Validate password match + if (emailErrors.length > 0) { setError(emailErrors[0]); setIsLoading(false); return; } + if (passwordErrors.length > 0) { setError(passwordErrors[0]); setIsLoading(false); return; } + if (nameErrors.length > 0) { setError(nameErrors[0]); setIsLoading(false); return; } if (formData.password !== formData.confirmPassword) { setError('Les mots de passe ne correspondent pas'); setIsLoading(false); @@ -141,7 +80,7 @@ export default function RegisterPage({ onSubmit, onNavigate, currentUser = null try { const result = await onSubmit(submitData); - + if (result.success) { setSuccess(result.message); setIsLoading(false); @@ -156,182 +95,140 @@ export default function RegisterPage({ onSubmit, onNavigate, currentUser = null } } - const inputClasses = 'w-full px-3 py-2.5 rounded-lg text-sm focus:outline-none transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20'; - return ( -
- {/* Header */} -
-

- Créer un compte -

-

- Inscrivez-vous pour commencer. -

-
- - {/* Already Connected Message */} - {currentUser && ( -
-
-
-
- - Vous êtes connecté en tant que {currentUser.name}.{' '} - - Se déconnecter ? - - -
-
-
- )} - - {/* Error Message */} - {error && ( -
-
-
- {error} -
-
- )} - - {/* Success Message */} - {success && ( -
-
-
- {success} -
-
- )} - - {/* Registration Form */} -
- {/* Honeypot — invisible to humans, filled by bots */} - -
- - -
- -
- - -
- -
- - - -
- -
- - -
- - -
- - {/* Login Link */} - + +
+

+ Créer un compte +

+

+ Inscrivez-vous pour commencer. +

+ + {currentUser && ( +
+
+
+ + Vous êtes connecté en tant que {currentUser.name}.{' '} + + Se déconnecter ? + + +
+
+ )} + + {error && ( +
+
+
+ {error} +
+
+ )} + + {success && ( +
+
+
+ {success} +
+
+ )} + +
+ + + setFormData(prev => ({ ...prev, name: value }))} + placeholder="John Doe" + disabled={!!success || !!currentUser} + maxLength="100" + autoComplete="name" + required + /> + + setFormData(prev => ({ ...prev, email: value }))} + placeholder="your@email.com" + disabled={!!success || !!currentUser} + maxLength="254" + autoComplete="email" + required + /> + +
+ setFormData(prev => ({ ...prev, password: value }))} + placeholder="••••••••" + disabled={!!success || !!currentUser} + minLength="8" + maxLength="128" + autoComplete="new-password" + required + /> + +
+ + setFormData(prev => ({ ...prev, confirmPassword: value }))} + placeholder="••••••••" + disabled={!!success || !!currentUser} + minLength="8" + maxLength="128" + autoComplete="new-password" + required + /> + + +
+ + +
); } - - - diff --git a/src/features/auth/pages/ResetPasswordPage.client.js b/src/features/auth/pages/ResetPasswordPage.client.js index 9ece52b..fcc7545 100644 --- a/src/features/auth/pages/ResetPasswordPage.client.js +++ b/src/features/auth/pages/ResetPasswordPage.client.js @@ -1,80 +1,38 @@ 'use client'; -/** - * Reset Password Page Component - */ - import { useState } from 'react'; -import { PasswordStrengthIndicator } from '@zen/core/shared/components'; +import { Card, Input, Button, PasswordStrengthIndicator } from '@zen/core/shared/components'; export default function ResetPasswordPage({ onSubmit, onNavigate, email, token }) { const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const [success, setSuccess] = useState(''); - const [formData, setFormData] = useState({ - newPassword: '', - confirmPassword: '' - }); + const [formData, setFormData] = useState({ newPassword: '', confirmPassword: '' }); - // Validation functions const validatePassword = (password) => { const errors = []; - - if (password.length < 8) { - errors.push('Le mot de passe doit contenir au moins 8 caractères'); - } - - if (password.length > 128) { - errors.push('Le mot de passe doit contenir 128 caractères ou moins'); - } - - if (!/[A-Z]/.test(password)) { - errors.push('Le mot de passe doit contenir au moins une majuscule'); - } - - if (!/[a-z]/.test(password)) { - errors.push('Le mot de passe doit contenir au moins une minuscule'); - } - - if (!/\d/.test(password)) { - errors.push('Le mot de passe doit contenir au moins un chiffre'); - } - + if (password.length < 8) errors.push('Le mot de passe doit contenir au moins 8 caractères'); + if (password.length > 128) errors.push('Le mot de passe doit contenir 128 caractères ou moins'); + if (!/[A-Z]/.test(password)) errors.push('Le mot de passe doit contenir au moins une majuscule'); + if (!/[a-z]/.test(password)) errors.push('Le mot de passe doit contenir au moins une minuscule'); + if (!/\d/.test(password)) errors.push('Le mot de passe doit contenir au moins un chiffre'); return errors; }; const isFormValid = () => { - const passwordErrors = validatePassword(formData.newPassword); - - return passwordErrors.length === 0 && + return validatePassword(formData.newPassword).length === 0 && formData.newPassword === formData.confirmPassword && formData.newPassword.length > 0; }; - const handleChange = (e) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; - async function handleSubmit(e) { e.preventDefault(); setError(''); setSuccess(''); setIsLoading(true); - // Frontend validation const passwordErrors = validatePassword(formData.newPassword); - - if (passwordErrors.length > 0) { - setError(passwordErrors[0]); // Show first error - setIsLoading(false); - return; - } - - // Validate password match + if (passwordErrors.length > 0) { setError(passwordErrors[0]); setIsLoading(false); return; } if (formData.newPassword !== formData.confirmPassword) { setError('Les mots de passe ne correspondent pas'); setIsLoading(false); @@ -89,14 +47,11 @@ export default function ResetPasswordPage({ onSubmit, onNavigate, email, token } try { const result = await onSubmit(submitData); - + if (result.success) { setSuccess(result.message); setIsLoading(false); - // Redirect to login after 2 seconds - setTimeout(() => { - onNavigate('login'); - }, 2000); + setTimeout(() => onNavigate('login'), 2000); } else { setError(result.error || 'Échec de la réinitialisation du mot de passe'); setIsLoading(false); @@ -108,115 +63,89 @@ export default function ResetPasswordPage({ onSubmit, onNavigate, email, token } } } - const inputClasses = 'w-full px-3 py-2.5 rounded-lg text-sm focus:outline-none transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed bg-white border border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:ring-1 focus:ring-neutral-500/20 dark:bg-neutral-900 dark:border-neutral-700/50 dark:text-white dark:placeholder-neutral-500 dark:focus:border-neutral-600 dark:focus:ring-neutral-600/20'; - return ( -
- {/* Header */} -
-

- Réinitialiser le mot de passe -

-

- Saisissez votre nouveau mot de passe ci-dessous. -

-
- - {/* Error Message */} - {error && ( -
-
-
- {error} -
-
- )} - - {/* Success Message */} - {success && ( -
-
-
- {success} -
-
- )} - - {/* Reset Password Form */} -
-
- - - -
- -
- - -
- - -
- - {/* Back to Login Link */} - + +
+

+ Réinitialiser le mot de passe +

+

+ Saisissez votre nouveau mot de passe ci-dessous. +

+ + {error && ( +
+
+
+ {error} +
+
+ )} + + {success && ( +
+
+
+ {success} +
+
+ )} + +
+
+ setFormData(prev => ({ ...prev, newPassword: value }))} + placeholder="••••••••" + disabled={!!success} + minLength="8" + maxLength="128" + autoComplete="new-password" + required + /> + +
+ + setFormData(prev => ({ ...prev, confirmPassword: value }))} + placeholder="••••••••" + disabled={!!success} + minLength="8" + maxLength="128" + autoComplete="new-password" + required + /> + + +
+ + +
); } - - -