'use client' import { useCallback, useEffect, useMemo, useState } from 'react' import Button from '@/components/formElements/Button' import Input from '@/components/formElements/Input' import Modal from '@/components/modals/Modal' import { formatIranianMobile } from '@/lib/formatters' import { addToast } from '@/lib/toast' import type { AdminUserDetail } from '@/services/adminUserDetail' import { ADMIN_CHANGE_USER_MOBILE } from '@/services/adminUsers' import { confirmsCurrentMobile, confirmsFinalMobileChange, MOBILE_CHANGE_FINAL_CONFIRMATION, normalizeAdminMobile, } from '@/validation/adminUserMobile' type MobileChangeUser = Pick interface UserMobileChangeModalProps { isOpen: boolean onOpenChange: (isOpen: boolean) => void user: MobileChangeUser onSuccess: () => void } const TOTAL_STEPS = 3 const UserMobileChangeModal = ({ isOpen, onOpenChange, user, onSuccess }: UserMobileChangeModalProps) => { const [step, setStep] = useState(1) const [newMobileInput, setNewMobileInput] = useState('') const [confirmedNewMobile, setConfirmedNewMobile] = useState('') const [currentMobileConfirmation, setCurrentMobileConfirmation] = useState('') const [finalConfirmation, setFinalConfirmation] = useState('') const [submitting, setSubmitting] = useState(false) const normalizedNewMobile = useMemo(() => normalizeAdminMobile(newMobileInput), [newMobileInput]) const newMobileError = useMemo(() => { if (!newMobileInput.trim()) return null if (!normalizedNewMobile) return 'شماره موبایل معتبر نیست.' if (normalizedNewMobile === user.mobile) return 'شماره جدید باید با شماره فعلی متفاوت باشد.' return null }, [newMobileInput, normalizedNewMobile, user.mobile]) const reset = useCallback(() => { setStep(1) setNewMobileInput('') setConfirmedNewMobile('') setCurrentMobileConfirmation('') setFinalConfirmation('') setSubmitting(false) }, []) useEffect(() => { if (isOpen) reset() }, [isOpen, reset, user.id]) const handleOpenChange = (nextOpen: boolean) => { if (!nextOpen) reset() onOpenChange(nextOpen) } const canContinue = step === 1 ? Boolean(normalizedNewMobile) && normalizedNewMobile !== user.mobile : step === 2 ? confirmsCurrentMobile(currentMobileConfirmation, user.mobile) : confirmsFinalMobileChange(finalConfirmation) const submit = async () => { setSubmitting(true) const result = await ADMIN_CHANGE_USER_MOBILE(user.id, confirmedNewMobile) setSubmitting(false) if (!result.ok) return addToast({ color: 'success', title: 'شماره موبایل کاربر تغییر کرد', description: 'تمام نشست‌های فعال کاربر باطل شدند.', }) onSuccess() handleOpenChange(false) } const handleAccept = () => { if (!canContinue) return if (step === 1 && normalizedNewMobile) { setConfirmedNewMobile(normalizedNewMobile) setStep(2) return } if (step === 2) { setStep(3) return } void submit() } const handleReject = () => { if (step > 1) { setStep((current) => current - 1) return } handleOpenChange(false) } const displayName = [user.firstName, user.lastName].filter(Boolean).join(' ') || formatIranianMobile(user.mobile) return (
{Array.from({ length: TOTAL_STEPS }, (_, index) => ( ))}
{step === 1 && (
شماره فعلی:{' '} {formatIranianMobile(user.mobile)}
{ setNewMobileInput(typeof value === 'string' ? value : '') }} /> {newMobileError &&

{newMobileError}

}
)} {step === 2 && (

پیامدهای این تغییر را دوباره بررسی کنید:

  • شماره قبلی برای ثبت‌نام یک حساب جدید آزاد می‌شود.
  • شماره جدید تا ورود موفق با OTP تأییدنشده خواهد بود.
  • تمام نشست‌ها و توکن‌های فعال کاربر فوراً باطل می‌شوند.
از {formatIranianMobile(user.mobile)} به {formatIranianMobile(confirmedNewMobile)}
{ setCurrentMobileConfirmation(typeof value === 'string' ? value : '') }} />
)} {step === 3 && (
این آخرین تأیید است. پس از انجام عملیات، کاربر از همه دستگاه‌ها خارج می‌شود و باید با شماره جدید OTP دریافت کند.
{ setFinalConfirmation(typeof value === 'string' ? value : '') }} />
)} {step > 1 && ( )}
) } export default UserMobileChangeModal