[dyad] Implemented 'Add Stock Item' functionality with a dialog - wrote 4 file(s), added react-hot-toast package(s)
This commit is contained in:
parent
66ea6792a2
commit
7a4277e7a3
4 changed files with 167 additions and 8 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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: {}
|
||||
|
|
|
|||
111
src/components/AddStockItemDialog.tsx
Normal file
111
src/components/AddStockItemDialog.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue