adding export to excel features in wallet detail dashboard
This commit is contained in:
@ -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>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user