'use client'; import { useMemo, useState } from 'react'; import { Page, Text, View, Document, Image, StyleSheet, Font, pdf, } from '@react-pdf/renderer'; import { Icon } from '@iconify/react'; import toast from 'react-hot-toast'; import Button from '@/components/Button'; import { Purchase } from '@/types/api/purchase/purchase'; import { formatDate, formatNumber } from '@/lib/helper'; Font.register({ family: 'Helvetica', src: 'helvetica', }); const pdfStyles = StyleSheet.create({ page: { fontSize: 10, fontFamily: 'Helvetica', padding: 20, backgroundColor: '#FFFFFF', }, header: { marginBottom: 20, }, logo: { width: 120, height: 30, marginBottom: 8, }, companyInfo: { fontSize: 12, fontWeight: 'bold', marginBottom: 4, color: '#1f74bf', }, address: { fontSize: 8, color: '#666666', maxWidth: 400, marginBottom: 10, }, divider: { borderBottomWidth: 1, borderBottomColor: '#000000', borderBottomStyle: 'solid', marginBottom: 15, }, titleSection: { flexDirection: 'row', marginBottom: 20, justifyContent: 'space-between', alignItems: 'flex-start', }, title: { fontSize: 18, fontWeight: 'bold', flex: 3, color: '#1f74bf', }, poInfo: { flex: 1, fontSize: 9, textAlign: 'right', }, sectionTitle: { fontSize: 12, fontWeight: 'bold', marginBottom: 8, color: '#1f74bf', }, table: { borderWidth: 1, borderColor: '#000000', marginBottom: 15, }, tableRow: { flexDirection: 'row', }, tableHeader: { backgroundColor: '#F5F5F5', }, tableCell: { flex: 1, borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', padding: 8, fontSize: 9, }, tableCellLast: { flex: 1, padding: 8, fontSize: 9, }, tableCellHeader: { flex: 1, borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', padding: 8, fontSize: 9, fontWeight: 'bold', backgroundColor: '#F5F5F5', }, tableCellHeaderLast: { flex: 1, padding: 8, fontSize: 9, fontWeight: 'bold', backgroundColor: '#F5F5F5', }, tableCellRight: { flex: 1, borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', padding: 8, fontSize: 9, textAlign: 'right', }, tableCellRightLast: { flex: 1, padding: 8, fontSize: 9, textAlign: 'right', }, tableBorderBottom: { borderBottomWidth: 1, borderBottomColor: '#000000', borderBottomStyle: 'solid', }, grandTotalRow: { flexDirection: 'row', borderTopWidth: 1, borderTopColor: '#000000', borderTopStyle: 'solid', }, grandTotalLabel: { flex: 3, padding: 8, fontSize: 9, fontWeight: 'bold', textAlign: 'right', borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', }, grandTotalValue: { flex: 1, padding: 8, fontSize: 9, fontWeight: 'bold', textAlign: 'right', borderRightWidth: 0, }, allocationSection: { marginBottom: 15, }, allocationTable: { borderWidth: 1, borderColor: '#000000', }, innerTable: { marginTop: 5, borderWidth: 1, borderColor: '#000000', }, innerRow: { flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: '#000000', borderBottomStyle: 'solid', }, innerCell: { flex: 1, borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', padding: 8, fontSize: 9, }, innerCellLast: { flex: 1, padding: 8, fontSize: 9, }, innerCellRight: { flex: 1, borderRightWidth: 1, borderRightColor: '#000000', borderRightStyle: 'solid', padding: 8, fontSize: 9, textAlign: 'right', }, innerCellRightLast: { flex: 1, padding: 8, fontSize: 9, textAlign: 'right', }, footer: { marginTop: 30, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', }, footerCompany: { fontSize: 12, fontWeight: 'bold', textAlign: 'right', flex: 1, color: '#1f74bf', }, specialInstructionTable: { width: '60%', maxWidth: 300, borderWidth: 1, borderColor: '#000000', flex: 1, }, }); interface PurchaseOrderInvoiceProps { data?: Purchase; className?: string; } const PurchaseOrderInvoice = ({ data }: PurchaseOrderInvoiceProps) => { const [, setIsGeneratingPDF] = useState(false); const purchaseData = data; const grandTotal = useMemo(() => { return ( purchaseData?.items?.reduce( (sum, item) => sum + (item.total_price || 0), 0 ) || 0 ); }, [purchaseData?.items]); const handleDownloadPDF = async () => { if (!purchaseData) { toast.error('No purchase order data available'); return; } setIsGeneratingPDF(true); try { const PDFDocument = () => ( {/* Header Section */} PT LUMBUNG TELUR INDONESIA SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel. Cipedes, Kec. Sukajadi, Kota Bandung 40162 {/* Purchase Order Title */} PURCHASE ORDER PO Number: {purchaseData?.po_number || '-'} Date:{' '} {purchaseData?.po_date ? formatDate(purchaseData.po_date, 'DD MMM YYYY') : formatDate(new Date(), 'DD MMM YYYY')} {/* Vendor and Ship To Table */} Vendor Ship To {purchaseData?.supplier?.name || '-'} ( {purchaseData?.supplier?.alias || ''}) {purchaseData?.supplier?.category || '-'} Credit Term: {purchaseData?.credit_term || 0} hari Due Date:{' '} {purchaseData?.due_date ? formatDate(purchaseData.due_date, 'DD MMM YYYY') : '-'} PT LUMBUNG TELUR INDONESIA {purchaseData?.items?.[0]?.warehouse && 'location' in purchaseData.items[0].warehouse ? purchaseData.items[0].warehouse.location.name : '-'} {purchaseData?.items?.[0]?.warehouse && 'location' in purchaseData.items[0].warehouse ? purchaseData.items[0].warehouse.location.address : '-'} {/* Item Description Table */} Item Description Unit Price Quantity Total Amount {purchaseData?.items?.map((item, index) => { const isLastItem = index === (purchaseData?.items?.length || 0) - 1; return ( {item.product?.name || '-'} Rp{formatNumber(item.price || 0)} {formatNumber(item.sub_qty || 0)} Rp{formatNumber(item.total_price || 0)} ); }) || []} {/* Grand Total Row inside table */} Grand Total Rp{formatNumber(grandTotal)} {/* Product Allocation Section */} Product Allocation Warehouse Name Area Location Address Product Allocation {purchaseData?.items?.map((item, itemIndex) => ( {item.warehouse?.name || '-'} {item.warehouse?.area?.name || '-'} {item.warehouse && 'location' in item.warehouse ? item.warehouse.location.address : '-'} {/* Inner table for product allocation */} {/* Header for inner table */} Item Quantity {/* Data row */} {item.product?.name || '-'} {formatNumber(item.total_qty || 0)} of{' '} {formatNumber(item.sub_qty || 0)} )) || []} {/* Footer with Special Instructions */} Notes {purchaseData?.notes || '-'} PT LUMBUNG TELUR INDONESIA ); const blob = await pdf().toBlob(); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `${purchaseData?.po_number || 'purchase-order'}.pdf`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } catch { toast.error('Failed to generate PDF. Please try again.'); } finally { setIsGeneratingPDF(false); } }; if (!purchaseData) { return (
No purchase order data available
); } return purchaseData?.po_number && purchaseData.po_number !== 'Belum dibuat' ? ( ) : null; }; export default PurchaseOrderInvoice;