import { useEffect, useState } from "react"; import { api } from "../api"; import Icon from "./Icon"; import { useConfirm } from "../confirm"; /** * Zubehör eines Einzelstücks: das Netzteil, das zum Laptop gehört. * * Ein Teil hängt an genau einem Gerät, ein Gerät trägt beliebig viele Teile. * Die Zuordnung läuft über eigene Endpunkte und nicht über `updateItem` – dessen * Schema sendet immer alle Felder mit, ein vergessenes Feld würde die Beziehung * still kappen. */ export default function Zubehoer({ item, isAdmin, onChanged, onError }) { const confirm = useConfirm(); const [alle, setAlle] = useState(null); const [waehlen, setWaehlen] = useState(false); const [suche, setSuche] = useState(""); const [busy, setBusy] = useState(false); useEffect(() => { if (!waehlen || alle != null) return; api.listAllItems().then(setAlle).catch((err) => onError(err.message)); }, [waehlen, alle, onError]); async function zuordnen(teil) { setBusy(true); try { await api.zubehoerZuordnen(item.id, teil.id); setWaehlen(false); setSuche(""); setAlle(null); // nach dem Umhängen stimmen die Zuordnungen nicht mehr if (onChanged) await onChanged(); } catch (err) { onError(err.message); } finally { setBusy(false); } } async function loesen(teil) { const ok = await confirm({ title: `„${teil.uid}“ vom Gerät lösen?`, message: "Das Einzelstück bleibt bestehen, es gehört danach nur zu nichts mehr.", confirmLabel: "Lösen", }); if (!ok) return; setBusy(true); try { await api.zubehoerLoesen(item.id, teil.id); setAlle(null); if (onChanged) await onChanged(); } catch (err) { onError(err.message); } finally { setBusy(false); } } const teile = item.zubehoer || []; // Weder sich selbst noch die eigenen Teile erneut anbieten. Ringe über mehrere // Stufen weist der Server ab – hier geht es nur darum, Unsinn gar nicht erst // zur Auswahl zu stellen. const kandidaten = (alle || []).filter((k) => { if (k.id === item.id) return false; if (k.gehoert_zu && k.gehoert_zu.id === item.id) return false; const q = suche.trim().toLowerCase(); if (!q) return true; return [k.uid, k.product_name, k.product_brand, k.note] .filter(Boolean).join(" ").toLowerCase().includes(q); }); return (
Zubehör {item.gehoert_zu && (

Gehört zu {item.gehoert_zu.product_name || "Einzelstück"} ({item.gehoert_zu.uid})

)} {teile.length === 0 && !item.gehoert_zu && (

Kein Zubehör.

)} {teile.length > 0 && ( )} {isAdmin && !waehlen && ( )} {isAdmin && waehlen && (
setSuche(e.target.value)} />
{alle == null && Wird geladen…} {alle != null && kandidaten.length === 0 && ( Nichts gefunden. )} {alle != null && kandidaten.length > 25 && ( {kandidaten.length - 25} weitere – bitte genauer suchen. )}
)}
); }