// User detail page with role assignment. // // Displays user info and lets an admin assign/revoke roles in one // click. The role changes take effect on the user's NEXT login // (the JWT carries the roles claim from login time). import { useCallback, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { identity } from '@/api/client' import type { Role, User } from '@/types/api' import { PageHeader } from '@/components/PageHeader' import { Loading } from '@/components/Loading' import { ErrorBox } from '@/components/ErrorBox' export function UserDetailPage() { const { id = '' } = useParams<{ id: string }>() const navigate = useNavigate() const [user, setUser] = useState(null) const [allRoles, setAllRoles] = useState([]) const [userRoleCodes, setUserRoleCodes] = useState([]) const [loading, setLoading] = useState(true) const [acting, setActing] = useState(false) const [error, setError] = useState(null) const refresh = useCallback(async () => { const [u, roles, uRoles] = await Promise.all([ identity.getUser(id), identity.listRoles(), identity.getUserRoles(id), ]) setUser(u) setAllRoles(roles) setUserRoleCodes(uRoles) }, [id]) useEffect(() => { refresh() .catch((e: unknown) => setError(e instanceof Error ? e : new Error(String(e)))) .finally(() => setLoading(false)) }, [refresh]) const toggle = async (roleCode: string, has: boolean) => { setActing(true) setError(null) try { if (has) { await identity.revokeRole(id, roleCode) } else { await identity.assignRole(id, roleCode) } await refresh() } catch (e: unknown) { setError(e instanceof Error ? e : new Error(String(e))) } finally { setActing(false) } } if (loading) return if (error && !user) return if (!user) return return (
navigate('/users')}> ← Back } /> {error && }

Roles

Toggle roles on/off. Changes take effect on the user's next login.

{allRoles.length === 0 && (

No roles defined yet. Create one on the Roles page.

)}
{allRoles.map((role) => { const has = userRoleCodes.includes(role.code) return (
{role.code} {role.name}
) })}
) }