diff --git a/frontend/package.json b/frontend/package.json index c857f8d..6649520 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "homehub-frontend", "private": true, - "version": "0.4.3", + "version": "0.4.4", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/pages/ShoppingPage.tsx b/frontend/src/pages/ShoppingPage.tsx index 5c9c63d..2c30b01 100644 --- a/frontend/src/pages/ShoppingPage.tsx +++ b/frontend/src/pages/ShoppingPage.tsx @@ -5,7 +5,7 @@ import type { ShoppingListDetail, ShoppingList, Store, Product, ShoppingItem } f import { fetchLists, createList, fetchListDetail, deleteList, addItem, updateItem, deleteItem, finishShopping, fetchStores, generateMagicList, - searchProducts, + searchProducts, createProduct, } from '../api/shopping' import Modal from '../components/Modal' import BottomSheet from '../components/BottomSheet' @@ -67,7 +67,9 @@ export default function ShoppingPage() { const [editQty, setEditQty] = useState('') const [editUnit, setEditUnit] = useState('') - type Selection = { type: 'product'; product: Product; qty: number } | { type: 'custom'; name: string; qty: number } + type Selection = + | { type: 'product'; product: Product; qty: number; existingItemId?: string; originalQty?: number } + | { type: 'custom'; name: string; qty: number; addToCatalogue: boolean; existingItemId?: string; originalQty?: number } const [itemSearch, setItemSearch] = useState('') const [selections, setSelections] = useState([]) const [addSaving, setAddSaving] = useState(false) @@ -137,6 +139,24 @@ export default function ShoppingPage() { setShowAddSheet(false) } + function openAddSheet() { + setItemSearch('') + const initial: Selection[] = [] + if (currentList) { + for (const item of currentList.items.filter(i => !i.is_checked)) { + const qty = Math.max(1, Math.round(parseFloat(item.quantity ?? '1') || 1)) + if (item.product_id) { + const product = products.find(p => p.id === item.product_id) + if (product) initial.push({ type: 'product', product, qty, existingItemId: item.id, originalQty: qty }) + } else if (item.custom_name) { + initial.push({ type: 'custom', name: item.custom_name, qty, addToCatalogue: false, existingItemId: item.id, originalQty: qty }) + } + } + } + setSelections(initial) + setShowAddSheet(true) + } + function getProductQty(id: string): number { return (selections.find(s => s.type === 'product' && s.product.id === id) as Extract | undefined)?.qty ?? 0 } @@ -164,11 +184,17 @@ export default function ShoppingPage() { setSelections(prev => { const exists = prev.some(s => s.type === 'custom' && s.name === name) if (exists) return prev - return [...prev, { type: 'custom' as const, name, qty: 1 }] + return [...prev, { type: 'custom' as const, name, qty: 1, addToCatalogue: true }] }) setItemSearch('') } + function toggleCatalogue(name: string) { + setSelections(prev => prev.map(s => + s.type === 'custom' && s.name === name ? { ...s, addToCatalogue: !s.addToCatalogue } : s + )) + } + function incrementCustom(name: string) { setSelections(prev => prev.map(s => s.type === 'custom' && s.name === name ? { ...s, qty: s.qty + 1 } : s)) } @@ -183,21 +209,31 @@ export default function ShoppingPage() { } async function handleConfirmAdd() { - if (!currentList || selections.length === 0) return + if (!currentList) return + const toProcess = selections.filter(sel => !sel.existingItemId || sel.qty !== sel.originalQty) + if (toProcess.length === 0) { closeAddSheet(); return } setAddSaving(true) try { - for (const sel of selections) { + for (const sel of toProcess) { if (sel.type === 'product') { - await addItem(currentList.id, { - product_id: sel.product.id, - quantity: String(sel.qty), - unit: sel.product.default_unit || undefined, - }) + if (sel.existingItemId) { + await updateItem(currentList.id, sel.existingItemId, { quantity: String(sel.qty) }) + } else { + await addItem(currentList.id, { + product_id: sel.product.id, + quantity: String(sel.qty), + unit: sel.product.default_unit || undefined, + }) + } } else { - await addItem(currentList.id, { - custom_name: sel.name, - quantity: String(sel.qty), - }) + if (sel.existingItemId) { + await updateItem(currentList.id, sel.existingItemId, { quantity: String(sel.qty) }) + } else if (sel.addToCatalogue) { + const newProduct = await createProduct({ name: sel.name }) + await addItem(currentList.id, { product_id: newProduct.id, quantity: String(sel.qty) }) + } else { + await addItem(currentList.id, { custom_name: sel.name, quantity: String(sel.qty) }) + } } } closeAddSheet() @@ -479,7 +515,7 @@ export default function ShoppingPage() { {/* FAB + — masqué quand le sheet est ouvert */} {!showAddSheet && ( - + {(() => { + const actionCount = selections.filter(sel => !sel.existingItemId || sel.qty !== sel.originalQty).length + return ( +
+ +
+ ) + })()} )}