import React, { useMemo, useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import { formatRial, formatDate, tomanToRial } from '../lib/utils'; import Pagination from '../components/ui/Pagination'; import SearchableSelect from '../components/ui/SearchableSelect'; import { digitsOnly } from '../lib/utils'; interface WalletBalance { balance_rials: number } interface RepSummary { income: { settlable_rials: number; settled_rials: number; pending_rials: number } } interface SettlementRow { uuid: string; amount_rials: number; status: 'pending' | 'approved' | 'rejected' | 'paid'; admin_note: string | null; created_at: number; } const STATUS_LABEL: Record = { pending: 'در انتظار بررسی', approved: 'تأیید شده', rejected: 'رد شده', paid: 'پرداخت شده', }; const STATUS_CLASS: Record = { pending: 'gray', approved: 'green', rejected: 'red', paid: 'green', }; interface IbanItem { id: string; iban: string; bank_name: string | null; verified: boolean } interface RepMe { bank_account: IbanItem[] | null } export default function RepresentationSettlementPage() { const qc = useQueryClient(); const [amount, setAmount] = useState(''); const [ibanId, setIbanId] = useState(''); const [page, setPage] = useState(1); const limit = 20; const balanceQ = useQuery({ queryKey: ['wallet-balance'], queryFn: () => api.get>('/api/v1/wallet/balance'), staleTime: 30_000, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const balance: number = ((balanceQ.data?.data as any)?.data ?? balanceQ.data?.data)?.balance_rials ?? 0; const meQ = useQuery({ queryKey: ['representation-me'], queryFn: () => api.get>('/api/v1/representation/me'), staleTime: 30_000, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const ibans: IbanItem[] = (((meQ.data?.data as any)?.data ?? meQ.data?.data)?.bank_account ?? []).filter((b: IbanItem) => b.verified); const summaryQ = useQuery({ queryKey: ['representation-summary'], queryFn: () => api.get>('/api/v1/representation/dashboard/summary'), staleTime: 60_000, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const income = useMemo(() => ((summaryQ.data?.data as any)?.data ?? summaryQ.data?.data)?.income, [summaryQ.data]); const listQ = useQuery({ queryKey: ['settlements-mine', page], queryFn: () => api.get>(`/api/v1/settlement?page=${page}&limit=${limit}`), staleTime: 30_000, }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const settlements: SettlementRow[] = (listQ.data?.data as any)?.data ?? listQ.data?.data ?? []; // eslint-disable-next-line @typescript-eslint/no-explicit-any const settlementsTotal: number = (listQ.data?.data as any)?.meta?.totalRecords ?? settlements.length; const createMut = useMutation({ mutationFn: (payload: { amount_rials: number; iban_id: string }) => api.post>('/api/v1/settlement', payload), onSuccess: () => { toast.success('درخواست تسویه ثبت شد'); setAmount(''); qc.invalidateQueries({ queryKey: ['settlements-mine'] }); qc.invalidateQueries({ queryKey: ['wallet-balance'] }); qc.invalidateQueries({ queryKey: ['representation-summary'] }); }, onError: (e: Error) => toast.error(e.message), }); const submit = () => { const n = Number(amount); // تومان if (!n || n <= 0) { toast.error('مبلغ نامعتبر است'); return; } const rial = tomanToRial(n); if (rial > balance) { toast.error('مبلغ بیشتر از موجودی قابل برداشت است'); return; } if (!ibanId) { toast.error('انتخاب شماره شبا الزامی است'); return; } createMut.mutate({ amount_rials: rial, iban_id: ibanId }); }; const cards = [ { label: 'موجودی قابل برداشت', value: formatRial(balance), color: 'var(--primary)' }, { label: 'مجموع تسویه‌شده', value: formatRial(income?.settled_rials ?? 0), color: 'var(--success)' }, { label: 'در انتظار تسویه', value: formatRial(income?.pending_rials ?? 0), color: 'var(--warning)' }, ]; return (

تسویه حساب

درخواست برداشت از کیف‌پول نماینده
{cards.map(c => (
{c.label}
{c.value}
))}

ثبت درخواست جدید

{ibans.length === 0 ? (
برای ثبت درخواست تسویه، ابتدا در{' '} پروفایل{' '} یک شماره شبای تأییدشده اضافه کنید.
) : (
setAmount(digitsOnly(e.target.value))} style={{ width: 200, height: 38, padding: '0 12px', borderRadius: 'var(--r-sm)', border: '1px solid var(--border)', background: 'var(--surface)', color: 'var(--text)', fontSize: 13.5, boxSizing: 'border-box' }} />
({ value: String(b.id), label: `${b.iban}${b.bank_name ? ` — ${b.bank_name}` : ''}` }))} value={ibanId || null} onChange={(v) => setIbanId(v ? String(v) : '')} placeholder="انتخاب شماره شبا..." isClearable height={38} />
حداکثر: {formatRial(balance)}
)}

درخواست‌های قبلی

{settlements.length === 0 && ( )} {settlements.map(s => ( ))}
مبلغوضعیتتوضیح مدیرتاریخ
درخواستی ثبت نشده است
{formatRial(s.amount_rials)} {STATUS_LABEL[s.status] ?? s.status} {s.admin_note ?? '—'} {formatDate(s.created_at)}
); }