diff --git a/components/modals/product-modal.tsx b/components/modals/product-modal.tsx index e854f18..0e1d31e 100644 --- a/components/modals/product-modal.tsx +++ b/components/modals/product-modal.tsx @@ -19,25 +19,40 @@ import { SelectValue, } from "@/components/ui/select"; import { Product } from "@/models/products"; +import { Trash, PlusCircle } from "lucide-react"; +import { toast } from "sonner"; interface Category { _id: string; name: string; } +interface PricingTier { + minQuantity: number; + pricePerUnit: number; + _id?: string; +} + +interface ProductData { + name: string; + description: string; + unitType: string; + category: string; + pricing: PricingTier[]; + image: string | File | null; +} + interface ProductModalProps { open: boolean; onClose: () => void; - onSave: (productData: Product) => void; - productData: Product; + onSave: (productData: ProductData) => void; + productData: ProductData; categories: Category[]; editing: boolean; - handleChange: (e: ChangeEvent) => void; - setProductData: React.Dispatch>; - handleTieredPricingChange: ( - e: ChangeEvent, - index: number + handleChange: ( + e: ChangeEvent ) => void; + setProductData: React.Dispatch>; } export const ProductModal = ({ @@ -48,12 +63,24 @@ export const ProductModal = ({ categories, editing, handleChange, - handleTieredPricingChange, setProductData, }: ProductModalProps) => { const [imagePreview, setImagePreview] = useState(null); + const [newCategory, setNewCategory] = useState(""); + const [imageDimensions, setImageDimensions] = useState({ + width: 300, + height: 200, + }); + + useEffect(() => { + if (productData?.pricing) { + setProductData((prev) => ({ + ...prev, + tieredPricing: productData.pricing, + })); + } + }, [productData.pricing]); - // Update image preview when product data changes useEffect(() => { if (productData.image && typeof productData.image === "string") { setImagePreview(productData.image); @@ -63,88 +90,282 @@ export const ProductModal = ({ const handleImageChange = (e: ChangeEvent) => { const file = e.target.files?.[0]; if (file) { - setProductData({ ...productData, image: file }); - setImagePreview(URL.createObjectURL(file)); + const image = new Image(); + const objectUrl = URL.createObjectURL(file); + + image.onload = () => { + const aspectRatio = image.naturalWidth / image.naturalHeight; + let width = 300; + let height = 200; + + if (aspectRatio > 1) { + width = 300; + height = 300 / aspectRatio; + } else { + height = 200; + width = 200 * aspectRatio; + } + + setProductData({ ...productData, image: file }); + setImagePreview(objectUrl); + setImageDimensions({ width, height }); + }; + + image.src = objectUrl; } else { setProductData({ ...productData, image: null }); setImagePreview(null); } }; - // ✅ FIXED: Moved Inside the Component & Used Type Assertion - const handleTieredPricingChangeInternal = ( + const handleSave = () => { + onSave(productData); + toast.success( + editing ? "Product updated successfully!" : "Product added successfully!" + ); + onClose(); + }; + + const handleTieredPricingChange = ( e: ChangeEvent, index: number ) => { - const updatedPricing = [...productData.tieredPricing]; - const field = e.target.name as keyof (typeof productData.tieredPricing)[number]; + const { name, valueAsNumber } = e.target; + + if (!productData.pricing) return; + const updatedPricing = [...productData.pricing]; updatedPricing[index] = { ...updatedPricing[index], - [field]: e.target.valueAsNumber || 0, + [name]: isNaN(valueAsNumber) ? 0 : valueAsNumber, // Ensure valid numbers }; - setProductData({ - ...productData, + setProductData((prev) => ({ + ...prev, tieredPricing: updatedPricing, - }); + })); }; return ( - + - + {editing ? "Edit Product" : "Add Product"} -
-
- - -
+
+
+
+ + +
-
- -