From 93173ee88cd9999d31e9a4eab7160730770eecfb Mon Sep 17 00:00:00 2001 From: Raja Oktafrianto Date: Thu, 12 Jun 2025 11:38:38 +0700 Subject: [PATCH] update details wallet statement --- .../blocks/ShowDetailDialog.tsx | 764 ------------------ .../details_wallet_statement/ExportData.tsx | 534 ++++++++++++ .../FilterSection.tsx | 6 +- .../ShowDetailDialog.tsx | 315 ++++++++ .../hooks/ManageWalletStatementContext.tsx | 5 +- 5 files changed, 854 insertions(+), 770 deletions(-) delete mode 100644 src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx create mode 100644 src/pages/wallet/wallet-statement/details_wallet_statement/ExportData.tsx rename src/pages/wallet/wallet-statement/{blocks => details_wallet_statement}/FilterSection.tsx (95%) create mode 100644 src/pages/wallet/wallet-statement/details_wallet_statement/ShowDetailDialog.tsx diff --git a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx deleted file mode 100644 index 8f96141..0000000 --- a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx +++ /dev/null @@ -1,764 +0,0 @@ -import React, { createContext, useCallback, useEffect, useState } from 'react'; -import { - Dialog, - DialogBody, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle -} from '@/components/ui/dialog'; -import { useCallApi } from '@/hooks'; -import { apiConfig } from '@/config/api.config'; -import { DataGridColumnHeader, DataGridProvider } from '@/components'; -import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; -import { toast, Toaster } from 'sonner'; -import { format } from 'date-fns'; -import FilterSection from './FilterSection'; -import * as XLSX from 'xlsx'; -import jsPDF from 'jspdf'; -import autoTable from 'jspdf-autotable'; -import ExcelJS from 'exceljs'; -import { toAbsoluteUrl } from '@/utils'; - -interface ContextProps { - doExportData: (sorting: any, filter: any) => Promise; - doExportExcel: () => Promise; - doExportPDF: () => Promise; -} - -const initialProps: ContextProps = { - doExportData: async () => ({ data: [], totalCount: 0 }), - doExportExcel: async () => {}, - doExportPDF: async () => {} -}; - -export const showDetailWalletContext = createContext(initialProps); - -const ShowDetailWalletDialog = () => { - const { GetData, GetExportData } = useCallApi(); - const { showDetailDialog, setShowDetailDialog, selectedWallet } = useManageStatementContext(); - const [filters, setFilters] = useState({}); - const [transaction, setTransaction] = useState([]); - - const categoryMap: Record = { - T: 'TRANSFER', - P: 'PURCHASE', - W: 'WITHDRAW', - U: 'TOP UP', - R: 'RETURN', - N: 'TOP UP PARTNER', - E: 'REWARD', - L: 'PURCHASE LOJA', - B: 'TOP UP P24', - A: 'TRANSFER AGENT', - M: 'WITHDRAWAL AGENT', - O: 'TOP UP AGENT', - S: 'TRANSFER P24', - I: 'WIJTDRAW MERCHANT', - D: 'DONATION', - F: 'FEE', - V: 'REVERSAL', - C: 'CASHBACK CASH', - H: 'CASHBACK POINT' - }; - - const columns = [ - { - accessorKey: 'transaction_code', - header: ({ column }: any) => ( - - ), - enableSorting: false, - meta: { headerClassName: 'min-w-[120px]' } - }, - { - accessorKey: 'msisdn_reff', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[120px]' } - }, - { - accessorKey: 'transaction_type.name', - header: ({ column }: any) => ( - - ), - enableSorting: false, - meta: { headerClassName: 'min-w-[180px]' } - }, - { - accessorKey: 'type', - header: ({ column }: any) => , - enableSorting: false, - meta: { headerClassName: 'min-w-[80px]' } - }, - { - accessorKey: 'pre_amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' } - }, - { - accessorKey: 'amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' } - }, - { - accessorKey: 'post_amount', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue()?.toFixed(2), - meta: { headerClassName: 'min-w-[100px]' } - }, - { - accessorFn: (row: any) => categoryMap[row.category] || '_', - accessorKey: 'category', - header: ({ column }: any) => , - enableSorting: false, - enableHiding: false, - meta: { headerClassName: 'w-[250px]' } - }, - { - accessorKey: 'date', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => { - const val = info.getValue(); - if (!val) return '-'; - return new Date(val).toLocaleString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }); - }, - meta: { headerClassName: 'min-w-[150px]' } - }, - { - accessorKey: 'purpose', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue() || '-', - meta: { headerClassName: 'min-w-[200px]' } - }, - { - accessorKey: 'notes', - header: ({ column }: any) => , - enableSorting: false, - cell: (info: any) => info.getValue() || '-', - meta: { headerClassName: 'min-w-[200px]' } - } - ]; - - const getTransactionLists = useCallback( - async (page: number, limit: number, sorting: any, _columnFilters: any) => { - try { - const response = await GetData( - `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, - { - limit, - page: page + 1, - with_deleted: false, - order_field: sorting?.[0]?.id ?? 'created_at', - order_direction: sorting?.[0]?.desc ? 'ASC' : 'DESC', - filter: JSON.stringify(filters) - } - ); - - if (!response || !response.data) { - console.warn('No data received:', response); - return { data: [], totalCount: 0 }; - } - - setTransaction(response.data.list); - return { data: response.data.list, totalCount: response.data.total_count }; - } catch (error) { - console.error('Error fetching transaction', error); - return { data: [], totalCount: 0 }; - } - }, - [GetData, filters, selectedWallet] - ); - - const getAllTransactionData = async () => { - try { - const response = await GetData( - `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, - { - 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 []; - } - }; - - const formatTransactionData = (data: any[]) => { - return data.map((item) => ({ - 'Transaction Code': item.transaction_code || '-', - 'MSISDN Reffer': item.msisdn_reff || '-', - 'Transaction Type': item.transaction_type?.name || '-', - Type: item.type || '-', - 'Pre Amount': item.pre_amount?.toFixed(2) || '0.00', - Amount: item.amount?.toFixed(2) || '0.00', - 'Post Amount': item.post_amount?.toFixed(2) || '0.00', - Category: categoryMap[item.category] || '-', - Date: item.date - ? new Date(item.date).toLocaleString('id-ID', { - day: '2-digit', - month: 'short', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }) - : '-', - Purpose: item.purpose || '-', - Notes: item.notes || '-' - })); - }; - - const doExportExcel = async () => { - try { - const allData = await getAllTransactionData(); - const formattedData = formatTransactionData(allData); - - const wb = XLSX.utils.book_new(); - const ws = XLSX.utils.json_to_sheet([]); - - // Membuat space untuk header image (sekitar 10 baris) - const imageSpaceRows = 10; - - const companyHeader = [ - // Baris kosong untuk space gambar header - ...Array(imageSpaceRows).fill(['']), - [''], - ['Wallet Statement Details'], - [`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`], - [`Wallet Name: ${selectedWallet?.name || '-'}`], - [''] - ]; - - const columnHeaders = [ - [ - 'Transaction Code', - 'MSISDN Reffer', - 'Transaction Type', - 'Type', - 'Pre Amount', - 'Amount', - 'Post Amount', - 'Category', - 'Date', - 'Purpose', - 'Notes' - ] - ]; - - const excelData = [ - ...companyHeader, - ...columnHeaders, - ...formattedData.map((item) => Object.values(item)) - ]; - - XLSX.utils.sheet_add_aoa(ws, excelData); - - // Set column widths - const colWidths = [ - { wch: 20 }, - { wch: 15 }, - { wch: 35 }, - { wch: 10 }, - { wch: 12 }, - { wch: 12 }, - { wch: 12 }, - { wch: 15 }, - { wch: 20 }, - { wch: 25 }, - { wch: 25 } - ]; - ws['!cols'] = colWidths; - - // Style untuk title "Wallet Statement Details" - const titleRowIndex = imageSpaceRows + 1; - const titleCell = XLSX.utils.encode_cell({ r: titleRowIndex, c: 0 }); - if (ws[titleCell]) { - ws[titleCell].s = { - font: { bold: true, sz: 16 }, - alignment: { horizontal: 'center' } - }; - } - - // Style untuk export date dan wallet ID - for (let i = titleRowIndex + 1; i < titleRowIndex + 3; i++) { - const cellRef = XLSX.utils.encode_cell({ r: i, c: 0 }); - if (ws[cellRef]) { - ws[cellRef].s = { - font: { sz: 11 }, - alignment: { horizontal: 'left' } - }; - } - } - - // Merge cells untuk header area - if (!ws['!merges']) ws['!merges'] = []; - - // Merge untuk space gambar header - for (let i = 0; i < imageSpaceRows; i++) { - const range = XLSX.utils.encode_range({ s: { r: i, c: 0 }, e: { r: i, c: 10 } }); - ws['!merges'].push(XLSX.utils.decode_range(range)); - } - - // Merge untuk title dan info - for (let i = titleRowIndex; i < titleRowIndex + 4; i++) { - const range = XLSX.utils.encode_range({ s: { r: i, c: 0 }, e: { r: i, c: 10 } }); - ws['!merges'].push(XLSX.utils.decode_range(range)); - } - - // Style untuk column headers - const headerRowIndex = titleRowIndex + 4; - for (let col = 0; col < columnHeaders[0].length; col++) { - const cellRef = XLSX.utils.encode_cell({ r: headerRowIndex, c: col }); - if (ws[cellRef]) { - ws[cellRef].s = { - font: { bold: true, color: { rgb: 'FFFFFF' } }, - fill: { fgColor: { rgb: '4472C4' } }, - alignment: { horizontal: 'center' }, - border: { - top: { style: 'thin', color: { rgb: '000000' } }, - bottom: { style: 'thin', color: { rgb: '000000' } }, - left: { style: 'thin', color: { rgb: '000000' } }, - right: { style: 'thin', color: { rgb: '000000' } } - } - }; - } - } - - // Style untuk data rows - const dataStartRow = headerRowIndex + 1; - for (let row = dataStartRow; row < dataStartRow + formattedData.length; row++) { - for (let col = 0; col < columnHeaders[0].length; col++) { - const cellRef = XLSX.utils.encode_cell({ r: row, c: col }); - if (ws[cellRef]) { - ws[cellRef].s = { - alignment: { horizontal: 'left' }, // Semua kolom rata kiri - border: { - top: { style: 'thin', color: { rgb: 'D9D9D9' } }, - bottom: { style: 'thin', color: { rgb: 'D9D9D9' } }, - left: { style: 'thin', color: { rgb: 'D9D9D9' } }, - right: { style: 'thin', color: { rgb: 'D9D9D9' } } - } - }; - } - } - } - - try { - // Import ExcelJS untuk menambahkan gambar - const ExcelJS = await import('exceljs'); - - // Buat workbook baru dengan ExcelJS - const workbook = new ExcelJS.Workbook(); - const worksheet = workbook.addWorksheet('Wallet Statement'); - - // Tambahkan data dari XLSX worksheet ke ExcelJS worksheet - const range = XLSX.utils.decode_range(ws['!ref'] || 'A1:K1'); - - for (let row = range.s.r; row <= range.e.r; row++) { - for (let col = range.s.c; col <= range.e.c; col++) { - const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); - const cell = ws[cellAddress]; - if (cell && cell.v !== undefined) { - const excelCell = worksheet.getCell(row + 1, col + 1); - excelCell.value = cell.v; - - // Apply styles - if (cell.s) { - if (cell.s.font) { - excelCell.font = { - bold: cell.s.font.bold || false, - size: cell.s.font.sz || 11, - color: cell.s.font.color ? { argb: cell.s.font.color.rgb } : undefined - }; - } - if (cell.s.fill) { - excelCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: cell.s.fill.fgColor.rgb } - }; - } - if (cell.s.alignment) { - excelCell.alignment = { - horizontal: cell.s.alignment.horizontal || 'left' - }; - } - if (cell.s.border) { - excelCell.border = { - top: cell.s.border.top ? { style: 'thin' } : undefined, - bottom: cell.s.border.bottom ? { style: 'thin' } : undefined, - left: cell.s.border.left ? { style: 'thin' } : undefined, - right: cell.s.border.right ? { style: 'thin' } : undefined - }; - } - } - } - } - } - - // Set column widths - colWidths.forEach((width, index) => { - worksheet.getColumn(index + 1).width = width.wch; - }); - - // Merge cells - if (ws['!merges']) { - ws['!merges'].forEach((merge) => { - worksheet.mergeCells(merge.s.r + 1, merge.s.c + 1, merge.e.r + 1, merge.e.c + 1); - }); - } - - // Tambahkan gambar header - try { - const response = await fetch( - toAbsoluteUrl('/media/avatars/KopDetailWalletStatement.png') - ); - if (response.ok) { - const imageBuffer = await response.arrayBuffer(); - - const imageId = workbook.addImage({ - buffer: imageBuffer, - extension: 'png' - }); - - // Posisikan gambar di area header - worksheet.addImage(imageId, { - tl: { col: 1.7, row: 1 }, - ext: { width: 1100, height: 180 } - }); - } - } catch (imageError) { - console.warn('Could not load header image, continuing without it:', imageError); - } - - // Export file - const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.xlsx`; - const buffer = await workbook.xlsx.writeBuffer(); - - // Download file - const blob = new Blob([buffer], { - type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - }); - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - link.click(); - window.URL.revokeObjectURL(url); - } catch (excelJSError) { - console.warn('ExcelJS not available, falling back to XLSX without image:', excelJSError); - - XLSX.utils.book_append_sheet(wb, ws, 'Wallet Statement'); - const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.xlsx`; - XLSX.writeFile(wb, fileName); - } - } catch (error) { - console.error('Error exporting to Excel:', error); - toast.error('Failed to export Excel'); - } - }; - - const doExportPDF = async () => { - try { - const allData = await getAllTransactionData(); - const formattedData = formatTransactionData(allData); - - const pdf = new jsPDF({ - orientation: 'landscape', - unit: 'mm', - format: 'a4' - }); - - // Pindahkan deklarasi variabel ke luar block try-catch - const pageWidth = pdf.internal.pageSize.getWidth(); - const pageHeight = pdf.internal.pageSize.getHeight(); - - const headerImageUrl = toAbsoluteUrl('/media/avatars/KopDetailWalletStatement.png'); - - // Definisikan table configuration yang akan digunakan berkali-kali - const tableHeaders = [ - 'Transaction Code', - 'MSISDN Reffer', - 'Transaction Type', - 'Type', - 'Pre Amount', - 'Amount', - 'Post Amount', - 'Category', - 'Date', - 'Purpose', - 'Notes' - ]; - - const tableData = formattedData.map((item) => [ - item['Transaction Code'], - item['MSISDN Reffer'], - item['Transaction Type'], - item['Type'], - item['Pre Amount'], - item['Amount'], - item['Post Amount'], - item['Category'], - item['Date'], - item['Purpose'], - item['Notes'] - ]); - - const columnStyles = { - 0: { cellWidth: 25, halign: 'left' as const }, - 1: { cellWidth: 20, halign: 'left' as const }, - 2: { cellWidth: 25, halign: 'left' as const }, - 3: { cellWidth: 15, halign: 'left' as const }, - 4: { cellWidth: 18, halign: 'left' as const }, - 5: { cellWidth: 18, halign: 'left' as const }, - 6: { cellWidth: 18, halign: 'left' as const }, - 7: { cellWidth: 20, halign: 'left' as const }, - 8: { cellWidth: 30, halign: 'left' as const }, - 9: { cellWidth: 25, halign: 'left' as const }, - 10: { cellWidth: 25, halign: 'left' as const } - }; - - const calculateLeftMargin = ( - columnStyles: Record, - pageWidth: number - ): number => { - const totalTableWidth = Object.values(columnStyles).reduce( - (sum, col) => sum + col.cellWidth, - 0 - ); - return (pageWidth - totalTableWidth) / 2; - }; - - const leftMargin = calculateLeftMargin(columnStyles, pageWidth); - - try { - // Coba tambahkan header image - const imageWidth = 250; - const imageHeight = 40; - const xPosition = (pageWidth - imageWidth) / 2; - - pdf.addImage(headerImageUrl, 'PNG', xPosition, 10, imageWidth, imageHeight); - - let currentY = 55; - - // Garis pemisah - pdf.setDrawColor(0, 0, 0); - pdf.setLineWidth(0.5); - pdf.line(20, currentY, pageWidth - 20, currentY); - - currentY += 10; - - // Title - pdf.setFontSize(16); - pdf.setFont('helvetica', 'bold'); - pdf.text('Wallet Statement Details', pageWidth / 2, currentY, { align: 'center' }); - - currentY += 10; - - // Info export - pdf.setFontSize(10); - pdf.setFont('helvetica', 'normal'); - pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, currentY); - pdf.text(`Wallet Name: ${selectedWallet?.name || '-'}`, 20, currentY + 6); - - currentY += 20; - - // Render table dengan header image - autoTable(pdf, { - head: [tableHeaders], - body: tableData, - startY: currentY, - styles: { - fontSize: 7, - cellPadding: 1.5, - overflow: 'linebreak', - halign: 'left', - lineWidth: 0.1, - lineColor: [200, 200, 200] - }, - headStyles: { - fillColor: [68, 114, 196], - textColor: [255, 255, 255], - fontStyle: 'bold', - halign: 'center', - cellPadding: 1.5 - }, - columnStyles: columnStyles, - tableWidth: 'wrap', - margin: { - left: leftMargin, - right: leftMargin, - top: 10, - bottom: 10 - }, - didDrawPage: (data: any) => { - if (data.pageNumber > 1) { - pdf.setFontSize(10); - pdf.setFont('helvetica', 'normal'); - } - }, - theme: 'grid', - didDrawCell: (data: any) => { - if (data.section === 'body') { - pdf.setDrawColor(200, 200, 200); - pdf.setLineWidth(0.1); - } - }, - showHead: 'everyPage' - }); - - } catch (imageError) { - console.error('Error loading header image:', imageError); - - // Fallback tanpa gambar header - pdf.setFontSize(16); - pdf.setFont('helvetica', 'bold'); - pdf.text('Wallet Statement Details', pageWidth / 2, 20, { align: 'center' }); - - pdf.setFontSize(10); - pdf.setFont('helvetica', 'normal'); - pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, 30); - pdf.text(`Wallet ID: ${selectedWallet?.ID || '-'}`, 20, 36); - - autoTable(pdf, { - head: [tableHeaders], - body: tableData, - startY: 45, - styles: { - fontSize: 7, - cellPadding: 1.5, - overflow: 'linebreak', - halign: 'left' - }, - headStyles: { - fillColor: [68, 114, 196], - textColor: [255, 255, 255], - fontStyle: 'bold', - halign: 'center' - }, - columnStyles: columnStyles, - tableWidth: 'wrap', - margin: { left: leftMargin, right: leftMargin, top: 10, bottom: 10 }, - theme: 'grid', - showHead: 'everyPage', - didDrawPage: (data: any) => { - if (data.pageNumber > 1) { - pdf.setFontSize(10); - pdf.setFont('helvetica', 'normal'); - } - } - }); - } - - const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`; - pdf.save(fileName); - - } catch (error) { - console.error('Error exporting to PDF:', error); - toast.error('Failed to export PDF'); - } -}; - - const doExportData = async (sorting: any, filter: any) => { - const user = localStorage.getItem( - `${import.meta.env.VITE_APP_NAME}-auth-v${import.meta.env.VITE_APP_VERSION}` - ); - - const parsedUser = user ? JSON.parse(user) : null; - sorting = sorting.length === 0 ? [{ id: 'created_at', desc: false }] : sorting; - filter = filter && filter.length > 0 ? filter : []; - - let dataFilter: any = {}; - - if (filter && filter.length > 0) { - filter.forEach((f: any) => { - if (f.id === 'username') { - dataFilter['username'] = { like: f.value }; - } else if (f.id === 'created_at') { - dataFilter['created_at'] = f.value; - } - }); - } - - if (!dataFilter['created_at']) { - const defaultFrom = new Date(new Date().setMonth(new Date().getMonth() - 1)); - const defaultTo = new Date(); - - dataFilter['created_at'] = { - from: `${format(defaultFrom, 'yyyy-MM-dd')} 00:00:00`, - to: `${format(defaultTo, 'yyyy-MM-dd')} 23:59:59` - }; - } - - let param = { - order_field: sorting[0].id || 'created_at', - order_direction: sorting[0].desc ? 'DESC' : 'ASC', - with_deleted: false, - filter: JSON.stringify(dataFilter), - token: parsedUser?.access_token - }; - - let url = `${apiConfig.service_wallet}/dashboard/balance/list-balance-download/${selectedWallet?.ID}`; - - GetExportData(url, param, 'user_activity_export_'); - }; - - return ( - - - - - - Details Wallets Statement - - - - - - -
- - getTransactionLists(pageIndex, pageSize, sorting, columnFilters) - } - /> -
-
-
-
-
- ); -}; - -export default ShowDetailWalletDialog; \ No newline at end of file diff --git a/src/pages/wallet/wallet-statement/details_wallet_statement/ExportData.tsx b/src/pages/wallet/wallet-statement/details_wallet_statement/ExportData.tsx new file mode 100644 index 0000000..ca11e7e --- /dev/null +++ b/src/pages/wallet/wallet-statement/details_wallet_statement/ExportData.tsx @@ -0,0 +1,534 @@ +import * as XLSX from 'xlsx'; +import jsPDF from 'jspdf'; +import autoTable from 'jspdf-autotable'; +import ExcelJS from 'exceljs'; +import { format } from 'date-fns'; +import { toast } from 'sonner'; +import { toAbsoluteUrl } from '@/utils'; + +interface WalletData { + ID?: string; + name?: string; + msisdn?: string; +} + +interface TransactionItem { + transaction_code?: string; + msisdn_reff?: string; + transaction_type?: { name?: string }; + type?: string; + pre_amount?: number; + amount?: number; + post_amount?: number; + category?: string; + date?: string; + purpose?: string; + notes?: string; +} + +const categoryMap: Record = { + T: 'TRANSFER', + P: 'PURCHASE', + W: 'WITHDRAW', + U: 'TOP UP', + R: 'RETURN', + N: 'TOP UP PARTNER', + E: 'REWARD', + L: 'PURCHASE LOJA', + B: 'TOP UP P24', + A: 'TRANSFER AGENT', + M: 'WITHDRAWAL AGENT', + O: 'TOP UP AGENT', + S: 'TRANSFER P24', + I: 'WIJTDRAW MERCHANT', + D: 'DONATION', + F: 'FEE', + V: 'REVERSAL', + C: 'CASHBACK CASH', + H: 'CASHBACK POINT' +}; + +// Helper function untuk format data +export const formatTransactionData = (data: TransactionItem[]) => { + return data.map((item) => ({ + 'Transaction Code': item.transaction_code || '-', + 'MSISDN Reffer': item.msisdn_reff || '-', + 'Transaction Type': item.transaction_type?.name || '-', + Type: item.type || '-', + 'Pre Amount': item.pre_amount?.toFixed(2) || '0.00', + Amount: item.amount?.toFixed(2) || '0.00', + 'Post Amount': item.post_amount?.toFixed(2) || '0.00', + Category: categoryMap[item.category || ''] || '-', + Date: item.date + ? new Date(item.date).toLocaleString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + }) + : '-', + Purpose: item.purpose || '-', + Notes: item.notes || '-' + })); +}; + +// Helper function untuk membuat text dengan alignment +const createAlignedText = (label: string, value: string) => { + const maxLabelWidth = 15; + const paddedLabel = label.padEnd(maxLabelWidth, ' '); + return `${paddedLabel}: ${value}`; +}; + +// Helper function untuk menggambar info dengan titik dua rata tengah di PDF +const drawAlignedInfo = ( + pdf: any, + label: string, + value: string, + x: number, + y: number, + colonPosition: number +) => { + pdf.text(label, x, y); + pdf.text(':', x + colonPosition, y); + pdf.text(value, x + colonPosition + 3, y); +}; + +// Helper function untuk menghitung left margin PDF +const calculateLeftMargin = ( + columnStyles: Record, + pageWidth: number +): number => { + const totalTableWidth = Object.values(columnStyles).reduce((sum, col) => sum + col.cellWidth, 0); + return (pageWidth - totalTableWidth) / 2; +}; + +// Function untuk export Excel +export const exportToExcel = async (allData: TransactionItem[], selectedWallet: WalletData) => { + try { + const formattedData = formatTransactionData(allData); + const wb = XLSX.utils.book_new(); + const ws = XLSX.utils.json_to_sheet([]); + + // Space untuk header image + const imageSpaceRows = 10; + + const companyHeader = [ + ...Array(imageSpaceRows).fill(['']), + [''], + ['Wallet Statement Details'], + [createAlignedText('Wallet Name', selectedWallet?.name || '-')], + [createAlignedText('MSISDN', selectedWallet?.msisdn || '-')], + [createAlignedText('Export Date', format(new Date(), 'dd MMM yyyy HH:mm:ss'))], + [''] + ]; + + const columnHeaders = [ + [ + 'Transaction Code', + 'MSISDN Reffer', + 'Transaction Type', + 'Type', + 'Pre Amount', + 'Amount', + 'Post Amount', + 'Category', + 'Date', + 'Purpose', + 'Notes' + ] + ]; + + const excelData = [ + ...companyHeader, + ...columnHeaders, + ...formattedData.map((item) => Object.values(item)) + ]; + + XLSX.utils.sheet_add_aoa(ws, excelData); + + // Set column widths + const colWidths = [ + { wch: 20 }, + { wch: 15 }, + { wch: 35 }, + { wch: 10 }, + { wch: 12 }, + { wch: 12 }, + { wch: 12 }, + { wch: 15 }, + { wch: 20 }, + { wch: 25 }, + { wch: 25 } + ]; + ws['!cols'] = colWidths; + + // Styling + const titleRowIndex = imageSpaceRows + 1; + const titleCell = XLSX.utils.encode_cell({ r: titleRowIndex, c: 0 }); + if (ws[titleCell]) { + ws[titleCell].s = { + font: { bold: true, sz: 16 }, + alignment: { horizontal: 'center' } + }; + } + + // Style untuk info rows + for (let i = titleRowIndex + 1; i < titleRowIndex + 4; i++) { + const cellRef = XLSX.utils.encode_cell({ r: i, c: 0 }); + if (ws[cellRef]) { + ws[cellRef].s = { + font: { sz: 11, name: 'Courier New' }, + alignment: { horizontal: 'left' } + }; + } + } + + // Merge cells + if (!ws['!merges']) ws['!merges'] = []; + + // Merge untuk space gambar header + for (let i = 0; i < imageSpaceRows; i++) { + const range = XLSX.utils.encode_range({ s: { r: i, c: 0 }, e: { r: i, c: 10 } }); + ws['!merges'].push(XLSX.utils.decode_range(range)); + } + + // Merge untuk title + const titleRange = XLSX.utils.encode_range({ + s: { r: titleRowIndex, c: 0 }, + e: { r: titleRowIndex, c: 10 } + }); + ws['!merges'].push(XLSX.utils.decode_range(titleRange)); + + // Merge untuk info rows + for (let i = titleRowIndex + 1; i < titleRowIndex + 4; i++) { + const range = XLSX.utils.encode_range({ s: { r: i, c: 0 }, e: { r: i, c: 10 } }); + ws['!merges'].push(XLSX.utils.decode_range(range)); + } + + // Style untuk column headers + const headerRowIndex = titleRowIndex + 5; + for (let col = 0; col < columnHeaders[0].length; col++) { + const cellRef = XLSX.utils.encode_cell({ r: headerRowIndex, c: col }); + if (ws[cellRef]) { + ws[cellRef].s = { + font: { bold: true, color: { rgb: 'FFFFFF' } }, + fill: { fgColor: { rgb: '4472C4' } }, + alignment: { horizontal: 'center' }, + border: { + top: { style: 'thin', color: { rgb: '000000' } }, + bottom: { style: 'thin', color: { rgb: '000000' } }, + left: { style: 'thin', color: { rgb: '000000' } }, + right: { style: 'thin', color: { rgb: '000000' } } + } + }; + } + } + + // Style untuk data rows + const dataStartRow = headerRowIndex + 1; + for (let row = dataStartRow; row < dataStartRow + formattedData.length; row++) { + for (let col = 0; col < columnHeaders[0].length; col++) { + const cellRef = XLSX.utils.encode_cell({ r: row, c: col }); + if (ws[cellRef]) { + ws[cellRef].s = { + alignment: { horizontal: 'left' }, + border: { + top: { style: 'thin', color: { rgb: 'D9D9D9' } }, + bottom: { style: 'thin', color: { rgb: 'D9D9D9' } }, + left: { style: 'thin', color: { rgb: 'D9D9D9' } }, + right: { style: 'thin', color: { rgb: 'D9D9D9' } } + } + }; + } + } + } + + try { + // Gunakan ExcelJS untuk menambahkan gambar + const workbook = new ExcelJS.Workbook(); + const worksheet = workbook.addWorksheet('Wallet Statement'); + + // Transfer data dari XLSX ke ExcelJS + const range = XLSX.utils.decode_range(ws['!ref'] || 'A1:K1'); + + for (let row = range.s.r; row <= range.e.r; row++) { + for (let col = range.s.c; col <= range.e.c; col++) { + const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); + const cell = ws[cellAddress]; + if (cell && cell.v !== undefined) { + const excelCell = worksheet.getCell(row + 1, col + 1); + excelCell.value = cell.v; + + // Apply styles + if (cell.s) { + if (cell.s.font) { + excelCell.font = { + bold: cell.s.font.bold || false, + size: cell.s.font.sz || 11, + name: cell.s.font.name || 'Calibri', + color: cell.s.font.color ? { argb: cell.s.font.color.rgb } : undefined + }; + } + if (cell.s.fill) { + excelCell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: cell.s.fill.fgColor.rgb } + }; + } + if (cell.s.alignment) { + excelCell.alignment = { + horizontal: cell.s.alignment.horizontal || 'left' + }; + } + if (cell.s.border) { + excelCell.border = { + top: cell.s.border.top ? { style: 'thin' } : undefined, + bottom: cell.s.border.bottom ? { style: 'thin' } : undefined, + left: cell.s.border.left ? { style: 'thin' } : undefined, + right: cell.s.border.right ? { style: 'thin' } : undefined + }; + } + } + } + } + } + + // Set column widths + colWidths.forEach((width, index) => { + worksheet.getColumn(index + 1).width = width.wch; + }); + + // Merge cells + if (ws['!merges']) { + ws['!merges'].forEach((merge) => { + worksheet.mergeCells(merge.s.r + 1, merge.s.c + 1, merge.e.r + 1, merge.e.c + 1); + }); + } + + // Tambahkan gambar header + try { + const response = await fetch(toAbsoluteUrl('/media/avatars/KopDetailWalletStatement.png')); + if (response.ok) { + const imageBuffer = await response.arrayBuffer(); + const imageId = workbook.addImage({ + buffer: imageBuffer, + extension: 'png' + }); + + worksheet.addImage(imageId, { + tl: { col: 1.7, row: 1 }, + ext: { width: 1100, height: 180 } + }); + } + } catch (imageError) { + console.warn('Could not load header image, continuing without it:', imageError); + } + + // Export file + const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.xlsx`; + const buffer = await workbook.xlsx.writeBuffer(); + + const blob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = fileName; + link.click(); + window.URL.revokeObjectURL(url); + } catch (excelJSError) { + console.warn('ExcelJS not available, falling back to XLSX without image:', excelJSError); + XLSX.utils.book_append_sheet(wb, ws, 'Wallet Statement'); + const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.xlsx`; + XLSX.writeFile(wb, fileName); + } + } catch (error) { + console.error('Error exporting to Excel:', error); + toast.error('Failed to export Excel'); + } +}; + +// Function untuk export PDF +export const exportToPDF = async (allData: TransactionItem[], selectedWallet: WalletData) => { + try { + const formattedData = formatTransactionData(allData); + const pdf = new jsPDF({ + orientation: 'landscape', + unit: 'mm', + format: 'a4' + }); + + const pageWidth = pdf.internal.pageSize.getWidth(); + const headerImageUrl = toAbsoluteUrl('/media/avatars/KopDetailWalletStatement.png'); + + // Table configuration + const tableHeaders = [ + 'Transaction Code', + 'MSISDN Reffer', + 'Transaction Type', + 'Type', + 'Pre Amount', + 'Amount', + 'Post Amount', + 'Category', + 'Date', + 'Purpose', + 'Notes' + ]; + + const tableData = formattedData.map((item) => [ + item['Transaction Code'], + item['MSISDN Reffer'], + item['Transaction Type'], + item['Type'], + item['Pre Amount'], + item['Amount'], + item['Post Amount'], + item['Category'], + item['Date'], + item['Purpose'], + item['Notes'] + ]); + + const columnStyles = { + 0: { cellWidth: 25, halign: 'left' as const }, + 1: { cellWidth: 20, halign: 'left' as const }, + 2: { cellWidth: 25, halign: 'left' as const }, + 3: { cellWidth: 15, halign: 'left' as const }, + 4: { cellWidth: 18, halign: 'left' as const }, + 5: { cellWidth: 18, halign: 'left' as const }, + 6: { cellWidth: 18, halign: 'left' as const }, + 7: { cellWidth: 20, halign: 'left' as const }, + 8: { cellWidth: 30, halign: 'left' as const }, + 9: { cellWidth: 25, halign: 'left' as const }, + 10: { cellWidth: 25, halign: 'left' as const } + }; + + const leftMargin = calculateLeftMargin(columnStyles, pageWidth); + + try { + // Tambahkan header image + const imageWidth = 250; + const imageHeight = 40; + const xPosition = (pageWidth - imageWidth) / 2; + + pdf.addImage(headerImageUrl, 'PNG', xPosition, 10, imageWidth, imageHeight); + + let currentY = 55; + + // Garis pemisah + pdf.setDrawColor(0, 0, 0); + pdf.setLineWidth(0.5); + pdf.line(20, currentY, pageWidth - 20, currentY); + + currentY += 10; + + // Title + pdf.setFontSize(16); + pdf.setFont('helvetica', 'bold'); + pdf.text('Wallet Statement Details', pageWidth / 2, currentY, { align: 'center' }); + + currentY += 10; + + // Info export + pdf.setFontSize(10); + pdf.setFont('helvetica', 'normal'); + const colonPosition = 25; + + drawAlignedInfo(pdf, 'Wallet Name', selectedWallet?.name || '-', 20, currentY, colonPosition); + drawAlignedInfo( + pdf, + 'MSISDN', + selectedWallet?.msisdn || '-', + 20, + currentY + 6, + colonPosition + ); + drawAlignedInfo( + pdf, + 'Export Date', + format(new Date(), 'dd MMM yyyy HH:mm:ss'), + 20, + currentY + 12, + colonPosition + ); + + currentY += 20; + + // Render table + autoTable(pdf, { + head: [tableHeaders], + body: tableData, + startY: currentY, + styles: { + fontSize: 7, + cellPadding: 1.5, + overflow: 'linebreak', + halign: 'left', + lineWidth: 0.1, + lineColor: [200, 200, 200] + }, + headStyles: { + fillColor: [68, 114, 196], + textColor: [255, 255, 255], + fontStyle: 'bold', + halign: 'center', + cellPadding: 1.5 + }, + columnStyles: columnStyles, + tableWidth: 'wrap', + margin: { left: leftMargin, right: leftMargin, top: 10, bottom: 10 }, + theme: 'grid', + showHead: 'everyPage' + }); + } catch (imageError) { + console.error('Error loading header image:', imageError); + + // Fallback tanpa gambar + pdf.setFontSize(16); + pdf.setFont('helvetica', 'bold'); + pdf.text('Wallet Statement Details', pageWidth / 2, 20, { align: 'center' }); + + pdf.setFontSize(10); + pdf.setFont('helvetica', 'normal'); + const colonPosition = 25; + + drawAlignedInfo( + pdf, + 'Export Date', + format(new Date(), 'dd MMM yyyy HH:mm:ss'), + 20, + 30, + colonPosition + ); + drawAlignedInfo(pdf, 'Wallet ID', selectedWallet?.ID || '-', 20, 36, colonPosition); + + autoTable(pdf, { + head: [tableHeaders], + body: tableData, + startY: 45, + styles: { fontSize: 7, cellPadding: 1.5, overflow: 'linebreak', halign: 'left' }, + headStyles: { + fillColor: [68, 114, 196], + textColor: [255, 255, 255], + fontStyle: 'bold', + halign: 'center' + }, + columnStyles: columnStyles, + tableWidth: 'wrap', + margin: { left: leftMargin, right: leftMargin, top: 10, bottom: 10 }, + theme: 'grid', + showHead: 'everyPage' + }); + } + + const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`; + pdf.save(fileName); + } catch (error) { + console.error('Error exporting to PDF:', error); + toast.error('Failed to export PDF'); + } +}; diff --git a/src/pages/wallet/wallet-statement/blocks/FilterSection.tsx b/src/pages/wallet/wallet-statement/details_wallet_statement/FilterSection.tsx similarity index 95% rename from src/pages/wallet/wallet-statement/blocks/FilterSection.tsx rename to src/pages/wallet/wallet-statement/details_wallet_statement/FilterSection.tsx index d4224e1..aa7e4e7 100644 --- a/src/pages/wallet/wallet-statement/blocks/FilterSection.tsx +++ b/src/pages/wallet/wallet-statement/details_wallet_statement/FilterSection.tsx @@ -33,7 +33,7 @@ const FilterSection: React.FC = ({ }) => { const { GetData } = useCallApi(); const [dateRange, setDateRange] = useState({ - from: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), + from: new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), to: new Date().toLocaleDateString('sv-SE') }); const [selectedTransferType, setSelectedTransferType] = useState(null); @@ -46,7 +46,6 @@ const FilterSection: React.FC = ({ const handleExportExcel = async () => { try { await doExportExcel(); - // console.log('Excel export initiated successfully'); } catch (error) { console.error('Error during Excel export:', error); } @@ -55,7 +54,6 @@ const FilterSection: React.FC = ({ const handleExportPDF = async () => { try { await doExportPDF(); - // console.log('PDF export initiated successfully'); } catch (error) { console.error('Error during PDF export:', error); } @@ -108,7 +106,7 @@ const FilterSection: React.FC = ({ const handleClearAllFilters = () => { setDateRange({ - from: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), + from: new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), to: new Date().toLocaleDateString('sv-SE') }); setSelectedTransferType(null); diff --git a/src/pages/wallet/wallet-statement/details_wallet_statement/ShowDetailDialog.tsx b/src/pages/wallet/wallet-statement/details_wallet_statement/ShowDetailDialog.tsx new file mode 100644 index 0000000..400ebdd --- /dev/null +++ b/src/pages/wallet/wallet-statement/details_wallet_statement/ShowDetailDialog.tsx @@ -0,0 +1,315 @@ +import React, { createContext, useCallback, useEffect, useState } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; +import { DataGridColumnHeader, DataGridProvider } from '@/components'; +import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; +import { toast, Toaster } from 'sonner'; +import { format } from 'date-fns'; +import FilterSection from './FilterSection'; +import { exportToExcel, exportToPDF } from './ExportData'; + +interface ContextProps { + doExportData: (sorting: any, filter: any) => Promise; + doExportExcel: () => Promise; + doExportPDF: () => Promise; +} + +const initialProps: ContextProps = { + doExportData: async () => ({ data: [], totalCount: 0 }), + doExportExcel: async () => {}, + doExportPDF: async () => {} +}; + +export const showDetailWalletContext = createContext(initialProps); + +const ShowDetailWalletDialog = () => { + const { GetData, GetExportData } = useCallApi(); + const { showDetailDialog, setShowDetailDialog, selectedWallet } = useManageStatementContext(); + const [filters, setFilters] = useState({}); + const [transaction, setTransaction] = useState([]); + + const categoryMap: Record = { + T: 'TRANSFER', + P: 'PURCHASE', + W: 'WITHDRAW', + U: 'TOP UP', + R: 'RETURN', + N: 'TOP UP PARTNER', + E: 'REWARD', + L: 'PURCHASE LOJA', + B: 'TOP UP P24', + A: 'TRANSFER AGENT', + M: 'WITHDRAWAL AGENT', + O: 'TOP UP AGENT', + S: 'TRANSFER P24', + I: 'WIJTDRAW MERCHANT', + D: 'DONATION', + F: 'FEE', + V: 'REVERSAL', + C: 'CASHBACK CASH', + H: 'CASHBACK POINT' + }; + + const columns = [ + { + accessorKey: 'transaction_code', + header: ({ column }: any) => ( + + ), + enableSorting: false, + meta: { headerClassName: 'min-w-[120px]' } + }, + { + accessorKey: 'msisdn_reff', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[120px]' } + }, + { + accessorKey: 'transaction_type.name', + header: ({ column }: any) => ( + + ), + enableSorting: false, + meta: { headerClassName: 'min-w-[180px]' } + }, + { + accessorKey: 'type', + header: ({ column }: any) => , + enableSorting: false, + meta: { headerClassName: 'min-w-[80px]' } + }, + { + accessorKey: 'pre_amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' } + }, + { + accessorKey: 'amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' } + }, + { + accessorKey: 'post_amount', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue()?.toFixed(2), + meta: { headerClassName: 'min-w-[100px]' } + }, + { + accessorFn: (row: any) => categoryMap[row.category] || '_', + accessorKey: 'category', + header: ({ column }: any) => , + enableSorting: false, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorKey: 'date', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => { + const val = info.getValue(); + if (!val) return '-'; + return new Date(val).toLocaleString('id-ID', { + day: '2-digit', + month: 'short', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + }, + meta: { headerClassName: 'min-w-[150px]' } + }, + { + accessorKey: 'purpose', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue() || '-', + meta: { headerClassName: 'min-w-[200px]' } + }, + { + accessorKey: 'notes', + header: ({ column }: any) => , + enableSorting: false, + cell: (info: any) => info.getValue() || '-', + meta: { headerClassName: 'min-w-[200px]' } + } + ]; + + const getTransactionLists = useCallback( + async (page: number, limit: number, sorting: any, _columnFilters: any) => { + try { + const response = await GetData( + `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, + { + limit, + page: page + 1, + with_deleted: false, + order_field: sorting?.[0]?.id ?? 'created_at', + order_direction: sorting?.[0]?.desc ? 'ASC' : 'DESC', + filter: JSON.stringify(filters) + } + ); + + if (!response || !response.data) { + console.warn('No data received:', response); + return { data: [], totalCount: 0 }; + } + + setTransaction(response.data.list); + return { data: response.data.list, totalCount: response.data.total_count }; + } catch (error) { + console.error('Error fetching transaction', error); + return { data: [], totalCount: 0 }; + } + }, + [GetData, filters, selectedWallet] + ); + + const getAllTransactionData = async () => { + try { + const response = await GetData( + `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, + { + 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 []; + } + }; + + const doExportExcel = async () => { + try { + if (!selectedWallet) { + console.error('Something went wrong. Please try again...'); + return; + } + + const allData = await getAllTransactionData(); + await exportToExcel(allData, selectedWallet); + } catch (error) { + console.error('Error in doExportExcel:', error); + toast.error('Failed to export Excel'); + } + }; + + const doExportPDF = async () => { + try { + if (!selectedWallet) { + console.error('Something went wrong. Please try again...'); + return; + } + + const allData = await getAllTransactionData(); + await exportToPDF(allData, selectedWallet); + } catch (error) { + console.error('Error in doExportPDF:', error); + toast.error('Failed to export PDF'); + } + }; + + const doExportData = async (sorting: any, filter: any) => { + const user = localStorage.getItem( + `${import.meta.env.VITE_APP_NAME}-auth-v${import.meta.env.VITE_APP_VERSION}` + ); + + const parsedUser = user ? JSON.parse(user) : null; + sorting = sorting.length === 0 ? [{ id: 'created_at', desc: false }] : sorting; + filter = filter && filter.length > 0 ? filter : []; + + let dataFilter: any = {}; + + if (filter && filter.length > 0) { + filter.forEach((f: any) => { + if (f.id === 'username') { + dataFilter['username'] = { like: f.value }; + } else if (f.id === 'created_at') { + dataFilter['created_at'] = f.value; + } + }); + } + + if (!dataFilter['created_at']) { + const defaultFrom = new Date(new Date().setMonth(new Date().getMonth() - 1)); + const defaultTo = new Date(); + + dataFilter['created_at'] = { + from: `${format(defaultFrom, 'yyyy-MM-dd')} 00:00:00`, + to: `${format(defaultTo, 'yyyy-MM-dd')} 23:59:59` + }; + } + + let param = { + order_field: sorting[0].id || 'created_at', + order_direction: sorting[0].desc ? 'DESC' : 'ASC', + with_deleted: false, + filter: JSON.stringify(dataFilter), + token: parsedUser?.access_token + }; + + let url = `${apiConfig.service_wallet}/dashboard/balance/list-balance-download/${selectedWallet?.ID}`; + + GetExportData(url, param, 'user_activity_export_'); + }; + + return ( + + + + + + Details Wallets Statement + + + + + + +
+ + getTransactionLists(pageIndex, pageSize, sorting, columnFilters) + } + /> +
+
+
+
+
+ ); +}; + +export default ShowDetailWalletDialog; diff --git a/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx index c461931..690c088 100644 --- a/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx +++ b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx @@ -5,7 +5,7 @@ import { useCallApi } from '@/hooks'; import { ColumnDef } from '@tanstack/react-table'; import React, { createContext, useCallback, useMemo, useState } from 'react'; import ListToolbar from '../blocks/ListToolbar'; -import ShowDetailDialog from '../blocks/ShowDetailDialog'; +import ShowDetailDialog from '../details_wallet_statement/ShowDetailDialog'; const formatNumber = (num: number): string => { return num.toLocaleString('en-US', { @@ -20,6 +20,7 @@ interface WalletProps { name: string; id_currency: string; status: string; + msisdn: string; } interface ContextProps { @@ -157,7 +158,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } }, { accessorKey: 'CreatedAt', - header: ({ column }) => , + header: ({ column }) => , cell: ({ row }) => new Date(row.original.CreatedAt).toLocaleString('id-ID', { day: '2-digit',