add payments in invoice detail
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user