"use client"; import { useCallback, useEffect, useState } from "react"; import { userApi, type UserDto, type UserRole } from "../../../frontend/utils/auth-api"; import { useAuth } from "../../../frontend/components/AuthProvider"; import { USER_ROLES, USER_ROLE_LABEL } from "../../../shared/constants/user-roles"; const zeitpunkt = new Intl.DateTimeFormat("de-DE", { dateStyle: "short", timeStyle: "short", }); export default function BenutzerPage() { const { user: currentUser } = useAuth(); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [busyUserId, setBusyUserId] = useState(null); const [resetPasswordFor, setResetPasswordFor] = useState(null); const load = useCallback(async () => { setLoading(true); try { const rows = await userApi.list(); setUsers(rows); setError(null); } catch (err) { setError(err instanceof Error ? err.message : "Benutzer konnten nicht geladen werden."); } finally { setLoading(false); } }, []); useEffect(() => { void load(); }, [load]); async function withBusy(userId: string, action: () => Promise) { setBusyUserId(userId); setError(null); try { await action(); } catch (err) { setError(err instanceof Error ? err.message : "Aktion fehlgeschlagen."); } finally { setBusyUserId(null); } } async function changeRole(item: UserDto, role: UserRole) { await withBusy(item.id, async () => { const updated = await userApi.update(item.id, { role }); setUsers((list) => list.map((row) => (row.id === updated.id ? updated : row))); }); } async function toggleActive(item: UserDto) { await withBusy(item.id, async () => { const updated = await userApi.update(item.id, { active: !item.active }); setUsers((list) => list.map((row) => (row.id === updated.id ? updated : row))); }); } return (

Benutzer

Es gibt kein Self-Signup: Jeder Zugang wird hier bewusst von einem Administrator angelegt. Das Startpasswort wird direkt eingetragen; die Person muss es beim ersten Anmelden durch ein eigenes ersetzen.

{ setUsers((list) => [...list, created]); }} /> {error &&

{error}

} {loading &&

Lädt…

} {!loading && users.length > 0 && ( {users.map((item) => { const isSelf = item.id === currentUser?.id; const busy = busyUserId === item.id; return ( ); })}
Name Anmeldename Rolle Aktiv Status Angelegt Aktionen
{item.name} {item.username} void toggleActive(item)} /> {item.mustChangePassword ? "Muss Passwort setzen" : "In Ordnung"} {zeitpunkt.format(new Date(item.createdAt))}
)} {!loading && users.length === 0 &&

Noch keine Benutzer angelegt.

} {resetPasswordFor && ( setResetPasswordFor(null)} onDone={(updated) => { setUsers((list) => list.map((row) => (row.id === updated.id ? updated : row))); setResetPasswordFor(null); }} /> )}
); } function NeuerBenutzerFormular({ onCreated }: { onCreated: (created: UserDto) => void }) { const [username, setUsername] = useState(""); const [name, setName] = useState(""); const [role, setRole] = useState("user"); const [initialPassword, setInitialPassword] = useState(""); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); setSubmitting(true); setError(null); try { const created = await userApi.create({ username, name, role, initialPassword }); onCreated(created); setUsername(""); setName(""); setRole("user"); setInitialPassword(""); } catch (err) { setError(err instanceof Error ? err.message : "Benutzer konnte nicht angelegt werden."); } finally { setSubmitting(false); } } return (
setUsername(event.target.value)} required />
setName(event.target.value)} required />
setInitialPassword(event.target.value)} minLength={8} required />
{error && (

{error}

)}
); } function PasswortZuruecksetzenDialog({ item, onClose, onDone, }: { item: UserDto; onClose: () => void; onDone: (updated: UserDto) => void; }) { const [newPassword, setNewPassword] = useState(""); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); setSubmitting(true); setError(null); try { const updated = await userApi.resetPassword(item.id, newPassword); onDone(updated); } catch (err) { setError(err instanceof Error ? err.message : "Passwort konnte nicht zurückgesetzt werden."); } finally { setSubmitting(false); } } return (

Passwort zurücksetzen für {item.name}

setNewPassword(event.target.value)} minLength={8} autoFocus required />
{error &&

{error}

}
); }