Sprint 8: Bereich/Kategorie/Objekttyp/Vorlage-CRUD im Admin-Portal
CI / backend-tests (push) Successful in 56s
CI / frontend-build (push) Successful in 18s

Vervollständigt die Stammdaten-Anlage im Frontend (bisher nur Standort/
Material/Objekt), damit ein Pilotbetrieb nicht zwingend Excel-Import
braucht. Jede Sektion eigene Datei unter pages/admin/ (Projekt-Vorgabe:
keine großen Monolith-Dateien).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
This commit is contained in:
2026-09-04 00:52:43 +02:00
co-authored by Claude Sonnet 5
parent 569f58b25b
commit dcc75dd2d0
6 changed files with 410 additions and 12 deletions
+40 -12
View File
@@ -1,22 +1,28 @@
import { useEffect, useState } from "react";
import { apiRequest } from "../api/client";
import type { Beladungsvorlage, Material, Objekt, Standort } from "../api/types";
import type { Bereich, Beladungsvorlage, Kategorie, Material, Objekt, Objekttyp, Standort } from "../api/types";
import { BereichSection } from "./admin/BereichSection";
import { KategorieSection } from "./admin/KategorieSection";
import { MaterialSection } from "./admin/MaterialSection";
import { ObjektSection } from "./admin/ObjektSection";
import { ObjekttypSection } from "./admin/ObjekttypSection";
import { StandortSection } from "./admin/StandortSection";
import { VorlageSection } from "./admin/VorlageSection";
/**
* Minimale Admin-Seite (Standort/Material/Objekt-Anlage), nachgezogen weil
* das Frontend bisher nur den Mitarbeiter-Kontrollflow (Sprint 7) abdeckte
* und Stammdaten/Objekte nur per API/Skript angelegt werden konnten. Bewusst
* schlank: keine Bereich-/Kategorie-/Vorlagen-CRUD, nur was für die
* Pilotphase sofort nötig ist (Vorlagen kommen aus dem Excel-Import).
* 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 (Standort/Material/Objekt) ist eine eigene Komponente unter
* pages/admin/ - hält diese Datei als reinen Orchestrator klein.
* 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 [bereiche, setBereiche] = useState<Bereich[]>([]);
const [kategorien, setKategorien] = useState<Kategorie[]>([]);
const [objekttypen, setObjekttypen] = useState<Objekttyp[]>([]);
const [standorte, setStandorte] = useState<Standort[]>([]);
const [vorlagen, setVorlagen] = useState<Beladungsvorlage[]>([]);
const [objekte, setObjekte] = useState<Objekt[]>([]);
@@ -25,14 +31,20 @@ export function AdminPage() {
const [laedt, setLaedt] = useState(true);
async function ladeAlles() {
const [s, v, o, m] = await Promise.all([
const [be, ka, ot, s, v, o, m] = await Promise.all([
apiRequest<Bereich[]>("/bereiche"),
apiRequest<Kategorie[]>("/kategorien"),
apiRequest<Objekttyp[]>("/objekttypen"),
apiRequest<Standort[]>("/standorte"),
apiRequest<Beladungsvorlage[]>("/vorlagen"),
apiRequest<Objekt[]>("/objekte"),
apiRequest<Material[]>("/materialien"),
]);
setBereiche(be);
setKategorien(ka);
setObjekttypen(ot);
setStandorte(s);
setVorlagen(v.filter((vorlage) => vorlage.status === "aktiv"));
setVorlagen(v);
setObjekte(o);
setMaterialien(m);
}
@@ -56,11 +68,27 @@ export function AdminPage() {
<h1>Administration</h1>
{fehler && <div className="alert alert-danger">{fehler}</div>}
<StandortSection standorte={standorte} onGeaendert={ladeAlles} onFehler={setFehler} />
<BereichSection bereiche={bereiche} onGeaendert={ladeAlles} onFehler={setFehler} />
<KategorieSection bereiche={bereiche} kategorien={kategorien} onGeaendert={ladeAlles} onFehler={setFehler} />
<ObjekttypSection
bereiche={bereiche}
kategorien={kategorien}
objekttypen={objekttypen}
onGeaendert={ladeAlles}
onFehler={setFehler}
/>
<MaterialSection materialien={materialien} onGeaendert={ladeAlles} onFehler={setFehler} />
<VorlageSection
vorlagen={vorlagen}
objekttypen={objekttypen}
materialien={materialien}
onGeaendert={ladeAlles}
onFehler={setFehler}
/>
<StandortSection standorte={standorte} onGeaendert={ladeAlles} onFehler={setFehler} />
<ObjektSection
objekte={objekte}
vorlagen={vorlagen}
vorlagen={vorlagen.filter((v) => v.status === "aktiv")}
standorte={standorte}
onGeaendert={ladeAlles}
onFehler={setFehler}