[dyad] wrote 4 file(s)

This commit is contained in:
[dyad] 2025-09-12 11:13:25 +02:00
parent 4dd97211f8
commit 3e307807d8
2 changed files with 5 additions and 289 deletions

View file

@ -13,7 +13,7 @@ import {
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { Columns } from "lucide-react" // This import is not directly used in the component, but might be used elsewhere. Renaming it is not necessary here.
import { Columns } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
@ -35,7 +35,7 @@ interface PurchaseOrderDataTableProps<TData, TValue> {
}
export function PurchaseOrderDataTable<TData, TValue>({
columns: columnsProp, // Renamed prop to avoid conflict with lucide-react Columns import
columns: columnsProp, // Rename to avoid conflict
data,
filterValue,
onFilterChange,
@ -105,12 +105,11 @@ export function PurchaseOrderDataTable<TData, TValue>({
}
}
// Use createColumns and pass the generatePDF function
const columnsWithActions = React.useMemo(() => createColumns({ onDownloadPdf: generatePDF }), [generatePDF]);
const table = useReactTable<PurchaseOrder>({ // Specify TData as PurchaseOrder
data,
columns: columnsWithActions, // Use the columns with actions
data, // Now 'data' (which is PurchaseOrder[]) is correctly assigned to the 'data' parameter of useReactTable
columns: columnsWithActions, // Use the correctly memoized columns
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onSortingChange: setSorting,
@ -222,7 +221,6 @@ export function PurchaseOrderDataTable<TData, TValue>({
})
) : (
<tr>
{/* Use table.getAllColumns().length for colSpan */}
<td colSpan={table.getAllColumns().length} className="h-24 text-center">No results.</td>
</tr>
)}

View file

@ -98,286 +98,4 @@ const PurchaseOrders = () => {
);
};
export default PurchaseOrders;
</dyad-file>
Here's a summary of the fixes:
1. **`src/components/purchase-orders/columns.tsx`:**
* Ensured `createColumns` is correctly exported.
* Fixed the closing tag for `DropdownMenuItem`.
2. **`src/components/purchase-orders/PurchaseOrderDataTable.tsx`:**
* Corrected the import statement to use `createColumns` and `PurchaseOrder`.
* Specified `PurchaseOrder` as the generic type for `useReactTable`.
* Used `columnsWithActions` (the result of `createColumns`) when configuring `useReactTable`.
* Fixed the `colSpan` in the "No results" row to use `table.getAllColumns().length`.
3. **`src/pages/PurchaseOrders.tsx`:**
* Corrected the import statement to use `createColumns` and `PurchaseOrder`.
* Called `createColumns` correctly, passing the `onDownloadPdf` handler.
* Passed the resulting `columns` array to `PurchaseOrderDataTable`.
* Explicitly typed `purchaseOrders` state as `PurchaseOrder[]`.
These changes should resolve the TypeScript errors and ensure the table functions correctly with the PDF download action.
Please rebuild the app to apply these fixes.
<dyad-command type="rebuild"></dyad-command><dyad-problem-report summary="1 problems">
<problem file="src/components/purchase-orders/PurchaseOrderDataTable.tsx" line="112" column="5" code="2322">Type 'TData[]' is not assignable to type 'PurchaseOrder[]'.
Type 'TData' is not assignable to type 'PurchaseOrder'.</problem>
</dyad-problem-report>You've encountered a common TypeScript issue when working with generics! The error "Type 'TData[]' is not assignable to type 'PurchaseOrder[]'" arises because `useReactTable` is defined with generic types `TData` and `TValue`, but when you're using it for `PurchaseOrder` data, you need to ensure that `TData` is explicitly `PurchaseOrder`.
The fix is to correctly specify the generic type when calling `useReactTable`.
Here's the corrected code:
<dyad-write path="src/components/purchase-orders/PurchaseOrderDataTable.tsx" description="Fixing TypeScript error by correctly specifying the generic type for useReactTable.">
"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<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
filterValue: string
onFilterChange: (value: string) => void
refreshData: () => void
}
export function PurchaseOrderDataTable<TData, TValue>({
columns: columnsProp, // Rename to avoid conflict
data,
filterValue,
onFilterChange,
refreshData,
}: PurchaseOrderDataTableProps<TData, TValue>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>(() => {
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<PurchaseOrder | null>(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)
}
}
const columnsWithActions = React.useMemo(() => createColumns({ onDownloadPdf: generatePDF }), [generatePDF]);
const table = useReactTable<PurchaseOrder>({ // Specify TData as PurchaseOrder
data, // Now 'data' (which is PurchaseOrder[]) is correctly assigned to the 'data' parameter of useReactTable
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 (
<>
<div>
<div className="flex items-center py-4">
<input
type="text"
placeholder="Filter by supplier name..."
value={filterValue}
onChange={(e) => onFilterChange(e.target.value)}
className="max-w-sm border border-gray-300 rounded px-2 py-1"
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon" className="ml-auto">
<Columns className="h-4 w-4" />
<span className="sr-only">Toggle columns</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter(
(column) => column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="rounded-md border bg-white">
<table className="w-full min-w-full table-auto">
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id} className="border-b px-4 py-2 text-left font-medium text-gray-900">
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map(row => {
const order = row.original as PurchaseOrder
return (
<tr key={row.id} className="border-b hover:bg-gray-50">
{row.getVisibleCells().map(cell => (
<td key={cell.id} className="px-4 py-2 align-top">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
<td className="px-4 py-2 space-x-2">
{order.status === "Pending Approval" && (
<>
<Button size="sm" variant="outline" onClick={() => approveOrder(order)}>Approve</Button>
<Button size="sm" variant="destructive" onClick={() => rejectOrder(order)}>Reject</Button>
</>
)}
{order.status === "Approved" && (
<>
<Button size="sm" onClick={() => generatePDF(order)}>Download PDF</Button>
<Button size="sm" variant="secondary" onClick={() => openReceiveDialog(order)}>Receive Stock</Button>
</>
)}
{order.status === "Received" && (
<span className="text-green-600 font-semibold">Received</span>
)}
{order.status === "Rejected" && (
<span className="text-red-600 font-semibold">Rejected</span>
)}
</td>
</tr>
)
})
) : (
<tr>
{/* Use table.getAllColumns().length for colSpan */}
<td colSpan={table.getAllColumns().length} className="h-24 text-center">No results.</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
{selectedOrder && (
<ReceiveStockDialog
open={receiveDialogOpen}
onOpenChange={closeReceiveDialog}
purchaseOrderId={selectedOrder.id}
items={selectedOrder.items.map((item, idx) => ({
stockItemId: item.stockItemId,
orderedQuantity: selectedOrder.quantities[idx] || 0,
itemName: item.itemName,
}))}
refreshData={refreshData}
/>
)}
</>
)
}
export default PurchaseOrders;