diff --git a/src/components/book-out/BookOutForm.tsx b/src/components/book-out/BookOutForm.tsx index 90e72ae..40abea9 100644 --- a/src/components/book-out/BookOutForm.tsx +++ b/src/components/book-out/BookOutForm.tsx @@ -17,54 +17,101 @@ import { import { Input } from "@/components/ui/input" import { showSuccess, showError } from "@/utils/toast" import { CustomerCombobox } from "./CustomerCombobox" +import { StockItemCombobox } from "./StockItemCombobox" // Import the new combobox import pb from "@/lib/pocketbase" const formSchema = z.object({ customer: z.string({ required_error: "Please select a customer." }), - item: z.string().min(2, { message: "Item name must be at least 2 characters." }), + stockItemId: z.string({ required_error: "Please select an item." }), // Changed from 'item' to 'stockItemId' quantity: z.coerce.number().int().positive({ message: "Quantity must be a positive number." }), }) interface BookOutFormProps { setOpen: (open: boolean) => void; + refreshData: () => void; // Added refreshData prop } -export function BookOutForm({ setOpen }: BookOutFormProps) { +export function BookOutForm({ setOpen, refreshData }: BookOutFormProps) { const [customerOptions, setCustomerOptions] = React.useState<{ value: string; label: string }[]>([]); + const [stockItemOptions, setStockItemOptions] = React.useState<{ value: string; label: string; quantity: number }[]>([]); + + const fetchCustomers = React.useCallback(async () => { + try { + const records = await pb.collection('customers').getList(1, 50); + const options = records.items.map((customer: any) => ({ + value: customer.id, + label: customer.comapny_name, + })); + setCustomerOptions(options); + } catch (error) { + console.error("Error fetching customers for combobox:", error); + showError("Failed to load customers."); + } + }, []); + + const fetchStockItems = React.useCallback(async () => { + try { + const records = await pb.collection('stock_items').getList(1, 50, { + filter: 'quantity > 0', // Only show items with quantity > 0 + }); + const options = records.items.map((item: any) => ({ + value: item.id, + label: item.name, + quantity: item.quantity, + })); + setStockItemOptions(options); + } catch (error) { + console.error("Error fetching stock items for combobox:", error); + showError("Failed to load stock items."); + } + }, []); React.useEffect(() => { - const fetchCustomers = async () => { - try { - const records = await pb.collection('customers').getList(1, 50); - const options = records.items.map((customer: any) => ({ - value: customer.id, // Use ID as value for uniqueness - label: customer.comapny_name, // Display company name - })); - setCustomerOptions(options); - } catch (error) { - console.error("Error fetching customers for combobox:", error); - showError("Failed to load customers."); - } - }; fetchCustomers(); - }, []); + fetchStockItems(); + }, [fetchCustomers, fetchStockItems]); const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { - item: "", quantity: 1, }, }) async function onSubmit(values: z.infer) { try { - // Here you would typically save the book-out record to PocketBase - // For now, we'll just log it and show a success message. - console.log("Book-out data:", values); - showSuccess("Item booked out successfully!"); + // Fetch the latest stock item data to prevent race conditions + const selectedStockItem = await pb.collection('stock_items').getOne(values.stockItemId); + + if (!selectedStockItem) { + showError("Selected item not found."); + return; + } + + const currentQuantity = selectedStockItem.quantity; + const bookedOutQuantity = values.quantity; + + if (bookedOutQuantity > currentQuantity) { + showError(`Not enough stock. Only ${currentQuantity} available.`); + return; + } + + const newQuantity = currentQuantity - bookedOutQuantity; + + // Update the stock item quantity in PocketBase + await pb.collection('stock_items').update(values.stockItemId, { + quantity: newQuantity, + }); + + // Optionally, you could create a 'book_out_records' collection here + // to log each book-out transaction with customer, item, quantity, date, etc. + // For now, we'll just update the stock. + + showSuccess(`Successfully booked out ${bookedOutQuantity} of ${selectedStockItem.name}!`); form.reset(); setOpen(false); + fetchStockItems(); // Re-fetch stock items to update quantities in the combobox + refreshData(); // Trigger refresh in parent component if needed } catch (error) { console.error("Error booking out item:", error); showError("Failed to book out item. Please try again."); @@ -91,13 +138,15 @@ export function BookOutForm({ setOpen }: BookOutFormProps) { /> ( - - Item Name - - - + + Item + )} diff --git a/src/components/book-out/StockItemCombobox.tsx b/src/components/book-out/StockItemCombobox.tsx new file mode 100644 index 0000000..597329c --- /dev/null +++ b/src/components/book-out/StockItemCombobox.tsx @@ -0,0 +1,79 @@ +"use client" + +import * as React from "react" +import { Check, ChevronsUpDown } from "lucide-react" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, +} from "@/components/ui/command" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover" + +interface StockItemOption { + value: string; // PocketBase ID of the stock item + label: string; // Item name + quantity: number; // Current quantity +} + +interface StockItemComboboxProps { + stockItems: StockItemOption[]; + value: string; + onChange: (value: string) => void; +} + +export function StockItemCombobox({ stockItems, value, onChange }: StockItemComboboxProps) { + const [open, setOpen] = React.useState(false) + + return ( + + + + + + + + No item found. + + {stockItems.map((item) => ( + { + onChange(item.value === value ? "" : item.value); + setOpen(false); + }} + > + + {item.label} (Qty: {item.quantity}) + + ))} + + + + + ) +} \ No newline at end of file diff --git a/src/pages/BookOut.tsx b/src/pages/BookOut.tsx index ce540ed..eee5e8b 100644 --- a/src/pages/BookOut.tsx +++ b/src/pages/BookOut.tsx @@ -13,6 +13,11 @@ import { const BookOut = () => { const [bookOutOpen, setBookOutOpen] = useState(false); + const [refreshTrigger, setRefreshTrigger] = useState(0); // State to trigger data refresh + + const handleRefreshData = () => { + setRefreshTrigger(prev => prev + 1); // Increment to trigger any future data fetching + }; return (
@@ -35,7 +40,7 @@ const BookOut = () => { Fill in the details below to record an item being booked out. - +