mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
refactor(FE): Enhance customer payment PDF export and filters
This commit is contained in:
@@ -136,41 +136,129 @@ const pdfStyles = StyleSheet.create({
|
|||||||
backgroundColor: '#F0F0F0',
|
backgroundColor: '#F0F0F0',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
|
badge: {
|
||||||
|
backgroundColor: '#1f74bf',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
padding: 2,
|
||||||
|
borderRadius: 2,
|
||||||
|
fontSize: 7,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
alignSelf: 'center',
|
||||||
|
marginRight: 4,
|
||||||
|
},
|
||||||
|
badgeLunas: {
|
||||||
|
backgroundColor: '#1f74bf',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
badgeBelumLunas: {
|
||||||
|
backgroundColor: '#F97316',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
parameterBadge: {
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
color: '#333333',
|
||||||
|
padding: 4,
|
||||||
|
borderRadius: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
marginRight: 8,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
parameterContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
interface CustomerPaymentExportPDFParams {
|
interface CustomerPaymentExportPDFParams {
|
||||||
data: CustomerPaymentReport[];
|
data: CustomerPaymentReport[];
|
||||||
|
params?: {
|
||||||
|
customer_name?: string;
|
||||||
|
sales?: string;
|
||||||
|
start_date?: string;
|
||||||
|
end_date?: string;
|
||||||
|
filter_by?: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getParameterText = (
|
||||||
|
params?: CustomerPaymentExportPDFParams['params']
|
||||||
|
) => {
|
||||||
|
const paramsText = [];
|
||||||
|
|
||||||
|
if (params?.customer_name) {
|
||||||
|
paramsText.push(`Customer: ${params.customer_name}`);
|
||||||
|
} else {
|
||||||
|
paramsText.push('Semua Customer');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params?.sales) {
|
||||||
|
paramsText.push(`Sales: ${params.sales}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params?.start_date && params?.end_date) {
|
||||||
|
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||||
|
const endDate = formatDate(params.end_date, 'DD MMM YYYY');
|
||||||
|
paramsText.push(`Periode: ${startDate} - ${endDate}`);
|
||||||
|
} else if (params?.start_date) {
|
||||||
|
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||||
|
paramsText.push(`Tanggal: ${startDate}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDate = formatDate(new Date(), 'DD MMM YYYY HH:mm');
|
||||||
|
paramsText.push(`Dicetak: ${currentDate}`);
|
||||||
|
|
||||||
|
return paramsText;
|
||||||
|
};
|
||||||
|
|
||||||
const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
||||||
return (
|
return (
|
||||||
<Document>
|
<Document>
|
||||||
{params.data.map((customerReport, customerIndex) => (
|
{params.data.map((customerReport, customerIndex) => (
|
||||||
<Page
|
<Page
|
||||||
key={customerIndex}
|
key={customerIndex}
|
||||||
size='A4'
|
size='A3'
|
||||||
orientation='landscape'
|
orientation='landscape'
|
||||||
style={pdfStyles.page}
|
style={pdfStyles.page}
|
||||||
>
|
>
|
||||||
{/* Title and Customer Info */}
|
{/* Title and Parameters */}
|
||||||
<View style={pdfStyles.titleSection}>
|
<View style={pdfStyles.titleSection}>
|
||||||
<Text style={pdfStyles.mainTitle}>
|
<Text style={pdfStyles.mainTitle}>
|
||||||
Laporan > Kontrol Pembayaran Customer
|
Laporan > Kontrol Pembayaran Customer
|
||||||
</Text>
|
</Text>
|
||||||
|
<View style={pdfStyles.parameterContainer}>
|
||||||
|
<View style={pdfStyles.parameterBadge}>
|
||||||
|
<Text>
|
||||||
|
Periode:{' '}
|
||||||
|
{params.params?.start_date
|
||||||
|
? formatDate(params.params.start_date, 'DD MMM YYYY')
|
||||||
|
: '-'}{' '}
|
||||||
|
s.d{' '}
|
||||||
|
{params.params?.end_date
|
||||||
|
? formatDate(params.params.end_date, 'DD MMM YYYY')
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.parameterBadge}>
|
||||||
|
<Text>Filter Tanggal: Tanggal DO</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.parameterBadge}>
|
||||||
|
<Text>
|
||||||
|
Customer: {params.params?.customer_name || 'Semua Customer'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.parameterBadge}>
|
||||||
|
<Text>
|
||||||
|
Dicetak: {formatDate(new Date(), 'DD MMM YYYY HH:mm')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
<Text style={pdfStyles.supplierTitle}>
|
<Text style={pdfStyles.supplierTitle}>
|
||||||
{customerReport.customer.name}
|
{customerReport.customer.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={pdfStyles.supplierInfo}>
|
<Text style={pdfStyles.supplierInfo}>
|
||||||
{customerReport.customer.address || ''}
|
Alamat: {customerReport.customer.address || '-'}
|
||||||
</Text>
|
</Text>
|
||||||
{customerReport.summary && (
|
|
||||||
<Text style={pdfStyles.supplierInfo}>
|
|
||||||
Total Saldo Piutang:{' '}
|
|
||||||
{formatCurrency(
|
|
||||||
customerReport.summary.total_accounts_receivable
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Table */}
|
{/* Table */}
|
||||||
@@ -181,10 +269,10 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
|||||||
<Text>No</Text>
|
<Text>No</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||||
<Text>Tgl DO/Bayar</Text>
|
<Text>Tanggal DO</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||||
<Text>Tgl Realisasi</Text>
|
<Text>Tanggal Realisasi</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 0.8 }]}>
|
||||||
<Text>Aging</Text>
|
<Text>Aging</Text>
|
||||||
@@ -193,16 +281,16 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
|||||||
<Text>Referensi</Text>
|
<Text>Referensi</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||||
<Text>No. Polisi</Text>
|
<Text>No Polisi</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||||
<Text>Qty</Text>
|
<Text>Qty</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1 }]}>
|
||||||
<Text>Berat (Kg)</Text>
|
<Text>Berat</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||||
<Text>AVG</Text>
|
<Text>Rata-Rata</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||||
<Text>Harga Awal</Text>
|
<Text>Harga Awal</Text>
|
||||||
@@ -214,7 +302,7 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
|||||||
<Text>Harga Akhir</Text>
|
<Text>Harga Akhir</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||||
<Text>PPN (%)</Text>
|
<Text>Pajak</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||||
<Text>Total</Text>
|
<Text>Total</Text>
|
||||||
@@ -223,10 +311,10 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
|||||||
<Text>Pembayaran</Text>
|
<Text>Pembayaran</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||||
<Text>Saldo Piutang</Text>
|
<Text>Saldo</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1.5 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.5 }]}>
|
||||||
<Text>Ket</Text>
|
<Text>Keterangan</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
<Text>Pengambilan</Text>
|
<Text>Pengambilan</Text>
|
||||||
@@ -304,7 +392,24 @@ const createPDFDocument = (params: CustomerPaymentExportPDFParams) => {
|
|||||||
<Text>{formatCurrency(item.accounts_receivable)}</Text>
|
<Text>{formatCurrency(item.accounts_receivable)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
<Text>{item.notes || '-'}</Text>
|
{item.notes ? (
|
||||||
|
<Text>{item.notes}</Text>
|
||||||
|
) : (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.badge,
|
||||||
|
item.accounts_receivable === 0
|
||||||
|
? pdfStyles.badgeLunas
|
||||||
|
: pdfStyles.badgeBelumLunas,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
{item.accounts_receivable === 0
|
||||||
|
? 'Lunas'
|
||||||
|
: 'Belum Lunas'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
<Text>{item.pickup_info || '-'}</Text>
|
<Text>{item.pickup_info || '-'}</Text>
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ const CustomerPaymentTab = () => {
|
|||||||
const [filterSales, setFilterSales] = useState<OptionType[]>([]);
|
const [filterSales, setFilterSales] = useState<OptionType[]>([]);
|
||||||
const [filterStartDate, setFilterStartDate] = useState('');
|
const [filterStartDate, setFilterStartDate] = useState('');
|
||||||
const [filterEndDate, setFilterEndDate] = useState('');
|
const [filterEndDate, setFilterEndDate] = useState('');
|
||||||
const [filterErrors, setFilterErrors] = useState<Record<string, string>>({});
|
|
||||||
|
|
||||||
const filterModal = useModal();
|
const filterModal = useModal();
|
||||||
|
|
||||||
@@ -75,27 +74,13 @@ const CustomerPaymentTab = () => {
|
|||||||
setFilterSales([]);
|
setFilterSales([]);
|
||||||
setFilterStartDate('');
|
setFilterStartDate('');
|
||||||
setFilterEndDate('');
|
setFilterEndDate('');
|
||||||
setFilterErrors({});
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleApplyFilters = useCallback(() => {
|
const handleApplyFilters = useCallback(() => {
|
||||||
const errors: Record<string, string> = {};
|
|
||||||
|
|
||||||
if (!filterStartDate) {
|
|
||||||
errors.start_date = 'Tanggal mulai wajib diisi';
|
|
||||||
}
|
|
||||||
if (!filterEndDate) {
|
|
||||||
errors.end_date = 'Tanggal akhir wajib diisi';
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilterErrors(errors);
|
|
||||||
|
|
||||||
if (Object.keys(errors).length === 0) {
|
|
||||||
setIsSubmitted(true);
|
setIsSubmitted(true);
|
||||||
setCurrentPage(1);
|
setCurrentPage(1);
|
||||||
filterModal.closeModal();
|
filterModal.closeModal();
|
||||||
}
|
}, [filterModal]);
|
||||||
}, [filterModal, filterStartDate, filterEndDate]);
|
|
||||||
|
|
||||||
// ===== DATA FETCHING =====
|
// ===== DATA FETCHING =====
|
||||||
const { data: customerPayment, isLoading } = useSWR(
|
const { data: customerPayment, isLoading } = useSWR(
|
||||||
@@ -218,7 +203,22 @@ const CustomerPaymentTab = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await generateCustomerPaymentPDF({ data: allDataForExport });
|
await generateCustomerPaymentPDF({
|
||||||
|
data: allDataForExport,
|
||||||
|
params: {
|
||||||
|
customer_name:
|
||||||
|
filterCustomer.length > 0
|
||||||
|
? filterCustomer.map((c) => c.label).join(', ')
|
||||||
|
: undefined,
|
||||||
|
sales:
|
||||||
|
filterSales.length > 0
|
||||||
|
? filterSales.map((s) => s.label).join(', ')
|
||||||
|
: undefined,
|
||||||
|
start_date: filterStartDate || undefined,
|
||||||
|
end_date: filterEndDate || undefined,
|
||||||
|
filter_by: 'do_date',
|
||||||
|
},
|
||||||
|
});
|
||||||
toast.success('PDF berhasil dibuat dan diunduh.');
|
toast.success('PDF berhasil dibuat dan diunduh.');
|
||||||
} catch {
|
} catch {
|
||||||
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
||||||
@@ -538,15 +538,9 @@ const CustomerPaymentTab = () => {
|
|||||||
value={filterStartDate}
|
value={filterStartDate}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setFilterStartDate(e.target.value);
|
setFilterStartDate(e.target.value);
|
||||||
setFilterErrors((prev) => ({ ...prev, start_date: '' }));
|
|
||||||
}}
|
}}
|
||||||
className={{ wrapper: 'w-full' }}
|
className={{ wrapper: 'w-full' }}
|
||||||
/>
|
/>
|
||||||
{filterErrors.start_date && (
|
|
||||||
<p className='text-red-500 text-sm mt-1'>
|
|
||||||
{filterErrors.start_date}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -556,15 +550,9 @@ const CustomerPaymentTab = () => {
|
|||||||
value={filterEndDate}
|
value={filterEndDate}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setFilterEndDate(e.target.value);
|
setFilterEndDate(e.target.value);
|
||||||
setFilterErrors((prev) => ({ ...prev, end_date: '' }));
|
|
||||||
}}
|
}}
|
||||||
className={{ wrapper: 'w-full' }}
|
className={{ wrapper: 'w-full' }}
|
||||||
/>
|
/>
|
||||||
{filterErrors.end_date && (
|
|
||||||
<p className='text-red-500 text-sm mt-1'>
|
|
||||||
{filterErrors.end_date}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user