From f48d7fdb2ff1870f3bd4fca2882fcf483aa99127 Mon Sep 17 00:00:00 2001 From: "[dyad]" Date: Wed, 10 Sep 2025 12:47:33 +0200 Subject: [PATCH] [dyad] Added a data table to the Book Out page to display booked-out items - wrote 3 file(s) --- src/components/book-out/BookOutDataTable.tsx | 186 +++++++++++++++++++ src/components/book-out/columns.tsx | 84 +++++++++ src/pages/BookOut.tsx | 38 +++- 3 files changed, 302 insertions(+), 6 deletions(-) create mode 100644 src/components/book-out/BookOutDataTable.tsx create mode 100644 src/components/book-out/columns.tsx diff --git a/src/components/book-out/BookOutDataTable.tsx b/src/components/book-out/BookOutDataTable.tsx new file mode 100644 index 0000000..633cb5d --- /dev/null +++ b/src/components/book-out/BookOutDataTable.tsx @@ -0,0 +1,186 @@ +"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 { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +interface BookOutDataTableProps { + columns: ColumnDef[] + data: TData[] +} + +export function BookOutDataTable({ + columns, + data, +}: BookOutDataTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState(() => { + if (typeof window !== 'undefined' && window.innerWidth < 768) { + return { + sku: false, + dateBookedOut: false, + actions: false, + }; + } + return {}; + }); + const [rowSelection, setRowSelection] = React.useState({}) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + return ( +
+
+ + table.getColumn("customerName")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter( + (column) => column.getCanHide() + ) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ) + })} + + +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+ + +
+
+ ) +} \ No newline at end of file diff --git a/src/components/book-out/columns.tsx b/src/components/book-out/columns.tsx new file mode 100644 index 0000000..7624063 --- /dev/null +++ b/src/components/book-out/columns.tsx @@ -0,0 +1,84 @@ +"use client" + +import { ColumnDef } from "@tanstack/react-table" +import { MoreHorizontal } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +export type BookOutRecord = { + id: string + customerName: string + itemName: string + sku: string + quantity: number + dateBookedOut: string +} + +export const columns: ColumnDef[] = [ + { + accessorKey: "customerName", + header: "Customer", + }, + { + accessorKey: "itemName", + header: "Item Name", + }, + { + accessorKey: "sku", + header: "SKU", + }, + { + accessorKey: "quantity", + header: "Quantity", + }, + { + accessorKey: "dateBookedOut", + header: "Date Booked Out", + cell: ({ row }) => { + const date = new Date(row.getValue("dateBookedOut")); + const formattedDate = date.toLocaleDateString("en-ZA", { + year: "numeric", + month: "short", + day: "numeric", + }); + return
{formattedDate}
; + }, + }, + { + id: "actions", + enableHiding: false, + cell: ({ row }) => { + const record = row.original + + return ( + + + + + + Actions + navigator.clipboard.writeText(record.id)} + > + Copy record ID + + + View Details + {/* Add more actions like 'Edit' or 'Delete' if needed */} + + + ) + }, + }, +] \ No newline at end of file diff --git a/src/pages/BookOut.tsx b/src/pages/BookOut.tsx index eee5e8b..7b58c29 100644 --- a/src/pages/BookOut.tsx +++ b/src/pages/BookOut.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect, useCallback } from "react"; import { BookOutForm } from "../components/book-out/BookOutForm"; import { Button } from "@/components/ui/button"; import { PlusCircle } from "lucide-react"; @@ -10,13 +10,42 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import { columns, BookOutRecord } from "../components/book-out/columns"; +import { BookOutDataTable } from "../components/book-out/BookOutDataTable"; +import pb from "@/lib/pocketbase"; const BookOut = () => { const [bookOutOpen, setBookOutOpen] = useState(false); + const [bookOutRecords, setBookOutRecords] = useState([]); const [refreshTrigger, setRefreshTrigger] = useState(0); // State to trigger data refresh + const fetchBookOutRecords = useCallback(async () => { + try { + const records = await pb.collection('book_out_records').getList(1, 50, { + sort: '-created', + expand: 'customer,items', // Expand related customer and stock items + }); + + const formattedData: BookOutRecord[] = records.items.map((record: any) => ({ + id: record.id, + customerName: record.expand?.customer?.comapny_name || 'N/A', + itemName: record.expand?.items?.name || 'N/A', + sku: record.expand?.items?.sku || 'N/A', + quantity: record.quantity, + dateBookedOut: record.date_booked_out, + })); + setBookOutRecords(formattedData); + } catch (error) { + console.error("Error fetching book out records:", error); + } + }, []); + + useEffect(() => { + fetchBookOutRecords(); + }, [fetchBookOutRecords, refreshTrigger]); + const handleRefreshData = () => { - setRefreshTrigger(prev => prev + 1); // Increment to trigger any future data fetching + setRefreshTrigger(prev => prev + 1); // Increment to trigger useEffect }; return ( @@ -44,10 +73,7 @@ const BookOut = () => { - {/* Placeholder for a table or list of booked out items, if needed later */} -
- No booked out items recorded yet. Use the "Book Out Item" button to add one. -
+ ) }