'use client'; import { useState } from 'react'; import { useTranslations } from 'next-intl'; import { FormProvider, useForm } from 'react-hook-form'; import { useSnackbar } from 'notistack'; import { Box, Stack, Typography } from '@mui/material'; import { AppButton, AppLoading, BankStatusPanel, EmptyState, ErrorState, RhfTextField } from '@/components'; import { useNurseBankAccounts, useAddNurseBankAccount, useSetPrimaryBankAccount } from '@/services/nurse'; import { isValidSheba } from '@/services/nurse/iban'; import { deriveBankStatus } from '@/services/nurse/types'; interface BankFormValues { iban: string; holder: string; } /** * Nurse payout bank settings — an **accounts section**, not a one-shot form (ui-phase-8 §3.7): submit * an IBAN (شبا) + account-holder name, then watch the ownership inquiry resolve through its three * states (pending → verified / mismatch, `BankStatusPanel` unchanged). Once at least one account * exists, a persistent «افزودن حساب دیگر» CTA replaces the old form-only-when-empty gate, so a nurse * switching banks is never dead-ended — the old account stays listed until the nurse makes the new * one primary. A failed accounts query renders the error state with retry, **never** the empty-state * form (which would invite a duplicate-IBAN submission blind). */ export default function NurseBankPage() { const t = useTranslations('bank'); const tc = useTranslations('common'); const { enqueueSnackbar } = useSnackbar(); const { data, isLoading, isError, refetch } = useNurseBankAccounts(); const addAccount = useAddNurseBankAccount(); const setPrimary = useSetPrimaryBankAccount(); const [showForm, setShowForm] = useState(false); const form = useForm({ mode: 'onTouched', defaultValues: { iban: '', holder: '' } }); const { handleSubmit, reset } = form; const accounts = data ?? []; const showFormNow = !isLoading && !isError && (accounts.length === 0 || showForm); const submit = (values: BankFormValues) => { addAccount.mutate( { iban: values.iban, accountHolderName: values.holder.trim() }, { onSuccess: () => { reset(); setShowForm(false); enqueueSnackbar(t('added'), { variant: 'success' }); }, onError: () => enqueueSnackbar(t('add_error'), { variant: 'error' }), }, ); }; return ( {t('title')} {t('subtitle')} {isLoading ? : null} {isError ? refetch()} /> : null} {!isError ? accounts.map((account) => { const status = deriveBankStatus(account); return ( setShowForm(true) : undefined} reenterLabel={t('reenter')} /> {/* Promote a verified non-primary account so payouts (gated on matchedNationalId) target it. */} {status === 'verified' && !account.isPrimary ? ( setPrimary.mutate(account.id, { onSuccess: () => enqueueSnackbar(t('primary_set'), { variant: 'success' }), onError: () => enqueueSnackbar(t('primary_set_error'), { variant: 'error' }), }) } sx={{ alignSelf: 'flex-start' }} > {t('make_primary')} ) : null} ); }) : null} {!isLoading && !isError && accounts.length === 0 ? ( ) : null} {/* An accounts section, not a one-shot form: once at least one account exists, a persistent CTA (rather than "no account yet") lets a nurse switching banks add another — the old account stays listed until they make the new one primary. */} {!isLoading && !isError && accounts.length > 0 && !showForm ? ( setShowForm(true)} sx={{ alignSelf: 'flex-start' }} > {t('add_another')} ) : null} {showFormNow ? ( name="iban" label={t('iban_label')} helperText={t('iban_hint')} transform={(raw) => raw.toUpperCase()} rules={{ validate: (value) => isValidSheba(String(value ?? '')) || t('iban_invalid') }} slotProps={{ htmlInput: { dir: 'ltr', style: { textAlign: 'start', letterSpacing: 1 } } }} fullWidth /> name="holder" label={t('holder_label')} helperText={t('holder_hint')} rules={{ validate: (value) => String(value ?? '').trim().length > 0 || t('holder_required') }} fullWidth /> {addAccount.isPending ? t('submitting') : t('submit')} {accounts.length > 0 ? ( { setShowForm(false); reset(); }} disabled={addAccount.isPending} > {tc('cancel')} ) : null} ) : null} ); }