"use client"; import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { useAppTheme } from "@/components/ThemeProvider"; import { Input } from "@/components/ui/input"; import { InputOTP, InputOTPGroup, InputOTPSlot, } from "@/components/ui/input-otp"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Loader2, X, CheckCircle2 } from "lucide-react"; import { useAuth } from "@/hooks/useAuth"; import { verifyOtpSchema, type VerifyOtpInput } from "@/lib/schema/auth"; import { toast } from "sonner"; interface VerifyOtpDialogProps { open: boolean; onOpenChange: (open: boolean) => void; email: string; context?: "registration" | "password_reset"; onVerificationSuccess?: () => void; title?: string; description?: string; } export function VerifyOtpDialog({ open, onOpenChange, email: initialEmail, context = "registration", onVerificationSuccess, title = "Verify your email", description = "Enter the verification code sent to your email" }: VerifyOtpDialogProps) { const { theme } = useAppTheme(); const isDark = theme === "dark"; const { verifyOtp, verifyOtpMutation, resendOtpMutation } = useAuth(); const [otpData, setOtpData] = useState({ email: initialEmail, otp: "", }); const [email, setEmail] = useState(initialEmail); const [otpSent, setOtpSent] = useState(false); const [isSendingOtp, setIsSendingOtp] = useState(false); // Update email when prop changes useEffect(() => { if (initialEmail) { setEmail(initialEmail); setOtpData(prev => ({ ...prev, email: initialEmail })); } }, [initialEmail]); // Automatically send OTP when dialog opens useEffect(() => { if (open && !otpSent) { const emailToSend = initialEmail || email; if (emailToSend) { setIsSendingOtp(true); resendOtpMutation.mutateAsync({ email: emailToSend, context }) .then(() => { toast.success("Verification code sent! Please check your email."); setOtpSent(true); setIsSendingOtp(false); }) .catch((err) => { const errorMessage = err instanceof Error ? err.message : "Failed to send verification code"; toast.error(errorMessage); setIsSendingOtp(false); // Still allow user to manually resend }); } } // Reset when dialog closes if (!open) { setOtpSent(false); setIsSendingOtp(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [open, initialEmail, email, context, otpSent]); const handleVerifyOtp = async (e: React.FormEvent) => { e.preventDefault(); const emailToVerify = email || otpData.email; if (!emailToVerify) { toast.error("Email address is required"); return; } const validation = verifyOtpSchema.safeParse({ email: emailToVerify, otp: otpData.otp, }); if (!validation.success) { const firstError = validation.error.issues[0]; toast.error(firstError.message); return; } try { const result = await verifyOtp({ email: emailToVerify, otp: otpData.otp, }); if (result.message || result.tokens) { toast.success("Email verified successfully!"); // Reset form setOtpData({ email: emailToVerify, otp: "" }); onOpenChange(false); // Call success callback if provided if (onVerificationSuccess) { onVerificationSuccess(); } } } catch (err) { const errorMessage = err instanceof Error ? err.message : "OTP verification failed. Please try again."; toast.error(errorMessage); } }; const handleResendOtp = async () => { const emailToResend = email || otpData.email; if (!emailToResend) { toast.error("Email address is required"); return; } try { setIsSendingOtp(true); await resendOtpMutation.mutateAsync({ email: emailToResend, context }); toast.success("OTP resent successfully! Please check your email."); setOtpSent(true); setIsSendingOtp(false); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Failed to resend OTP"; toast.error(errorMessage); setIsSendingOtp(false); } }; const handleOtpChange = (field: keyof VerifyOtpInput, value: string) => { setOtpData((prev) => ({ ...prev, [field]: value })); }; // Reset form when dialog closes const handleDialogChange = (isOpen: boolean) => { if (!isOpen) { setOtpData({ email: initialEmail || "", otp: "" }); setOtpSent(false); setIsSendingOtp(false); } onOpenChange(isOpen); }; return ( {/* Header with Close Button - Fixed */}
{title} {description} {/* Close Button */}
{/* Scrollable Content */}
{/* Loading indicator while sending */} {isSendingOtp && !otpSent && (

Sending verification code...

)} {/* Success message after sending */} {otpSent && (

Check your email

We've sent a 6-digit verification code to {email || otpData.email || "your email address"}.

)} {/* Show info message if OTP hasn't been sent yet but dialog is open */} {!isSendingOtp && !otpSent && (

Enter verification code

Enter the 6-digit verification code sent to {email || otpData.email || "your email address"}.

)} {/* Email Field (if not provided or editable) */} {!initialEmail && (
{ setEmail(e.target.value); handleOtpChange("email", e.target.value); }} className={`h-11 sm:h-12 text-sm sm:text-base ${isDark ? 'bg-gray-700 border-gray-600 text-white placeholder:text-gray-400' : 'bg-white border-gray-300 text-gray-900'}`} required />
)} {/* OTP Field */}
handleOtpChange("otp", value)} >
{/* Resend OTP */}
{/* Submit Button */}
); }