198 lines
6.5 KiB
TypeScript
198 lines
6.5 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
import { AlertCircle, CheckCircle, Lock } from "lucide-react";
|
|
import userService from "@/api/user";
|
|
|
|
export default function ResetPassword() {
|
|
const [searchParams] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const token = searchParams.get("token");
|
|
|
|
const [newPassword, setNewPassword] = useState("");
|
|
const [confirmPassword, setConfirmPassword] = useState("");
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [status, setStatus] = useState<{
|
|
type: "success" | "error";
|
|
message: string;
|
|
} | null>(null);
|
|
const [countdown, setCountdown] = useState(0);
|
|
|
|
useEffect(() => {
|
|
// Vérifier si le token est présent
|
|
if (!token) {
|
|
setStatus({
|
|
type: "error",
|
|
message: "Token de réinitialisation manquant. Veuillez demander un nouveau lien de réinitialisation."
|
|
});
|
|
}
|
|
}, [token]);
|
|
|
|
useEffect(() => {
|
|
// Rediriger vers la page de connexion après un succès
|
|
if (status?.type === "success" && countdown > 0) {
|
|
const timer = setTimeout(() => {
|
|
setCountdown(countdown - 1);
|
|
}, 1000);
|
|
|
|
return () => clearTimeout(timer);
|
|
} else if (status?.type === "success" && countdown === 0) {
|
|
navigate("/auth/login");
|
|
}
|
|
}, [status, countdown, navigate]);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
// Réinitialiser le statut
|
|
setStatus(null);
|
|
|
|
// Vérifier si le token est présent
|
|
if (!token) {
|
|
setStatus({
|
|
type: "error",
|
|
message: "Token de réinitialisation manquant. Veuillez demander un nouveau lien de réinitialisation."
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Vérifier que les mots de passe correspondent
|
|
if (newPassword !== confirmPassword) {
|
|
setStatus({
|
|
type: "error",
|
|
message: "Les mots de passe ne correspondent pas."
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Vérifier la longueur du mot de passe
|
|
if (newPassword.length < 8) {
|
|
setStatus({
|
|
type: "error",
|
|
message: "Le mot de passe doit contenir au moins 8 caractères."
|
|
});
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setIsSubmitting(true);
|
|
|
|
await userService.resetPassword({
|
|
token,
|
|
newPassword
|
|
});
|
|
|
|
setStatus({
|
|
type: "success",
|
|
message: "Votre mot de passe a été réinitialisé avec succès. Vous allez être redirigé vers la page de connexion."
|
|
});
|
|
|
|
// Démarrer le compte à rebours pour la redirection
|
|
setCountdown(5);
|
|
|
|
} catch (error) {
|
|
console.error("Erreur lors de la réinitialisation du mot de passe:", error);
|
|
|
|
setStatus({
|
|
type: "error",
|
|
message: "Impossible de réinitialiser le mot de passe. Le lien est peut-être expiré ou invalide."
|
|
});
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="container flex items-center justify-center min-h-screen py-10">
|
|
<Card className="w-full max-w-md">
|
|
<CardHeader className="space-y-1">
|
|
<div className="flex justify-center mb-4">
|
|
<div className="p-3 rounded-full bg-primary/10">
|
|
<Lock className="h-6 w-6 text-primary" />
|
|
</div>
|
|
</div>
|
|
<CardTitle className="text-2xl text-center">Réinitialisation du mot de passe</CardTitle>
|
|
<CardDescription className="text-center">
|
|
Créez un nouveau mot de passe pour votre compte
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
{status && (
|
|
<Alert className={`mb-4 ${status.type === "error" ? "bg-red-50 text-red-700 dark:bg-red-900/20 dark:text-red-300" : "bg-green-50 text-green-700 dark:bg-green-900/20 dark:text-green-300"}`}>
|
|
{status.type === "error" ? (
|
|
<AlertCircle className="h-4 w-4 mr-2" />
|
|
) : (
|
|
<CheckCircle className="h-4 w-4 mr-2" />
|
|
)}
|
|
<AlertTitle>{status.type === "error" ? "Erreur" : "Succès"}</AlertTitle>
|
|
<AlertDescription>
|
|
{status.message}
|
|
{status.type === "success" && countdown > 0 && (
|
|
<span className="font-bold"> ({countdown})</span>
|
|
)}
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="new-password">Nouveau mot de passe</Label>
|
|
<Input
|
|
id="new-password"
|
|
type="password"
|
|
placeholder="••••••••"
|
|
value={newPassword}
|
|
onChange={(e) => setNewPassword(e.target.value)}
|
|
required
|
|
disabled={isSubmitting || status?.type === "success"}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="confirm-password">Confirmer le mot de passe</Label>
|
|
<Input
|
|
id="confirm-password"
|
|
type="password"
|
|
placeholder="••••••••"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
required
|
|
disabled={isSubmitting || status?.type === "success"}
|
|
/>
|
|
</div>
|
|
|
|
<Button
|
|
type="submit"
|
|
className="w-full"
|
|
disabled={isSubmitting || status?.type === "success"}
|
|
>
|
|
{isSubmitting ? (
|
|
<>
|
|
<div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent"></div>
|
|
Réinitialisation en cours...
|
|
</>
|
|
) : (
|
|
"Réinitialiser le mot de passe"
|
|
)}
|
|
</Button>
|
|
</form>
|
|
</CardContent>
|
|
|
|
<CardFooter className="flex justify-center">
|
|
<Button
|
|
variant="link"
|
|
onClick={() => navigate("/auth/login")}
|
|
disabled={isSubmitting}
|
|
>
|
|
Retour à la connexion
|
|
</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|