feat(shopping): proposition d'ajout au catalogue pour les articles libres
Quand un article tapé n'existe pas dans le catalogue et qu'aucun produit n'est sélectionné, une case "Ajouter au catalogue" apparaît (cochée par défaut). Si cochée, le produit est créé via POST /api/shopping/products avant l'ajout à la liste, avec l'unité pré-remplie si saisie. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import type { ShoppingListDetail, ShoppingList, Store, Product } from '../api/sh
|
||||
import {
|
||||
fetchLists, createList, fetchListDetail, deleteList,
|
||||
addItem, updateItem, deleteItem, finishShopping, fetchStores, generateMagicList,
|
||||
searchProducts,
|
||||
searchProducts, createProduct,
|
||||
} from '../api/shopping'
|
||||
import Modal from '../components/Modal'
|
||||
import ItemRow from '../components/shopping/ItemRow'
|
||||
@@ -44,6 +44,7 @@ export default function ShoppingPage() {
|
||||
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null)
|
||||
const [newItemQty, setNewItemQty] = useState('')
|
||||
const [newItemUnit, setNewItemUnit] = useState('')
|
||||
const [addToCatalogue, setAddToCatalogue] = useState(true)
|
||||
|
||||
useWakeLock(currentList !== null)
|
||||
|
||||
@@ -109,6 +110,7 @@ export default function ShoppingPage() {
|
||||
setSelectedProduct(null)
|
||||
setNewItemQty('')
|
||||
setNewItemUnit('')
|
||||
setAddToCatalogue(true)
|
||||
setShowAddItemModal(false)
|
||||
}
|
||||
|
||||
@@ -120,13 +122,25 @@ export default function ShoppingPage() {
|
||||
|
||||
async function handleAddItem() {
|
||||
if (!currentList) return
|
||||
const hasProduct = selectedProduct !== null
|
||||
const customName = hasProduct ? undefined : itemSearch.trim()
|
||||
if (!hasProduct && !customName) return
|
||||
const customName = itemSearch.trim()
|
||||
if (!selectedProduct && !customName) return
|
||||
try {
|
||||
let productId = selectedProduct?.id
|
||||
|
||||
// Article libre + case "Ajouter au catalogue" cochée → créer le produit d'abord
|
||||
if (!selectedProduct && customName && addToCatalogue) {
|
||||
const newProduct = await createProduct({
|
||||
name: customName,
|
||||
default_unit: newItemUnit || undefined,
|
||||
})
|
||||
productId = newProduct.id
|
||||
// Met à jour la liste locale des produits pour les prochains ajouts
|
||||
setProducts(prev => [...prev, newProduct].sort((a, b) => a.name.localeCompare(b.name, 'fr')))
|
||||
}
|
||||
|
||||
await addItem(currentList.id, {
|
||||
product_id: selectedProduct?.id,
|
||||
custom_name: customName,
|
||||
product_id: productId,
|
||||
custom_name: !productId ? customName : undefined,
|
||||
quantity: newItemQty || undefined,
|
||||
unit: newItemUnit || undefined,
|
||||
})
|
||||
@@ -425,7 +439,7 @@ export default function ShoppingPage() {
|
||||
color: 'var(--ink-4)', fontFamily: 'var(--font-ui)', fontSize: 13,
|
||||
textAlign: 'center', padding: '12px 16px', margin: 0, ...noSelect,
|
||||
}}>
|
||||
{itemSearch.trim() ? `"${itemSearch}" — sera ajouté comme article libre` : 'Catalogue vide'}
|
||||
{itemSearch.trim() ? `"${itemSearch}" — article libre` : 'Catalogue vide'}
|
||||
</p>
|
||||
)}
|
||||
{filteredProducts.map((p, idx) => {
|
||||
@@ -460,6 +474,21 @@ export default function ShoppingPage() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Case "Ajouter au catalogue" — uniquement si article libre sans correspondance */}
|
||||
{!selectedProduct && itemSearch.trim() && filteredProducts.length === 0 && (
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', userSelect: 'none', padding: '6px 2px' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={addToCatalogue}
|
||||
onChange={e => setAddToCatalogue(e.target.checked)}
|
||||
style={{ width: 18, height: 18, accentColor: 'var(--ok)', cursor: 'pointer', flexShrink: 0 }}
|
||||
/>
|
||||
<span style={{ fontFamily: 'var(--font-ui)', fontSize: 13, color: 'var(--ink-2)' }}>
|
||||
Ajouter <strong style={{ color: 'var(--ink-1)' }}>{itemSearch.trim()}</strong> au catalogue
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{/* Quantité + Unité */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user