adding export to excel features in wallet detail dashboard

This commit is contained in:
Raja Oktafrianto
2025-07-09 15:02:03 +07:00
parent 76d1cd3f89
commit bcbcf2b84e
2 changed files with 441 additions and 358 deletions

View File

@ -16,9 +16,14 @@ import {
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue
} from '@/components/ui/select'; } from '@/components/ui/select';
import { DefaultTooltip, KeenIcon } from '@/components'; import { DefaultTooltip, KeenIcon } from '@/components';
import { toAbsoluteUrl } from '@/utils';
import { toast } from 'sonner';
import * as XLSX from 'xlsx';
import ExcelJS from 'exceljs';
import { exportToExcel } from '@/pages/wallet/wallet-statement/details_wallet_statement/ExportData';
interface ShowDetailWalletDialogProps { interface ShowDetailWalletDialogProps {
open: boolean; open: boolean;
@ -37,14 +42,14 @@ const getDefaultDateRange = () => {
const sevenDaysAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); const sevenDaysAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
return { return {
from: formatDate(sevenDaysAgo), from: formatDate(sevenDaysAgo),
to: formatDate(today), to: formatDate(today)
}; };
}; };
const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
open, open,
onClose, onClose,
idbalance, idbalance
}) => { }) => {
const { GetData } = useCallApi(); const { GetData } = useCallApi();
@ -64,7 +69,7 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
page: 1, page: 1,
with_deleted: false, with_deleted: false,
order_field: 'created_at', order_field: 'created_at',
order_direction: 'ASC', order_direction: 'ASC'
}); });
setTransferType(response?.data?.list || []); setTransferType(response?.data?.list || []);
} catch (error) { } catch (error) {
@ -96,7 +101,7 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
F: 'FEE', F: 'FEE',
V: 'REVERSAL', V: 'REVERSAL',
C: 'CASHBACK CASH', C: 'CASHBACK CASH',
H: 'CASHBACK POINT', H: 'CASHBACK POINT'
}; };
const uniqueCategories = Array.from( const uniqueCategories = Array.from(
@ -110,7 +115,6 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
setCategory(uniqueCategories); setCategory(uniqueCategories);
}, [transaction]); }, [transaction]);
const handleTransferTypeChange = (value: string) => { const handleTransferTypeChange = (value: string) => {
setSelectedTransferType(value === 'all' ? null : value); setSelectedTransferType(value === 'all' ? null : value);
}; };
@ -135,7 +139,7 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
const toDate = new Date(`${dateRange.to}T23:59:59Z`); const toDate = new Date(`${dateRange.to}T23:59:59Z`);
appliedFilters.date = { appliedFilters.date = {
from: fromDate.toISOString(), from: fromDate.toISOString(),
to: toDate.toISOString(), to: toDate.toISOString()
}; };
} }
@ -154,76 +158,99 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
setFilters(appliedFilters); setFilters(appliedFilters);
}; };
const columns = [ const columns = [
{ {
accessorKey: 'transaction_code', accessorKey: 'transaction_code',
header: ({ column }: any) => <DataGridColumnHeader title="Transaction Code" column={column} />, header: ({ column }: any) => (
<DataGridColumnHeader title="Transaction Code" column={column} />
),
enableSorting: false, enableSorting: false,
meta: { headerClassName: 'min-w-[120px]' }, meta: { headerClassName: 'min-w-[120px]' }
}, },
{ {
accessorKey: 'msisdn_reff', accessorKey: 'msisdn_reff',
header: ({ column }: any) => <DataGridColumnHeader title="MSISDN Reffer" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="MSISDN Reffer" column={column} />,
enableSorting: false, enableSorting: false,
meta: { headerClassName: 'min-w-[120px]' }, meta: { headerClassName: 'min-w-[120px]' }
}, },
{ {
accessorKey: 'transaction_type.name', accessorKey: 'transaction_type.name',
header: ({ column }: any) => <DataGridColumnHeader title="Transaction Type" column={column} />, header: ({ column }: any) => (
<DataGridColumnHeader title="Transaction Type" column={column} />
),
enableSorting: false, enableSorting: false,
meta: { headerClassName: 'min-w-[180px]' }, meta: { headerClassName: 'min-w-[180px]' }
}, },
{ {
accessorKey: 'type', accessorKey: 'type',
header: ({ column }: any) => <DataGridColumnHeader title="Type" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Type" column={column} />,
enableSorting: false, enableSorting: false,
meta: { headerClassName: 'min-w-[80px]' }, meta: { headerClassName: 'min-w-[80px]' }
}, },
{ {
accessorKey: 'pre_amount', accessorKey: 'pre_amount',
header: ({ column }: any) => <DataGridColumnHeader title="Pre Amount" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Pre Amount" column={column} />,
enableSorting: false, enableSorting: false,
cell: (info: any) => info.getValue()?.toFixed(2), cell: (info: any) => info.getValue()?.toFixed(2),
meta: { headerClassName: 'min-w-[100px]' }, meta: { headerClassName: 'min-w-[100px]' }
}, },
{ {
accessorKey: 'amount', accessorKey: 'amount',
header: ({ column }: any) => <DataGridColumnHeader title="Amount" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Amount" column={column} />,
enableSorting: false, enableSorting: false,
cell: (info: any) => info.getValue()?.toFixed(2), cell: (info: any) => info.getValue()?.toFixed(2),
meta: { headerClassName: 'min-w-[100px]' }, meta: { headerClassName: 'min-w-[100px]' }
}, },
{ {
accessorKey: 'post_amount', accessorKey: 'post_amount',
header: ({ column }: any) => <DataGridColumnHeader title="Post Amount" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Post Amount" column={column} />,
enableSorting: false, enableSorting: false,
cell: (info: any) => info.getValue()?.toFixed(2), cell: (info: any) => info.getValue()?.toFixed(2),
meta: { headerClassName: 'min-w-[100px]' }, meta: { headerClassName: 'min-w-[100px]' }
}, },
{ {
accessorFn: (row: any) => { accessorFn: (row: any) => {
switch (row.category) { switch (row.category) {
case 'T': return 'TRANSFER'; case 'T':
case 'P': return 'PURCHASE'; return 'TRANSFER';
case 'W': return 'WITHDRAW'; case 'P':
case 'U': return 'TOP UP'; return 'PURCHASE';
case 'R': return 'RETURN'; case 'W':
case 'N': return 'TOP UP PARTNER'; return 'WITHDRAW';
case 'E': return 'REWARD'; case 'U':
case 'L': return 'PURCHASE LOJA'; return 'TOP UP';
case 'B': return 'TOP UP P24'; case 'R':
case 'A': return 'TRANSFER AGENT'; return 'RETURN';
case 'M': return 'WITHDRAWAL AGENT'; case 'N':
case 'O': return 'TOP UP AGENT'; return 'TOP UP PARTNER';
case 'S': return 'TRANSFER P24'; case 'E':
case 'I': return 'WIJTDRAW MERCHANT'; return 'REWARD';
case 'D': return 'DONATION'; case 'L':
case 'F': return 'FEE'; return 'PURCHASE LOJA';
case 'V': return 'REVERSAL'; case 'B':
case 'C': return 'CASHBACK CASH'; return 'TOP UP P24';
case 'H': return 'CASHBACK POINT'; case 'A':
default: return '_'; return 'TRANSFER AGENT';
case 'M':
return 'WITHDRAWAL AGENT';
case 'O':
return 'TOP UP AGENT';
case 'S':
return 'TRANSFER P24';
case 'I':
return 'WIJTDRAW MERCHANT';
case 'D':
return 'DONATION';
case 'F':
return 'FEE';
case 'V':
return 'REVERSAL';
case 'C':
return 'CASHBACK CASH';
case 'H':
return 'CASHBACK POINT';
default:
return '_';
} }
}, },
accessorKey: 'category', accessorKey: 'category',
@ -246,39 +273,42 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
month: 'short', month: 'short',
year: 'numeric', year: 'numeric',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit'
}); });
}, },
meta: { headerClassName: 'min-w-[150px]' }, meta: { headerClassName: 'min-w-[150px]' }
}, },
{ {
accessorKey: 'purpose', accessorKey: 'purpose',
header: ({ column }: any) => <DataGridColumnHeader title="Purpose" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Purpose" column={column} />,
enableSorting: false, enableSorting: false,
cell: (info: any) => info.getValue() || '-', cell: (info: any) => info.getValue() || '-',
meta: { headerClassName: 'min-w-[200px]' }, meta: { headerClassName: 'min-w-[200px]' }
}, },
{ {
accessorKey: 'notes', accessorKey: 'notes',
header: ({ column }: any) => <DataGridColumnHeader title="Notes" column={column} />, header: ({ column }: any) => <DataGridColumnHeader title="Notes" column={column} />,
enableSorting: false, enableSorting: false,
cell: (info: any) => info.getValue() || '-', cell: (info: any) => info.getValue() || '-',
meta: { headerClassName: 'min-w-[200px]' }, meta: { headerClassName: 'min-w-[200px]' }
}, }
]; ];
const getTransactionLists = useCallback( const getTransactionLists = useCallback(
async (page: number, limit: number, sorting: any, _columnFilters: any) => { async (page: number, limit: number, sorting: any, _columnFilters: any) => {
// console.log(idbalance); // console.log(idbalance);
try { try {
const response = await GetData(`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${idbalance}`, { const response = await GetData(
`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${idbalance}`,
{
limit, limit,
page: page + 1, page: page + 1,
with_deleted: false, with_deleted: false,
order_field: "created_at", order_field: 'created_at',
order_direction: 'DESC', order_direction: 'DESC',
filter: JSON.stringify(filters) filter: JSON.stringify(filters)
}); }
);
// console.log(response); // console.log(response);
@ -297,6 +327,46 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
[GetData, idbalance, filters] [GetData, idbalance, filters]
); );
const getAllTransactionData = async () => {
try {
const response = await GetData(
`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${idbalance}`,
{
limit: 10000,
page: 1,
with_deleted: false,
order_field: 'created_at',
order_direction: 'DESC',
filter: JSON.stringify(filters)
}
);
return response?.data?.list || [];
} catch (error) {
console.error('Error fetching all transaction data', error);
return [];
}
};
// Tambahkan fungsi handle export excel
const handleExportExcel = async () => {
try {
const allData = await getAllTransactionData();
// Buat objek wallet dummy untuk kompatibilitas dengan fungsi exportToExcel
const walletData = {
ID: idbalance,
name: 'Wallet Details',
msisdn: '-'
};
await exportToExcel(allData, walletData);
} catch (error) {
console.error('Error exporting to Excel:', error);
toast.error('Failed to export Excel');
}
};
return ( return (
<Dialog open={open} onOpenChange={onClose}> <Dialog open={open} onOpenChange={onClose}>
<DialogContent className="w-screen max-w-screen max-h-screen p-4 overflow-hidden"> <DialogContent className="w-screen max-w-screen max-h-screen p-4 overflow-hidden">
@ -327,7 +397,10 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
</label> </label>
<div className="w-full sm:w-[160px]"> <div className="w-full sm:w-[160px]">
<Select value={selectedTransferType || 'all'} onValueChange={handleTransferTypeChange}> <Select
value={selectedTransferType || 'all'}
onValueChange={handleTransferTypeChange}
>
<SelectTrigger className="h-[32px]"> <SelectTrigger className="h-[32px]">
<SelectValue placeholder="Transaction Type" /> <SelectValue placeholder="Transaction Type" />
</SelectTrigger> </SelectTrigger>
@ -378,9 +451,19 @@ const ShowDetailWalletDialog: React.FC<ShowDetailWalletDialogProps> = ({
</Button> </Button>
</DefaultTooltip> </DefaultTooltip>
<Button variant="outline" className="h-8" onClick={handleApplyFilters}> <Button variant="default" className="h-8" onClick={handleApplyFilters}>
Filter Data Filter Data
</Button> </Button>
<DefaultTooltip title={'Export to Excel'} placement={'top'}>
<Button
variant={'outline'}
className="h-7.5 min-w-[58px]"
onClick={handleExportExcel}
>
<img src={toAbsoluteUrl('/media/file-types/xls.svg')} className="" alt="Excel" />
</Button>
</DefaultTooltip>
</div> </div>
</div> </div>