import { useState, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import parsePhoneNumberFromString from 'libphonenumber-js'; import { PageWrapper } from '../PageWrapper'; import { CardContainer } from '@/components/CardContainer'; import PhoneDisplay from './phoneNumber/PhoneDisplay'; import PhoneEditForm from './phoneNumber/PhoneEditForm'; import PhoneActionButtons from './phoneNumber/PhoneActionButtons'; import { CircularProgress, Box } from '@mui/material'; import { toLocaleDigits } from '@/utils/persianDigit'; import { useApi } from '@/hooks/useApi'; import { sendVerificationCode, confirmPhoneNumberCode, changePhoneNumber, } from '../../api/settingsApi'; import { type Phone } from '../../types/settingsType'; import { useToast } from '@rkheftan/harmony-ui'; import { useProfile } from '../../hooks/useProfile'; import type { CountryCode } from '@/types/commonTypes'; export function PhoneNumber() { const { t, i18n } = useTranslation('setting'); const toast = useToast(); const [isEditing, setIsEditing] = useState(false); const [phoneNumber, setPhoneNumber] = useState(''); const [verificationCode, setVerificationCode] = useState(''); const [buttonState, setButtonState] = useState<'default' | 'counting'>( 'default', ); const [isVerified, setIsVerified] = useState(false); const [isCodeSent, setIsCodeSent] = useState(false); const [phones, setPhones] = useState([]); const [countryCode, setCountryCode] = useState('+98'); const [phoneNumberError, setPhoneNumberError] = useState(); const [verificationCodeError, setVerificationCodeError] = useState(); const [phoneNumberTouched, setPhoneNumberTouched] = useState(false); const [verificationCodeTouched, setVerificationCodeTouched] = useState(false); const { isLoadingProfile, refetchProfile } = useProfile(); const { loading: isSendingCode, execute: executeSendCode } = useApi(sendVerificationCode); const { loading: isVerifying, execute: executeConfirmCode } = useApi( confirmPhoneNumberCode, ); const { loading: isChangingPhone, execute: executeChangePhone } = useApi(changePhoneNumber); const isBusy = useMemo( () => isVerifying || isSendingCode || isChangingPhone, [isVerifying, isSendingCode, isChangingPhone], ); useEffect(() => { const loadProfile = async () => { const profileData = await refetchProfile(); if (!profileData) return; if (profileData?.success) { setPhones([ { phone: profileData.phoneNumber, time: '', withCode: profileData.phoneNumber, }, ]); } else { toast({ message: profileData.message, severity: 'error', }); } }; void loadProfile(); }, [refetchProfile, toast]); useEffect(() => { if (!phoneNumberTouched) return; if (!phoneNumber) { setPhoneNumberError(t('settingForm.thisFieldIsRequired')); return; } const parsed = parsePhoneNumberFromString(countryCode + phoneNumber); const valid = Boolean(parsed?.isValid()); if (!valid) { setPhoneNumberError(t('settingForm.phoneNumberIsInvalid')); } else { setPhoneNumberError(undefined); } }, [countryCode, phoneNumber, phoneNumberTouched, t]); useEffect(() => { if (!verificationCodeTouched) return; if (!verificationCode) { setVerificationCodeError(t('settingForm.verificationCodeRequired')); return; } setVerificationCodeError(undefined); }, [verificationCode, verificationCodeTouched, t]); const handleBlur = (key: string) => { if (key === 'phoneNumber') { setPhoneNumberTouched(true); } else { setVerificationCodeTouched(true); } }; const toggleEdit = () => { setIsEditing((prev) => { if (!prev) { setPhoneNumber(''); setVerificationCode(''); setIsVerified(false); setButtonState('default'); setPhoneNumberError(undefined); setPhoneNumberTouched(false); setVerificationCodeError(undefined); setVerificationCodeTouched(false); setIsCodeSent(false); } return !prev; }); }; const handleSendCode = async () => { setPhoneNumberTouched(true); if (!phoneNumber || phoneNumberError) return; const result = await executeSendCode({ phoneNumber: countryCode + phoneNumber.replace(/^0/, ''), }); if (!result) return; if (result?.success) { setButtonState('counting'); setIsVerified(false); setIsCodeSent(true); toast({ message: result.message || t('settingForm.codeSentSuccessfully'), severity: 'success', }); } else { toast({ message: result.message || t('message.serverError'), severity: 'error', }); } }; const handleVerifyCode = async () => { setVerificationCodeTouched(true); if (!verificationCode || verificationCodeError) return; const fullPhoneNumber = countryCode + phoneNumber.replace(/^0/, ''); const confirmResult = await executeConfirmCode({ phoneNumber: fullPhoneNumber, verifyCode: verificationCode, }); if (!confirmResult) return; if (!confirmResult.success || !confirmResult.confirm) { toast({ message: confirmResult?.message || t('message.serverError'), severity: 'error', }); return; } setIsVerified(true); toast({ message: t('settingForm.phoneVerified'), severity: 'success', }); const changeResult = await executeChangePhone({ phoneNumber: fullPhoneNumber, }); if (!changeResult) return; if (changeResult?.success) { setPhones([ { phone: phoneNumber, time: t('settingForm.justNow'), withCode: fullPhoneNumber, }, ]); setIsEditing(false); refetchProfile({ force: true }); } else { toast({ message: changeResult?.message || t('message.serverError'), severity: 'error', }); } }; return ( } > {isLoadingProfile ? ( ) : isEditing ? ( { e.preventDefault(); e.stopPropagation(); if (!isBusy) void handleVerifyCode(); }} > ) : ( { let localPhone = p.withCode; if (localPhone.startsWith('+98')) { localPhone = '0' + localPhone.slice(3); } return { ...p, phone: toLocaleDigits(localPhone, i18n.language), }; })} /> )} ); }