diff --git a/web/src/pages/Categories.jsx b/web/src/pages/Categories.jsx index cb2a80b..e971b50 100644 --- a/web/src/pages/Categories.jsx +++ b/web/src/pages/Categories.jsx @@ -421,7 +421,6 @@ function CategoryFields({ category, isAdmin, onClose }) { ); } -const BASIS_LABEL = { gram: "Gramm", milliliter: "Milliliter", piece: "Stück" }; const BASIS_KURZ = { gram: "g", milliliter: "ml", piece: "Stk" }; /** @@ -443,6 +442,10 @@ function CategoryMasse({ category, isAdmin, onClose, onFrist }) { const [frist, setFrist] = useState(category.open_days ?? ""); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); + // Masse, die als leere Eingabezeile offen stehen, weil jemand sie gerade + // hinzugefuegt hat. Alles andere ohne Wert bleibt unsichtbar: Ein Dutzend + // leere Felder sehen aus wie Pflichtangaben, und keines davon ist eine. + const [offen, setOffen] = useState(() => new Set()); async function load() { setLoading(true); @@ -475,10 +478,19 @@ function CategoryMasse({ category, isAdmin, onClose, onFrist }) { setError(null); try { await api.deleteCategoryMeasure(category.id, mass.id); + setOffen((alt) => { const neu = new Set(alt); neu.delete(mass.id); return neu; }); load(); } catch (err) { setError(err.message); } } + function aufklappen(id) { + setOffen((alt) => new Set(alt).add(Number(id))); + } + + function zuklappen(id) { + setOffen((alt) => { const neu = new Set(alt); neu.delete(id); return neu; }); + } + async function fristSpeichern() { const roh = String(frist).trim(); const zahl = roh === "" ? null : Number(roh); @@ -525,22 +537,20 @@ function CategoryMasse({ category, isAdmin, onClose, onFrist }) { Es gibt noch keine Maße. Angelegt werden sie unter Stammdaten ▸ Maße.
)} - {!loading && masse.map((m) => { - const w = wertFuer(m.id); - return ( -
„1 EL Mehl ≈ 10 g", „1 Tasse Milch ≈ 200 ml". Damit lässt sich beim
Verbrauchen „2 EL" buchen, statt Gramm zu schätzen. Die Art (Gramm,
@@ -551,6 +561,80 @@ function CategoryMasse({ category, isAdmin, onClose, onFrist }) {
);
}
+/**
+ * Die Maße einer Kategorie – aber nur die, die etwas bedeuten.
+ *
+ * Es gibt beliebig viele Maß-Namen; für eine einzelne Kategorie sind fast immer
+ * nur zwei oder drei davon sinnvoll. Jedes als leeres Feld hinzustellen sah aus
+ * wie ein Formular voller Pflichtangaben, und keine davon ist eine. Deshalb drei
+ * Sorten:
+ *
+ * - **hier eingetragen** – bearbeitbare Zeile mit Mülleimer,
+ * - **von oben geerbt** – eine Lesezeile mit Herkunft und „abweichen",
+ * - **alles andere** – steckt in der Auswahl „Maß hinzufügen" und stört nicht.
+ */
+function MassListe({
+ masse, wertFuer, istEigen, offen, isAdmin,
+ onAufklappen, onZuklappen, onSpeichern, onEntfernen,
+}) {
+ const eigene = masse.filter((m) => istEigen(wertFuer(m.id)) || offen.has(m.id));
+ const geerbte = masse.filter((m) => !eigene.includes(m) && wertFuer(m.id) !== null);
+ const uebrige = masse.filter((m) => !eigene.includes(m) && !geerbte.includes(m));
+
+ return (
+ <>
+ {eigene.map((m) => {
+ const w = wertFuer(m.id);
+ return (
+
+ Für diese Kategorie ist noch kein Maß hinterlegt – „2 EL" lässt sich
+ hier deshalb nicht buchen.
+