veza/apps/web/src/features/auth/pages/ForgotPasswordPage.tsx
2025-12-12 21:34:34 -05:00

128 lines
4 KiB
TypeScript

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { AuthLayout } from '../components/AuthLayout';
import { AuthInput } from '../components/AuthInput';
import { AuthButton } from '../components/AuthButton';
import { usePasswordReset } from '../hooks/usePasswordReset';
import type { ForgotPasswordFormData } from '../types';
export function ForgotPasswordPage() {
const { handleRequestReset, loading, error, success } = usePasswordReset();
const [formData, setFormData] = useState<ForgotPasswordFormData>({
email: '',
});
const [errors, setErrors] = useState<
Partial<Record<keyof ForgotPasswordFormData, string>>
>({});
const validate = (): boolean => {
const newErrors: Partial<Record<keyof ForgotPasswordFormData, string>> = {};
if (!formData.email) {
newErrors.email = 'Email requis';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email invalide';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleChange = (field: keyof ForgotPasswordFormData, value: string) => {
setFormData({ ...formData, [field]: value });
// Clear error for this field when user starts typing
if (errors[field]) {
setErrors({ ...errors, [field]: undefined });
}
};
const handleBlur = (field: keyof ForgotPasswordFormData) => {
const value = formData[field];
let error: string | undefined;
if (field === 'email') {
if (!value) {
error = 'Email requis';
} else if (!/\S+@\S+\.\S+/.test(value)) {
error = 'Email invalide';
}
}
if (error) {
setErrors({ ...errors, [field]: error });
} else {
setErrors({ ...errors, [field]: undefined });
}
};
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (validate()) {
await handleRequestReset(formData);
}
};
return (
<AuthLayout
title="Mot de passe oublié"
subtitle="Entrez votre email pour recevoir un lien de réinitialisation"
footerLinks={[{ label: 'Retour à la connexion', to: '/login' }]}
>
{success ? (
<div className="text-center space-y-4" role="status" aria-live="polite">
<div
className="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded"
role="alert"
aria-live="assertive"
>
<p className="font-medium">Email envoyé !</p>
<p className="text-sm mt-1">
Un lien de réinitialisation a é envoyé à {formData.email}
</p>
</div>
<p className="text-sm text-gray-600">
Veuillez vérifier votre boîte mail et cliquer sur le lien pour
réinitialiser votre mot de passe.
</p>
<Link
to="/login"
className="text-blue-600 hover:underline text-sm block focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded"
>
Retour à la connexion
</Link>
</div>
) : (
<form
onSubmit={onSubmit}
className="space-y-4"
aria-label="Formulaire de réinitialisation de mot de passe"
>
{error && (
<div
className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded"
role="alert"
aria-live="assertive"
>
{error.message}
</div>
)}
<AuthInput
type="email"
label="Email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
onBlur={() => handleBlur('email')}
error={errors.email}
required
autoComplete="email"
/>
<AuthButton type="submit" loading={loading}>
Envoyer le lien de réinitialisation
</AuthButton>
</form>
)}
</AuthLayout>
);
}
export default ForgotPasswordPage;