'use client'; import { Document, Image, Link, Page, StyleSheet, Text, View, } from '@react-pdf/renderer'; import { Expense } from '@/types/api/expense'; import { formatCurrency, formatDate, formatNumber } from '@/lib/helper'; interface ExpensePDFProps { expense?: Expense; } const ExpensePDFStyle = StyleSheet.create({ page: { paddingTop: 24, paddingBottom: 64, paddingHorizontal: 32, }, companyInfoHeader: { width: '100%', display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8, }, companyLogo: { width: 64, height: 'auto', }, companyInfoHeaderDate: { paddingTop: 8, fontSize: 12, }, companyName: { fontSize: 12, fontWeight: 'bold', marginBottom: 4, }, companyAddress: { fontSize: 8, maxWidth: 400, marginBottom: 10, }, title: { marginTop: 16, fontSize: 16, lineHeight: '150%', textAlign: 'center', fontFamily: 'Times-Roman', fontWeight: 'bold', }, footer: { width: '100%', display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 32, position: 'absolute', fontSize: 10, bottom: 30, left: 0, right: 0, textAlign: 'center', color: 'grey', }, // wrapper generalInfoTable: { width: '100%', marginTop: 8, borderWidth: 1, borderColor: '#000000', borderBottomWidth: 0, fontSize: 12, }, generalInfoTableRow: { flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: '#000000', }, // columns generalInfoTableColLabel: { width: '30%', paddingVertical: 6, paddingHorizontal: 8, }, generalInfoTableColSeparator: { width: '3%', justifyContent: 'center', alignItems: 'center', paddingVertical: 6, }, generalInfoTableColValue: { width: '67%', paddingVertical: 6, paddingHorizontal: 8, }, generalInfoTableLabelText: { fontWeight: 'bold', }, generalInfoTableValueText: {}, // expense detail table expenseDetailContainer: { width: '100%', marginTop: 12, }, expenseDetailTitle: { fontSize: 14, lineHeight: '150%', fontFamily: 'Times-Roman', fontWeight: 'bold', textAlign: 'center', }, kandangExpenseContainer: { width: '100%', marginTop: 8, }, kandangExpenseTitle: { fontSize: 14, lineHeight: '150%', fontFamily: 'Times-Roman', fontWeight: 'bold', textAlign: 'center', }, kandangExpenseTable: { width: '100%', marginTop: 8, borderWidth: 1, borderColor: '#000000', borderBottomWidth: 0, fontSize: 12, }, kandangExpenseTableRow: { flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: '#000000', }, kandangExpenseTableColLabel: { width: '20%', paddingVertical: 6, paddingHorizontal: 8, }, kandangExpenseTableColLabelBorderRight: { borderRight: '1px solid #000000', }, kandangExpenseTableColNonstock: { width: '20%', }, kandangExpenseTableColNote: { width: '40%', }, kandangExpenseHeaderLabelText: { fontWeight: 'bold', }, kandangExpenseLabelText: { fontSize: 10, }, kandangExpenseTableFooterColTotalExpenseCaption: { width: '40%', paddingVertical: 6, paddingHorizontal: 8, textAlign: 'right', }, kandangExpenseTableFooterColTotalExpenseValue: { width: '60%', paddingVertical: 6, paddingHorizontal: 8, }, // utils doubleDivider: { width: '100%', height: 6, borderTop: '2px solid black', borderBottom: '2px solid black', }, }); const ExpensePDF = ({ expense }: ExpensePDFProps) => { const isLatestApprovalRejected = expense?.latest_approval?.action === 'REJECTED'; const isExpenseRealized = expense?.latest_approval?.step_number && expense?.latest_approval.step_number >= 4; const realizationStatus = isExpenseRealized ? 'Sudah Realisasi' : 'Belum Realisasi'; const rows = [ { label: 'Nomor PO', value: expense?.po_number }, { label: 'Nomor Referensi', value: expense?.reference_number }, { label: 'Kategori', value: expense?.category === 'BOP' ? 'Biaya Operasional' : expense?.category === 'NON-BOP' ? 'Non Biaya Operasional' : '', }, { label: 'Lokasi', value: expense?.location.name }, { label: 'Kandang', value: expense?.kandangs.map((item) => item.name).join(', '), }, { label: 'Vendor', value: expense?.supplier.name }, { label: 'Tanggal Transaksi', value: formatDate(expense?.transaction_date, 'DD MMMM YYYY'), }, { label: 'Tanggal Realisasi', value: expense?.realization_date ? formatDate(expense?.realization_date, 'DD MMMM YYYY') : '-', }, { label: 'Nama Pengaju', value: expense?.created_user.name }, { label: 'Nominal Biaya', value: formatCurrency(expense?.grand_total ?? 0), }, { label: 'Nominal Pengajuan', value: formatCurrency(expense?.total_pengajuan ?? 0), }, { label: 'Nominal Realisasi', value: expense?.total_realisasi ? formatCurrency(expense?.total_realisasi ?? 0) : '-', }, { label: 'Status Pencairan', value: realizationStatus }, { label: 'Status Biaya', value: isLatestApprovalRejected ? 'Ditolak' : expense?.latest_approval?.step_name, }, ]; 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 Laporan{' '} {expense?.category === 'BOP' ? 'Biaya Operasional' : 'Non-Biaya Operasional'}{' '} {expense?.po_number} {/* General info table */} {rows.map((row) => ( {row.label} : {row.value} ))} {/* Detail expense request */} Rincian Pengajuan Biaya Operasional {expense?.kandangs.map((kandangExpense, kandangExpenseIdx) => { let expenseRequestTotal = 0; kandangExpense.pengajuans?.forEach( (item) => (expenseRequestTotal += item.price) ); return ( {kandangExpense.name} Nonstock Kuantitas Harga Satuan Catatan {kandangExpense.pengajuans?.map((pengajuan, pengajuanIdx) => ( {pengajuan.nonstock.name} {formatNumber(pengajuan.qty)} {formatCurrency(pengajuan.price)} {pengajuan.note} ))} Total Biaya Keseluruhan {formatCurrency(expenseRequestTotal)} ); })} {/* Detail expense realization */} Rincian Realisasi Biaya Operasional {expense?.kandangs.map((kandangExpense, kandangExpenseIdx) => { let expenseRealizationTotal = 0; kandangExpense.realisasi?.forEach( (item) => (expenseRealizationTotal += item.price) ); return ( {kandangExpense.name} Nonstock Kuantitas Harga Satuan Catatan {kandangExpense.realisasi?.map((realisasi, realisasiIdx) => ( {realisasi.nonstock.name} {formatNumber(realisasi.qty)} {formatCurrency(realisasi.price)} {realisasi.note} ))} Total Biaya Keseluruhan {formatCurrency(expenseRealizationTotal)} ); })} {expense?.po_number} `${pageNumber} / ${totalPages}` } fixed /> ); }; export default ExpensePDF;