import { useState, useRef, 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, Typography } from '@mui/material'; import { toLocaleDigits } from '@/utils/persianDigit'; import { useApi } from '@/hooks/useApi'; import { fetchProfile, sendVerificationCode, confirmPhoneNumberCode, changePhoneNumber, } from '../../api/settingsApi'; import { type Phone } from '../../types/settingsType'; import { useToast } from '@rkheftan/harmony-ui'; 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 [showToast, setShowToast] = useState(false); const [buttonState, setButtonState] = useState<'default' | 'counting'>( 'default', ); const [isVerified, setIsVerified] = useState(false); const [phones, setPhones] = useState([]); const [countryCode, setCountryCode] = useState('+98'); const [formError, setFormError] = useState(); const [touched, setTouched] = useState(false); const textFieldRef = useRef(null); const inputRef = useRef(null); const { data: profileData, loading: isLoading, error: fetchError, } = useApi(fetchProfile, { immediate: true }); const { data: sendCodeData, loading: isSendingCode, error: sendCodeError, execute: executeSendCode, } = useApi(sendVerificationCode); const { data: confirmData, loading: isVerifying, error: confirmError, execute: executeConfirmCode, } = useApi(confirmPhoneNumberCode); const { data: changePhoneData, loading: isChangingPhone, error: changePhoneError, execute: executeChangePhone, } = useApi(changePhoneNumber); useEffect(() => { if (profileData?.success && profileData.phoneNumber) { setPhones([ { phone: profileData.phoneNumber, time: '', withCode: profileData.phoneNumber, }, ]); } }, [profileData]); useEffect(() => { if (fetchError) { toast({ message: getErrorMessage(fetchError) || t('settingForm.errorFetchPhoneNumber'), severity: 'error', }); } }, [fetchError, toast, t]); useEffect(() => { if (sendCodeData?.success) { setButtonState('counting'); setIsVerified(false); toast({ message: t('settingForm.codeSentSuccessfully'), severity: 'success', }); } }, [sendCodeData, t, toast]); useEffect(() => { if (sendCodeError) { toast({ message: getErrorMessage(sendCodeError) || t('settingForm.errorSendCode'), severity: 'error', }); } }, [sendCodeError, toast, t]); useEffect(() => { if (confirmData?.success && confirmData.confirm) { setIsVerified(true); setShowToast(true); const fullPhoneNumber = countryCode + phoneNumber.replace(/^0/, ''); executeChangePhone({ phoneNumber: fullPhoneNumber }); toast({ message: t('settingForm.phoneVerified'), severity: 'success', }); } }, [confirmData, countryCode, phoneNumber, executeChangePhone, t, toast]); useEffect(() => { if (confirmError) { toast({ message: getErrorMessage(confirmError) || t('settingForm.errorConfirmCode'), severity: 'error', }); } }, [confirmError, toast, t]); useEffect(() => { if (changePhoneData?.success) { const fullPhoneNumber = countryCode + phoneNumber.replace(/^0/, ''); setPhones([ { phone: phoneNumber, time: t('settingForm.justNow'), withCode: fullPhoneNumber, }, ]); setIsEditing(false); toast({ message: t('settingForm.phoneChangedSuccessfully'), severity: 'success', }); } }, [changePhoneData, countryCode, phoneNumber, t, toast]); useEffect(() => { if (changePhoneError) { toast({ message: getErrorMessage(changePhoneError) || t('settingForm.errorChangePhone'), severity: 'error', }); } }, [changePhoneError, toast, t]); const apiError = useMemo( () => sendCodeError || confirmError || changePhoneError, [sendCodeError, confirmError, changePhoneError], ); const getErrorMessage = (error: unknown): string | undefined => { if (!error) return undefined; if (error instanceof Error) return error.message; return String(error); }; const isPhoneValid = (code: string, phone: string) => { const phoneNum = parsePhoneNumberFromString(code + phone); return phoneNum?.isValid(); }; const handleBlur = () => { setTouched(true); if (!phoneNumber) { setFormError(t('settingForm.thisFieldIsRequired')); return; } if (!isPhoneValid(countryCode, phoneNumber)) { setFormError(t('settingForm.phoneNumberIsInvalid')); } else { setFormError(undefined); } }; const toggleEdit = () => { setIsEditing((prev) => { if (!prev) { setPhoneNumber(''); setVerificationCode(''); setIsVerified(false); setButtonState('default'); setShowToast(false); setFormError(undefined); setTouched(false); } return !prev; }); }; const handleSendCode = () => { handleBlur(); if (formError || !isPhoneValid(countryCode, phoneNumber)) return; executeSendCode({ phoneNumber: countryCode + phoneNumber.replace(/^0/, ''), }); }; const handleVerifyCode = () => { if (!verificationCode) { setFormError(t('settingForm.verificationCodeRequired')); return; } setFormError(undefined); executeConfirmCode({ phoneNumber: countryCode + phoneNumber.replace(/^0/, ''), verifyCode: verificationCode, }); }; const combinedError = formError || getErrorMessage(apiError); const inputError: boolean = touched && !!combinedError; return ( } > {isLoading ? ( ) : fetchError ? ( {getErrorMessage(fetchError) || t('settingForm.errorFetchPhoneNumber')} ) : isEditing ? ( } inputRef={inputRef as React.RefObject} phones={phones} showToast={showToast} setShowToast={setShowToast} t={t} /> ) : ( { let localPhone = p.withCode; if (localPhone.startsWith('+98')) { localPhone = '0' + localPhone.slice(3); } return { ...p, phone: toLocaleDigits(localPhone, i18n.language), }; })} /> )} ); }