'use client' import { useState } from 'react' import type { PaginationListColumnType } from '@/types' import { addToast } from '@/lib/toast' import PaginatedList from '@/components/PaginatedList' import PageNavbar from '@/components/layouts/PageNavbar' import Input from '@/components/formElements/Input' import Button from '@/components/formElements/Button' import CloseCircleIcon from '@/components/icons/CloseCircleIcon' import FileCheckIcon from '@/components/icons/FileCheckIcon' import ManualPayoutModal from '@/components/admin/ManualPayoutModal' import PlayCircleIcon from '@/components/icons/PlayCircleIcon' import Modal from '@/components/modals/Modal' import AdminTableActions from '@/components/ui/AdminTableActions' import AdminTableViewButton from '@/components/ui/AdminTableViewButton' import StatusChip from '@/components/ui/StatusChip' import axiosInstance from '@/config/axios' import { APP_ROUTES } from '@/constants/routes' import { getWithdrawalRequestStatus, WITHDRAWAL_REQUEST_STATUS_FILTER_ITEMS } from '@/constants/status' import { formatCurrency, formatPersonName, coerceToString } from '@/helpers' import useAlertModal from '@/hooks/useAlertModal' import useAdminMutation from '@/hooks/useAdminMutation' import { formatIranianMobile, formatPersianDate } from '@/lib/formatters' import { API_ROUTES } from '@/services/config' type WithdrawalRequestStatusValue = 'pending' | 'processing' | 'completed' | 'rejected' interface WithdrawalRequestUserSummary { mobile: string firstName: string | null lastName: string | null } interface WithdrawalRequestBankAccountSummary { iban: string bankName: string | null accountHolder: string | null } interface WithdrawalRequestRow { id: string userId: string walletId: string bankAccountId: string withdrawalCode: string amount: number status: WithdrawalRequestStatusValue rejectionReason: string | null processedAt: string | null createdAt: string updatedAt: string user?: WithdrawalRequestUserSummary bankAccount?: WithdrawalRequestBankAccountSummary [key: string]: unknown } const columns: PaginationListColumnType[] = [ { field: 'withdrawalCode', label: 'کد درخواست', filterable: false, sortable: false, type: 'text', }, { field: 'userId', label: 'کاربر', filterable: true, sortable: false, type: 'text', }, { field: 'amount', label: 'مبلغ', filterable: false, sortable: true, }, { field: 'status', label: 'وضعیت', filterable: true, sortable: true, type: 'select', filterItems: WITHDRAWAL_REQUEST_STATUS_FILTER_ITEMS, }, { field: 'createdAt', label: 'تاریخ ثبت', filterable: false, sortable: true, }, { field: 'processedAt', label: 'تاریخ پردازش', filterable: false, sortable: false, }, { field: 'bankDetails', label: 'حساب بانکی', filterable: false, sortable: false, }, { field: 'actions', label: 'عملیات', }, ] const WithdrawalRequestsPage = () => { const { showAlert } = useAlertModal() const { pendingId, runAction } = useAdminMutation({ url: API_ROUTES.WITHDRAWAL_REQUESTS.ADMIN_LIST }) const [rejectTarget, setRejectTarget] = useState(null) const [manualTarget, setManualTarget] = useState(null) const [rejectReason, setRejectReason] = useState('') const isRejecting = rejectTarget?.id === pendingId const handleProcess = (row: WithdrawalRequestRow) => { showAlert('این درخواست برداشت به وضعیت «در حال پردازش» تغییر کند؟', () => runAction( row.id, () => axiosInstance.patch(API_ROUTES.WITHDRAWAL_REQUESTS.ADMIN_PROCESS(row.id)), 'درخواست به «در حال پردازش» تغییر کرد' ) ) } const openRejectModal = (row: WithdrawalRequestRow) => { setRejectReason('') setRejectTarget(row) } const closeRejectModal = () => { if (isRejecting) return setRejectTarget(null) setRejectReason('') } const handleReject = async () => { if (!rejectTarget) return const reason = rejectReason.trim() if (reason.length < 3) { addToast({ title: 'دلیل رد باید حداقل ۳ کاراکتر باشد', color: 'warning' }) return } const succeeded = await runAction( rejectTarget.id, () => axiosInstance.patch(API_ROUTES.WITHDRAWAL_REQUESTS.ADMIN_REJECT(rejectTarget.id), { reason }), 'درخواست رد شد' ) if (succeeded) { setRejectTarget(null) setRejectReason('') } } const renderStatusCell = (row: WithdrawalRequestRow, cellValue: unknown) => { const { label, chipColor } = getWithdrawalRequestStatus(coerceToString(cellValue)) return ( ) } return (
{{ userId: (row) => { const withdrawal = row as WithdrawalRequestRow return (
{formatPersonName(withdrawal.user?.firstName, withdrawal.user?.lastName)} {withdrawal.user?.mobile ? ( {formatIranianMobile(withdrawal.user.mobile)} ) : null}
) }, amount: (_row, cellValue) => formatCurrency(Number(cellValue ?? 0)), status: (row, cellValue) => renderStatusCell(row as WithdrawalRequestRow, cellValue), createdAt: (_row, cellValue) => formatPersianDate(cellValue), processedAt: (_row, cellValue) => formatPersianDate(cellValue), bankDetails: (row) => { const withdrawal = row as WithdrawalRequestRow const bankAccount = withdrawal.bankAccount if (!bankAccount) { return } return (
{bankAccount.iban || '—'} {bankAccount.bankName ?? '—'} {bankAccount.accountHolder ?? '—'}
) }, actions: (row) => { const withdrawal = row as WithdrawalRequestRow const isBusy = pendingId === withdrawal.id const canProcess = withdrawal.status === 'pending' || withdrawal.status === 'processing' return ( {canProcess && withdrawal.status === 'pending' ? ( ) : null} {canProcess ? ( <> ) : null} ) }, }}
{ if (!open) closeRejectModal() }} onReject={closeRejectModal} >

دلیل رد این درخواست را بنویسید. این توضیح برای کاربر نمایش داده می‌شود.

{ setRejectReason(coerceToString(next)) }} />
{ setManualTarget(null) }} onSubmit={async (payload) => { if (!manualTarget) return false return runAction( manualTarget.id, () => axiosInstance.patch(API_ROUTES.WITHDRAWAL_REQUESTS.ADMIN_COMPLETE(manualTarget.id), payload), 'برداشت با رسید دستی تکمیل شد' ) }} />
) } export default WithdrawalRequestsPage