Web: Produkte und Kategorien nach Typ filtern (Lebensmittel/Gegenstand)

Zum leichteren Unterscheiden gibt es in der Produkte-Liste und in der
Kategorien-Verwaltung einen Umschalter Alle/Lebensmittel/Gegenstaende. Er filtert
die jeweilige Liste und in der Produktsuche auch die Kategorieauswahl auf den Typ.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-25 23:55:27 +02:00
parent c532492286
commit 5edb830afd
2 changed files with 34 additions and 5 deletions

View File

@@ -25,6 +25,8 @@ export default function Products() {
const [categories, setCategories] = useState([]);
// "" = alle, "0" = ohne Kategorie, sonst die ID (Unterkategorien zaehlen mit).
const [categoryId, setCategoryId] = useState("");
// "" = alle, sonst "food"/"object": trennt Lebensmittel und Gegenstände.
const [typ, setTyp] = useState("");
const [error, setError] = useState(null);
async function load(cat = categoryId) {
@@ -46,12 +48,23 @@ export default function Products() {
load();
}
// Typ umschalten: passt der Kategoriefilter nicht mehr, zurücksetzen.
function changeTyp(neu) {
setTyp(neu);
if (neu && categoryId && categoryId !== "0") {
const cat = categories.find((c) => String(c.id) === String(categoryId));
if (cat && cat.tracking !== neu) { setCategoryId(""); load(""); }
}
}
const sichtbar = products.filter((p) => !typ || p.tracking === typ);
return (
<div>
<div className="page-head">
<div>
<h1>Produkte</h1>
<div className="sub">{products.length} Produkte im Katalog</div>
<div className="sub">{sichtbar.length} Produkte{typ ? (typ === "food" ? " · Lebensmittel" : " · Gegenstände") : " im Katalog"}</div>
</div>
{isAdmin && (
<Link className="btn primary" to="/products/new"><Icon name="plus" size={16} />Neues Produkt</Link>
@@ -60,6 +73,12 @@ export default function Products() {
{error && <div className="alert error"><Icon name="alert" size={16} />{error}</div>}
<div className="segmented" style={{ marginBottom: "var(--sp-3)" }}>
<button type="button" className={typ === "" ? "active" : ""} onClick={() => changeTyp("")}>Alle</button>
<button type="button" className={typ === "food" ? "active" : ""} onClick={() => changeTyp("food")}>Lebensmittel</button>
<button type="button" className={typ === "object" ? "active" : ""} onClick={() => changeTyp("object")}>Gegenstände</button>
</div>
<form className="field-inline" style={{ marginBottom: "var(--sp-4)", maxWidth: 640 }} onSubmit={onSearch}>
<label className="grow" style={{ margin: 0 }}>
<input placeholder="Produkt suchen…" value={q} onChange={(e) => setQ(e.target.value)} />
@@ -68,7 +87,7 @@ export default function Products() {
<select value={categoryId} onChange={(e) => { setCategoryId(e.target.value); load(e.target.value); }}>
<option value="">Alle Kategorien</option>
<option value="0">Ohne Kategorie</option>
{asTree(categories).map((c) => (
{asTree(categories).filter((c) => !typ || c.tracking === typ).map((c) => (
<option key={c.id} value={c.id}>{"— ".repeat(c.depth)}{c.name}</option>
))}
</select>
@@ -92,7 +111,7 @@ export default function Products() {
</tr>
</thead>
<tbody>
{products.map((p) => {
{sichtbar.map((p) => {
const low = p.min_stock != null && p.stock < p.min_stock;
return (
<tr key={p.id}>
@@ -134,7 +153,7 @@ export default function Products() {
</tr>
);
})}
{products.length === 0 && (
{sichtbar.length === 0 && (
<tr><td colSpan={8} className="empty">Keine Produkte gefunden.</td></tr>
)}
</tbody>