diff --git a/backend/gestion/db/db_product.go b/backend/gestion/db/db_product.go
index d1fa452b..46902129 100644
--- a/backend/gestion/db/db_product.go
+++ b/backend/gestion/db/db_product.go
@@ -69,8 +69,8 @@ func (d *Database) CreateProduct(product any) error {
p.SetUpdatedAt(result.UpdatedAt)
for i, price := range p.GetPrices() {
- err := d.GDB.Exec(`INSERT INTO product_prices (product_id, quantity, price) VALUES (?, ?, ?)`,
- result.ID, price.Quantity, price.Price).Error
+ err := d.GDB.Exec(`INSERT INTO product_prices (product_id, quantity, price, active_price) VALUES (?, ?, ?, ?)`,
+ result.ID, price.Quantity, price.Price, price.ActivePrice).Error
if err != nil {
log.Printf("❌ [DB CreateProduct] Erreur insertion prix[%d]: %v", i, err)
return fmt.Errorf("erreur insertion prix: %v", err)
@@ -190,8 +190,8 @@ func (d *Database) UpdateProduct(productID int, name, category, description, uni
d.GDB.Exec(`DELETE FROM product_prices WHERE product_id = ?`, productID)
for _, price := range prices {
- if err := d.GDB.Exec(`INSERT INTO product_prices (product_id, quantity, price) VALUES (?, ?, ?)`,
- productID, price.Quantity, price.Price).Error; err != nil {
+ if err := d.GDB.Exec(`INSERT INTO product_prices (product_id, quantity, price, active_price) VALUES (?, ?, ?, ?)`,
+ productID, price.Quantity, price.Price, price.ActivePrice).Error; err != nil {
log.Printf("❌ [UpdateProduct] Erreur prix: %v", err)
}
}
diff --git a/frontend-admin/src/api/api_admin.ts b/frontend-admin/src/api/api_admin.ts
index ebe26110..697e3b48 100644
--- a/frontend-admin/src/api/api_admin.ts
+++ b/frontend-admin/src/api/api_admin.ts
@@ -747,6 +747,20 @@ export const deleteProductMediaAdmin = async (
return { success: true, message: data.message };
};
+export const activateProductPrice = async (priceId: number) => {
+ const { data } = await apiClient.post(
+ `${V2}/admin/protected/active/product/price/${priceId}`,
+ );
+ return { success: true, message: data.message };
+};
+
+export const deactivateProductPrice = async (priceId: number) => {
+ const { data } = await apiClient.post(
+ `${V2}/admin/protected/desactive/product/price/${priceId}`,
+ );
+ return { success: true, message: data.message };
+};
+
// ============================================
// ADDRESSES
// ============================================
diff --git a/frontend-admin/src/api/types.ts b/frontend-admin/src/api/types.ts
index bd82bb33..8de7bb33 100644
--- a/frontend-admin/src/api/types.ts
+++ b/frontend-admin/src/api/types.ts
@@ -102,7 +102,7 @@ export interface Product {
category: string;
stock: number;
unit: string;
- prices?: Array<{ quantity: number; price: number }>;
+ prices?: Array<{ id?: number; quantity: number; price: number; active_price?: boolean }>;
media?: Array<{ url: string; type: string; id?: number; created_at?: string }>;
created_at?: string;
updated_at?: string;
diff --git a/frontend-admin/src/screens/admin/ProductsScreen.tsx b/frontend-admin/src/screens/admin/ProductsScreen.tsx
index f9a2944b..7da6b72f 100644
--- a/frontend-admin/src/screens/admin/ProductsScreen.tsx
+++ b/frontend-admin/src/screens/admin/ProductsScreen.tsx
@@ -26,6 +26,8 @@ import {
deleteProductAdmin,
uploadProductMediaAdmin,
deleteProductMediaAdmin,
+ activateProductPrice,
+ deactivateProductPrice,
getCategories,
} from "../../api/api_admin";
import type { Category } from "../../api/api_admin";
@@ -40,8 +42,10 @@ import { useAlert } from "../../hooks/useAlert";
// Types
// --------------------------------------------------
interface PriceRow {
+ id?: number;
quantity: string;
price: string;
+ active: boolean;
}
interface MediaItem {
id?: number;
@@ -82,7 +86,7 @@ const emptyForm = (firstCategory = ""): FormState => ({
description: "",
stock: "",
unit: "u",
- prices: [{ quantity: "1", price: "" }],
+ prices: [{ quantity: "1", price: "", active: true }],
});
// ==================================================
@@ -162,10 +166,12 @@ export default function ProductsScreen() {
prices:
product.prices && product.prices.length > 0
? product.prices.map((p) => ({
+ id: p.id,
quantity: p.quantity.toString(),
price: p.price.toString(),
+ active: p.active_price ?? true,
}))
- : [{ quantity: "1", price: "" }],
+ : [{ quantity: "1", price: "", active: true }],
});
setExistingMedia(
(product.media || []).map((m) => ({
@@ -191,8 +197,15 @@ export default function ProductsScreen() {
const addPriceRow = () =>
setForm((f) => ({
...f,
- prices: [...f.prices, { quantity: "1", price: "" }],
+ prices: [...f.prices, { quantity: "1", price: "", active: true }],
}));
+
+ const togglePriceActive = (idx: number) =>
+ setForm((f) => {
+ const prices = [...f.prices];
+ prices[idx] = { ...prices[idx], active: !prices[idx].active };
+ return { ...f, prices };
+ });
const removePriceRow = (idx: number) =>
setForm((f) => ({
...f,
@@ -292,6 +305,7 @@ export default function ProductsScreen() {
const prices = form.prices.map((p) => ({
quantity: parseFloat(p.quantity),
price: parseFloat(p.price),
+ active_price: p.active,
}));
try {
@@ -329,11 +343,10 @@ export default function ProductsScreen() {
fd.append("stock", form.stock);
fd.append("unit", form.unit);
- // ✅ FIX PRINCIPAL : Envoyer les prix au format que Go attend
- // Backend attend : prices[0][quantity], prices[0][price], etc.
prices.forEach((p, i) => {
fd.append(`prices[${i}][quantity]`, String(p.quantity));
fd.append(`prices[${i}][price]`, String(p.price));
+ fd.append(`prices[${i}][active_price]`, p.active_price ? "true" : "false");
});
// Attacher les médias en attente
@@ -647,6 +660,7 @@ export default function ProductsScreen() {
paddingHorizontal: spacing.m,
},
removePriceBtn: { padding: spacing.s, marginBottom: 4 },
+ toggleActiveBtn: { padding: spacing.s, marginBottom: 4 },
// Media section
mediaSectionBox: { marginTop: spacing.m },
@@ -803,11 +817,24 @@ export default function ProductsScreen() {
)}
Stock: {item.stock} {item.unit || "u"}
{item.prices && item.prices.length > 0 && (
-
- {item.prices
- .map((p) => `${p.quantity}${item.unit || "u"} = ${p.price}€`)
- .join(" | ")}
-
+
+ {item.prices.map((p, i) => (
+
+ {p.quantity}{item.unit || "u"} = {p.price}€
+ {i < item.prices!.length - 1 ? " |" : ""}
+
+ ))}
+
)}
{item.description && (
@@ -1055,6 +1082,16 @@ export default function ProductsScreen() {
}
/>
+ togglePriceActive(idx)}
+ >
+
+
{form.prices.length > 1 && (