From ca0d379c2c900d1cb3bfc7daeba9122c3e13c071 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 28 Jan 2026 10:00:01 +0700 Subject: [PATCH] refactor(FE): Rename initialBalanceRow to firstRow --- src/components/helper/pdf/table/PdfTable.tsx | 10 +- src/components/helper/pdf/table/PdfTbody.tsx | 23 +- .../export/CustomerPaymentExportPDF.tsx | 600 ++++++------------ 3 files changed, 197 insertions(+), 436 deletions(-) diff --git a/src/components/helper/pdf/table/PdfTable.tsx b/src/components/helper/pdf/table/PdfTable.tsx index d1dc1df8..27369db5 100644 --- a/src/components/helper/pdf/table/PdfTable.tsx +++ b/src/components/helper/pdf/table/PdfTable.tsx @@ -18,7 +18,7 @@ interface PdfTableProps { data: PdfTbodyCell[][]; footer?: PdfTfootCell[]; footerLabel?: string; - initialBalanceRow?: { + firstRow?: { valueKey: string; value: number; align?: 'right'; @@ -31,16 +31,12 @@ export const PdfTable = ({ data, footer, footerLabel = 'Total', - initialBalanceRow, + firstRow, }: PdfTableProps) => { return ( - + {footer && footer.length > 0 && ( )} diff --git a/src/components/helper/pdf/table/PdfTbody.tsx b/src/components/helper/pdf/table/PdfTbody.tsx index 819c4dec..fee79726 100644 --- a/src/components/helper/pdf/table/PdfTbody.tsx +++ b/src/components/helper/pdf/table/PdfTbody.tsx @@ -74,7 +74,7 @@ const styles = StyleSheet.create({ interface PdfTbodyProps { columns: PdfColumn[]; rows: PdfTbodyCell[][]; - initialBalanceRow?: { + firstRow?: { valueKey: string; value: number; align?: 'right'; @@ -85,31 +85,26 @@ interface PdfTbodyProps { formatCurrency?: (num: number) => string; } -export const PdfTbody = ({ - columns, - rows, - initialBalanceRow, -}: PdfTbodyProps) => { +export const PdfTbody = ({ columns, rows, firstRow }: PdfTbodyProps) => { return ( <> - {/* Initial Balance Row */} - {initialBalanceRow && ( + {/* First Row */} + {firstRow && ( {columns.map((column, index) => { const isLastColumn = index === columns.length - 1; - const isInitialBalanceColumn = - column.key === initialBalanceRow.valueKey; + const isfirstRowColumn = column.key === firstRow.valueKey; const align = column.align || 'center'; const cellStyle = column.key === 'no' ? [styles.tableCellNo, { flex: column.flex }] - : isInitialBalanceColumn + : isfirstRowColumn ? [ styles.tableCellRight, { flex: column.flex, - color: initialBalanceRow.color || 'black', + color: firstRow.color || 'black', borderRightWidth: isLastColumn ? 0 : 1, }, ] @@ -141,9 +136,7 @@ export const PdfTbody = ({ return ( - - {isInitialBalanceColumn ? initialBalanceRow.value : ''} - + {isfirstRowColumn ? firstRow.value : ''} ); })} diff --git a/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx b/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx index d4f6587a..e6c5d66e 100644 --- a/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx +++ b/src/components/pages/report/finance/export/CustomerPaymentExportPDF.tsx @@ -12,6 +12,12 @@ import { import { formatDate, formatCurrency, formatNumber } from '@/lib/helper'; import { CustomerPaymentReport } from '@/types/api/report/customer-payment'; +import { + PdfTable, + PdfColumn, + PdfTbodyCell, + PdfTfootCell, +} from '@/components/helper/pdf/table'; Font.register({ family: 'Helvetica', @@ -45,97 +51,6 @@ const pdfStyles = StyleSheet.create({ marginBottom: 5, color: '#333333', }, - table: { - borderWidth: 1, - borderColor: '#000000', - marginBottom: 15, - }, - tableRow: { - flexDirection: 'row', - }, - tableHeader: { - backgroundColor: '#F5F5F5', - }, - tableCell: { - flex: 1, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - textAlign: 'left', - }, - tableCellNo: { - flex: 0.5, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - textAlign: 'center', - }, - tableCellLast: { - flex: 1, - padding: 4, - fontSize: 7, - }, - tableCellHeader: { - flex: 1, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - fontWeight: 'bold', - backgroundColor: '#F5F5F5', - borderBottomWidth: 1, - borderBottomColor: '#000000', - borderBottomStyle: 'solid', - paddingVertical: 12, - textAlign: 'center', - }, - tableCellHeaderRight: { - flex: 1, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - fontWeight: 'bold', - backgroundColor: '#F5F5F5', - textAlign: 'right', - borderBottomWidth: 1, - borderBottomColor: '#000000', - borderBottomStyle: 'solid', - paddingVertical: 12, - }, - tableCellRight: { - flex: 1, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - textAlign: 'right', - }, - tableCellCenter: { - flex: 1, - borderRightWidth: 1, - borderRightColor: '#000000', - borderRightStyle: 'solid', - padding: 4, - fontSize: 7, - textAlign: 'center', - }, - tableBorderBottom: { - borderBottomWidth: 1, - borderBottomColor: '#000000', - borderBottomStyle: 'solid', - }, - summaryRow: { - backgroundColor: '#F0F0F0', - fontWeight: 'bold', - }, badge: { backgroundColor: '#1f74bf', color: '#FFFFFF', @@ -217,6 +132,165 @@ const getParameterText = ( return paramsText; }; +// Helper functions for PdfTable +const getTableColumns = (): PdfColumn[] => [ + { key: 'no', header: 'No', flex: 0.5, align: 'center' }, + { key: 'trans_date', header: 'Tanggal DO', flex: 1.2, align: 'center' }, + { + key: 'delivery_date', + header: 'Tanggal Realisasi', + flex: 1.2, + align: 'center', + }, + { key: 'aging', header: 'Aging', flex: 0.8, align: 'center' }, + { key: 'reference', header: 'Referensi', flex: 1.5, align: 'left' }, + { key: 'vehicle_numbers', header: 'No Polisi', flex: 1.2, align: 'left' }, + { key: 'qty', header: 'Qty', flex: 0.8, align: 'right' }, + { key: 'weight', header: 'Berat', flex: 1, align: 'right' }, + { key: 'average_weight', header: 'Rata-Rata', flex: 0.8, align: 'right' }, + { key: 'unit_price', header: 'Harga/Unit', flex: 1.2, align: 'right' }, + { key: 'final_price', header: 'Harga Akhir', flex: 1.2, align: 'right' }, + { key: 'total_price', header: 'Total', flex: 1.2, align: 'right' }, + { key: 'payment_amount', header: 'Pembayaran', flex: 1.2, align: 'right' }, + { key: 'accounts_receivable', header: 'Saldo', flex: 1.2, align: 'right' }, + { key: 'status', header: 'Keterangan', flex: 1.5, align: 'center' }, + { key: 'pickup_info', header: 'Pengambilan', flex: 1, align: 'left' }, + { key: 'sales_person', header: 'Sales', flex: 1.5, align: 'left' }, +]; + +const getTableData = ( + rows: CustomerPaymentReport['rows'] +): PdfTbodyCell[][] => { + return rows.map((item, index) => [ + { key: 'no', value: index + 1 }, + { + key: 'trans_date', + value: item.trans_date ? formatDate(item.trans_date, 'DD MMM YY') : '-', + }, + { + key: 'delivery_date', + value: item.delivery_date + ? formatDate(item.delivery_date, 'DD MMM YY') + : '-', + }, + { + key: 'aging', + value: + item.aging_day != null ? `${formatNumber(item.aging_day)} hari` : '-', + }, + { key: 'reference', value: item.reference || '-' }, + { + key: 'vehicle_numbers', + value: + Array.isArray(item.vehicle_numbers) && item.vehicle_numbers.length > 0 + ? item.vehicle_numbers.join(', ') + : '-', + }, + { key: 'qty', value: formatNumber(item.qty), align: 'right' }, + { key: 'weight', value: formatNumber(item.weight), align: 'right' }, + { + key: 'average_weight', + value: formatNumber(item.average_weight), + align: 'right', + }, + { + key: 'unit_price', + value: formatCurrency(item.unit_price), + align: 'right', + }, + { + key: 'final_price', + value: formatCurrency(item.final_price), + align: 'right', + }, + { + key: 'total_price', + value: formatCurrency(item.total_price), + align: 'right', + }, + { + key: 'payment_amount', + value: formatCurrency(item.payment_amount), + align: 'right', + }, + { + key: 'accounts_receivable', + value: formatCurrency(item.accounts_receivable), + align: 'right', + color: item.accounts_receivable < 0 ? '#DC2626' : undefined, + }, + { + key: 'status', + value: item.status ? ( + + {item.status === 'LUNAS' ? 'Lunas' : 'Belum Lunas'} + + ) : ( + '-' + ), + }, + { + key: 'pickup_info', + value: + Array.isArray(item.pickup_info) && item.pickup_info.length > 0 + ? item.pickup_info.join(', ') + : '-', + }, + { key: 'sales_person', value: item.sales_person || '-' }, + ]); +}; + +const getTableFooter = ( + summary: CustomerPaymentReport['summary'] +): PdfTfootCell[] => [ + { key: 'no', value: 'Total' }, + { key: 'trans_date', value: '' }, + { key: 'delivery_date', value: '' }, + { key: 'aging', value: '' }, + { key: 'reference', value: '' }, + { key: 'vehicle_numbers', value: '' }, + { key: 'qty', value: formatNumber(summary?.total_qty || 0), align: 'right' }, + { + key: 'weight', + value: formatNumber(summary?.total_weight || 0), + align: 'right', + }, + { key: 'average_weight', value: '' }, + { key: 'unit_price', value: '' }, + { + key: 'final_price', + value: formatCurrency(summary?.total_final_amount || 0), + align: 'right', + }, + { + key: 'total_price', + value: formatCurrency(summary?.total_grand_amount || 0), + align: 'right', + }, + { + key: 'payment_amount', + value: formatCurrency(summary?.total_payment || 0), + align: 'right', + }, + { + key: 'accounts_receivable', + value: formatCurrency(summary?.total_accounts_receivable || 0), + align: 'right', + color: + (summary?.total_accounts_receivable || 0) < 0 ? '#DC2626' : undefined, + }, + { key: 'status', value: '' }, + { key: 'pickup_info', value: '' }, + { key: 'sales_person', value: '' }, +]; + const createPDFDocument = (params: CustomerPaymentExportPDFParams) => { return ( @@ -269,329 +343,27 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => { {/* Table */} - - {/* Table Header */} - - - No - - - Tanggal DO - - - Tanggal Realisasi - - - Aging - - - Referensi - - - No Polisi - - - Qty - - - Berat - - - Rata-Rata - - - Harga/Unit - - - Harga Akhir - - - Total - - - Pembayaran - - - Saldo - - - Keterangan - - - Pengambilan - - - Sales - - - - {/* Table Body */} - <> - {/* Initial Balance Row */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {formatCurrency(customerReport.initial_balance || 0)} - - - - - - - - - - - - - - {/* Data Rows */} - {customerReport.rows.map((item, index) => ( - - - {index + 1} - - - - {item.trans_date - ? formatDate(item.trans_date, 'DD MMM YY') - : '-'} - - - - - {item.delivery_date - ? formatDate(item.delivery_date, 'DD MMM YY') - : '-'} - - - - - {item.aging_day != null - ? `${formatNumber(item.aging_day)} hari` - : '-'} - - - - {item.reference || '-'} - - - - {Array.isArray(item.vehicle_numbers) - ? item.vehicle_numbers.length > 0 - ? item.vehicle_numbers.join(', ') - : '-' - : '-'} - - - - {formatNumber(item.qty)} - - - {formatNumber(item.weight)} - - - {formatNumber(item.average_weight)} - - - {formatCurrency(item.unit_price)} - - - {formatCurrency(item.final_price)} - - - {formatCurrency(item.total_price)} - - - {formatCurrency(item.payment_amount)} - - - - {formatCurrency(item.accounts_receivable)} - - - - {item.status ? ( - - - {item.status === 'LUNAS' ? 'Lunas' : 'Belum Lunas'} - - - ) : ( - - - )} - - - - {Array.isArray(item.pickup_info) - ? item.pickup_info.length > 0 - ? item.pickup_info.join(', ') - : '-' - : '-'} - - - - {item.sales_person || '-'} - - - ))} - - - {/* Summary Row */} - {customerReport.summary && ( - - - Total - - - - - - - - - - - - - - - - - - {formatNumber(customerReport.summary.total_qty)} - - - - {formatNumber(customerReport.summary.total_weight)} - - - - - - - - - - - {formatCurrency(customerReport.summary.total_final_amount)} - - - - - {formatCurrency(customerReport.summary.total_grand_amount)} - - - - - {formatCurrency(customerReport.summary.total_payment)} - - - - - {formatCurrency( - customerReport.summary.total_accounts_receivable - )} - - - - - - - - - - - - - )} - + ))}