173 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import type { Route } from "./+types/verify";
 | |
| import {
 | |
|   ArrowLeft,
 | |
|   CheckCircleIcon,
 | |
|   // LoaderIcon,
 | |
|   // RefreshCwIcon,
 | |
| } from "lucide-react";
 | |
| import { useEffect, useState } from "react";
 | |
| import { useNavigate } from "react-router";
 | |
| import { useSearchParams } from "react-router";
 | |
| import OtpInput from "~/components/input-otp";
 | |
| import { Alert, AlertDescription } from "~/components/ui/alert";
 | |
| import { Button } from "~/components/ui/button";
 | |
| import { AuthLayout } from "~/layout";
 | |
| 
 | |
| export function meta({ }: Route.MetaArgs) {
 | |
|   return [
 | |
|     { title: "Khollisé - Connexion" },
 | |
|     { name: "description", content: "Connectez-vous à Khollisé" },
 | |
|   ];
 | |
| }
 | |
| 
 | |
| export default function Verify() {
 | |
|   const navigate = useNavigate();
 | |
|   const [searchParams] = useSearchParams()
 | |
|   const email = searchParams.get("email");
 | |
| 
 | |
|   useEffect(() => {
 | |
|     if (!email) {
 | |
|       navigate("/login", { replace: true });
 | |
|       return;
 | |
|     }
 | |
|   }, [email]);
 | |
| 
 | |
|   // const [isResending, setIsResending] = useState(false);
 | |
|   // const [resendSuccess, setResendSuccess] = useState(false);
 | |
|   const [cooldown, setCooldown] = useState(0);
 | |
|   const [otpError, setOtpError] = useState<string | null>(null);
 | |
| 
 | |
|   // Countdown for the resend button
 | |
|   useEffect(() => {
 | |
|     if (cooldown <= 0) return;
 | |
| 
 | |
|     const timer = setInterval(() => {
 | |
|       setCooldown((prev) => Math.max(0, prev - 1));
 | |
|     }, 1000);
 | |
| 
 | |
|     return () => clearInterval(timer);
 | |
|   }, [cooldown]);
 | |
| 
 | |
|   // const handleResendOtp = async () => {
 | |
|   //   if (cooldown > 0) return;
 | |
| 
 | |
|   //   setIsResending(true);
 | |
|   //   setResendSuccess(false);
 | |
| 
 | |
|   //   try {
 | |
|   //     // Appeler l'API pour renvoyer un code OTP
 | |
|   //     const response = await fetch("/api/auth/resend-otp", {
 | |
|   //       method: "POST",
 | |
|   //       headers: {
 | |
|   //         "Content-Type": "application/json",
 | |
|   //       },
 | |
|   //       body: JSON.stringify({ email }),
 | |
|   //     });
 | |
| 
 | |
|   //     const data = await response.json();
 | |
| 
 | |
|   //     if (!response.ok) {
 | |
|   //       throw new Error(data.error || "Échec de l'envoi du nouveau code");
 | |
|   //     }
 | |
| 
 | |
|   //     // Afficher le message de succès
 | |
|   //     setResendSuccess(true);
 | |
|   //     // Démarrer le cooldown (60 secondes)
 | |
|   //     setCooldown(60);
 | |
|   //   } catch (error) {
 | |
|   //     console.error("Erreur lors de la demande d'un nouveau code:", error);
 | |
|   //     setOtpError(
 | |
|   //       error instanceof Error
 | |
|   //         ? error.message
 | |
|   //         : "Échec de l'envoi du nouveau code"
 | |
|   //     );
 | |
|   //   } finally {
 | |
|   //     setIsResending(false);
 | |
|   //   }
 | |
|   // };
 | |
| 
 | |
|   return (
 | |
|     <AuthLayout>
 | |
|       <div className="space-y-4">
 | |
|         <Alert className="bg-green-50 border-green-200 pb-2">
 | |
|           <CheckCircleIcon className="h-4 w-4 text-green-600" />
 | |
|           <AlertDescription className="text-green-600">
 | |
|             Nous avons envoyé un email à <strong>{email}</strong>
 | |
|           </AlertDescription>
 | |
|         </Alert>
 | |
| 
 | |
|         <div className="space-y-2 mt-4">
 | |
|           <h3 className="font-medium">Que se passe-t-il ensuite ?</h3>
 | |
|           <ul className="list-disc pl-5 space-y-1 text-sm">
 | |
|             <li>Consultez votre email (vérifiez le dossier spam)</li>
 | |
|             <li>
 | |
|               {/* TODO: Magic link
 | |
|               Cliquez sur le lien pour vous connecter ou entrez le code à 6
 | |
|               chiffres */}
 | |
|               Entrez le code à 6 chiffres que vous avez reçu
 | |
|             </li>
 | |
|           </ul>
 | |
|         </div>
 | |
| 
 | |
|         <div className="mt-6 border-t pt-4">
 | |
|           <h3 className="text-sm text-center font-medium mb-2">
 | |
|             Entrez le code de vérification
 | |
|           </h3>
 | |
|           <OtpInput
 | |
|             email={email!}
 | |
|             setOtpError={setOtpError}
 | |
|             otpError={otpError}
 | |
|           />
 | |
| 
 | |
|           {/* TODO: Resend OTP
 | |
|           {resendSuccess && (
 | |
|             <Alert className="bg-green-50 border-green-200 mt-2">
 | |
|               <CheckCircleIcon className="h-4 w-4 text-green-600" />
 | |
|               <AlertDescription className="text-green-600">
 | |
|                 Un nouveau code a été envoyé à votre adresse email
 | |
|               </AlertDescription>
 | |
|             </Alert>
 | |
|           )} */}
 | |
| 
 | |
|           <div className="flex justify-between mt-4">
 | |
|             <Button
 | |
|               className="flex items-center text-sm"
 | |
|               size="sm"
 | |
|               variant="ghost"
 | |
|               onClick={() => navigate("/")}
 | |
|             >
 | |
|               <ArrowLeft className="h-4 w-4" />
 | |
|               Retour
 | |
|             </Button>
 | |
| 
 | |
|             {/* <Button
 | |
|               type="button"
 | |
|               variant="secondary"
 | |
|               size="sm"
 | |
|               onClick={handleResendOtp}
 | |
|               disabled={cooldown > 0 || isResending}
 | |
|               className="flex items-center text-sm"
 | |
|             >
 | |
|               {isResending ? (
 | |
|                 <>
 | |
|                   <LoaderIcon className="h-4 w-4 animate-spin" />
 | |
|                   Envoi en cours...
 | |
|                 </>
 | |
|               ) : cooldown > 0 ? (
 | |
|                 <>
 | |
|                   <RefreshCwIcon className="h-4 w-4" />
 | |
|                   Renvoyer le code ({cooldown}s)
 | |
|                 </>
 | |
|               ) : (
 | |
|                 <>
 | |
|                   <RefreshCwIcon className="h-4 w-4" />
 | |
|                   Renvoyer le code
 | |
|                 </>
 | |
|               )}
 | |
|             </Button> */}
 | |
|           </div>
 | |
|         </div>
 | |
|       </div>
 | |
|     </AuthLayout>
 | |
|   );
 | |
| }
 | 
