"use client"; import { useCallback, useEffect, useState } from "react"; import type { FormEvent } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { ArrowLeft, KeyRound, Pencil } from "lucide-react"; import StatusBadge from "@/components/common/StatusBadge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import UserFormDialog from "@/components/users/UserFormDialog"; import { api } from "@/lib/api"; import { hasPermission } from "@/lib/permissions"; import type { CurrentUser, Role } from "@/types/rbac"; import type { User, UserPayload } from "@/types/user"; function getErrorMessage(error: unknown) { if (typeof error === "object" && error !== null && "response" in error) { const response = (error as { response?: { data?: { detail?: string } } }).response; return response?.data?.detail ?? "Aktion konnte nicht abgeschlossen werden"; } return "Aktion konnte nicht abgeschlossen werden"; } function formatDateTime(value: string) { return new Intl.DateTimeFormat("de-DE", { dateStyle: "medium", timeStyle: "short", }).format(new Date(value)); } export default function UserDetailPage() { const params = useParams<{ id: string }>(); const [user, setUser] = useState(null); const [roles, setRoles] = useState([]); const [currentUser, setCurrentUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [pending, setPending] = useState(false); const [formOpen, setFormOpen] = useState(false); const [formError, setFormError] = useState(""); const [passwordOpen, setPasswordOpen] = useState(false); const [password, setPassword] = useState(""); const [passwordError, setPasswordError] = useState(""); const loadUser = useCallback(async () => { try { const [userResponse, meResponse] = await Promise.all([ api.get(`/users/${params.id}`), api.get("/me"), ]); setUser(userResponse.data); setCurrentUser(meResponse.data); if (hasPermission(meResponse.data, "roles.read")) { const rolesResponse = await api.get("/roles"); setRoles(rolesResponse.data); } else { setRoles([userResponse.data.primary_role]); } } catch (err) { setError(getErrorMessage(err)); } finally { setLoading(false); } }, [params.id]); useEffect(() => { queueMicrotask(() => { void loadUser(); }); }, [loadUser]); async function saveUser(payload: UserPayload) { if (!user) { return; } setPending(true); setFormError(""); try { const response = await api.put(`/users/${user.id}`, payload); setUser(response.data); setFormOpen(false); } catch (err) { setFormError(getErrorMessage(err)); } finally { setPending(false); } } async function savePassword(event: FormEvent) { event.preventDefault(); if (!user || password.length < 8) { setPasswordError("Passwort muss mindestens 8 Zeichen lang sein"); return; } setPending(true); setPasswordError(""); try { const response = await api.put(`/users/${user.id}?action=password`, { password, }); setUser(response.data); setPassword(""); setPasswordOpen(false); } catch (err) { setPasswordError(getErrorMessage(err)); } finally { setPending(false); } } if (loading) { return
Benutzer wird geladen...
; } if (error || !user) { return (
Zurück
{error || "Benutzer nicht gefunden"}
); } return (
Zurück zur Benutzerliste

{user.username}

{user.email}

{hasPermission(currentUser, "users.password.update") && ( )} {hasPermission(currentUser, "users.update") && ( )}

Informationen

Status
Passwort ändern Das Passwort wird serverseitig mit pwdlib gehasht.
setPassword(event.target.value)} /> {passwordError &&

{passwordError}

}
); } function Detail({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); }