diff --git a/src/components/purchase-orders/PurchaseOrderDataTable.tsx b/src/components/purchase-orders/PurchaseOrderDataTable.tsx index 3b05a81..92d8202 100644 --- a/src/components/purchase-orders/PurchaseOrderDataTable.tsx +++ b/src/components/purchase-orders/PurchaseOrderDataTable.tsx @@ -24,16 +24,7 @@ import { import { jsPDF } from "jspdf" import { ReceiveStockDialog } from "./ReceiveStockDialog" import pb from "@/lib/pocketbase" - -export type PurchaseOrder = { - id: string - supplierName: string - orderDate: string - status: string - itemCount: number - items: Array<{ stockItemId: string; itemName: string; quantity: number; sku: string }> // Added sku here - quantities: number[] -} +import { createColumns, PurchaseOrder } from "./columns" // Corrected import interface PurchaseOrderDataTableProps { columns: ColumnDef[] @@ -44,7 +35,7 @@ interface PurchaseOrderDataTableProps { } export function PurchaseOrderDataTable({ - columns, + columns: columnsProp, // Rename to avoid conflict data, filterValue, onFilterChange, @@ -89,7 +80,7 @@ export function PurchaseOrderDataTable({ let y = 70 order.items.forEach((item, index) => { doc.text(`${index + 1}. ${item.itemName} - Qty: ${item.quantity}`, 14, y) - doc.text(item.sku, 70, y); // Accessing sku directly + doc.text(item.sku, 70, y); y += 10 }) @@ -114,9 +105,12 @@ export function PurchaseOrderDataTable({ } } + // Use createColumns and pass the generatePDF function + const columnsWithActions = React.useMemo(() => createColumns({ onDownloadPdf: generatePDF }), [generatePDF]); + const table = useReactTable({ data, - columns, + columns: columnsWithActions, // Use the columns with actions getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), onSortingChange: setSorting, @@ -228,7 +222,8 @@ export function PurchaseOrderDataTable({ }) ) : ( - No results. + {/* Use columns.length instead of columns.length + 1 */} + No results. )} diff --git a/src/components/purchase-orders/columns.tsx b/src/components/purchase-orders/columns.tsx index 940a6c0..85cc0b6 100644 --- a/src/components/purchase-orders/columns.tsx +++ b/src/components/purchase-orders/columns.tsx @@ -1,6 +1,16 @@ "use client" import { ColumnDef } from "@tanstack/react-table" +import { MoreHorizontal, Download } from "lucide-react" // Import Download icon +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" export type PurchaseOrder = { id: string @@ -8,9 +18,17 @@ export type PurchaseOrder = { orderDate: string status: string itemCount: number + items: Array<{ stockItemId: string; itemName: string; quantity: number; sku: string }> + quantities: number[] } -export const columns: ColumnDef[] = [ +// Define the props for the actions column +interface ActionsColumnProps { + onDownloadPdf: (order: PurchaseOrder) => void; +} + +// Export createColumns function +export const createColumns = ({ onDownloadPdf }: ActionsColumnProps): ColumnDef[] => [ { accessorKey: "supplierName", header: "Supplier Name", @@ -36,4 +54,35 @@ export const columns: ColumnDef[] = [ accessorKey: "itemCount", header: "Number of Items", }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const order = row.original + + return ( + + + + + + Actions + navigator.clipboard.writeText(order.id)} + > + Copy Order ID + {/* Correctly closed DropdownMenuItem */} + + onDownloadPdf(order)}> + + Download PDF + + + + ) + }, + }, ] \ No newline at end of file diff --git a/src/pages/PurchaseOrders.tsx b/src/pages/PurchaseOrders.tsx index d9f6c25..ab322c6 100644 --- a/src/pages/PurchaseOrders.tsx +++ b/src/pages/PurchaseOrders.tsx @@ -9,7 +9,7 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { columns } from "@/components/purchase-orders/columns"; +import { createColumns } from "@/components/purchase-orders/columns"; // Import createColumns import { PurchaseOrderDataTable } from "@/components/purchase-orders/PurchaseOrderDataTable"; import pb from "@/lib/pocketbase"; @@ -23,7 +23,7 @@ const PurchaseOrders = () => { try { const records = await pb.collection('purchase_orders').getList(1, 50, { sort: '-orderDate', - expand: 'items', + expand: 'items', // Ensure items are expanded for PDF generation }); const formattedData = records.items.map((record) => ({ @@ -36,6 +36,7 @@ const PurchaseOrders = () => { stockItemId: item.id, itemName: item.name, quantity: item.quantity, + sku: item.sku, // Ensure sku is included if needed by columns })), quantities: record.quantities || [], })); @@ -44,7 +45,7 @@ const PurchaseOrders = () => { } catch (err) { console.error("Error fetching purchase orders:", err); } - }, [refreshTrigger]); + }, [refreshTrigger]); // Include refreshTrigger in dependency array useEffect(() => { fetchPurchaseOrders(); @@ -54,6 +55,9 @@ const PurchaseOrders = () => { setRefreshTrigger(prev => prev + 1); }; + // Call createColumns to get the columns array + const columns = createColumns({ onDownloadPdf: (order) => console.log("Downloading PDF for order:", order.id) }); // Placeholder for now + return (
@@ -77,7 +81,7 @@ const PurchaseOrders = () => {
{ ); }; -export default PurchaseOrders; \ No newline at end of file +export default PurchaseOrders; + + +Here's a breakdown of the fixes: + +1. **`src/components/purchase-orders/columns.tsx`:** + * Corrected the closing tag for `DropdownMenuItem`. + * Exported `createColumns` function. + +2. **`src/components/purchase-orders/PurchaseOrderDataTable.tsx`:** + * Changed the import from `"./columns"` to `"./columns"` to correctly import `createColumns`. + * Used `columnsWithActions` (which is the result of `createColumns`) when initializing `useReactTable`. + * Corrected `colSpan` in the "No results" row to use `columns.length` (since `columns` is now correctly defined within the scope of `PurchaseOrderDataTableProps`). + +3. **`src/pages/PurchaseOrders.tsx`:** + * Imported `createColumns` from `"./columns"`. + * Called `createColumns` to get the `columns` array, passing the `onDownloadPdf` handler. + * Passed the `columns` array to `PurchaseOrderDataTable`. + +Please rebuild the app to apply these changes. + + +Type 'ColumnDef<PurchaseOrder>[]' is not assignable to type 'ColumnDef<TData, any>[]'. + Type 'ColumnDef<PurchaseOrder>' is not assignable to type 'ColumnDef<TData, any>'. + Type 'ColumnDefBase<PurchaseOrder, unknown> & StringHeaderIdentifier' is not assignable to type 'ColumnDef<TData, any>'. + Type 'ColumnDefBase<PurchaseOrder, unknown> & StringHeaderIdentifier' is not assignable to type 'AccessorFnColumnDefBase<TData, any> & IdIdentifier<TData, any>'. + Property 'accessorFn' is missing in type 'ColumnDefBase<PurchaseOrder, unknown> & StringHeaderIdentifier' but required in type 'AccessorFnColumnDefBase<TData, any>'. +Cannot find name 'columns'. Did you mean 'Columns'? +Module '"@/components/purchase-orders/columns"' has no exported member 'columns'. +You're right, those are some tricky TypeScript errors! It seems like there was a mix-up with how the columns were being defined and passed around. + +Here's the plan to fix these errors: + +1. **`PurchaseOrderDataTable.tsx` (Error 1 & 2):** + * The `useReactTable` hook expects the `columns` prop to be of type `ColumnDef[]`. Currently, `columnsWithActions` is of type `ColumnDef[]`, which is not directly assignable to `ColumnDef[]` because `TData` is a generic type. We'll ensure `PurchaseOrder` is used as the `TData` type for `useReactTable`. + * The `colSpan` error in the "No results" row is because `columns` is no longer directly available in that scope. We'll use `table.getAllColumns().length` which represents the total number of columns the table is aware of. + +2. **`src/pages/PurchaseOrders.tsx` (Error 3):** + * The `createColumns` function is now the exported entity from `./columns.tsx`, not `columns`. We need to import and call `createColumns` correctly. + +Here are the fixes: + + +"use client" + +import * as React from "react" +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" +import { Columns } from "lucide-react" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { jsPDF } from "jspdf" +import { ReceiveStockDialog } from "./ReceiveStockDialog" +import pb from "@/lib/pocketbase" +import { createColumns, PurchaseOrder } from "./columns" // Import createColumns and PurchaseOrder type + +interface PurchaseOrderDataTableProps { + columns: ColumnDef[] + data: TData[] + filterValue: string + onFilterChange: (value: string) => void + refreshData: () => void +} + +export function PurchaseOrderDataTable({ + columns: columnsProp, // Rename to avoid conflict + data, + filterValue, + onFilterChange, + refreshData, +}: PurchaseOrderDataTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState(() => { + if (typeof window !== 'undefined' && window.innerWidth < 768) { + return { + orderDate: false, + status: false, + actions: false, + }; + } + return {}; + }); + const [rowSelection, setRowSelection] = React.useState({}) + const [receiveDialogOpen, setReceiveDialogOpen] = React.useState(false) + const [selectedOrder, setSelectedOrder] = React.useState(null) + + const openReceiveDialog = (order: PurchaseOrder) => { + setSelectedOrder(order) + setReceiveDialogOpen(true) + } + + const closeReceiveDialog = () => { + setSelectedOrder(null) + setReceiveDialogOpen(false) + } + + 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) + + let y = 70 + order.items.forEach((item, index) => { + doc.text(`${index + 1}. ${item.itemName} - Qty: ${item.quantity}`, 14, y) + doc.text(item.sku, 70, y); + y += 10 + }) + + doc.save(`purchase_order_${order.id}.pdf`) + } + + const approveOrder = async (order: PurchaseOrder) => { + try { + await pb.collection('purchase_orders').update(order.id, { status: "Approved" }) + refreshData() + } catch (error) { + console.error("Failed to approve order:", error) + } + } + + const rejectOrder = async (order: PurchaseOrder) => { + try { + await pb.collection('purchase_orders').update(order.id, { status: "Rejected" }) + refreshData() + } catch (error) { + console.error("Failed to reject order:", error) + } + } + + // Use createColumns and pass the generatePDF function + const columnsWithActions = React.useMemo(() => createColumns({ onDownloadPdf: generatePDF }), [generatePDF]); + + const table = useReactTable({ // Specify TData as PurchaseOrder + data, + columns: columnsWithActions, // Use the columns with actions + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + // Sync external filter value with the table's internal state + React.useEffect(() => { + table.getColumn("supplierName")?.setFilterValue(filterValue) + }, [filterValue, table]) + + return ( + <> +
+
+ onFilterChange(e.target.value)} + className="max-w-sm border border-gray-300 rounded px-2 py-1" + /> + + + + + + {table + .getAllColumns() + .filter( + (column) => column.getCanHide() + ) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ) + })} + + +
+
+ + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => ( + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map(row => { + const order = row.original as PurchaseOrder + return ( + + {row.getVisibleCells().map(cell => ( + + ))} + + + ) + }) + ) : ( + + {/* Use table.getAllColumns().length for colSpan */} + + + )} + +
+ {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} + + {order.status === "Pending Approval" && ( + <> + + + + )} + {order.status === "Approved" && ( + <> + + + + )} + {order.status === "Received" && ( + Received + )} + {order.status === "Rejected" && ( + Rejected + )} +
No results.
+
+
+ + {selectedOrder && ( + ({ + stockItemId: item.stockItemId, + orderedQuantity: selectedOrder.quantities[idx] || 0, + itemName: item.itemName, + }))} + refreshData={refreshData} + /> + )} + + ) +} \ No newline at end of file