UX polish for delete-user: username toast, hide self-delete
S-03: Delete toast now shows the deleted username from the API response S-04: Delete button hidden for the current admin's own row (backend still guards with 403, but no reason to show a dead button) Adds username to auth status response so the frontend can identify the current user. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7cb6de7d5
commit
48e15fa677
@ -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,
|
||||
}
|
||||
|
||||
|
||||
@ -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)}
|
||||
</td>
|
||||
<td className="px-5 py-3 text-right">
|
||||
<UserActionsMenu user={user} />
|
||||
<UserActionsMenu user={user} currentUsername={authStatus?.username ?? null} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
|
||||
@ -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<string | null>(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'}
|
||||
</button>
|
||||
|
||||
{/* Delete User — hidden for own account */}
|
||||
{currentUsername !== user.username && (
|
||||
<>
|
||||
<div className="my-1 border-t border-border" />
|
||||
|
||||
{/* Delete User — destructive, red two-click confirm */}
|
||||
<button
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors',
|
||||
@ -298,6 +307,8 @@ export default function UserActionsMenu({ user }: UserActionsMenuProps) {
|
||||
<Trash2 className="h-4 w-4" />
|
||||
{deleteUserConfirm.confirming ? 'Sure? This is permanent' : 'Delete User'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -194,6 +194,7 @@ export interface AuthStatus {
|
||||
authenticated: boolean;
|
||||
setup_required: boolean;
|
||||
role: UserRole | null;
|
||||
username: string | null;
|
||||
registration_open: boolean;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user