radja terakhir

This commit is contained in:
Raja Oktafrianto
2025-06-05 19:04:37 +07:00
parent 3ab4a8a8e0
commit 86e9811c5a
4 changed files with 149 additions and 104 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

View File

@ -119,7 +119,7 @@ const AddDialog = () => {
} }
const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, {
limit: 100, limit: 1000,
page: 1, page: 1,
with_deleted: false, with_deleted: false,
order_field: 'fullname', order_field: 'fullname',

View File

@ -158,7 +158,7 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode })
const getNotificationList = async (page: number, limit: number, sorting: any, filter: any) => { const getNotificationList = async (page: number, limit: number, sorting: any, filter: any) => {
try { try {
const sortField = sorting.length > 0 ? sorting[0].id : 'created_at'; 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 // Initialize filter object
let filterParams: any = {}; let filterParams: any = {};
@ -219,7 +219,7 @@ const ManageNotifContextProvider = ({ children }: { children: React.ReactNode })
pagination={{ size: 10 }} pagination={{ size: 10 }}
toolbar={<ListToolBar />} toolbar={<ListToolBar />}
layout={{ card: true }} layout={{ card: true }}
sorting={[{ id: 'created_at', desc: true }]} sorting={[{ id: 'created_at', desc: false }]}
serverSide={true} serverSide={true}
onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) =>
getNotificationList(pageIndex, pageSize, sorting, columnFilters) getNotificationList(pageIndex, pageSize, sorting, columnFilters)

View File

@ -11,13 +11,19 @@ import { useCallApi } from '@/hooks';
import { apiConfig } from '@/config/api.config'; import { apiConfig } from '@/config/api.config';
import { DataGridColumnHeader, DataGridProvider } from '@/components'; import { DataGridColumnHeader, DataGridProvider } from '@/components';
import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; import { useManageStatementContext } from '../hooks/useManageWalletStatementContext';
import { Toaster } from 'sonner'; import { toast, Toaster } from 'sonner';
import { format } from 'date-fns'; import { format } from 'date-fns';
import FilterSection from './FilterSection'; import FilterSection from './FilterSection';
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
import jsPDF from 'jspdf'; import jsPDF from 'jspdf';
import 'jspdf-autotable'; import 'jspdf-autotable';
interface AutoTableData {
pageNumber: number;
table: any;
doc: jsPDF;
}
interface ContextProps { interface ContextProps {
doExportData: (sorting: any, filter: any) => Promise<any>; doExportData: (sorting: any, filter: any) => Promise<any>;
doExportExcel: () => Promise<void>; doExportExcel: () => Promise<void>;
@ -186,7 +192,7 @@ const ShowDetailWalletDialog = () => {
const response = await GetData( const response = await GetData(
`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`, `${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`,
{ {
limit: 10000, limit: 10000,
page: 1, page: 1,
with_deleted: false, with_deleted: false,
order_field: 'amount', order_field: 'amount',
@ -233,19 +239,19 @@ const ShowDetailWalletDialog = () => {
const wb = XLSX.utils.book_new(); const wb = XLSX.utils.book_new();
const ws = XLSX.utils.json_to_sheet([]); const ws = XLSX.utils.json_to_sheet([]);
const companyHeader = [ const companyHeader = [
['T•PAY'], ['T•PAY'],
['Telin Digital Solution'], ['Telin Digital Solution'],
['Av. Pres. Nicolau Lobato, Dili'], ['Av. Pres. Nicolau Lobato, Dili'],
['Tel: (+670) 74147147 / 147'], ['Tel: (+670) 74147147 / 147'],
['www.t-pay.tl'], ['www.t-pay.tl'],
[''], [''],
['Wallet Statement Details'], ['Wallet Statement Details'],
[`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`], [`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`],
[`Wallet ID: ${selectedWallet?.ID || '-'}`], [`Wallet ID: ${selectedWallet?.ID || '-'}`],
[''] ['']
]; ];
const columnHeaders = [ const columnHeaders = [
@ -273,17 +279,17 @@ const ShowDetailWalletDialog = () => {
XLSX.utils.sheet_add_aoa(ws, excelData); XLSX.utils.sheet_add_aoa(ws, excelData);
const colWidths = [ const colWidths = [
{ wch: 20 }, { wch: 20 },
{ wch: 15 }, { wch: 15 },
{ wch: 25 }, { wch: 25 },
{ wch: 10 }, { wch: 10 },
{ wch: 12 }, { wch: 12 },
{ wch: 12 }, { wch: 12 },
{ wch: 12 }, { wch: 12 },
{ wch: 15 }, { wch: 15 },
{ wch: 20 }, { wch: 20 },
{ wch: 25 }, { wch: 25 },
{ wch: 25 } { wch: 25 }
]; ];
ws['!cols'] = colWidths; ws['!cols'] = colWidths;
@ -292,7 +298,7 @@ const ShowDetailWalletDialog = () => {
ws[tpayCell].s = { ws[tpayCell].s = {
font: { bold: true, sz: 18, color: { rgb: '000000' } }, font: { bold: true, sz: 18, color: { rgb: '000000' } },
alignment: { horizontal: 'center' }, alignment: { horizontal: 'center' },
fill: { fgColor: { rgb: 'F4C2C2' } } fill: { fgColor: { rgb: 'F4C2C2' } }
}; };
} }
@ -302,7 +308,7 @@ const ShowDetailWalletDialog = () => {
ws[cellRef].s = { ws[cellRef].s = {
font: { sz: 12, color: { rgb: '000000' } }, font: { sz: 12, color: { rgb: '000000' } },
alignment: { horizontal: 'center' }, alignment: { horizontal: 'center' },
fill: { fgColor: { rgb: 'F4C2C2' } } fill: { fgColor: { rgb: 'F4C2C2' } }
}; };
} }
} }
@ -336,7 +342,7 @@ const ShowDetailWalletDialog = () => {
if (ws[cellRef]) { if (ws[cellRef]) {
ws[cellRef].s = { ws[cellRef].s = {
font: { bold: true, color: { rgb: 'FFFFFF' } }, font: { bold: true, color: { rgb: 'FFFFFF' } },
fill: { fgColor: { rgb: '4472C4' } }, fill: { fgColor: { rgb: '4472C4' } },
alignment: { horizontal: 'center' }, alignment: { horizontal: 'center' },
border: { border: {
top: { style: 'thin', color: { rgb: '000000' } }, top: { style: 'thin', color: { rgb: '000000' } },
@ -379,98 +385,137 @@ const ShowDetailWalletDialog = () => {
} }
}; };
const doExportPDF = async () => { // Perbaikan untuk fungsi doExportPDF
try { const doExportPDF = async () => {
const allData = await getAllTransactionData(); try {
const formattedData = formatTransactionData(allData); // 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); // Header perusahaan
pdf.setFont('helvetica', 'bold'); pdf.setFontSize(18);
pdf.text('T•PAY', 148, 20, { align: 'center' }); 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); // Garis pemisah
pdf.setFont('helvetica', 'normal'); pdf.setDrawColor(0, 0, 0);
pdf.text('Telin Digital Solution', 148, 30, { align: 'center' }); pdf.setLineWidth(0.5);
pdf.text('Av. Pres. Nicolau Lobato, Dili', 148, 36, { align: 'center' }); pdf.line(20, 52, pdf.internal.pageSize.getWidth() - 20, 52);
pdf.text('Tel : (+670) 7414747 / 147', 148, 42, { align: 'center' });
pdf.text('www.t-pay.tl', 148, 48, { align: 'center' });
pdf.setFontSize(14); // Judul laporan
pdf.setFont('helvetica', 'bold'); pdf.setFontSize(16);
pdf.text('Wallet Statement Details', 148, 60, { align: 'center' }); pdf.setFont('helvetica', 'bold');
pdf.text('Wallet Statement Details', pdf.internal.pageSize.getWidth() / 2, 62, { align: 'center' });
pdf.setFontSize(10); // Informasi tambahan
pdf.setFont('helvetica', 'normal'); pdf.setFontSize(10);
pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, 70); pdf.setFont('helvetica', 'normal');
pdf.text(`Wallet ID: ${selectedWallet?.ID || '-'}`, 20, 76); 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) => [ // Siapkan data tabel
item['Transaction Code'], const tableHeaders = [
item['MSISDN Reffer'], 'Transaction Code',
item['Transaction Type'], 'MSISDN Reffer',
item['Type'], 'Transaction Type',
item['Pre Amount'], 'Type',
item['Amount'], 'Pre Amount',
item['Post Amount'], 'Amount',
item['Category'], 'Post Amount',
item['Date'], 'Category',
item['Purpose'], 'Date',
item['Notes'] 'Purpose',
]); 'Notes'
];
(pdf as any).autoTable({ const tableData = formattedData.map((item) => [
head: [ item['Transaction Code'],
[ item['MSISDN Reffer'],
'Transaction Code', item['Transaction Type'],
'MSISDN Reffer', item['Type'],
'Transaction Type', item['Pre Amount'],
'Type', item['Amount'],
'Pre Amount', item['Post Amount'],
'Amount', item['Category'],
'Post Amount', item['Date'],
'Category', item['Purpose'],
'Date', item['Notes']
'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 fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`; // Gunakan autoTable dengan cara yang benar
pdf.save(fileName); 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'); // Generate nama file
} catch (error) { 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); console.error('Error exporting to PDF:', error);
toast.error('Failed to export PDF');
} }
}; };
const doExportData = async (sorting: any, filter: any) => { const doExportData = async (sorting: any, filter: any) => {
const user = localStorage.getItem( const user = localStorage.getItem(