231 lines
7.4 KiB
TypeScript
231 lines
7.4 KiB
TypeScript
"use client"
|
|
|
|
import type React from "react"
|
|
|
|
import { useState } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Textarea } from "@/components/ui/textarea"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog"
|
|
import type { Product } from "@/types/business"
|
|
|
|
interface ProductFormProps {
|
|
product?: Product
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
onSubmit: (product: Omit<Product, "id">) => void
|
|
}
|
|
|
|
const categories = [
|
|
"Electronics",
|
|
"Audio",
|
|
"Accessories",
|
|
"Mobile",
|
|
"Computing",
|
|
"Gaming",
|
|
"Home & Garden",
|
|
"Sports",
|
|
"Other",
|
|
]
|
|
|
|
export function ProductForm({ product, open, onOpenChange, onSubmit }: ProductFormProps) {
|
|
const [formData, setFormData] = useState({
|
|
name: product?.name || "",
|
|
category: product?.category || "",
|
|
description: product?.description || "",
|
|
buyPrice: product?.buyPrice || 0,
|
|
sellPrice: product?.sellPrice || 0,
|
|
stock: product?.stock || 0,
|
|
minStock: product?.minStock || 5,
|
|
supplier: product?.supplier || "",
|
|
sku: product?.sku || "",
|
|
})
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
onSubmit(formData)
|
|
onOpenChange(false)
|
|
// Reset form if it's a new product
|
|
if (!product) {
|
|
setFormData({
|
|
name: "",
|
|
category: "",
|
|
description: "",
|
|
buyPrice: 0,
|
|
sellPrice: 0,
|
|
stock: 0,
|
|
minStock: 5,
|
|
supplier: "",
|
|
sku: "",
|
|
})
|
|
}
|
|
}
|
|
|
|
const profitMargin =
|
|
formData.sellPrice > 0 && formData.buyPrice > 0
|
|
? (((formData.sellPrice - formData.buyPrice) / formData.sellPrice) * 100).toFixed(1)
|
|
: "0"
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
|
|
<DialogHeader>
|
|
<DialogTitle>{product ? "Edit Product" : "Add New Product"}</DialogTitle>
|
|
<DialogDescription>
|
|
{product ? "Update product information" : "Enter the details for the new product"}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="name">Product Name *</Label>
|
|
<Input
|
|
id="name"
|
|
value={formData.name}
|
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
placeholder="Enter product name"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="sku">SKU</Label>
|
|
<Input
|
|
id="sku"
|
|
value={formData.sku}
|
|
onChange={(e) => setFormData({ ...formData, sku: e.target.value })}
|
|
placeholder="Product SKU"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="category">Category *</Label>
|
|
<Select
|
|
value={formData.category}
|
|
onValueChange={(value) => setFormData({ ...formData, category: value })}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Select category" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{categories.map((category) => (
|
|
<SelectItem key={category} value={category}>
|
|
{category}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="supplier">Supplier</Label>
|
|
<Input
|
|
id="supplier"
|
|
value={formData.supplier}
|
|
onChange={(e) => setFormData({ ...formData, supplier: e.target.value })}
|
|
placeholder="Supplier name"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="description">Description</Label>
|
|
<Textarea
|
|
id="description"
|
|
value={formData.description}
|
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
|
placeholder="Product description"
|
|
rows={3}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="buyPrice">Buy Price ($) *</Label>
|
|
<Input
|
|
id="buyPrice"
|
|
type="number"
|
|
step="0.01"
|
|
min="0"
|
|
value={formData.buyPrice}
|
|
onChange={(e) => setFormData({ ...formData, buyPrice: Number.parseFloat(e.target.value) || 0 })}
|
|
placeholder="0.00"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="sellPrice">Sell Price ($) *</Label>
|
|
<Input
|
|
id="sellPrice"
|
|
type="number"
|
|
step="0.01"
|
|
min="0"
|
|
value={formData.sellPrice}
|
|
onChange={(e) => setFormData({ ...formData, sellPrice: Number.parseFloat(e.target.value) || 0 })}
|
|
placeholder="0.00"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{formData.buyPrice > 0 && formData.sellPrice > 0 && (
|
|
<div className="p-3 bg-muted rounded-lg">
|
|
<p className="text-sm text-muted-foreground">
|
|
Profit Margin: <span className="font-medium text-foreground">{profitMargin}%</span> ($
|
|
{(formData.sellPrice - formData.buyPrice).toFixed(2)} profit per unit)
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="stock">Current Stock *</Label>
|
|
<Input
|
|
id="stock"
|
|
type="number"
|
|
min="0"
|
|
value={formData.stock}
|
|
onChange={(e) => setFormData({ ...formData, stock: Number.parseInt(e.target.value) || 0 })}
|
|
placeholder="0"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="minStock">Minimum Stock Alert</Label>
|
|
<Input
|
|
id="minStock"
|
|
type="number"
|
|
min="0"
|
|
value={formData.minStock}
|
|
onChange={(e) => setFormData({ ...formData, minStock: Number.parseInt(e.target.value) || 0 })}
|
|
placeholder="5"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit">{product ? "Update Product" : "Add Product"}</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|