Einkaufsliste: Fehlmenge als Gebinde (Glaeser/Dosen), Basiseinheit klein

Statt 'fehlt 500 Gramm' jetzt die Produktgroesse als Leitangabe:
'fehlt 3 Glaeser (500 g)'. Auf ganze Gebinde aufgerundet, weil man nur
ganze Glaeser/Dosen kauft; Basiseinheit als kleiner Hinweis.

Backend: neues ShoppingNeed-Objekt an jeder Einkaufslisten-Zeile (Produkte
+ Gruppen, gesamt + je Ort) - damit die Angabe auch direkt ueber die API
kommt ('x Glaeser (y g)'), inkl. Pluralisierung aus der Gebinde-Tabelle.
Gruppen leiten das Gebinde ab, wenn alle passenden Produkte dasselbe haben,
sonst bleibt es bei der Basiseinheit. Bestehende Felder unveraendert.

Frontend: gemeinsame Komponente ShoppingNeedText fuer Karte und volle Seite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-07 18:03:37 +02:00
parent e214bb76a9
commit f2c657ff31
6 changed files with 294 additions and 29 deletions

View File

@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { api } from "../api";
import Icon from "../components/Icon";
import { amountText, fmt, unitShort } from "../units";
import ShoppingNeedText from "../components/ShoppingNeedText";
export default function ShoppingList() {
const [items, setItems] = useState([]);
@@ -51,8 +51,7 @@ export default function ShoppingList() {
<span className="item-name">{it.name}</span>
</label>
<span className="muted small">
fehlt <strong>{fmt(it.deficit)} {it.unit_name}</strong>{" "}
(Bestand {fmt(it.stock)} / min {fmt(it.min_stock)} {it.unit_name})
<ShoppingNeedText need={it.need} stock={it.stock} minStock={it.min_stock} unitName={it.unit_name} />
</span>
</li>
);
@@ -66,8 +65,7 @@ export default function ShoppingList() {
<span className="item-name">{it.name}</span>
</label>
<span className="muted small">
fehlt <strong>{amountText(it.deficit, it.package_size, it.base_unit)}</strong>{" "}
(Bestand {amountText(it.stock, it.package_size, it.base_unit)})
<ShoppingNeedText need={it.need} stock={it.stock} minStock={it.min_stock} unitName={it.base_unit} />
</span>
</li>
);
@@ -93,8 +91,7 @@ export default function ShoppingList() {
<span className="item-name">{it.name}</span>
</label>
<span className="muted small">
fehlt <strong>{fmt(it.deficit)} {it.unit_name}</strong>{" "}
(Bestand {fmt(it.stock)} / min {fmt(it.min_stock)})
<ShoppingNeedText need={it.need} stock={it.stock} minStock={it.min_stock} unitName={it.unit_name} />
</span>
</li>
);
@@ -108,8 +105,7 @@ export default function ShoppingList() {
<span className="item-name">{it.name}</span>
</label>
<span className="muted small">
fehlt <strong>{fmt(it.deficit)} {it.unit_label}</strong>{" "}
(Bestand {fmt(it.stock)} / min {fmt(it.min_stock)})
<ShoppingNeedText need={it.need} stock={it.stock} minStock={it.min_stock} unitName={it.unit_label} />
</span>
</li>
);