diff --git a/src/components/pages/report/DailyMarketingReportPDF.tsx b/src/components/pages/report/DailyMarketingReportPDF.tsx
index 86ee29bc..53b36b80 100644
--- a/src/components/pages/report/DailyMarketingReportPDF.tsx
+++ b/src/components/pages/report/DailyMarketingReportPDF.tsx
@@ -1,275 +1,226 @@
'use client';
-import {
- Document,
- Image,
- Page,
- StyleSheet,
- Text,
- View,
-} from '@react-pdf/renderer';
-
+import { Page, View, Document, StyleSheet, Font } from '@react-pdf/renderer';
import {
DailyMarketingReport,
SalesSummary,
} from '@/types/api/report/marketing';
-import { formatCurrency, formatDate, formatNumber } from '@/lib/helper';
+import {
+ formatCurrency,
+ formatDate,
+ formatNumber,
+ formatTitleCase,
+} from '@/lib/helper';
+import {
+ PdfTable,
+ PdfColumn,
+ PdfTbodyCell,
+ PdfTfootCell,
+} from '@/components/helper/pdf/table';
+import { PdfParamBadge } from '@/components/helper/pdf/badge/PdfParamBadge';
+import { PdfStatusBadge } from '@/components/helper/pdf/badge/PdfStatusBadge';
+import { PdfTypography } from '@/components/helper/pdf/typography/PdfTypography';
+import { PdfPageNumber } from '@/components/helper/pdf/layout/PdfPageNumber';
+
+Font.register({
+ family: 'Helvetica',
+ src: 'helvetica',
+});
+
+const pdfStyles = StyleSheet.create({
+ page: {
+ fontSize: 10,
+ fontFamily: 'Helvetica',
+ padding: 20,
+ backgroundColor: '#FFFFFF',
+ },
+ titleSection: {
+ marginBottom: 10,
+ },
+ parameterContainer: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ marginBottom: 8,
+ },
+});
interface DailyMarketingReportPDFProps {
data?: DailyMarketingReport;
total?: SalesSummary;
}
-const DailyMarketingReportPDFStyle = StyleSheet.create({
- page: {
- paddingTop: 24,
- paddingBottom: 64,
- paddingHorizontal: 16, // Reduce padding to fit more columns
- orientation: 'landscape',
+const getTableColumns = (): PdfColumn[] => [
+ { key: 'no', header: 'No', flex: 0.5, align: 'center' },
+ { key: 'so_date', header: 'Tanggal Sales Order', flex: 1.3, align: 'center' },
+ {
+ key: 'do_date',
+ header: 'Tanggal Delivery Order',
+ flex: 1.3,
+ align: 'center',
},
+ { key: 'aging', header: 'Aging (Hari)', flex: 0.7, align: 'center' },
+ { key: 'warehouse', header: 'Gudang', flex: 1.2, align: 'left' },
+ { key: 'customer', header: 'Pelanggan', flex: 1.5, align: 'left' },
+ { key: 'sales', header: 'Sales', flex: 1, align: 'left' },
+ { key: 'product', header: 'Produk', flex: 1.3, align: 'left' },
+ { key: 'do_number', header: 'Nomor DO', flex: 1.2, align: 'left' },
+ { key: 'vehicle', header: 'Nomor Polisi', flex: 1, align: 'left' },
+ { key: 'marketing_type', header: 'Tipe Marketing', flex: 1, align: 'center' },
+ { key: 'qty', header: 'Quantity', flex: 0.7, align: 'right' },
+ { key: 'avg_weight', header: 'Rata-Rata (Kg)', flex: 0.8, align: 'right' },
+ {
+ key: 'total_weight',
+ header: 'Total Berat (Kg)',
+ flex: 0.9,
+ align: 'right',
+ },
+ { key: 'sales_price', header: 'Harga Jual (Rp)', flex: 0.9, align: 'right' },
+ { key: 'hpp_price', header: 'HPP (Rp)', flex: 1.3, align: 'right' },
+ { key: 'sales_amount', header: 'Total Jual (Rp)', flex: 1, align: 'right' },
+ { key: 'hpp_amount', header: 'Total HPP (Rp)', flex: 1.3, align: 'right' },
+];
- companyInfoHeader: {
- width: '100%',
- display: 'flex',
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'flex-start',
- marginBottom: 8,
- },
- companyLogo: {
- width: 64,
- height: 'auto',
- },
- companyInfoHeaderDate: {
- paddingTop: 8,
- fontSize: 10,
- },
- companyName: {
- fontSize: 12,
- fontWeight: 'bold',
- marginBottom: 4,
- },
- companyAddress: {
- fontSize: 8,
- maxWidth: 400,
- marginBottom: 10,
- },
+const getTableData = (rows: DailyMarketingReport): PdfTbodyCell[][] => {
+ return rows.map((row, index) => [
+ { key: 'no', value: index + 1 },
+ {
+ key: 'so_date',
+ value: row.so_date ? formatDate(row.so_date, 'DD MMM YY') : '-',
+ },
+ {
+ key: 'do_date',
+ value: row.realization_date
+ ? formatDate(row.realization_date, 'DD MMM YY')
+ : '-',
+ },
+ { key: 'aging', value: row.aging_days ?? '-' },
+ { key: 'warehouse', value: row.warehouse?.name ?? '-' },
+ { key: 'customer', value: row.customer?.name ?? '-' },
+ { key: 'sales', value: row.sales?.name ?? '-' },
+ { key: 'product', value: row.product?.name ?? '-' },
+ { key: 'do_number', value: row.do_number ?? '-' },
+ { key: 'vehicle', value: row.vehicle_number ?? '-' },
+ {
+ key: 'marketing_type',
+ value: row.marketing_type ? (
+
+
+ {formatTitleCase(row.marketing_type)}
+
+
+ ) : (
+ '-'
+ ),
+ },
+ { key: 'qty', value: formatNumber(row.qty ?? 0), align: 'right' },
+ {
+ key: 'avg_weight',
+ value: formatNumber(row.average_weight_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'total_weight',
+ value: formatNumber(row.total_weight_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'sales_price',
+ value: formatCurrency(row.sales_price_per_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'hpp_price',
+ value: formatCurrency(row.hpp_price_per_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'sales_amount',
+ value: formatCurrency(row.sales_amount ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'hpp_amount',
+ value: formatCurrency(row.hpp_amount ?? 0),
+ align: 'right',
+ },
+ ]);
+};
- title: {
- marginTop: 16,
- fontSize: 14,
- lineHeight: '150%',
- textAlign: 'center',
- fontFamily: 'Times-Roman',
- fontWeight: 'bold',
- },
+const getTableFooter = (summary?: SalesSummary): PdfTfootCell[] => {
+ if (!summary) return [];
- footer: {
- width: '100%',
- display: 'flex',
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- paddingHorizontal: 16,
-
- position: 'absolute',
- fontSize: 8,
- bottom: 30,
- left: 0,
- right: 0,
- textAlign: 'center',
- color: 'grey',
- },
-
- // Table Styles
- table: {
- width: '100%',
- marginTop: 16,
- borderWidth: 1,
- borderColor: '#000000',
- borderBottomWidth: 0,
- fontSize: 7, // Smaller font for report
- },
- tableRow: {
- flexDirection: 'row',
- borderBottomWidth: 1,
- borderBottomColor: '#000000',
- alignItems: 'center',
- minHeight: 20,
- },
- tableHeader: {
- backgroundColor: '#f0f0f0',
- fontWeight: 'bold',
- },
-
- // Columns definition (Total 100%)
- colNo: {
- width: '3%',
- padding: 2,
- textAlign: 'center',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colSoDate: {
- width: '6%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colDoDate: {
- width: '6%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colAging: {
- width: '3%',
- padding: 2,
- textAlign: 'center',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colWarehouse: {
- width: '7%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colCustomer: {
- width: '9%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- }, // Reduced slightly
- colSales: {
- width: '6%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colProduct: {
- width: '8%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- }, // Reduced slightly
- colDoNumber: {
- width: '7%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colVehicle: {
- width: '5%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colMarketingType: {
- width: '5%',
- padding: 2,
- textAlign: 'left',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colQty: {
- width: '4%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colAvgWeight: {
- width: '4%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colTotalWeight: {
- width: '5%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colSalesPrice: {
- width: '5%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colHppPrice: {
- width: '5%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colSalesAmount: {
- width: '6%',
- padding: 2,
- textAlign: 'right',
- borderRightWidth: 1,
- borderRightColor: '#000000',
- },
- colHppAmount: { width: '6%', padding: 2, textAlign: 'right' }, // Last column
-
- // Text inside columns
- cellText: {
- fontSize: 6,
- },
- headerText: {
- fontSize: 7,
- fontWeight: 'bold',
- textAlign: 'center',
- },
-
- // Utils
- doubleDivider: {
- width: '100%',
- height: 6,
- borderTop: '2px solid black',
- borderBottom: '2px solid black',
- },
-
- // Summary
- summaryContainer: {
- marginTop: 12,
- flexDirection: 'row',
- justifyContent: 'flex-end',
- width: '100%',
- },
- summaryTable: {
- width: '30%',
- borderWidth: 1,
- borderColor: '#000000',
- fontSize: 8,
- },
- summaryRow: {
- flexDirection: 'row',
- padding: 2,
- borderBottomWidth: 1,
- borderBottomColor: '#eee',
- },
- summaryLabel: {
- width: '50%',
- fontWeight: 'bold',
- },
- summaryValue: {
- width: '50%',
- textAlign: 'right',
- },
-});
+ return [
+ { key: 'no', value: 'TOTAL' },
+ { key: 'so_date', value: '' },
+ { key: 'do_date', value: '' },
+ { key: 'aging', value: '' },
+ { key: 'warehouse', value: '' },
+ { key: 'customer', value: '' },
+ { key: 'sales', value: '' },
+ { key: 'product', value: '' },
+ { key: 'do_number', value: '' },
+ { key: 'vehicle', value: '' },
+ { key: 'marketing_type', value: '' },
+ {
+ key: 'qty',
+ value: formatNumber(summary.total_qty ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'avg_weight',
+ value: formatNumber(summary.total_weight_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'total_weight',
+ value: formatNumber(summary.total_weight_kg ?? 0),
+ align: 'right',
+ },
+ { key: 'sales_price', value: '' },
+ {
+ key: 'hpp_price',
+ value: formatCurrency(summary.total_hpp_price_per_kg ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'sales_amount',
+ value: formatCurrency(summary.total_sales_amount ?? 0),
+ align: 'right',
+ },
+ {
+ key: 'hpp_amount',
+ value: formatCurrency(summary.total_hpp_amount ?? 0),
+ align: 'right',
+ },
+ ];
+};
const DailyMarketingReportPDF = ({
data,
@@ -280,288 +231,31 @@ const DailyMarketingReportPDF = ({
return (
-
-
-
-
-
-
- {formatDate(Date.now(), 'DD MMMM YYYY')}
-
-
-
-
-
- PT LUMBUNG TELUR INDONESIA
-
-
- SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel.
- Cipedes, Kec. Sukajadi, Kota Bandung 40162
-
-
-
+
+ {/* Title and Parameters */}
+
+
+ Laporan > Penjualan Harian
+
+
+
+ Tanggal: {formatDate(Date.now(), 'DD MMMM YYYY')}
+
+
+ Dicetak: {formatDate(new Date(), 'DD MMM YYYY HH:mm')}
+
-
- Laporan Penjualan Harian
-
+ {/* Table */}
+
- {/* Data Table */}
-
- {/* Header */}
-
-
- No
-
-
-
- Tgl SO
-
-
-
-
- Tgl DO
-
-
-
- Aging
-
-
-
- Gudang
-
-
-
-
- Pelanggan
-
-
-
- Sales
-
-
-
- Produk
-
-
-
- No DO
-
-
-
- Plat No
-
-
-
- Tipe
-
-
- Qty
-
-
-
- Rerata
-
-
-
- Berat
-
-
-
- Hrg Jual
-
-
-
-
- HPP/kg
-
-
-
-
- Total Jual
-
-
-
-
- Total HPP
-
-
-
-
- {/* Rows */}
- {rows.map((row, index) => (
-
-
-
- {index + 1}
-
-
-
-
- {formatDate(row.so_date, 'DD/MM/YYYY')}
-
-
-
-
- {formatDate(row.realization_date, 'DD/MM/YYYY')}
-
-
-
-
- {row.aging_days}
-
-
-
-
- {row.warehouse?.name}
-
-
-
-
- {row.customer?.name}
-
-
-
-
- {row.sales.name}
-
-
-
-
- {row.product?.name}
-
-
-
-
- {row.do_number}
-
-
-
-
- {row.vehicle_number}
-
-
-
-
- {row.marketing_type}
-
-
-
-
- {formatNumber(row.qty)}
-
-
-
-
- {formatNumber(row.average_weight_kg)}
-
-
-
-
- {formatNumber(row.total_weight_kg)}
-
-
-
-
- {formatCurrency(row.sales_price_per_kg)}
-
-
-
-
- {formatCurrency(row.hpp_price_per_kg)}
-
-
-
-
- {formatCurrency(row.sales_amount)}
-
-
-
-
- {formatCurrency(row.hpp_amount)}
-
-
-
- ))}
-
-
- {/* Summary */}
-
-
-
-
- Total Qty:
-
-
- {formatNumber(summary?.total_qty ?? 0)}
-
-
-
-
- Total Berat (kg):
-
-
- {formatNumber(summary?.total_weight_kg ?? 0)}
-
-
-
-
- Total Penjualan:
-
-
- {formatCurrency(summary?.total_sales_amount ?? 0)}
-
-
-
-
- Total HPP Per KG:
-
-
- {formatCurrency(summary?.total_hpp_price_per_kg ?? 0)}
-
-
-
-
- Total HPP:
-
-
- {formatCurrency(summary?.total_hpp_amount ?? 0)}
-
-
-
-
-
-
-
- `${pageNumber} / ${totalPages}`
- }
- fixed
- />
-
+
);