import { useEffect, useState } from "react"; import { apiRequest } from "../../api/client"; import type { Material, Objektposition } from "../../api/types"; interface Props { objektId: number; materialien: Material[]; onFehler: (text: string) => void; } interface ZeilenFormular { ablaufdatum: string; chargennummer: string; seriennummer: string; } function leeresFormular(p: Objektposition): ZeilenFormular { return { ablaufdatum: p.ablaufdatum ?? "", chargennummer: p.chargennummer ?? "", seriennummer: p.seriennummer ?? "", }; } /** * Prompt 10: Ablaufdatum/Chargennummer (materialtyp 'ablauf_charge') und * Seriennummer (materialtyp 'geraet_sn') gehören zur Objektposition, nicht * zur Kontrolle selbst (Vier-Kernbegriffe: Kontrolle erfasst nur die Menge). * Backend-Endpoint (PATCH .../positionen/{id}) existierte schon, war im * Frontend bisher nirgends angebunden. */ export function ObjektPositionenPanel({ objektId, materialien, onFehler }: Props) { const [positionen, setPositionen] = useState([]); const [formulare, setFormulare] = useState>({}); const [speichertId, setSpeichertId] = useState(null); useEffect(() => { apiRequest(`/objekte/${objektId}/positionen`) .then((liste) => { setPositionen(liste); setFormulare(Object.fromEntries(liste.map((p) => [p.id, leeresFormular(p)]))); }) .catch(() => onFehler("Positionen konnten nicht geladen werden.")); // eslint-disable-next-line react-hooks/exhaustive-deps }, [objektId]); function materialName(materialId: number) { return materialien.find((m) => m.id === materialId)?.name ?? `Material ${materialId}`; } function materialtyp(materialId: number) { return materialien.find((m) => m.id === materialId)?.materialtyp; } async function speichern(position: Objektposition) { const formular = formulare[position.id]; setSpeichertId(position.id); try { const aktualisiert = await apiRequest(`/objekte/${objektId}/positionen/${position.id}`, { method: "PATCH", body: { ablaufdatum: formular.ablaufdatum || null, chargennummer: formular.chargennummer || null, seriennummer: formular.seriennummer || null, }, }); setPositionen((bisherige) => bisherige.map((p) => (p.id === position.id ? aktualisiert : p))); } catch { onFehler("Position konnte nicht gespeichert werden."); } finally { setSpeichertId(null); } } const relevante = positionen.filter((p) => materialtyp(p.material_id) !== "standard"); if (relevante.length === 0) { return

Kein Material mit Ablaufdatum/Charge oder Seriennummer in diesem Objekt.

; } return (
    {relevante.map((p) => { const typ = materialtyp(p.material_id); const formular = formulare[p.id] ?? leeresFormular(p); return (
  • {materialName(p.material_id)} {typ}
    {typ === "ablauf_charge" && ( <> setFormulare((f) => ({ ...f, [p.id]: { ...formular, ablaufdatum: e.target.value } })) } /> setFormulare((f) => ({ ...f, [p.id]: { ...formular, chargennummer: e.target.value } })) } /> )} {typ === "geraet_sn" && ( setFormulare((f) => ({ ...f, [p.id]: { ...formular, seriennummer: e.target.value } })) } /> )}
  • ); })}
); }