"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]); // Reset modal state when closed or opened useEffect(() => { if (!isOpen) { 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); if ((res as any).code) { toast.info(`کد تایید (تست): ${(res as any).code}`, { duration: 10000 }); } else { toast.success("کد تایید پیامک شد"); } setStep("otp"); setCountdown(120); // 2 minutes cooldown } catch (err: any) { toast.error(err.message || "خطا در ارسال کد تایید"); } finally { setIsLoading(false); } }; const handleVerifyOtp = async (e: React.FormEvent) => { e.preventDefault(); const cleanCode = otpCode.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: any) { toast.error(err.message || "کد تایید اشتباه است"); } finally { setIsLoading(false); } }; const handleResendOtp = async () => { if (countdown > 0) return; setIsLoading(true); try { await authService.sendOtp(phoneNumber.trim()); toast.success("کد تایید جدید ارسال شد"); setCountdown(120); } catch (err: any) { toast.error(err.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" />
) : (
setOtpCode(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-black text-2xl text-center tracking-[0.5em]" />

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

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