"use client"; import { useState, useCallback } from "react"; import Image from "next/image"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { toast } from "sonner"; import Logo from "@/public/logo.webp"; import { useLogin, useRegister, useVerifyToken } from "@/lib/hooks/useAuth"; import { useTranslations } from "next-intl"; interface AuthDialogProps { isOpen: boolean; onClose: () => void; } type AuthStep = "phone" | "register" | "verify"; export default function AuthDialog({ isOpen, onClose }: AuthDialogProps) { const [phone, setPhone] = useState("+993 "); const [name, setName] = useState(""); const [address, setAddress] = useState(""); const [otp, setOtp] = useState(""); const [authStep, setAuthStep] = useState("phone"); const [isNewUser, setIsNewUser] = useState(false); const t = useTranslations(); const { mutate: login, isPending: isLoginLoading } = useLogin(); const { mutate: register, isPending: isRegisterLoading } = useRegister(); const { mutate: verifyToken, isPending: isVerifyLoading } = useVerifyToken(); const resetDialog = useCallback(() => { setAuthStep("phone"); setPhone("+993 "); setName(""); setAddress(""); setOtp(""); setIsNewUser(false); onClose(); }, [onClose]); const formatPhoneForBackend = (phoneNumber: string): string => { return phoneNumber.replace(/^\+993\s*/, "").replace(/\s+/g, ""); }; const handlePhoneChange = (e: React.ChangeEvent) => { const input = e.target.value; const prefix = "+993 "; if (input.length < prefix.length) { setPhone(prefix); return; } const digitsOnly = input.substring(prefix.length).replace(/\D/g, ""); const limitedDigits = digitsOnly.substring(0, 8); let formattedPhone = prefix; if (limitedDigits.length > 0) { formattedPhone += limitedDigits.substring(0, 2); if (limitedDigits.length > 2) { formattedPhone += " " + limitedDigits.substring(2); } } setPhone(formattedPhone); }; const isPhoneValid = (): boolean => { const phoneDigits = formatPhoneForBackend(phone); return phoneDigits.length === 8; }; const handleCheckPhone = useCallback(() => { if (!isPhoneValid()) { toast.error(t("invalid_phone")); return; } const phoneNumber = formatPhoneForBackend(phone); // Try to login first to check if user exists login( { phone_number: parseInt(phoneNumber, 10) }, { onSuccess: () => { toast.success(t("code_sent")); setIsNewUser(false); setAuthStep("verify"); }, onError: (error: any) => { // Check if error indicates user not found const errorMessage = error?.response?.data?.message || ""; const lowerMessage = errorMessage.toLowerCase(); if ( lowerMessage.includes("tapylmady") || lowerMessage.includes("not found") || lowerMessage.includes("does not exist") || lowerMessage.includes("not exist") || error?.response?.status === 404 ) { // User doesn't exist, show registration form setIsNewUser(true); setAuthStep("register"); } else { toast.error(errorMessage || t("error_occurred")); } }, }, ); }, [phone, login, t]); const handleRegister = useCallback(() => { if (!name.trim()) { toast.error(t("name_required") || "Adyňyzy giriziň"); return; } if (!address.trim()) { toast.error(t("address_required") || "Salgyňyzy giriziň"); return; } const phoneNumber = formatPhoneForBackend(phone); register( { phone_number: phoneNumber, name: name.trim(), address: address.trim(), }, { onSuccess: () => { toast.success( t("registration_success") || "Hasaba alyndy! Kody giriziň", ); setAuthStep("verify"); }, onError: (error: any) => { toast.error(error?.response?.data?.message || t("error_occurred")); }, }, ); }, [phone, name, address, register, t]); const handleVerify = useCallback(() => { if (otp.length < 4) { toast.error(t("invalid_code")); return; } const phoneNumber = formatPhoneForBackend(phone); verifyToken( { phone_number: parseInt(phoneNumber, 10), code: parseInt(otp, 10), }, { onSuccess: () => { toast.success(t("login_success")); resetDialog(); window.location.reload(); }, onError: (error: any) => { toast.error(error?.response?.data?.message || t("wrong_code")); }, }, ); }, [otp, phone, verifyToken, resetDialog, t]); const handleKeyPress = useCallback( (e: React.KeyboardEvent, action: () => void) => { if (e.key === "Enter") { action(); } }, [], ); const getTitle = () => { switch (authStep) { case "phone": return t("common.enterPhone"); case "register": return t("register_title") || "Hasaba alyş"; case "verify": return t("verify_title") || "Kody giriziň"; default: return t("common.enterPhone"); } }; const getDescription = () => { switch (authStep) { case "phone": return t("common.weWillSendCode"); case "register": return t("register_description") || "Maglumatyňyzy dolduryň"; case "verify": return t("verify_description") || "Telefonyňyza gelen kody giriziň"; default: return t("common.weWillSendCode"); } }; return (
Logo
{getTitle()}

{getDescription()}

{/* Phone Input - Always shown but disabled after first step */}
handleKeyPress(e, handleCheckPhone)} disabled={authStep !== "phone" || isLoginLoading} />

{t("phone_format")}

{/* Registration Form */} {authStep === "register" && ( <> setName(e.target.value)} className="h-12 rounded-xl" disabled={isRegisterLoading} autoFocus /> setAddress(e.target.value)} className="h-12 rounded-xl" onKeyDown={(e) => handleKeyPress(e, handleRegister)} disabled={isRegisterLoading} /> )} {/* Verification Code Input */} {authStep === "verify" && ( setOtp(e.target.value.replace(/\D/g, "").substring(0, 6)) } className="h-12 rounded-xl" onKeyDown={(e) => handleKeyPress(e, handleVerify)} disabled={isVerifyLoading} autoFocus maxLength={6} /> )} {/* Action Button */} {/* Back Button for Register and Verify steps */} {authStep !== "phone" && ( )}
); }