import { useEffect, useState } from "react"; import { api } from "../api"; import { useConfirm } from "../confirm"; import Icon from "../components/Icon"; export default function Locations() { const confirm = useConfirm(); const [locations, setLocations] = useState([]); const [name, setName] = useState(""); const [parentId, setParentId] = useState(""); const [error, setError] = useState(null); async function load() { try { setLocations(await api.listLocations()); } catch (err) { setError(err.message); } } useEffect(() => { load(); }, []); async function add(e) { e.preventDefault(); setError(null); try { await api.createLocation({ name, parent_id: parentId === "" ? null : Number(parentId) }); setName(""); setParentId(""); load(); } catch (err) { setError(err.message); } } async function remove(id) { const ok = await confirm({ title: "Lagerort löschen?", message: "Untergeordnete Orte rücken eine Ebene nach oben.", confirmLabel: "Löschen", danger: true, }); if (!ok) return; try { await api.deleteLocation(id); load(); } catch (err) { setError(err.message); } } const nameById = Object.fromEntries(locations.map((l) => [l.id, l.name])); const ids = new Set(locations.map((l) => l.id)); const isRoot = (l) => !l.parent_id || !ids.has(l.parent_id); // Rekursiv über beliebig viele Ebenen (Schrank -> Fach -> Kiste -> …). const ordered = []; const seen = new Set(); function walk(node, depth) { if (seen.has(node.id)) return; // Schutz vor Zyklen seen.add(node.id); ordered.push({ ...node, depth }); for (const c of locations.filter((l) => l.parent_id === node.id)) walk(c, depth + 1); } for (const r of locations.filter(isRoot)) walk(r, 0); return (

Lagerorte

Orte lassen sich verschachteln (z.B. Keller → Regal 2 → Fach A)
{error &&
{error}
}
); }