[dyad] Added a QR scanner to the 'Book Out Stock' form - wrote 1 file(s)

This commit is contained in:
davidels1 2025-09-09 01:12:17 +02:00
parent 98ad0d5b7b
commit 26cd13764e

View file

@ -9,12 +9,13 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { Input } from "../ui/input"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "../ui/card"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table"
import { Trash2 } from "lucide-react"
import { Trash2, Camera } from "lucide-react"
import { showSuccess, showError } from "../../utils/toast"
import { CustomerCombobox } from "./CustomerCombobox"
import { StockItemSearch } from "./StockItemSearch"
import { Customer } from "../customers/columns"
import { StockItem } from "../stock/columns"
import QRScannerDialog from "../stock/QRScannerDialog"
// Sample data - in a real app, this would come from an API
const customersData: Customer[] = [
@ -53,6 +54,7 @@ const formSchema = z.object({
export function BookOutForm() {
const [customers, setCustomers] = React.useState(customersData.map(c => ({ value: c.id, label: c.companyName })));
const [stockItems, setStockItems] = React.useState(stockData);
const [scannerOpen, setScannerOpen] = React.useState(false);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
@ -85,6 +87,16 @@ export function BookOutForm() {
});
};
const handleScanSuccess = (decodedText: string) => {
const item = stockItems.find(i => i.sku.toLowerCase() === decodedText.toLowerCase());
if (item) {
handleAddItem(item);
} else {
showError("Scanned item not found in stock.");
}
setScannerOpen(false);
};
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
showSuccess("Stock booked out successfully!")
@ -92,98 +104,113 @@ export function BookOutForm() {
}
return (
<Card className="max-w-4xl mx-auto">
<CardHeader>
<CardTitle>Book Out Stock</CardTitle>
<CardDescription>Select a customer and add items to book out from your inventory.</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<div className="grid md:grid-cols-2 gap-6">
<FormField
control={form.control}
name="customerId"
render={({ field }) => (
<FormItem>
<FormLabel>Customer</FormLabel>
<CustomerCombobox
customers={customers}
value={field.value}
onChange={field.onChange}
/>
<FormMessage />
</FormItem>
)}
/>
<FormItem>
<FormLabel>Add Stock Item</FormLabel>
<StockItemSearch
stockItems={stockItems}
onItemSelect={handleAddItem}
<>
<QRScannerDialog
open={scannerOpen}
onOpenChange={setScannerOpen}
onScanSuccess={handleScanSuccess}
/>
<Card className="max-w-4xl mx-auto">
<CardHeader>
<CardTitle>Book Out Stock</CardTitle>
<CardDescription>Select a customer and add items to book out from your inventory.</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<div className="grid md:grid-cols-2 gap-6">
<FormField
control={form.control}
name="customerId"
render={({ field }) => (
<FormItem>
<FormLabel>Customer</FormLabel>
<CustomerCombobox
customers={customers}
value={field.value}
onChange={field.onChange}
/>
<FormMessage />
</FormItem>
)}
/>
</FormItem>
</div>
<FormItem>
<FormLabel>Add Stock Item</FormLabel>
<div className="flex items-center gap-2">
<div className="flex-grow">
<StockItemSearch
stockItems={stockItems}
onItemSelect={handleAddItem}
/>
</div>
<Button variant="outline" size="icon" type="button" onClick={() => setScannerOpen(true)}>
<Camera className="h-4 w-4" />
<span className="sr-only">Scan Barcode</span>
</Button>
</div>
</FormItem>
</div>
<div className="space-y-2">
<h3 className="text-sm font-medium">Selected Items</h3>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Item</TableHead>
<TableHead className="w-[120px] text-center">Available</TableHead>
<TableHead className="w-[120px]">Quantity</TableHead>
<TableHead className="w-[50px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{fields.length > 0 ? (
fields.map((field, index) => (
<TableRow key={field.id}>
<TableCell>
<p className="font-medium">{field.name}</p>
<p className="text-sm text-muted-foreground">SKU: {field.sku}</p>
</TableCell>
<TableCell className="text-center">{field.maxQuantity}</TableCell>
<TableCell>
<FormField
control={form.control}
name={`items.${index}.quantity`}
render={({ field }) => (
<FormItem>
<FormControl>
<Input type="number" {...field} className="text-center" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
<TableCell>
<Button variant="ghost" size="icon" onClick={() => remove(index)}>
<Trash2 className="h-4 w-4 text-red-500" />
</Button>
<div className="space-y-2">
<h3 className="text-sm font-medium">Selected Items</h3>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Item</TableHead>
<TableHead className="w-[120px] text-center">Available</TableHead>
<TableHead className="w-[120px]">Quantity</TableHead>
<TableHead className="w-[50px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{fields.length > 0 ? (
fields.map((field, index) => (
<TableRow key={field.id}>
<TableCell>
<p className="font-medium">{field.name}</p>
<p className="text-sm text-muted-foreground">SKU: {field.sku}</p>
</TableCell>
<TableCell className="text-center">{field.maxQuantity}</TableCell>
<TableCell>
<FormField
control={form.control}
name={`items.${index}.quantity`}
render={({ field }) => (
<FormItem>
<FormControl>
<Input type="number" {...field} className="text-center" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</TableCell>
<TableCell>
<Button variant="ghost" size="icon" onClick={() => remove(index)}>
<Trash2 className="h-4 w-4 text-red-500" />
</Button>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={4} className="text-center h-24">
No items added yet.
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={4} className="text-center h-24">
No items added yet.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)}
</TableBody>
</Table>
</div>
<FormMessage>{form.formState.errors.items?.message || form.formState.errors.items?.root?.message}</FormMessage>
</div>
<FormMessage>{form.formState.errors.items?.message || form.formState.errors.items?.root?.message}</FormMessage>
</div>
<Button type="submit" className="w-full" disabled={fields.length === 0}>Book Out Stock</Button>
</form>
</Form>
</CardContent>
</Card>
<Button type="submit" className="w-full" disabled={fields.length === 0}>Book Out Stock</Button>
</form>
</Form>
</CardContent>
</Card>
</>
)
}