diff --git a/backend/app/routers/auth.py b/backend/app/routers/auth.py
index 16e8ed5..d9cd550 100644
--- a/backend/app/routers/auth.py
+++ b/backend/app/routers/auth.py
@@ -531,6 +531,7 @@ async def auth_status(
"authenticated": authenticated,
"setup_required": setup_required,
"role": role,
+ "username": u.username if authenticated and u else None,
"registration_open": registration_open,
}
diff --git a/frontend/src/components/admin/IAMPage.tsx b/frontend/src/components/admin/IAMPage.tsx
index aed1a85..3800b4c 100644
--- a/frontend/src/components/admin/IAMPage.tsx
+++ b/frontend/src/components/admin/IAMPage.tsx
@@ -20,6 +20,7 @@ import {
useUpdateConfig,
getErrorMessage,
} from '@/hooks/useAdmin';
+import { useAuth } from '@/hooks/useAuth';
import { getRelativeTime } from '@/lib/date-utils';
import type { AdminUserDetail, UserRole } from '@/types';
import { cn } from '@/lib/utils';
@@ -55,6 +56,7 @@ function RoleBadge({ role }: { role: UserRole }) {
export default function IAMPage() {
const [createOpen, setCreateOpen] = useState(false);
+ const { authStatus } = useAuth();
const { data: users, isLoading: usersLoading } = useAdminUsers();
const { data: dashboard } = useAdminDashboard();
@@ -205,7 +207,7 @@ export default function IAMPage() {
{getRelativeTime(user.created_at)}
-
+
|
))}
diff --git a/frontend/src/components/admin/UserActionsMenu.tsx b/frontend/src/components/admin/UserActionsMenu.tsx
index c2d8c43..a2318e0 100644
--- a/frontend/src/components/admin/UserActionsMenu.tsx
+++ b/frontend/src/components/admin/UserActionsMenu.tsx
@@ -30,6 +30,7 @@ import { cn } from '@/lib/utils';
interface UserActionsMenuProps {
user: AdminUserDetail;
+ currentUsername: string | null;
}
const ROLES: { value: UserRole; label: string }[] = [
@@ -38,7 +39,7 @@ const ROLES: { value: UserRole; label: string }[] = [
{ value: 'public_event_manager', label: 'Public Event Manager' },
];
-export default function UserActionsMenu({ user }: UserActionsMenuProps) {
+export default function UserActionsMenu({ user, currentUsername }: UserActionsMenuProps) {
const [open, setOpen] = useState(false);
const [roleSubmenuOpen, setRoleSubmenuOpen] = useState(false);
const [tempPassword, setTempPassword] = useState(null);
@@ -91,8 +92,14 @@ export default function UserActionsMenu({ user }: UserActionsMenuProps) {
handleAction(() => revokeSessions.mutateAsync(user.id), 'Sessions revoked');
});
- const deleteUserConfirm = useConfirmAction(() => {
- handleAction(() => deleteUser.mutateAsync(user.id), 'User permanently deleted');
+ const deleteUserConfirm = useConfirmAction(async () => {
+ try {
+ const result = await deleteUser.mutateAsync(user.id);
+ toast.success(`User '${(result as { deleted_username: string }).deleted_username}' permanently deleted`);
+ setOpen(false);
+ } catch (err) {
+ toast.error(getErrorMessage(err, 'Delete failed'));
+ }
});
const isLoading =
@@ -283,9 +290,11 @@ export default function UserActionsMenu({ user }: UserActionsMenuProps) {
{revokeSessionsConfirm.confirming ? 'Sure? Click to confirm' : 'Revoke All Sessions'}
+ {/* Delete User — hidden for own account */}
+ {currentUsername !== user.username && (
+ <>
- {/* Delete User — destructive, red two-click confirm */}
{deleteUserConfirm.confirming ? 'Sure? This is permanent' : 'Delete User'}
+ >
+ )}
)}
diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts
index 542e3d4..ba85daf 100644
--- a/frontend/src/types/index.ts
+++ b/frontend/src/types/index.ts
@@ -194,6 +194,7 @@ export interface AuthStatus {
authenticated: boolean;
setup_required: boolean;
role: UserRole | null;
+ username: string | null;
registration_open: boolean;
}