// Kategorien sind verschachtelbar (Süßwaren → Schokolade). Damit Liste, // Auswahlfeld und Filter dieselbe Reihenfolge und Einrückung zeigen, steht die // Aufbereitung hier einmal. Gleiches Vorgehen wie bei den Lagerorten. /** * Bringt eine flache Liste in Baumreihenfolge und ergänzt `depth`. * Kategorien, deren Elternteil fehlt, gelten als oberste Ebene – so geht * nichts verloren, falls eine Oberkategorie gelöscht wurde. */ export function asTree(categories = []) { const ids = new Set(categories.map((c) => c.id)); const isRoot = (c) => !c.parent_id || !ids.has(c.parent_id); const ordered = []; function walk(node, depth) { ordered.push({ ...node, depth }); for (const child of categories.filter((c) => c.parent_id === node.id)) { walk(child, depth + 1); } } for (const root of categories.filter(isRoot)) walk(root, 0); return ordered; } /** Einrückung für Auswahlfelder – dort geht kein CSS-Abstand. */ export function indentLabel(category) { return `${"  ".repeat(category.depth || 0)}${category.name}`; }