diff --git a/public/media/avatars/KopDetailWalletStatement.png b/public/media/avatars/KopDetailWalletStatement.png new file mode 100644 index 0000000..a2c150b Binary files /dev/null and b/public/media/avatars/KopDetailWalletStatement.png differ diff --git a/src/pages/notification/blocks/AddDialog.tsx b/src/pages/notification/blocks/AddDialog.tsx index 3477d9b..2e9322c 100644 --- a/src/pages/notification/blocks/AddDialog.tsx +++ b/src/pages/notification/blocks/AddDialog.tsx @@ -119,7 +119,7 @@ const AddDialog = () => { } const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { - limit: 100, + limit: 1000, page: 1, with_deleted: false, order_field: 'fullname', diff --git a/src/pages/notification/hooks/ManageNotificationContext.tsx b/src/pages/notification/hooks/ManageNotificationContext.tsx index c4995f3..b6b7ca4 100644 --- a/src/pages/notification/hooks/ManageNotificationContext.tsx +++ b/src/pages/notification/hooks/ManageNotificationContext.tsx @@ -158,7 +158,7 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode }) const getNotificationList = async (page: number, limit: number, sorting: any, filter: any) => { try { const sortField = sorting.length > 0 ? sorting[0].id : 'created_at'; - const sortDirection = sorting.length > 0 ? (sorting[0].desc ? 'DESC' : 'ASC') : 'DESC'; + const sortDirection = sorting.length > 0 ? (sorting[0].desc ? 'ASC' : 'DESC') : 'ASC'; // Initialize filter object let filterParams: any = {}; @@ -219,7 +219,7 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode }) pagination={{ size: 10 }} toolbar={} layout={{ card: true }} - sorting={[{ id: 'created_at', desc: true }]} + sorting={[{ id: 'created_at', desc: false }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => getNotificationList(pageIndex, pageSize, sorting, columnFilters) diff --git a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx index 53e9047..2dc26a4 100644 --- a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx +++ b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx @@ -11,13 +11,19 @@ import { useCallApi } from '@/hooks'; import { apiConfig } from '@/config/api.config'; import { DataGridColumnHeader, DataGridProvider } from '@/components'; import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; -import { Toaster } from 'sonner'; +import { toast, Toaster } from 'sonner'; import { format } from 'date-fns'; import FilterSection from './FilterSection'; import * as XLSX from 'xlsx'; import jsPDF from 'jspdf'; import 'jspdf-autotable'; +interface AutoTableData { + pageNumber: number; + table: any; + doc: jsPDF; +} + interface ContextProps { doExportData: (sorting: any, filter: any) => Promise; doExportExcel: () => Promise; @@ -186,7 +192,7 @@ const ShowDetailWalletDialog = () => { const response = await GetData( `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, { - limit: 10000, + limit: 10000, page: 1, with_deleted: false, order_field: 'amount', @@ -233,19 +239,19 @@ const ShowDetailWalletDialog = () => { const wb = XLSX.utils.book_new(); - const ws = XLSX.utils.json_to_sheet([]); + const ws = XLSX.utils.json_to_sheet([]); const companyHeader = [ - ['T•PAY'], + ['T•PAY'], ['Telin Digital Solution'], ['Av. Pres. Nicolau Lobato, Dili'], ['Tel: (+670) 74147147 / 147'], ['www.t-pay.tl'], - [''], + [''], ['Wallet Statement Details'], [`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`], [`Wallet ID: ${selectedWallet?.ID || '-'}`], - [''] + [''] ]; const columnHeaders = [ @@ -273,17 +279,17 @@ const ShowDetailWalletDialog = () => { XLSX.utils.sheet_add_aoa(ws, excelData); const colWidths = [ - { wch: 20 }, - { wch: 15 }, - { wch: 25 }, - { wch: 10 }, - { wch: 12 }, - { wch: 12 }, - { wch: 12 }, - { wch: 15 }, - { wch: 20 }, - { wch: 25 }, - { wch: 25 } + { wch: 20 }, + { wch: 15 }, + { wch: 25 }, + { wch: 10 }, + { wch: 12 }, + { wch: 12 }, + { wch: 12 }, + { wch: 15 }, + { wch: 20 }, + { wch: 25 }, + { wch: 25 } ]; ws['!cols'] = colWidths; @@ -292,7 +298,7 @@ const ShowDetailWalletDialog = () => { ws[tpayCell].s = { font: { bold: true, sz: 18, color: { rgb: '000000' } }, alignment: { horizontal: 'center' }, - fill: { fgColor: { rgb: 'F4C2C2' } } + fill: { fgColor: { rgb: 'F4C2C2' } } }; } @@ -302,7 +308,7 @@ const ShowDetailWalletDialog = () => { ws[cellRef].s = { font: { sz: 12, color: { rgb: '000000' } }, alignment: { horizontal: 'center' }, - fill: { fgColor: { rgb: 'F4C2C2' } } + fill: { fgColor: { rgb: 'F4C2C2' } } }; } } @@ -336,7 +342,7 @@ const ShowDetailWalletDialog = () => { if (ws[cellRef]) { ws[cellRef].s = { font: { bold: true, color: { rgb: 'FFFFFF' } }, - fill: { fgColor: { rgb: '4472C4' } }, + fill: { fgColor: { rgb: '4472C4' } }, alignment: { horizontal: 'center' }, border: { top: { style: 'thin', color: { rgb: '000000' } }, @@ -379,98 +385,137 @@ const ShowDetailWalletDialog = () => { } }; - const doExportPDF = async () => { - try { - const allData = await getAllTransactionData(); - const formattedData = formatTransactionData(allData); + // Perbaikan untuk fungsi doExportPDF +const doExportPDF = async () => { + try { + // Import jsPDF dengan cara yang benar + const jsPDF = (await import('jspdf')).default; + + // Import autoTable plugin + const autoTable = (await import('jspdf-autotable')).default; + + const allData = await getAllTransactionData(); + const formattedData = formatTransactionData(allData); - const pdf = new jsPDF('l', 'mm', 'a4'); + // Buat instance jsPDF + const pdf = new jsPDF({ + orientation: 'landscape', // Ubah ke landscape untuk tabel yang lebar + unit: 'mm', + format: 'a4' + }); - pdf.setFontSize(20); - pdf.setFont('helvetica', 'bold'); - pdf.text('T•PAY', 148, 20, { align: 'center' }); + // Header perusahaan + pdf.setFontSize(18); + pdf.setFont('helvetica', 'bold'); + pdf.text('T•PAY', pdf.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); + + pdf.setFontSize(12); + pdf.setFont('helvetica', 'normal'); + pdf.text('Telin Digital Solution', pdf.internal.pageSize.getWidth() / 2, 28, { align: 'center' }); + pdf.text('Av. Pres. Nicolau Lobato, Dili', pdf.internal.pageSize.getWidth() / 2, 34, { align: 'center' }); + pdf.text('Tel: (+670) 74147147 / 147', pdf.internal.pageSize.getWidth() / 2, 40, { align: 'center' }); + pdf.text('www.t-pay.tl', pdf.internal.pageSize.getWidth() / 2, 46, { align: 'center' }); - pdf.setFontSize(12); - pdf.setFont('helvetica', 'normal'); - pdf.text('Telin Digital Solution', 148, 30, { align: 'center' }); - pdf.text('Av. Pres. Nicolau Lobato, Dili', 148, 36, { align: 'center' }); - pdf.text('Tel : (+670) 7414747 / 147', 148, 42, { align: 'center' }); - pdf.text('www.t-pay.tl', 148, 48, { align: 'center' }); + // Garis pemisah + pdf.setDrawColor(0, 0, 0); + pdf.setLineWidth(0.5); + pdf.line(20, 52, pdf.internal.pageSize.getWidth() - 20, 52); - pdf.setFontSize(14); - pdf.setFont('helvetica', 'bold'); - pdf.text('Wallet Statement Details', 148, 60, { align: 'center' }); + // Judul laporan + pdf.setFontSize(16); + pdf.setFont('helvetica', 'bold'); + pdf.text('Wallet Statement Details', pdf.internal.pageSize.getWidth() / 2, 62, { align: 'center' }); - pdf.setFontSize(10); - pdf.setFont('helvetica', 'normal'); - pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, 70); - pdf.text(`Wallet ID: ${selectedWallet?.ID || '-'}`, 20, 76); + // Informasi tambahan + pdf.setFontSize(10); + pdf.setFont('helvetica', 'normal'); + pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, 72); + pdf.text(`Wallet ID: ${selectedWallet?.ID || '-'}`, 20, 78); - 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'] - ]); + // Siapkan data tabel + const tableHeaders = [ + 'Transaction Code', + 'MSISDN Reffer', + 'Transaction Type', + 'Type', + 'Pre Amount', + 'Amount', + 'Post Amount', + 'Category', + 'Date', + 'Purpose', + 'Notes' + ]; - (pdf as any).autoTable({ - head: [ - [ - 'Transaction Code', - 'MSISDN Reffer', - 'Transaction Type', - 'Type', - 'Pre Amount', - 'Amount', - 'Post Amount', - 'Category', - 'Date', - 'Purpose', - 'Notes' - ] - ], - body: tableData, - startY: 85, - styles: { - fontSize: 8, - cellPadding: 2 - }, - headStyles: { - fillColor: [66, 66, 66], - textColor: [255, 255, 255], - fontStyle: 'bold' - }, - columnStyles: { - 0: { cellWidth: 20 }, - 1: { cellWidth: 20 }, - 2: { cellWidth: 25 }, - 3: { cellWidth: 15 }, - 4: { cellWidth: 18 }, - 5: { cellWidth: 18 }, - 6: { cellWidth: 18 }, - 7: { cellWidth: 25 }, - 8: { cellWidth: 25 }, - 9: { cellWidth: 30 }, - 10: { cellWidth: 30 } - }, - margin: { top: 85, left: 10, right: 10 } - }); + 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 fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`; - pdf.save(fileName); + // Gunakan autoTable dengan cara yang benar + autoTable(pdf, { + head: [tableHeaders], + body: tableData, + startY: 85, + styles: { + fontSize: 7, + cellPadding: 2, + overflow: 'linebreak', + halign: 'center' + }, + headStyles: { + fillColor: [68, 114, 196], + textColor: [255, 255, 255], + fontStyle: 'bold', + halign: 'center' + }, + columnStyles: { + 0: { cellWidth: 25, halign: 'left' }, // Transaction Code + 1: { cellWidth: 20, halign: 'left' }, // MSISDN Reffer + 2: { cellWidth: 25, halign: 'left' }, // Transaction Type + 3: { cellWidth: 15, halign: 'center' }, // Type + 4: { cellWidth: 18, halign: 'right' }, // Pre Amount + 5: { cellWidth: 18, halign: 'right' }, // Amount + 6: { cellWidth: 18, halign: 'right' }, // Post Amount + 7: { cellWidth: 20, halign: 'left' }, // Category + 8: { cellWidth: 30, halign: 'left' }, // Date + 9: { cellWidth: 25, halign: 'left' }, // Purpose + 10: { cellWidth: 25, halign: 'left' } // Notes + }, + margin: { top: 85, left: 10, right: 10 }, + tableWidth: 'auto', + // Callback untuk styling baris + didDrawCell: (data: any) => { + // Tambahkan border pada setiap cell + if (data.section === 'body') { + pdf.setDrawColor(200, 200, 200); + pdf.setLineWidth(0.1); + } + } + }); - // console.log('PDF export completed successfully'); - } catch (error) { + // Generate nama file + const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`; + + // Save file + pdf.save(fileName); + + toast.success('PDF exported successfully'); + + } 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(