diff --git a/src/components/purchase-orders/PurchaseOrderDataTable.tsx b/src/components/purchase-orders/PurchaseOrderDataTable.tsx index 213ad45..23fcf58 100644 --- a/src/components/purchase-orders/PurchaseOrderDataTable.tsx +++ b/src/components/purchase-orders/PurchaseOrderDataTable.tsx @@ -24,9 +24,9 @@ import { import { jsPDF } from "jspdf" import { ReceiveStockDialog } from "./ReceiveStockDialog" import pb from "@/lib/pocketbase" -import { createColumns, PurchaseOrder } from "./columns" // Import createColumns and PurchaseOrder type +import { createColumns, PurchaseOrder } from "./columns" import { - Dialog, // Import Dialog components + Dialog, DialogContent, DialogDescription, DialogHeader, @@ -43,7 +43,7 @@ interface PurchaseOrderDataTableProps { } export function PurchaseOrderDataTable({ - columns: columnsProp, // Rename to avoid conflict + columns: columnsProp, data, filterValue, onFilterChange, @@ -64,7 +64,7 @@ export function PurchaseOrderDataTable({ const [rowSelection, setRowSelection] = React.useState({}) const [receiveDialogOpen, setReceiveDialogOpen] = React.useState(false) const [selectedOrder, setSelectedOrder] = React.useState(null) - const [viewDialogOpen, setViewDialogOpen] = React.useState(false) // State for the view dialog + const [viewDialogOpen, setViewDialogOpen] = React.useState(false) const openReceiveDialog = (order: PurchaseOrder) => { setSelectedOrder(order) @@ -87,23 +87,224 @@ export function PurchaseOrderDataTable({ } const generatePDF = (order: PurchaseOrder) => { - const doc = new jsPDF() - doc.setFontSize(16) - doc.text("Purchase Order", 14, 20) - doc.setFontSize(12) - doc.text(`Supplier: ${order.supplierName}`, 14, 30) - doc.text(`Order Date: ${new Date(order.orderDate).toLocaleDateString()}`, 14, 40) - doc.text(`Status: ${order.status}`, 14, 50) - doc.text("Items:", 14, 60) + const doc = new jsPDF({ + unit: "mm", + format: "a4", + orientation: "portrait", + }); - let y = 70 + const pageWidth = doc.internal.pageSize.getWidth(); + + // Colors + const primaryColor = "#FFC905"; + const blackColor = "#000000"; + const darkGray = "#333333"; + const lightGray = "#F3F4F6"; + + // --- Header --- + doc.setFillColor(primaryColor); + doc.rect(0, 0, pageWidth, 40, "F"); + + // Logo rectangle + doc.setFillColor("#FFA500"); + doc.rect(15, 10, 40, 20, "F"); + doc.setTextColor(blackColor); + doc.setFontSize(12); + doc.setFont("helvetica", "bold"); + const logoText = "LOGO"; + const logoTextWidth = doc.getTextWidth(logoText); + doc.text(logoText, 15 + 20 - logoTextWidth / 2, 22); + + // Header title + doc.setTextColor(blackColor); + doc.setFontSize(24); + doc.text("PURCHASE ORDER", 65, 25); + + // --- Company Info (left) --- + doc.setFontSize(10); + doc.setTextColor(darkGray); + const companyInfoX = 15; + let y = 50; + doc.text("Your Company Name", companyInfoX, y); + y += 6; + doc.text("77 Hammersmith Road, West Kensington", companyInfoX, y); + y += 6; + doc.text("London, W14 0QH", companyInfoX, y); + y += 6; + doc.text("Phone: 0208 668 381", companyInfoX, y); + + // --- PO Details (right) --- + const poDetailsX = 130; + const poDetailsY = 45; + const poDetailsWidth = 65; + const poDetailsHeight = 55; + + doc.setFillColor(lightGray); + doc.roundedRect(poDetailsX, poDetailsY, poDetailsWidth, poDetailsHeight, 3, 3, "F"); + + doc.setTextColor(darkGray); + doc.setFontSize(10); + const poLabelX = poDetailsX + 5; + let poLabelY = poDetailsY + 8; + const poValueX = poDetailsX + poDetailsWidth - 5; + + const poLabels = [ + "PO no:", + "Status:", + "Date:", + "Requested By:", + "Approved By:", + "Department:", + ]; + + const poValues = [ + "POO1234", + order.status, + order.orderDate ? new Date(order.orderDate).toLocaleDateString() : "", + "Billy Buyer", + "John Smith", + "IT Department", + ]; + + poLabels.forEach((label, i) => { + doc.text(label, poLabelX, poLabelY); + doc.text(poValues[i], poValueX - doc.getTextWidth(poValues[i]), poLabelY); + poLabelY += 8; + }); + + // --- Ship To --- + const shipToX = 15; + let shipToY = 110; + doc.setFontSize(12); + doc.setTextColor(blackColor); + doc.setFont("helvetica", "bold"); + doc.text("Ship to", shipToX, shipToY); + shipToY += 8; + + doc.setFontSize(10); + doc.setFont("helvetica", "normal"); + const shipToLines = [ + "Manchester Office", + "Attn: Billy Buyer", + "43 Customer Road", + "Manchester, M4 1HS", + "Phone: 07394 123456", + ]; + shipToLines.forEach(line => { + doc.text(line, shipToX, shipToY); + shipToY += 6; + }); + + // --- Supplier --- + const supplierX = 15; + let supplierY = 160; + doc.setFontSize(12); + doc.setFont("helvetica", "bold"); + doc.text("Supplier", supplierX, supplierY); + supplierY += 8; + + doc.setFontSize(10); + doc.setFont("helvetica", "normal"); + const supplierLines = [ + "Mr. Peter McDonald", + "17 Springdale Rd,", + "N16 9NS, London", + "Phone: 1234 567 890", + "Email: supplier@email.co.uk", + "Terms: 30 days", + ]; + supplierLines.forEach(line => { + doc.text(line, supplierX, supplierY); + supplierY += 6; + }); + + // --- Terms of sale --- + const termsX = 130; + let termsY = 110; + doc.setFontSize(12); + doc.setFont("helvetica", "bold"); + doc.text("Terms of sale and other comments", termsX, termsY); + termsY += 8; + + doc.setFontSize(10); + doc.setFont("helvetica", "normal"); + doc.text("Add any additional instructions or terms here.", termsX, termsY); + + // --- Items Table Header --- + const tableX = 10; + let tableY = 190; + const tableWidth = pageWidth - 20; + + doc.setFillColor(lightGray); + doc.roundedRect(tableX, tableY, tableWidth, 10, 3, 3, "F"); + + doc.setTextColor(darkGray); + doc.setFontSize(11); + doc.setFont("helvetica", "bold"); + + const headers = [ + { label: "Item #", x: tableX + 5, width: 15 }, + { label: "Description", x: tableX + 25, width: 80 }, + { label: "Qty", x: tableX + 110, width: 15 }, + { label: "Unit", x: tableX + 130, width: 20 }, + { label: "Unit Price", x: tableX + 155, width: 25 }, + { label: "Total", x: tableX + 185, width: 20 }, + ]; + + headers.forEach(h => { + doc.text(h.label, h.x, tableY + 7); + }); + + // --- Items Table Rows --- + doc.setFont("helvetica", "normal"); + let rowY = tableY + 17; order.items.forEach((item, index) => { - doc.text(`${index + 1}. ${item.itemName} - Qty: ${item.quantity}`, 14, y) - doc.text(item.sku, 70, y); - y += 10 - }) + if (rowY > 270) { + doc.addPage(); + rowY = 20; + } + doc.setTextColor(darkGray); + doc.setFontSize(10); + doc.text(String(index + 1), headers[0].x, rowY); + doc.text(item.itemName, headers[1].x, rowY); + doc.text(String(item.quantity), headers[2].x, rowY); + doc.text("Unit", headers[3].x, rowY); // Placeholder for unit + doc.text("£75.00", headers[4].x, rowY); // Placeholder for unit price + doc.text("£75.00", headers[5].x, rowY); // Placeholder for total + rowY += 8; + }); - doc.save(`purchase_order_${order.id}.pdf`) + // --- Totals Section --- + const totalsX = tableX + tableWidth - 60; + let totalsY = rowY + 10; + + const totalsLabels = ["Subtotal", "Tax", "Shipping", "Other"]; + const totalsValues = ["£2,325.00", "£0", "£0", "£0"]; + + doc.setFontSize(10); + doc.setFont("helvetica", "normal"); + doc.setTextColor(darkGray); + + totalsLabels.forEach((label, i) => { + doc.text(label, totalsX, totalsY + i * 7); + doc.text(totalsValues[i], totalsX + 40, totalsY + i * 7); + }); + + // Total line + totalsY += totalsLabels.length * 7 + 3; + doc.setDrawColor(primaryColor); + doc.setLineWidth(0.5); + doc.line(totalsX, totalsY, totalsX + 50, totalsY); + + // Total amount + totalsY += 7; + doc.setFontSize(14); + doc.setFont("helvetica", "bold"); + doc.setTextColor(primaryColor); + doc.text("Total", totalsX, totalsY); + doc.text("£2,325.00", totalsX + 40, totalsY); + + doc.save(`purchase_order_${order.id}.pdf`); } const approveOrder = async (order: PurchaseOrder) => { @@ -126,9 +327,9 @@ export function PurchaseOrderDataTable({ const columnsWithActions = React.useMemo(() => createColumns({ onDownloadPdf: generatePDF, onViewOrder: handleViewOrder }), [generatePDF, handleViewOrder]); - const table = useReactTable({ // Specify TData as PurchaseOrder - data: data as PurchaseOrder[], // Explicitly type data as PurchaseOrder[] - columns: columnsWithActions, // Use the columns with actions + const table = useReactTable({ + data: data as PurchaseOrder[], + columns: columnsWithActions, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), onSortingChange: setSorting, @@ -145,7 +346,6 @@ export function PurchaseOrderDataTable({ }, }) - // Sync external filter value with the table's internal state React.useEffect(() => { table.getColumn("supplierName")?.setFilterValue(filterValue) }, [filterValue, table]) @@ -174,20 +374,18 @@ export function PurchaseOrderDataTable({ .filter( (column) => column.getCanHide() ) - .map((column) => { - return ( - - column.toggleVisibility(!!value) - } - > - {column.id} - - ) - })} + .map((column) => ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ))}