import { useEffect, useState } from "react"; import { apiRequest } from "../api/client"; import { useAuth } from "../auth/AuthContext"; import type { Benutzer, Bereich, Beladungsvorlage, Einheit, Fach, Kategorie, Material, Objekt, Objekttyp, Qualifikationstyp, Standort } from "../api/types"; import { BenutzerSection } from "./admin/BenutzerSection"; import { BereichSection } from "./admin/BereichSection"; import { EinheitSection } from "./admin/EinheitSection"; import { EskalationSection } from "./admin/EskalationSection"; import { FachSection } from "./admin/FachSection"; import { HistorieSection } from "./admin/HistorieSection"; import { KategorieSection } from "./admin/KategorieSection"; import { LagerbewegungSection } from "./admin/LagerbewegungSection"; import { LagerSection } from "./admin/LagerSection"; import { RolleSection } from "./admin/RolleSection"; import { KontrollverantwortungSection } from "./admin/KontrollverantwortungSection"; import { MaterialSection } from "./admin/MaterialSection"; import { ObjektSection } from "./admin/ObjektSection"; import { ObjekttypSection } from "./admin/ObjekttypSection"; import { QualifikationSection } from "./admin/QualifikationSection"; import { StandortSection } from "./admin/StandortSection"; import { VorlageSection } from "./admin/VorlageSection"; import { ZustaendigkeitSection } from "./admin/ZustaendigkeitSection"; type Tab = | "objekte" | "vorlagen" | "material" | "struktur" | "standorte" | "benutzer" | "historie" | "eskalation" | "kontrollverantwortung" | "zustaendigkeit" | "personal" | "lagerbewegungen" | "lager" | "rollen"; // Deckt sich mit den require_roles()-Gates der jeweiligen Backend-Endpunkte // (Rollen-Vorgabe: Material-/Leitungsverantwortliche sahen bisher exakt // dasselbe wie Mitarbeiter - hier je Tab, wer laut Backend tatsächlich // etwas damit anfangen kann). const TABS: { key: Tab; label: string; rollen: ("administration" | "materialverantwortlicher" | "leitungsverantwortlicher")[] }[] = [ { key: "objekte", label: "Objekte", rollen: ["administration", "materialverantwortlicher"] }, { key: "vorlagen", label: "Vorlagen", rollen: ["administration", "materialverantwortlicher"] }, { key: "material", label: "Material", rollen: ["administration"] }, { key: "struktur", label: "Struktur", rollen: ["administration"] }, { key: "standorte", label: "Standorte", rollen: ["administration"] }, { key: "benutzer", label: "Benutzer", rollen: ["administration"] }, { key: "zustaendigkeit", label: "Zuständigkeit", rollen: ["administration"] }, { key: "kontrollverantwortung", label: "Kontrollverantwortung", rollen: ["administration", "materialverantwortlicher", "leitungsverantwortlicher"], }, { key: "historie", label: "Änderungslog", rollen: ["administration", "materialverantwortlicher", "leitungsverantwortlicher"], }, { key: "eskalation", label: "Eskalation", rollen: ["administration"] }, { key: "personal", label: "Personal", rollen: ["administration"] }, { key: "lagerbewegungen", label: "Lagerbewegungen", rollen: ["administration", "materialverantwortlicher", "leitungsverantwortlicher"], }, { key: "lager", label: "Lager", rollen: ["administration", "materialverantwortlicher"] }, { key: "rollen", label: "Rollen & Rechte", rollen: ["administration"] }, ]; /** * Admin-Seite (Stammdaten/Objekt-Anlage), nachgezogen weil das Frontend * bisher nur den Mitarbeiter-Kontrollflow (Sprint 7) abdeckte und * Stammdaten/Objekte nur per API/Skript angelegt werden konnten. * * Jeder Abschnitt ist eine eigene Komponente unter pages/admin/ - hält diese * Datei als reinen Orchestrator klein (siehe Projekt-Vorgabe: keine großen * Monolith-Dateien). */ export function AdminPage() { const { rollen, istAdmin } = useAuth(); const sichtbareTabs = TABS.filter((t) => t.rollen.some((r) => rollen.includes(r))); const [bereiche, setBereiche] = useState([]); const [kategorien, setKategorien] = useState([]); const [objekttypen, setObjekttypen] = useState([]); const [standorte, setStandorte] = useState([]); const [vorlagen, setVorlagen] = useState([]); const [objekte, setObjekte] = useState([]); const [materialien, setMaterialien] = useState([]); const [benutzer, setBenutzer] = useState([]); const [faecher, setFaecher] = useState([]); const [einheiten, setEinheiten] = useState([]); const [qualifikationstypen, setQualifikationstypen] = useState([]); const [fehler, setFehler] = useState(null); const [laedt, setLaedt] = useState(true); const [tab, setTab] = useState(null); const aktiverTab = tab && sichtbareTabs.some((t) => t.key === tab) ? tab : sichtbareTabs[0]?.key ?? null; async function ladeAlles() { // /benutzer ist admin-only (Backend require_roles) - Promise.all würde bei // Material-/Leitungsverantwortlichen mit 403 durchfallen und die komplette // Seite als "nicht geladen" zeigen, obwohl deren Tabs (z.B. Kontroll- // verantwortung) trotzdem funktionieren sollen. allSettled + leerer // Fallback statt hartem Fehler. const [be, ka, ot, s, v, o, m, b, f, ei, qt] = await Promise.allSettled([ apiRequest("/bereiche"), apiRequest("/kategorien"), apiRequest("/objekttypen"), apiRequest("/standorte"), apiRequest("/vorlagen"), apiRequest("/objekte"), apiRequest("/materialien"), apiRequest("/benutzer"), apiRequest("/faecher"), apiRequest("/einheiten"), apiRequest("/qualifikationstypen"), ]); const wert = (r: PromiseSettledResult): T[] => (r.status === "fulfilled" ? r.value : []); setBereiche(wert(be)); setKategorien(wert(ka)); setObjekttypen(wert(ot)); setStandorte(wert(s)); setVorlagen(wert(v)); setObjekte(wert(o)); setMaterialien(wert(m)); setBenutzer(wert(b)); setFaecher(wert(f)); setEinheiten(wert(ei)); setQualifikationstypen(wert(qt)); } useEffect(() => { ladeAlles() .catch(() => setFehler("Stammdaten konnten nicht geladen werden.")) .finally(() => setLaedt(false)); }, []); if (laedt) { return (

Lade…

); } return (

{istAdmin ? "Administration" : "Verwaltung"}

{fehler &&
{fehler}
} {aktiverTab === "objekte" && ( v.status === "aktiv")} standorte={standorte} materialien={materialien} nurPflegen={!istAdmin} onGeaendert={ladeAlles} onFehler={setFehler} /> )} {aktiverTab === "vorlagen" && ( )} {aktiverTab === "material" && ( )} {aktiverTab === "struktur" && ( <> )} {aktiverTab === "standorte" && ( )} {aktiverTab === "benutzer" && ( )} {aktiverTab === "zustaendigkeit" && ( )} {aktiverTab === "kontrollverantwortung" && ( )} {aktiverTab === "historie" && } {aktiverTab === "lagerbewegungen" && ( )} {aktiverTab === "lager" && } {aktiverTab === "rollen" && } {aktiverTab === "eskalation" && } {aktiverTab === "personal" && ( <> )} {aktiverTab === null &&

Keine Bereiche für deine Rolle verfügbar.

}
); }