Admin-Portal: Benutzerverwaltung (anlegen, Rollen, aktivieren/deaktivieren)
Backend-API existierte bereits (/benutzer, admin-only), war im Frontend bisher nicht angebunden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { apiRequest } from "../../api/client";
|
||||
import type { Benutzer, Rolle } from "../../api/types";
|
||||
|
||||
interface Props {
|
||||
benutzer: Benutzer[];
|
||||
onGeaendert: () => Promise<void>;
|
||||
onFehler: (text: string) => void;
|
||||
}
|
||||
|
||||
const ALLE_ROLLEN: Rolle[] = [
|
||||
"mitarbeiter",
|
||||
"materialverantwortlicher",
|
||||
"leitungsverantwortlicher",
|
||||
"administration",
|
||||
];
|
||||
|
||||
export function BenutzerSection({ benutzer, onGeaendert, onFehler }: Props) {
|
||||
const [name, setName] = useState("");
|
||||
const [login, setLogin] = useState("");
|
||||
const [passwort, setPasswort] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [rollen, setRollen] = useState<Rolle[]>(["mitarbeiter"]);
|
||||
const [wirdAngelegt, setWirdAngelegt] = useState(false);
|
||||
|
||||
function rolleUmschalten(rolle: Rolle) {
|
||||
setRollen((bisherige) =>
|
||||
bisherige.includes(rolle) ? bisherige.filter((r) => r !== rolle) : [...bisherige, rolle]
|
||||
);
|
||||
}
|
||||
|
||||
async function anlegen() {
|
||||
setWirdAngelegt(true);
|
||||
try {
|
||||
await apiRequest("/benutzer", {
|
||||
method: "POST",
|
||||
body: { name, login, passwort, email: email || null, rollen },
|
||||
});
|
||||
setName("");
|
||||
setLogin("");
|
||||
setPasswort("");
|
||||
setEmail("");
|
||||
setRollen(["mitarbeiter"]);
|
||||
await onGeaendert();
|
||||
} catch {
|
||||
onFehler("Benutzer konnte nicht angelegt werden (Login evtl. schon vergeben).");
|
||||
} finally {
|
||||
setWirdAngelegt(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function aktivSchalten(b: Benutzer) {
|
||||
try {
|
||||
await apiRequest(`/benutzer/${b.id}`, { method: "PATCH", body: { aktiv: !b.aktiv } });
|
||||
await onGeaendert();
|
||||
} catch {
|
||||
onFehler("Status konnte nicht geändert werden.");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="section">
|
||||
<h2>Benutzer anlegen</h2>
|
||||
<div className="card">
|
||||
<div className="row" style={{ flexWrap: "wrap", gap: "0.5rem", marginBottom: "0.75rem" }}>
|
||||
<input className="input" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
|
||||
<input className="input" value={login} onChange={(e) => setLogin(e.target.value)} placeholder="Login" />
|
||||
<input
|
||||
className="input"
|
||||
type="password"
|
||||
value={passwort}
|
||||
onChange={(e) => setPasswort(e.target.value)}
|
||||
placeholder="Passwort"
|
||||
/>
|
||||
<input
|
||||
className="input"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="E-Mail (optional)"
|
||||
/>
|
||||
</div>
|
||||
<div className="row" style={{ flexWrap: "wrap", gap: "0.5rem", marginBottom: "0.75rem" }}>
|
||||
{ALLE_ROLLEN.map((r) => (
|
||||
<label key={r} className="row" style={{ gap: "0.3rem" }}>
|
||||
<input type="checkbox" checked={rollen.includes(r)} onChange={() => rolleUmschalten(r)} />
|
||||
{r}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={anlegen}
|
||||
disabled={!name || !login || !passwort || wirdAngelegt}
|
||||
>
|
||||
Anlegen
|
||||
</button>
|
||||
|
||||
{benutzer.length > 0 && (
|
||||
<ul className="card-list" style={{ marginTop: "1rem" }}>
|
||||
{benutzer.map((b) => (
|
||||
<li key={b.id} className="row-between" style={{ padding: "0.4rem 0" }}>
|
||||
<span>
|
||||
<strong>{b.name}</strong> ({b.login}) – {b.rollen.join(", ")}
|
||||
{!b.aktiv && " – deaktiviert"}
|
||||
</span>
|
||||
<button className="btn btn-secondary" onClick={() => aktivSchalten(b)}>
|
||||
{b.aktiv ? "Deaktivieren" : "Aktivieren"}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user