-
-
- {form.formState.errors.name && (
-
- {form.formState.errors.name.message}
-
- )}
-
+
+
+
+ {form.formState.errors.name && (
+
+ {form.formState.errors.name.message}
+
+ )}
+
parseFloat(v).toFixed(2)
+ })}
placeholder="0.00"
/>
+ {form.formState.errors.price && (
+
+ {form.formState.errors.price.message}
+
+ )}
@@ -93,27 +101,31 @@ export default function ProductDialog({
{/* Image upload & preview */}
-
-
+
+
+
{imagePreview ? (

) : (
-
-
+
)}
-
+
+
JPG or PNG only. Max size: 2MB.
+
diff --git a/frontend/src/pages/products/components/product-list.tsx b/frontend/src/pages/products/components/product-list.tsx
index 1206b89..2cfc19a 100644
--- a/frontend/src/pages/products/components/product-list.tsx
+++ b/frontend/src/pages/products/components/product-list.tsx
@@ -8,10 +8,12 @@ import {
} from "@/components/ui/card";
export function ProductList({
+ currency,
products,
isLoading,
onClick
}: {
+ currency: string,
products: ProductWithDetails[];
isLoading: boolean;
onClick: (id: number) => void;
@@ -37,12 +39,15 @@ export function ProductList({
className="h-full w-full object-cover"
/>
) : (
-
+
)}
-
+
{product.stock_quantity} in stock
+
+ {product.price.toFixed(2)} {currency}
+
diff --git a/frontend/src/pages/products/hooks/use-product-form.tsx b/frontend/src/pages/products/hooks/use-product-form.tsx
index c16621a..8d5d6b2 100644
--- a/frontend/src/pages/products/hooks/use-product-form.tsx
+++ b/frontend/src/pages/products/hooks/use-product-form.tsx
@@ -8,7 +8,7 @@ import { z } from "zod";
export const schema = z.object({
name: z.string().min(1, "Name is required"),
description: z.string().min(1, "Description is required"),
- price: z.coerce.number().min(0),
+ price: z.coerce.number().min(0.01, "Price must be greater than 0.01").step(0.01),
stock_quantity: z.coerce.number().int().min(0),
image_data: z.string().optional()
});
diff --git a/frontend/src/pages/products/index.tsx b/frontend/src/pages/products/index.tsx
index 9aa95fb..ba5bb2e 100644
--- a/frontend/src/pages/products/index.tsx
+++ b/frontend/src/pages/products/index.tsx
@@ -28,6 +28,7 @@ import { useProductForm } from "./hooks/use-product-form";
import { ProductList } from "./components/product-list";
import { ProductDialog } from "./components/product-dialog";
import { toast } from "@/hooks/useToast";
+import { useShop } from "@/hooks/useShop";
export default function Products() {
const [sort, setSort] = useState<"ascending" | "descending">("ascending");
@@ -38,6 +39,7 @@ export default function Products() {
number | undefined
>(undefined);
+ const { shop } = useShop();
const { data: products = [], isLoading } = useProducts();
const { product, createProduct, updateProduct, deleteProduct } =
useProduct(selectedProductId);
@@ -52,7 +54,7 @@ export default function Products() {
reader.readAsDataURL(file);
};
- const handleCreateSubmit = form.handleSubmit((data) => {
+ const handleCreateClicked = () => {
form.reset({
name: "",
description: "",
@@ -60,6 +62,11 @@ export default function Products() {
stock_quantity: 0,
image_data: ""
});
+ setSelectedProductId(undefined);
+ setDialogOpen(true);
+ };
+
+ const handleCreateSubmit = form.handleSubmit((data) => {
createProduct.mutate(data);
setDialogOpen(false);
toast({ title: `${data.name} created`, variant: "default" });
@@ -144,6 +151,7 @@ export default function Products() {
{
@@ -153,7 +161,7 @@ export default function Products() {
/>