mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-272): adding DO PDF export
This commit is contained in:
+1
-1
@@ -49,4 +49,4 @@
|
|||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import SalesOrderExport from '@/components/pages/marketing/pdf/SalesOrderExport';
|
import SalesOrderExport from '@/components/pages/marketing/pdf/SalesOrderExport';
|
||||||
|
import DeliveryOrderExport from '../pdf/DeliveryOrderExport';
|
||||||
|
|
||||||
const MarketingDetail = ({
|
const MarketingDetail = ({
|
||||||
initialValues,
|
initialValues,
|
||||||
@@ -386,10 +387,10 @@ const MarketingDetail = ({
|
|||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
<div className='flex flex-row gap-3 my-3'>
|
<div className='flex flex-row gap-3 my-3'>
|
||||||
<Button className='py-2 px-3 font-medium text-md'>
|
<DeliveryOrderExport
|
||||||
<Icon icon='mdi:file-pdf' width={16} height={16} />
|
data={initialValues}
|
||||||
{delivery.do_number}
|
deliveryOrder={delivery}
|
||||||
</Button>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
import Button from '@/components/Button';
|
||||||
|
import { BaseDeliveryOrder, Marketing } from '@/types/api/marketing/marketing';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import { Document, Image, Page, pdf, Text, View } from '@react-pdf/renderer';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import pdfStyles from './styles/MarketingPDFStyles';
|
||||||
|
import { formatDate, formatNumber, formatVechicleNumber } from '@/lib/helper';
|
||||||
|
import { format } from 'path';
|
||||||
|
import { date } from 'yup';
|
||||||
|
|
||||||
|
interface DeliveryOrderExportProps {
|
||||||
|
data?: Marketing;
|
||||||
|
deliveryOrder: BaseDeliveryOrder;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeliveryOrderExport = ({
|
||||||
|
data,
|
||||||
|
deliveryOrder,
|
||||||
|
}: DeliveryOrderExportProps) => {
|
||||||
|
const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);
|
||||||
|
const salesData = data;
|
||||||
|
|
||||||
|
const handleDownloadPDF = async () => {
|
||||||
|
if (!salesData) {
|
||||||
|
alert('No sales order data available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIsGeneratingPDF(true);
|
||||||
|
try {
|
||||||
|
const blob = await pdf(
|
||||||
|
<PDFDocument data={salesData} deliveryOrder={deliveryOrder} />
|
||||||
|
).toBlob();
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `${deliveryOrder?.do_number || 'delivery-order'}.pdf`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating PDF:', error);
|
||||||
|
alert('Failed to generate PDF. Please try again.');
|
||||||
|
} finally {
|
||||||
|
setIsGeneratingPDF(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!salesData) {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-center min-h-screen'>
|
||||||
|
<div className='text-gray-500'>No sales order data available</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return salesData?.so_number && salesData.so_number !== 'Belum dibuat' ? (
|
||||||
|
<Button
|
||||||
|
color='primary'
|
||||||
|
className='w-fit min-w-32 flex items-center justify-start gap-1 px-2 py-1 text-sm font-mono'
|
||||||
|
onClick={handleDownloadPDF}
|
||||||
|
isLoading={isGeneratingPDF}
|
||||||
|
>
|
||||||
|
<Icon icon='material-symbols:file-open-outline' width={16} height={16} />
|
||||||
|
{deliveryOrder.do_number}
|
||||||
|
</Button>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeliveryOrderExport;
|
||||||
|
const PDFDocument = ({
|
||||||
|
data,
|
||||||
|
deliveryOrder,
|
||||||
|
}: {
|
||||||
|
data: Marketing;
|
||||||
|
deliveryOrder: BaseDeliveryOrder;
|
||||||
|
}) => {
|
||||||
|
const grandTotal = useMemo(() => {
|
||||||
|
return (
|
||||||
|
deliveryOrder.deliveries?.reduce((a, b) => a + b.total_price, 0) ?? 0
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Document>
|
||||||
|
<Page size='A4' style={pdfStyles.page}>
|
||||||
|
{/* Header Section */}
|
||||||
|
<View style={pdfStyles.header}>
|
||||||
|
<Image
|
||||||
|
src={'https://placehold.co/120x30/png'}
|
||||||
|
style={pdfStyles.logo}
|
||||||
|
id={'mbu-logo'}
|
||||||
|
/>
|
||||||
|
<Text style={pdfStyles.companyInfo}>PT LUMBUNG TELUR INDONESIA</Text>
|
||||||
|
<Text style={pdfStyles.address}>
|
||||||
|
SOHO Building Lt.3 (Paris Van Java), Jalan Karang Tinggal, Kel.
|
||||||
|
Cipedes, Kec. Sukajadi, Kota Bandung 40162
|
||||||
|
</Text>
|
||||||
|
<View style={pdfStyles.divider} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Delivery Order Title */}
|
||||||
|
<View style={pdfStyles.titleSection}>
|
||||||
|
<Text style={pdfStyles.title}>DELIVERY ORDER</Text>
|
||||||
|
<View style={pdfStyles.poInfo}>
|
||||||
|
<Text>{deliveryOrder.do_number || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Depature Table */}
|
||||||
|
<View style={pdfStyles.table}>
|
||||||
|
<View style={[pdfStyles.tableRow, pdfStyles.tableHeader]}>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Ship To</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeaderLast}>
|
||||||
|
<Text>Depature From</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableRow}>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text style={{ fontWeight: 'bold' }}>
|
||||||
|
{data?.customer?.name || '-'} ({data?.customer?.type || '-'})
|
||||||
|
</Text>
|
||||||
|
<Text style={{ marginTop: '2px' }}>
|
||||||
|
{data?.customer.email || ''} - {data?.customer.phone || ''}
|
||||||
|
</Text>
|
||||||
|
<Text></Text>
|
||||||
|
<Text>{data?.customer.address || ''}</Text>
|
||||||
|
<Text style={{ fontSize: '7px', marginTop: '3px' }}></Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellLast}>
|
||||||
|
<Text style={{ fontWeight: 'bold' }}>
|
||||||
|
{deliveryOrder.warehouse?.name || '-'}
|
||||||
|
</Text>
|
||||||
|
<Text style={{ marginTop: '2px' }}>
|
||||||
|
{formatDate(deliveryOrder.delivery_date, 'DD MMM YYYY')}
|
||||||
|
</Text>
|
||||||
|
<Text>{deliveryOrder.warehouse?.area?.name}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Delivery Table */}
|
||||||
|
<Text style={pdfStyles.sectionTitle}>Product Shipped</Text>
|
||||||
|
<View style={pdfStyles.table}>
|
||||||
|
<View style={[pdfStyles.tableRow, pdfStyles.tableHeader]}>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Item Description</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Vehicle Number</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Unit Price</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Quantity</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeaderLast}>
|
||||||
|
<Text>Total Amount</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{deliveryOrder.deliveries?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<View key={index} style={[pdfStyles.tableRow]}>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>{item.product_warehouse?.product?.name || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>
|
||||||
|
{formatVechicleNumber(item.vehicle_number) || '-'}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellRight}>
|
||||||
|
<Text>Rp{formatNumber(item.unit_price || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellRight}>
|
||||||
|
<Text>{formatNumber(item.qty || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellRightLast}>
|
||||||
|
<Text>Rp{formatNumber(item.total_price || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}) || []}
|
||||||
|
|
||||||
|
{/* Grand Total Row inside table */}
|
||||||
|
<View style={pdfStyles.grandTotalRow}>
|
||||||
|
<View style={[pdfStyles.tableCell, { borderRightWidth: 0 }]}>
|
||||||
|
<Text></Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCell, { borderRightWidth: 0 }]}>
|
||||||
|
<Text></Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { borderRightWidth: 0 }]}>
|
||||||
|
<Text></Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellRight}>
|
||||||
|
<Text style={{ fontWeight: 'bold' }}>Grand Total</Text>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={[pdfStyles.tableCellRightLast, { fontWeight: 'bold' }]}
|
||||||
|
>
|
||||||
|
<Text>Rp{formatNumber(grandTotal)}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Footer with Special Instructions */}
|
||||||
|
<View style={pdfStyles.footer}>
|
||||||
|
<View style={pdfStyles.specialInstructionTable}>
|
||||||
|
<View style={[pdfStyles.tableRow, pdfStyles.tableHeader]}>
|
||||||
|
<View style={pdfStyles.tableCellHeaderLast}>
|
||||||
|
<Text>From Sales Order</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableRow}>
|
||||||
|
<View style={pdfStyles.tableCellLast}>
|
||||||
|
<Text>
|
||||||
|
{data?.so_number || '-'} -{' '}
|
||||||
|
{formatDate(data.so_date, 'DD MMM YYYY')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.footerCompany}>
|
||||||
|
<Text>PT LUMBUNG TELUR INDONESIA</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Page>
|
||||||
|
</Document>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user