"use client"; import React, { useState, useEffect, useRef } from "react"; import { motion, AnimatePresence } from "motion/react"; import { X, ShieldCheck, Phone, Key, LogIn, ArrowRight, RefreshCw } from "lucide-react"; import { authService } from "../lib/services/authService"; import { useUserStore } from "../lib/store/userStore"; import { toast } from "sonner"; import { toPersian } from "../lib/utils"; interface LoginModalProps { isOpen: boolean; onClose: () => void; onLogin: () => void; petName?: string; isAdvisorContext?: boolean; } export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdvisorContext }: LoginModalProps) { const [step, setStep] = useState<"phone" | "otp">("phone"); const [phoneNumber, setPhoneNumber] = useState(""); const [otpCode, setOtpCode] = useState(""); const [isLoading, setIsLoading] = useState(false); const [countdown, setCountdown] = useState(0); const { fetchProfile } = useUserStore(); const otpInputRef = useRef(null); useEffect(() => { if (step === "otp") { const timer = setTimeout(() => { otpInputRef.current?.focus(); }, 100); return () => clearTimeout(timer); } }, [step]); const handleVerifyOtpWithCode = React.useCallback(async (code: string) => { const cleanCode = code.trim(); if (cleanCode.length !== 5) { toast.error("کد تایید باید ۵ رقم باشد"); return; } setIsLoading(true); try { const response = await authService.verifyOtp(phoneNumber.trim(), cleanCode); if (response.success) { await fetchProfile(); toast.success("ورود با موفقیت انجام شد"); onLogin(); onClose(); } } catch (err: unknown) { const errObj = err as { message?: string }; toast.error(errObj.message || "کد تایید اشتباه است"); } finally { setIsLoading(false); } }, [phoneNumber, fetchProfile, onLogin, onClose]); // WebOTP API & Auto-Submit useEffect(() => { if (step === "otp" && typeof window !== "undefined" && "OTPCredential" in window) { const ac = new AbortController(); const creds = (navigator as unknown as { credentials?: { get?: (opt: unknown) => Promise<{ code?: string }> } }).credentials; if (creds && creds.get) { creds.get({ otp: { transport: ["sms"] }, signal: ac.signal, }) .then((otp) => { if (otp && otp.code) { setOtpCode(otp.code); handleVerifyOtpWithCode(otp.code); } }) .catch(() => {}); } return () => ac.abort(); } }, [step, handleVerifyOtpWithCode]); const handleOtpInputChange = (e: React.ChangeEvent) => { const val = e.target.value.replace(/[^0-9]/g, "").slice(0, 5); setOtpCode(val); if (val.length === 5) { handleVerifyOtpWithCode(val); } }; const handleOtpPaste = (e: React.ClipboardEvent) => { const pasted = e.clipboardData.getData("text").replace(/[^0-9]/g, "").slice(0, 5); if (pasted.length === 5) { e.preventDefault(); setOtpCode(pasted); handleVerifyOtpWithCode(pasted); } }; // Reset modal state when closed or opened useEffect(() => { if (!isOpen) { Promise.resolve().then(() => { setStep("phone"); setPhoneNumber(""); setOtpCode(""); setIsLoading(false); setCountdown(0); }); } }, [isOpen]); // Countdown timer for OTP resend useEffect(() => { if (countdown > 0) { const timer = setTimeout(() => setCountdown(countdown - 1), 1000); return () => clearTimeout(timer); } }, [countdown]); const handleSendOtp = async (e: React.FormEvent) => { e.preventDefault(); const cleanPhone = phoneNumber.trim(); if (!/^09\d{9}$/.test(cleanPhone)) { toast.error("شماره موبایل باید با ۰۹ شروع شده و ۱۱ رقم باشد"); return; } setIsLoading(true); try { const res = await authService.sendOtp(cleanPhone); const resObj = res as unknown as { code?: string }; if (resObj.code) { toast.info(`کد تایید (تست): ${resObj.code}`, { duration: 10000 }); } else { toast.success("کد تایید پیامک شد"); } setStep("otp"); setCountdown(120); // 2 minutes cooldown } catch (err: unknown) { const errObj = err as { message?: string }; toast.error(errObj.message || "خطا در ارسال کد تایید"); } finally { setIsLoading(false); } }; const handleVerifyOtp = async (e: React.FormEvent) => { e.preventDefault(); handleVerifyOtpWithCode(otpCode); }; const handleResendOtp = async () => { if (countdown > 0) return; setIsLoading(true); try { await authService.sendOtp(phoneNumber.trim()); toast.success("کد تایید جدید ارسال شد"); setCountdown(120); } catch (err: unknown) { const errObj = err as { message?: string }; toast.error(errObj.message || "خطا در ارسال مجدد کد تایید"); } finally { setIsLoading(false); } }; return ( {isOpen && (
{/* Backdrop */} {/* Modal Container */} {/* Top color indicator */}
{/* Close Button */} {/* Header info */}

ورود به کنینا

{isAdvisorContext ? (

تحلیل سلامت {petName || "همدم شما"} آماده است! برای مشاهده رژیم مکمل پیشنهادی و ذخیره شناسنامه، وارد شوید.

) : (

برای دسترسی به پنل مدیریت سلامت، وارد شوید

)}
{/* Step-based Forms */} {step === "phone" ? (
setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))} disabled={isLoading} className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 focus:border-canina-blue outline-none font-bold text-lg text-left tracking-widest" />
) : (

کد تایید به شماره {toPersian(phoneNumber)} ارسال گردید.

{countdown > 0 ? ( ارسال مجدد کد پس از {toPersian(countdown)} ثانیه ) : ( )}
)}
)} ); }