import React, { useState } from 'react'; import { Transaction } from '../types'; import { Download, X, Eye } from 'lucide-react'; import jsPDF from 'jspdf'; import 'jspdf-autotable'; interface PdfInvoiceProps { transaction: Transaction; className?: string; children?: React.ReactNode; } const PdfInvoice: React.FC = ({ transaction, className, children }) => { const [showPreview, setShowPreview] = useState(false); const [pdfUrl, setPdfUrl] = useState(''); const formatINR = (v: number) => `₹${v.toFixed(2)}`; const formatDate = (dateStr: string) => { const date = new Date(dateStr); return date.toLocaleDateString('en-IN', { day: '2-digit', month: '2-digit', year: 'numeric' }); }; const generatePDF = (download: boolean = false) => { const doc = new jsPDF(); const subtotal = transaction.subtotal || 0; const packing = transaction.expenses?.poti_amount || 0; const cess = transaction.expenses?.cess_amount || 0; const adat = transaction.expenses?.adat_amount || 0; const hamali = (transaction.expenses?.hamali_amount || 0) + (transaction.expenses?.packaging_hamali_amount || 0); const grandTotal = transaction.total_amount || 0; const paidAmount = transaction.paid_amount || 0; const balanceAmount = transaction.balance_amount || 0; // Header - Invoice Date on left, Bill No on right doc.setFontSize(13); doc.setFont('helvetica', 'bold'); doc.text(`Invoice Date: ${formatDate(transaction.bill_date)}`, 14, 15); doc.text(`Bill No: ${transaction.bill_number}`, 196, 15, { align: 'right' }); // Party Details Section - LEFT ALIGNED doc.setFontSize(11); doc.setFont('helvetica', 'bold'); doc.text('Party Details', 14, 25); doc.setLineWidth(0.5); doc.line(14, 26, 55, 26); // Party info - explicitly left aligned at x=14 doc.setFont('helvetica', 'normal'); doc.setFontSize(9); const partyName = transaction.party_name || '-'; const partyCity = transaction.party_city || '-'; const partyPhone = transaction.party_phone || '-'; doc.text(`Name: ${partyName}`, 14, 31, { align: 'left' }); doc.text(`Place: ${partyCity}`, 14, 36, { align: 'left' }); doc.text(`Mobile: ${partyPhone}`, 14, 41, { align: 'left' }); // Items Table const tableData = transaction.items.map((item, idx) => { const potiWeights = Array.isArray(item.poti_weights) ? item.poti_weights.join(', ') : (typeof item.poti_weights === 'string' ? item.poti_weights : '-'); const amount = item.net_weight * item.rate_per_kg; return [idx + 1, `${item.mirchi_name}\n${potiWeights}`, item.poti_count, item.net_weight, item.rate_per_kg, formatINR(amount)]; }); (doc as any).autoTable({ startY: 47, head: [['#', 'Product Type', 'Bags', 'Net (kg)', 'Rate (₹)', 'Amount (₹)']], body: tableData, theme: 'grid', styles: { fontSize: 8, cellPadding: 2, lineWidth: 0.5, lineColor: [0, 0, 0] }, headStyles: { fillColor: [255, 255, 255], textColor: [0, 0, 0], fontStyle: 'bold' }, bodyStyles: { textColor: [0, 0, 0] }, columnStyles: { 0: { halign: 'center', cellWidth: 10 }, 1: { halign: 'left', cellWidth: 60 }, 2: { halign: 'center', cellWidth: 20 }, 3: { halign: 'center', cellWidth: 25 }, 4: { halign: 'center', cellWidth: 25 }, 5: { halign: 'right', cellWidth: 35 } } }); // Summary Table - Right side const finalY = (doc as any).lastAutoTable.finalY + 5; const summaryData = [ ['Sub Total', formatINR(subtotal)], ['Packing', formatINR(packing)], ['CESS', formatINR(cess)], ['Adat', formatINR(adat)], ['Hamali', formatINR(hamali)], ['Total Amount', formatINR(grandTotal)] ]; (doc as any).autoTable({ startY: finalY, body: summaryData, theme: 'grid', styles: { fontSize: 8, cellPadding: 2, lineWidth: 0.5, lineColor: [0, 0, 0] }, bodyStyles: { textColor: [0, 0, 0] }, columnStyles: { 0: { halign: 'left', cellWidth: 50 }, 1: { halign: 'right', cellWidth: 35 } }, margin: { left: 111 } }); // Payment Status Section - LEFT ALIGNED const paymentY = (doc as any).lastAutoTable.finalY + 10; doc.setFontSize(11); doc.setFont('helvetica', 'bold'); doc.text('Payment Status', 14, paymentY, { align: 'left' }); doc.setLineWidth(0.5); doc.line(14, paymentY + 1, 60, paymentY + 1); doc.setFont('helvetica', 'normal'); doc.setFontSize(9); let currentY = paymentY + 6; if (transaction.payments && transaction.payments.length > 0) { transaction.payments.forEach((payment) => { const mode = payment.mode === 'cash' ? 'Cash' : payment.mode === 'online' ? 'Online' : payment.mode; doc.text(`${mode}: ${formatINR(payment.amount)}`, 14, currentY, { align: 'left' }); currentY += 5; }); doc.setFont('helvetica', 'bold'); doc.text(`Total Paid: ${formatINR(paidAmount)}`, 14, currentY, { align: 'left' }); currentY += 5; } else { doc.text(`Paid Amount: ${formatINR(paidAmount)}`, 14, currentY, { align: 'left' }); currentY += 5; } if (balanceAmount > 0) { doc.setFont('helvetica', 'bold'); doc.setTextColor(211, 47, 47); doc.text(`Due Amount: ${formatINR(balanceAmount)}`, 14, currentY, { align: 'left' }); doc.setTextColor(0, 0, 0); } // Signature - Right side doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.text('(Authorised Signatory)', 196, paymentY + 20, { align: 'right' }); if (download) { doc.save(`Invoice_${transaction.bill_number}.pdf`); } else { const pdfBlob = doc.output('blob'); const url = URL.createObjectURL(pdfBlob); setPdfUrl(url); setShowPreview(true); } }; const handleDownload = () => { generatePDF(true); setShowPreview(false); if (pdfUrl) { URL.revokeObjectURL(pdfUrl); } }; const handleClose = () => { setShowPreview(false); if (pdfUrl) { URL.revokeObjectURL(pdfUrl); } }; return ( <> {showPreview && (

PDF Preview