224 lines
6.7 KiB
TypeScript
224 lines
6.7 KiB
TypeScript
import { type FC, useState } from 'react';
|
||
import moment from 'moment-jalaali';
|
||
import Table from '@/components/Table';
|
||
import ModalConfrim from '@/components/ModalConfrim';
|
||
import type { ColumnType } from '@/components/types/TableTypes';
|
||
import { toast } from '@/shared/toast';
|
||
import { extractErrorMessage } from '@/config/func';
|
||
import {
|
||
useConfirmCashPayment,
|
||
useDenyCashPayment,
|
||
useGetPayments,
|
||
useVerifyOnlinePayment,
|
||
} from '@/pages/payment/hooks/usePaymentData';
|
||
import {
|
||
PaymentMethodEnum,
|
||
PaymentStatusEnum,
|
||
} from '@/pages/payment/enum/PaymentEnum';
|
||
import type { PaymentType } from '@/pages/payment/types/Types';
|
||
|
||
type Props = {
|
||
invoiceId: string;
|
||
};
|
||
|
||
const methodLabels: Record<PaymentMethodEnum, string> = {
|
||
[PaymentMethodEnum.Online]: 'آنلاین',
|
||
[PaymentMethodEnum.Cash]: 'نقدی',
|
||
[PaymentMethodEnum.Credit]: 'اعتبار',
|
||
};
|
||
|
||
const statusLabels: Record<PaymentStatusEnum, string> = {
|
||
[PaymentStatusEnum.Pending]: 'در انتظار',
|
||
[PaymentStatusEnum.Paid]: 'پرداخت شده',
|
||
[PaymentStatusEnum.Failed]: 'ناموفق',
|
||
[PaymentStatusEnum.Refunded]: 'بازگشت داده شده',
|
||
};
|
||
|
||
const statusBadgeClass: Record<PaymentStatusEnum, string> = {
|
||
[PaymentStatusEnum.Pending]: 'bg-amber-100 text-amber-800',
|
||
[PaymentStatusEnum.Paid]: 'bg-green-100 text-green-800',
|
||
[PaymentStatusEnum.Failed]: 'bg-red-100 text-red-800',
|
||
[PaymentStatusEnum.Refunded]: 'bg-gray-100 text-gray-800',
|
||
};
|
||
|
||
const formatAmount = (amount: number) =>
|
||
Number(amount).toLocaleString('fa-IR') + ' تومان';
|
||
|
||
const InvoicePaymentsSection: FC<Props> = ({ invoiceId }) => {
|
||
const [page, setPage] = useState(1);
|
||
const [confirmAction, setConfirmAction] = useState<{
|
||
type: 'cash-confirm' | 'cash-deny' | 'online-verify';
|
||
payment: PaymentType;
|
||
} | null>(null);
|
||
|
||
const { data, isLoading } = useGetPayments({
|
||
page,
|
||
limit: 10,
|
||
invoiceId,
|
||
});
|
||
|
||
const confirmCash = useConfirmCashPayment();
|
||
const denyCash = useDenyCashPayment();
|
||
const verifyOnline = useVerifyOnlinePayment();
|
||
|
||
const payments = data?.data ?? [];
|
||
const meta = data?.meta;
|
||
|
||
const isActionLoading =
|
||
confirmCash.isPending || denyCash.isPending || verifyOnline.isPending;
|
||
|
||
const handleConfirmAction = () => {
|
||
if (!confirmAction) return;
|
||
|
||
const { type, payment } = confirmAction;
|
||
const onSuccess = () => {
|
||
toast('عملیات با موفقیت انجام شد', 'success');
|
||
setConfirmAction(null);
|
||
};
|
||
const onError = (error: unknown) => {
|
||
toast(extractErrorMessage(error), 'error');
|
||
};
|
||
|
||
if (type === 'cash-confirm') {
|
||
confirmCash.mutate(payment.id, { onSuccess, onError });
|
||
return;
|
||
}
|
||
if (type === 'cash-deny') {
|
||
denyCash.mutate(payment.id, { onSuccess, onError });
|
||
return;
|
||
}
|
||
if (type === 'online-verify' && payment.token) {
|
||
verifyOnline.mutate(payment.token, { onSuccess, onError });
|
||
}
|
||
};
|
||
|
||
const getConfirmLabel = () => {
|
||
if (!confirmAction) return '';
|
||
switch (confirmAction.type) {
|
||
case 'cash-confirm':
|
||
return 'آیا از تایید این پرداخت نقدی اطمینان دارید؟';
|
||
case 'cash-deny':
|
||
return 'آیا از رد این پرداخت نقدی اطمینان دارید؟';
|
||
case 'online-verify':
|
||
return 'آیا از تایید این پرداخت آنلاین اطمینان دارید؟';
|
||
default:
|
||
return '';
|
||
}
|
||
};
|
||
|
||
const columns: ColumnType<PaymentType>[] = [
|
||
{
|
||
title: 'مبلغ',
|
||
key: 'amount',
|
||
render: (item) => formatAmount(item.amount),
|
||
},
|
||
{
|
||
title: 'روش پرداخت',
|
||
key: 'method',
|
||
render: (item) => methodLabels[item.method] ?? item.method,
|
||
},
|
||
{
|
||
title: 'وضعیت',
|
||
key: 'status',
|
||
render: (item) => (
|
||
<span
|
||
className={`inline-flex h-6 items-center rounded-full px-2.5 text-xs ${statusBadgeClass[item.status] ?? 'bg-gray-100 text-gray-800'}`}
|
||
>
|
||
{statusLabels[item.status] ?? item.status}
|
||
</span>
|
||
),
|
||
},
|
||
{
|
||
title: 'تاریخ',
|
||
key: 'createdAt',
|
||
render: (item) =>
|
||
item.createdAt
|
||
? moment(item.createdAt).format('jYYYY/jMM/jDD HH:mm')
|
||
: '-',
|
||
},
|
||
{
|
||
title: 'عملیات',
|
||
key: 'actions',
|
||
render: (item) => {
|
||
const isPending = item.status === PaymentStatusEnum.Pending;
|
||
const isCash = item.method === PaymentMethodEnum.Cash;
|
||
const isOnline = item.method === PaymentMethodEnum.Online;
|
||
|
||
return (
|
||
<div className="flex flex-wrap items-center gap-2">
|
||
{isPending && isCash && (
|
||
<>
|
||
<button
|
||
type="button"
|
||
className="rounded-lg bg-green-600 px-2 py-1 text-xs text-white hover:opacity-90"
|
||
onClick={() =>
|
||
setConfirmAction({ type: 'cash-confirm', payment: item })
|
||
}
|
||
>
|
||
تایید
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="rounded-lg bg-red-600 px-2 py-1 text-xs text-white hover:opacity-90"
|
||
onClick={() =>
|
||
setConfirmAction({ type: 'cash-deny', payment: item })
|
||
}
|
||
>
|
||
رد
|
||
</button>
|
||
</>
|
||
)}
|
||
{isPending && isOnline && item.token && (
|
||
<button
|
||
type="button"
|
||
className="rounded-lg bg-primary px-2 py-1 text-xs text-black hover:opacity-90"
|
||
onClick={() =>
|
||
setConfirmAction({ type: 'online-verify', payment: item })
|
||
}
|
||
>
|
||
تایید آنلاین
|
||
</button>
|
||
)}
|
||
</div>
|
||
);
|
||
},
|
||
},
|
||
];
|
||
|
||
return (
|
||
<>
|
||
<div className="bg-white rounded-3xl p-6 mt-8">
|
||
<div className="font-light">پرداختها</div>
|
||
|
||
<div className="mt-6">
|
||
<Table
|
||
columns={columns}
|
||
data={payments}
|
||
isLoading={isLoading}
|
||
noDataMessage="پرداختی برای این پیشفاکتور یافت نشد."
|
||
pagination={
|
||
meta && meta.totalPages > 1
|
||
? {
|
||
currentPage: meta.page,
|
||
totalPages: meta.totalPages,
|
||
onPageChange: setPage,
|
||
}
|
||
: undefined
|
||
}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<ModalConfrim
|
||
isOpen={!!confirmAction}
|
||
close={() => setConfirmAction(null)}
|
||
onConfrim={handleConfirmAction}
|
||
isloading={isActionLoading}
|
||
label={getConfirmLabel()}
|
||
/>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default InvoicePaymentsSection;
|