"use client"; import { FormEvent, useCallback, useEffect, useRef, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { storeTokens, consumePostLoginRedirect, fetchLoginUrl } from "@/lib/auth"; import { identityApi } from "@/lib/identity"; import { isValidMobile, normalizeOtpCode, normalizePhone, persianToEnglish, } from "@/lib/phone"; import { useAuth } from "@/hooks/useAuth"; import { Button } from "@/components/ui"; type Step = "phone" | "code"; export interface AuthPanelProps { /** true = نمایش فیلدهای ثبت‌نام از ابتدا */ initialSignup?: boolean; /** مسیر بعد از ورود؛ اگر نباشد از sessionStorage خوانده می‌شود */ redirectTo?: string; } function ProfileFields({ displayName, setDisplayName, email, setEmail, username, setUsername, password, setPassword, disabled, }: { displayName: string; setDisplayName: (v: string) => void; email: string; setEmail: (v: string) => void; username: string; setUsername: (v: string) => void; password: string; setPassword: (v: string) => void; disabled?: boolean; }) { return (

اطلاعات حساب کاربری

); } export function AuthPanel({ initialSignup = false, redirectTo }: AuthPanelProps) { const router = useRouter(); const { isAuthenticated, reload } = useAuth(); const [passwordLoading, setPasswordLoading] = useState(false); const [step, setStep] = useState("phone"); const [signupMode, setSignupMode] = useState(initialSignup); const [intent, setIntent] = useState<"login" | "register">("login"); const [mobile, setMobile] = useState(""); const [displayName, setDisplayName] = useState(""); const [email, setEmail] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [code, setCode] = useState(""); const [countdown, setCountdown] = useState(0); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const verifyingRef = useRef(false); const showProfileFields = signupMode || (step === "code" && intent === "register"); const profileComplete = displayName.trim().length > 0 && email.trim().length > 0 && username.trim().length >= 3 && password.length >= 8; useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get("signup") === "1") setSignupMode(true); const prefilled = params.get("mobile"); if (prefilled) setMobile(prefilled); }, []); useEffect(() => { if (countdown <= 0) return; const timer = setTimeout(() => setCountdown((c) => c - 1), 1000); return () => clearTimeout(timer); }, [countdown]); const finishSession = useCallback( async (tokens: { access_token: string; refresh_token?: string; expires_in: number; token_type: string; }) => { storeTokens(tokens); await reload(); router.replace(redirectTo ?? consumePostLoginRedirect("/dashboard")); }, [redirectTo, reload, router] ); const validateProfile = useCallback(() => { if (!profileComplete) { setError("نام، ایمیل، نام کاربری (حداقل ۳ کاراکتر) و رمز (حداقل ۸) الزامی است"); return false; } return true; }, [profileComplete]); const handleRequestOtp = async (e?: FormEvent) => { e?.preventDefault(); setError(""); const normalized = normalizePhone(mobile); if (!isValidMobile(normalized)) { setError("شماره موبایل صحیح نیست"); return; } if (signupMode && !validateProfile()) return; setMobile(normalized); setLoading(true); try { const res = await identityApi.mobileStart(normalized); setIntent(res.intent); if (res.intent === "login" && signupMode) { setSignupMode(false); setError("این شماره قبلاً ثبت شده — کد ورود ارسال شد"); } setCountdown(res.expires_in); setStep("code"); } catch (err) { setError(err instanceof Error ? err.message : "ارسال کد ناموفق بود"); } finally { setLoading(false); } }; const handleVerify = useCallback( async (codeOverride?: string) => { if (verifyingRef.current) return; const normalizedCode = normalizeOtpCode(codeOverride ?? code); if (normalizedCode.length !== 4) { setError("کد تأیید باید ۴ رقم باشد"); return; } if (intent === "register" && !validateProfile()) return; verifyingRef.current = true; setLoading(true); let keepLoading = false; try { const session = await identityApi.mobileComplete({ mobile, code: normalizedCode, display_name: displayName.trim() || undefined, email: showProfileFields && profileComplete ? email.trim() : undefined, username: showProfileFields && profileComplete ? username.trim() : undefined, password: showProfileFields && profileComplete ? password : undefined, }); keepLoading = true; await finishSession(session); } catch (err) { setError(err instanceof Error ? err.message : "تأیید کد ناموفق بود"); } finally { if (!keepLoading) { setLoading(false); verifyingRef.current = false; } } }, [ code, displayName, email, finishSession, intent, mobile, password, profileComplete, showProfileFields, username, validateProfile, ] ); const handleCodeChange = (value: string) => { const next = normalizeOtpCode(value); setCode(next); const canAutoVerify = intent === "login" || (intent === "register" && profileComplete); if (next.length === 4 && canAutoVerify && !verifyingRef.current && !loading) { void handleVerify(next); } }; if (isAuthenticated) { return (

شما وارد شده‌اید.

); } return (

{signupMode ? "ثبت‌نام" : "ورود"}

{step === "phone" ? "شماره موبایل خود را وارد کنید" : intent === "login" ? "کد ورود را وارد کنید" : "کد تأیید و اطلاعات حساب را تکمیل کنید"}

{error && (

{error}

)} {step === "phone" ? (
{signupMode && ( )} {!signupMode ? ( ) : ( )}
یا
) : (

کد به{" "} {mobile} {" "} ارسال شد

{countdown > 0 && (

ارسال مجدد تا {countdown} ثانیه

)} handleCodeChange(e.target.value)} className="w-full rounded-xl border border-gray-200 px-4 py-3 text-center font-mono text-lg tracking-[0.4em]" placeholder="••••" /> {intent === "register" && !signupMode && ( )}
)} بازگشت به صفحه اصلی
); }