[dyad] Implemented 'Add Stock Item' functionality with a dialog - wrote 4 file(s), added react-hot-toast package(s)

This commit is contained in:
[dyad] 2025-09-11 11:51:34 +02:00
parent 66ea6792a2
commit 7a4277e7a3
4 changed files with 167 additions and 8 deletions

View file

@ -57,6 +57,7 @@
"react-day-picker": "^8.10.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.0",
"react-hot-toast": "^2.6.0",
"react-resizable-panels": "^2.1.3",
"react-router-dom": "^6.26.2",
"recharts": "^2.12.7",

View file

@ -146,6 +146,9 @@ importers:
react-hook-form:
specifier: ^7.53.0
version: 7.55.0(react@18.3.1)
react-hot-toast:
specifier: ^2.6.0
version: 2.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-resizable-panels:
specifier: ^2.1.3
version: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -1824,6 +1827,11 @@ packages:
resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
engines: {node: '>=18'}
goober@2.1.16:
resolution: {integrity: sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==}
peerDependencies:
csstype: ^3.0.10
graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@ -2158,6 +2166,13 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
react-hot-toast@2.6.0:
resolution: {integrity: sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==}
engines: {node: '>=10'}
peerDependencies:
react: '>=16'
react-dom: '>=16'
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@ -4056,6 +4071,10 @@ snapshots:
globals@15.15.0: {}
goober@2.1.16(csstype@3.1.3):
dependencies:
csstype: 3.1.3
graphemer@1.4.0: {}
has-flag@4.0.0: {}
@ -4332,6 +4351,13 @@ snapshots:
dependencies:
react: 18.3.1
react-hot-toast@2.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
csstype: 3.1.3
goober: 2.1.16(csstype@3.1.3)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-is@16.13.1: {}
react-is@18.3.1: {}

View file

@ -0,0 +1,111 @@
import React, { useState } from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { toast } from 'react-hot-toast'; // Assuming react-hot-toast is available or will be added
interface AddStockItemDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onAddItem: (item: { name: string; sku: string; quantity: number; price: number; location: string }) => void;
}
export const AddStockItemDialog: React.FC<AddStockItemDialogProps> = ({ open, onOpenChange, onAddItem }) => {
const [name, setName] = useState('');
const [sku, setSku] = useState('');
const [quantity, setQuantity] = useState('');
const [price, setPrice] = useState('');
const [location, setLocation] = useState('');
const handleSubmit = () => {
if (!name || !sku || !quantity || !price || !location) {
toast.error('Please fill in all fields.');
return;
}
const parsedQuantity = parseInt(quantity);
const parsedPrice = parseFloat(price);
if (isNaN(parsedQuantity) || parsedQuantity <= 0) {
toast.error('Quantity must be a positive number.');
return;
}
if (isNaN(parsedPrice) || parsedPrice <= 0) {
toast.error('Price must be a positive number.');
return;
}
onAddItem({
name,
sku,
quantity: parsedQuantity,
price: parsedPrice,
location,
});
// Reset form fields
setName('');
setSku('');
setQuantity('');
setPrice('');
setLocation('');
onOpenChange(false); // Close dialog
toast.success('Stock item added successfully!');
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Add New Stock Item</DialogTitle>
<DialogDescription>
Enter the details for the new stock item. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" value={name} onChange={(e) => setName(e.target.value)} className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="sku" className="text-right">
SKU
</Label>
<Input id="sku" value={sku} onChange={(e) => setSku(e.target.value)} className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="quantity" className="text-right">
Quantity
</Label>
<Input id="quantity" type="number" value={quantity} onChange={(e) => setQuantity(e.target.value)} className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="price" className="text-right">
Price
</Label>
<Input id="price" type="number" value={price} onChange={(e) => setPrice(e.target.value)} className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="location" className="text-right">
Location
</Label>
<Input id="location" value={location} onChange={(e) => setLocation(e.target.value)} className="col-span-3" />
</div>
</div>
<DialogFooter>
<Button type="submit" onClick={handleSubmit}>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

View file

@ -1,27 +1,43 @@
import React from 'react';
import React, { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Plus, QrCode } from 'lucide-react'; // Import icons
import { Plus, QrCode } from 'lucide-react';
import { AddStockItemDialog } from '@/components/AddStockItemDialog'; // Import the new dialog component
import { toast } from 'react-hot-toast'; // Import toast for notifications
interface StockItem {
id: string;
name: string;
sku: string;
quantity: number;
price: number;
location: string;
}
const StockList = () => {
// Mock data for demonstration
const stockItems = [
const [stockItems, setStockItems] = useState<StockItem[]>([
{ id: '1', name: 'Wireless Mouse', sku: 'WM001', quantity: 150, price: 25.00, location: 'A1' },
{ id: '2', name: 'Mechanical Keyboard', sku: 'MK002', quantity: 80, price: 75.00, location: 'A2' },
{ id: '3', name: 'USB-C Hub', sku: 'UH003', quantity: 200, price: 30.00, location: 'B1' },
{ id: '4', name: 'External SSD 1TB', sku: 'ES004', quantity: 50, price: 120.00, location: 'C3' },
{ id: '5', name: 'Monitor Stand', sku: 'MS005', quantity: 100, price: 45.00, location: 'A1' },
];
]);
const [isAddStockDialogOpen, setIsAddStockDialogOpen] = useState(false);
const handleAddStockItem = () => {
console.log('Add Stock Item clicked');
// Implement navigation or modal for adding a new item
setIsAddStockDialogOpen(true);
};
const handleScanQrCode = () => {
console.log('Scan QR Code clicked');
toast.info('QR Code scanning functionality not yet implemented.');
// Implement QR code scanning functionality
};
const handleAddNewStockItem = (newItem: Omit<StockItem, 'id'>) => {
const newId = (stockItems.length + 1).toString(); // Simple ID generation
setStockItems((prevItems) => [...prevItems, { id: newId, ...newItem }]);
};
return (
<div className="flex-1 space-y-4 p-4 md:p-8 pt-6">
<div className="flex flex-col md:flex-row md:justify-between md:items-center gap-4 mb-6">
@ -39,7 +55,6 @@ const StockList = () => {
</div>
</div>
{/* Placeholder for stock list table or display */}
<div className="rounded-md border">
<div className="p-4">
<h3 className="text-lg font-semibold mb-4">Current Stock</h3>
@ -83,6 +98,12 @@ const StockList = () => {
)}
</div>
</div>
<AddStockItemDialog
open={isAddStockDialogOpen}
onOpenChange={setIsAddStockDialogOpen}
onAddItem={handleAddNewStockItem}
/>
</div>
);
};