@burdenoff/microfe-auth 2026.514.3 → 2026.514.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UsersPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/UsersPage.tsx"],"names":[],"mappings":"AA6CA;;GAEG;AACH,wBAAgB,SAAS,
|
|
1
|
+
{"version":3,"file":"UsersPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/UsersPage.tsx"],"names":[],"mappings":"AA6CA;;GAEG;AACH,wBAAgB,SAAS,4CAw0CxB"}
|
|
@@ -3,10 +3,10 @@ import { useUserOperations as t } from "../hooks/useUserOperations.js";
|
|
|
3
3
|
import { useAuthPermissions as n } from "../hooks/useAuthPermissions.js";
|
|
4
4
|
import "../hooks/index.js";
|
|
5
5
|
import { AlertIcon as r, SpinnerIcon as i } from "../components/AuthIcons.js";
|
|
6
|
-
import { ConfirmActionDialog as
|
|
7
|
-
import { nativeImpact as
|
|
8
|
-
import { useCallback as
|
|
9
|
-
import { useNavigate as
|
|
6
|
+
import { ConfirmActionDialog as a } from "../components/ConfirmActionDialog.js";
|
|
7
|
+
import { nativeImpact as o, nativeNotify as s } from "../../utils/nativeBridge.js";
|
|
8
|
+
import { useCallback as ee, useEffect as te, useId as c, useState as l } from "react";
|
|
9
|
+
import { useNavigate as ne } from "react-router-dom";
|
|
10
10
|
import { useI18n as re } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
11
11
|
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
12
12
|
//#region src/auth/pages/UsersPage.tsx
|
|
@@ -24,19 +24,55 @@ var p = [
|
|
|
24
24
|
"DELETED"
|
|
25
25
|
];
|
|
26
26
|
function h() {
|
|
27
|
-
let h =
|
|
27
|
+
let h = ne(), { t: ie } = re(), g = (e, t) => {
|
|
28
28
|
let n = ie(e);
|
|
29
29
|
return n === e ? t : n;
|
|
30
|
-
}, _ = e((e) => e.isAuthenticated), v = e((e) => e.user), { canViewUsers: ae, canUpdateUsers: oe, canDeleteUsers: y, isLoading: se } = n(), { listUsers: b, updateUser: ce, deleteUser: le, hardDeleteUser: ue, isLoading: x } = t(), S =
|
|
30
|
+
}, _ = e((e) => e.isAuthenticated), v = e((e) => e.user), { canViewUsers: ae, canUpdateUsers: oe, canDeleteUsers: y, isLoading: se } = n(), { listUsers: b, updateUser: ce, deleteUser: le, hardDeleteUser: ue, isLoading: x } = t(), S = c(), C = c(), w = c(), T = c(), de = c(), [E, D] = l(!1), fe = async () => {
|
|
31
31
|
D(!0);
|
|
32
32
|
try {
|
|
33
|
-
|
|
33
|
+
let e = {};
|
|
34
|
+
U && (e.search = U), W && (e.role = W), G && (e.status = G);
|
|
35
|
+
let t = (await b(e, {
|
|
36
|
+
offset: 0,
|
|
37
|
+
limit: 1e4
|
|
38
|
+
})).users, n = [
|
|
39
|
+
"ID",
|
|
40
|
+
"Email",
|
|
41
|
+
"Username",
|
|
42
|
+
"First Name",
|
|
43
|
+
"Last Name",
|
|
44
|
+
"Phone",
|
|
45
|
+
"Role",
|
|
46
|
+
"Status",
|
|
47
|
+
"Email Verified",
|
|
48
|
+
"MFA Enabled",
|
|
49
|
+
"Last Login",
|
|
50
|
+
"Created At"
|
|
51
|
+
], r = (e) => {
|
|
52
|
+
if (e == null) return "";
|
|
53
|
+
let t = String(e);
|
|
54
|
+
return t.includes(",") || t.includes("\"") || t.includes("\n") ? `"${t.replace(/"/g, "\"\"")}"` : t;
|
|
55
|
+
}, i = [n.join(","), ...t.map((e) => [
|
|
56
|
+
r(e.id),
|
|
57
|
+
r(e.email),
|
|
58
|
+
r(e.username),
|
|
59
|
+
r(e.firstName),
|
|
60
|
+
r(e.lastName),
|
|
61
|
+
r(e.phoneNumber),
|
|
62
|
+
r(e.role),
|
|
63
|
+
r(e.status),
|
|
64
|
+
r(String(e.emailVerified)),
|
|
65
|
+
r(String(e.mfaEnabled)),
|
|
66
|
+
r(e.lastLoginAt),
|
|
67
|
+
r(e.createdAt)
|
|
68
|
+
].join(","))], a = new Blob([i.join("\n")], { type: "text/csv;charset=utf-8;" }), o = URL.createObjectURL(a), s = document.createElement("a");
|
|
69
|
+
s.href = o, s.download = `users-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`, s.click(), URL.revokeObjectURL(o);
|
|
34
70
|
} catch (e) {
|
|
35
|
-
L(e instanceof Error ? e.message : "Failed to
|
|
71
|
+
L(e instanceof Error ? e.message : "Failed to export users");
|
|
36
72
|
} finally {
|
|
37
73
|
D(!1);
|
|
38
74
|
}
|
|
39
|
-
}, [O, pe] =
|
|
75
|
+
}, [O, pe] = l([]), [k, me] = l(0), [he, ge] = l(!1), [A, j] = l("list"), [M, N] = l(null), [P, F] = l({
|
|
40
76
|
username: "",
|
|
41
77
|
firstName: "",
|
|
42
78
|
lastName: "",
|
|
@@ -45,7 +81,7 @@ function h() {
|
|
|
45
81
|
role: "MEMBER",
|
|
46
82
|
status: "ACTIVE",
|
|
47
83
|
emailVerified: !1
|
|
48
|
-
}), [I, L] =
|
|
84
|
+
}), [I, L] = l(null), [_e, R] = l(!1), [z, B] = l(null), [V, H] = l(null), [U, ve] = l(""), [W, ye] = l(""), [G, be] = l(""), [K, q] = l(0), J = ee(async () => {
|
|
49
85
|
if (_) try {
|
|
50
86
|
R(!1);
|
|
51
87
|
let e = {};
|
|
@@ -68,7 +104,7 @@ function h() {
|
|
|
68
104
|
K,
|
|
69
105
|
_
|
|
70
106
|
]);
|
|
71
|
-
|
|
107
|
+
te(() => {
|
|
72
108
|
J();
|
|
73
109
|
}, [J]);
|
|
74
110
|
let Y = () => {
|
|
@@ -101,12 +137,12 @@ function h() {
|
|
|
101
137
|
}
|
|
102
138
|
}
|
|
103
139
|
}, Se = async (e) => {
|
|
104
|
-
|
|
140
|
+
o("medium");
|
|
105
141
|
try {
|
|
106
142
|
let t = await le(e.id);
|
|
107
|
-
t.success ? (
|
|
143
|
+
t.success ? (s("success"), B(g("auth.users.userDeactivated", `User "${e.email}" has been deactivated.`)), H(null), J()) : (s("error"), L(t.message));
|
|
108
144
|
} catch (e) {
|
|
109
|
-
|
|
145
|
+
s("error"), L(e instanceof Error ? e.message : "Failed to delete user");
|
|
110
146
|
}
|
|
111
147
|
}, Ce = async (e) => {
|
|
112
148
|
try {
|
|
@@ -126,7 +162,7 @@ function h() {
|
|
|
126
162
|
status: e.status,
|
|
127
163
|
emailVerified: e.emailVerified
|
|
128
164
|
}), j("edit"), L(null);
|
|
129
|
-
}, Z = /* @__PURE__ */ d(
|
|
165
|
+
}, Z = /* @__PURE__ */ d(a, {
|
|
130
166
|
open: V !== null,
|
|
131
167
|
onOpenChange: (e) => {
|
|
132
168
|
e || H(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UsersPage.js","names":[],"sources":["../../../src/auth/pages/UsersPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useId } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuthPermissions, useUserOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport type {\n User,\n UserRole,\n UserStatus,\n UserFilterInput,\n PaginationInput,\n} from \"../types\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\ntype ViewMode = \"list\" | \"edit\" | \"view\";\n\ninterface FormData {\n username: string;\n firstName: string;\n lastName: string;\n name: string;\n phoneNumber: string;\n role: UserRole;\n status: UserStatus;\n emailVerified: boolean;\n}\n\nconst USER_ROLES: UserRole[] = [\n \"SUPER_ADMIN\",\n \"TENANT_ADMIN\",\n \"ORG_ADMIN\",\n \"WORKSPACE_ADMIN\",\n \"MEMBER\",\n \"GUEST\",\n];\n\nconst USER_STATUSES: UserStatus[] = [\n \"ACTIVE\",\n \"INACTIVE\",\n \"SUSPENDED\",\n \"DELETED\",\n];\n\n/**\n * Users CRUDL page for managing users (admin only)\n */\nexport function UsersPage() {\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const currentUser = useAuthStore((state) => state.user);\n const {\n canViewUsers,\n canUpdateUsers,\n canDeleteUsers,\n isLoading: permissionsLoading,\n } = useAuthPermissions();\n const { listUsers, updateUser, deleteUser, hardDeleteUser, isLoading } =\n useUserOperations();\n\n // Stable IDs for ARIA associations (accessibility)\n const searchId = useId();\n const roleFilterId = useId();\n const statusFilterId = useId();\n const errorId = useId();\n const successId = useId();\n\n const [isExporting, setIsExporting] = useState(false);\n\n const handleExport = async () => {\n setIsExporting(true);\n try {\n // Export logic placeholder — integrate with export service when available\n await new Promise<void>((resolve) => setTimeout(resolve, 500));\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to start export\");\n } finally {\n setIsExporting(false);\n }\n };\n\n const [users, setUsers] = useState<User[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [viewMode, setViewMode] = useState<ViewMode>(\"list\");\n const [selectedUser, setSelectedUser] = useState<User | null>(null);\n const [formData, setFormData] = useState<FormData>({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n role: \"MEMBER\",\n status: \"ACTIVE\",\n emailVerified: false,\n });\n const [error, setError] = useState<string | null>(null);\n const [isUnauthorized, setIsUnauthorized] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [pendingAction, setPendingAction] = useState<{\n type: \"deactivate\" | \"hard-delete\";\n user: User;\n } | null>(null);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [filterRole, setFilterRole] = useState<UserRole | \"\">(\"\");\n const [filterStatus, setFilterStatus] = useState<UserStatus | \"\">(\"\");\n const [currentPage, setCurrentPage] = useState(0);\n const pageSize = 10;\n\n const fetchUsers = useCallback(async () => {\n if (!isAuthenticated) return;\n\n try {\n setIsUnauthorized(false);\n const filter: UserFilterInput = {};\n if (searchQuery) filter.search = searchQuery;\n if (filterRole) filter.role = filterRole;\n if (filterStatus) filter.status = filterStatus;\n\n const pagination: PaginationInput = {\n offset: currentPage * pageSize,\n limit: pageSize,\n };\n\n const result = await listUsers(filter, pagination);\n setUsers(result.users);\n setTotalCount(result.totalCount);\n setHasMore(result.hasMore);\n setError(null);\n } catch (err) {\n // Ignore abort errors - they happen during component unmount/re-render\n if (\n err instanceof Error &&\n (err.name === \"AbortError\" || err.message.includes(\"aborted\"))\n ) {\n return;\n }\n const errorMessage =\n err instanceof Error ? err.message : \"Failed to fetch users\";\n // Check if it's an authorization error\n if (\n errorMessage.toLowerCase().includes(\"not authorized\") ||\n errorMessage.toLowerCase().includes(\"forbidden\")\n ) {\n setIsUnauthorized(true);\n setError(null);\n } else {\n setError(errorMessage);\n }\n }\n }, [\n listUsers,\n searchQuery,\n filterRole,\n filterStatus,\n currentPage,\n isAuthenticated,\n ]);\n\n useEffect(() => {\n fetchUsers();\n }, [fetchUsers]);\n\n const resetForm = () => {\n setFormData({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n role: \"MEMBER\",\n status: \"ACTIVE\",\n emailVerified: false,\n });\n setSelectedUser(null);\n setError(null);\n setSuccessMessage(null);\n };\n\n const handleUpdate = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!selectedUser) return;\n setError(null);\n\n try {\n await updateUser(selectedUser.id, {\n username: formData.username || undefined,\n firstName: formData.firstName || undefined,\n lastName: formData.lastName || undefined,\n name: formData.name || undefined,\n phoneNumber: formData.phoneNumber || undefined,\n role: formData.role,\n status: formData.status,\n emailVerified: formData.emailVerified,\n });\n setSuccessMessage(\n tr(\"auth.users.updateSuccess\", \"User updated successfully!\"),\n );\n setViewMode(\"list\");\n resetForm();\n fetchUsers();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to update user\");\n }\n };\n\n const handleDelete = async (user: User) => {\n void nativeImpact(\"medium\");\n try {\n const result = await deleteUser(user.id);\n if (result.success) {\n void nativeNotify(\"success\");\n setSuccessMessage(\n tr(\n \"auth.users.userDeactivated\",\n `User \"${user.email}\" has been deactivated.`,\n ),\n );\n setPendingAction(null);\n fetchUsers();\n } else {\n void nativeNotify(\"error\");\n setError(result.message);\n }\n } catch (err) {\n void nativeNotify(\"error\");\n setError(err instanceof Error ? err.message : \"Failed to delete user\");\n }\n };\n\n const handleHardDelete = async (user: User) => {\n try {\n const result = await hardDeleteUser(user.id);\n if (result.success) {\n setSuccessMessage(\n tr(\n \"auth.users.userPermanentlyDeleted\",\n `User \"${user.email}\" has been permanently deleted.`,\n ),\n );\n setPendingAction(null);\n fetchUsers();\n } else {\n setError(result.message);\n }\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to hard delete user\",\n );\n }\n };\n\n const startEdit = (user: User) => {\n setSelectedUser(user);\n setFormData({\n username: user.username || \"\",\n firstName: user.firstName || \"\",\n lastName: user.lastName || \"\",\n name: user.name || \"\",\n phoneNumber: user.phoneNumber || \"\",\n role: user.role,\n status: user.status,\n emailVerified: user.emailVerified,\n });\n setViewMode(\"edit\");\n setError(null);\n };\n\n const pendingActionDialog = (\n <ConfirmActionDialog\n open={pendingAction !== null}\n onOpenChange={(open) => {\n if (!open) {\n setPendingAction(null);\n }\n }}\n title={\n pendingAction?.type === \"hard-delete\"\n ? tr(\"auth.users.hardDeleteTitle\", \"Permanently delete user?\")\n : tr(\"auth.users.deactivateTitle\", \"Deactivate user?\")\n }\n description={\n pendingAction?.type === \"hard-delete\"\n ? pendingAction\n ? tr(\n \"auth.users.hardDeleteDesc\",\n `This permanently deletes \"${pendingAction.user.email}\" and cannot be undone.`,\n )\n : \"\"\n : pendingAction\n ? tr(\n \"auth.users.deactivateDesc\",\n `\"${pendingAction.user.email}\" will be prevented from signing in until reactivated.`,\n )\n : \"\"\n }\n confirmText={\n pendingAction?.type === \"hard-delete\"\n ? tr(\"auth.users.hardDeleteConfirm\", \"Delete permanently\")\n : tr(\"auth.users.deactivateConfirm\", \"Deactivate user\")\n }\n variant={pendingAction?.type === \"hard-delete\" ? \"danger\" : \"warning\"}\n onConfirm={async () => {\n if (!pendingAction) return;\n if (pendingAction.type === \"hard-delete\") {\n await handleHardDelete(pendingAction.user);\n return;\n }\n await handleDelete(pendingAction.user);\n }}\n />\n );\n\n const getRoleColor = (role: UserRole) => {\n switch (role) {\n case \"SUPER_ADMIN\":\n return \"bg-accent-purple-subtle text-accent-purple\";\n case \"TENANT_ADMIN\":\n return \"bg-status-info-bg-subtle text-status-info-text\";\n case \"ORG_ADMIN\":\n return \"bg-accent-indigo-subtle text-accent-indigo\";\n case \"WORKSPACE_ADMIN\":\n return \"bg-accent-cyan-subtle text-accent-cyan\";\n case \"MEMBER\":\n return \"bg-status-success-bg-subtle text-status-success-text\";\n case \"GUEST\":\n return \"bg-bg-sunken text-text-primary\";\n default:\n return \"bg-bg-sunken text-text-primary\";\n }\n };\n\n const getStatusColor = (status: UserStatus) => {\n switch (status) {\n case \"ACTIVE\":\n return \"bg-status-success-bg-subtle text-status-success-text\";\n case \"INACTIVE\":\n return \"bg-status-warning-bg-subtle text-status-warning-text\";\n case \"SUSPENDED\":\n return \"bg-status-warning-bg-subtle text-status-warning-text\";\n case \"DELETED\":\n return \"bg-status-error-bg-subtle text-status-error-text\";\n default:\n return \"bg-bg-sunken text-text-primary\";\n }\n };\n\n // Authentication check\n if (!isAuthenticated) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-status-warning-text\" />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\"auth.users.signInToManage\", \"Please sign in to manage users\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Role-based guard — only admin roles may access this page\n const ALLOWED_ROLES: UserRole[] = [\n \"SUPER_ADMIN\",\n \"TENANT_ADMIN\",\n \"ORG_ADMIN\",\n ];\n if (currentUser && !ALLOWED_ROLES.includes(currentUser.role)) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636\"\n />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\n \"auth.users.notAllowed\",\n \"You are not allowed to access this page\",\n )}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.users.notAllowedDesc\",\n \"This page is restricted to administrators only. Contact your admin if you need access.\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading permissions\n if (permissionsLoading) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16\">\n <SpinnerIcon className=\"w-8 h-8 mx-auto text-text-secondary animate-spin\" />\n <p className=\"mt-4 text-text-secondary\">\n {tr(\"auth.users.loadingPermissions\", \"Loading permissions...\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Authorization check - user needs user:read permission\n if (!canViewUsers || isUnauthorized) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636\"\n />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.adminAccessRequired\", \"Admin Access Required\")}\n </h2>\n <p className=\"text-text-secondary mb-4\">\n {tr(\n \"auth.users.adminAccessDesc\",\n \"You need administrator privileges to view and manage users.\",\n )}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.users.requiredRoles\",\n \"Required roles: Super Admin, Tenant Admin, or Org Admin\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // List view\n if (viewMode === \"list\") {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n {pendingActionDialog}\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div>\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.users.title\", \"Users\")}\n </h1>\n <p className=\"text-text-secondary mt-2\">\n {tr(\"auth.users.subtitle\", \"Manage users in your organization\")} (\n {totalCount} {tr(\"auth.users.paginationUsers\", \"total\")})\n </p>\n </div>\n {/* Export button */}\n <button\n type=\"button\"\n onClick={() => void handleExport()}\n disabled={isExporting}\n aria-label={tr(\"auth.users.exportAriaLabel\", \"Export user list\")}\n className=\"flex items-center gap-2 px-4 py-2.5 rounded-xl border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {isExporting ? (\n <>\n <SpinnerIcon\n className=\"w-4 h-4 animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\"auth.users.exporting\", \"Exporting...\")}\n </>\n ) : (\n <>\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n {tr(\"auth.users.export\", \"Export\")}\n </>\n )}\n </button>\n </div>\n\n {/* Live region for status announcements */}\n <div aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {successMessage}\n </div>\n <div\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {error}\n </div>\n\n {/* Success Message */}\n {successMessage && (\n <div\n id={successId}\n role=\"status\"\n className=\"mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\"\n >\n <p className=\"text-status-success-text\">{successMessage}</p>\n <button\n type=\"button\"\n onClick={() => setSuccessMessage(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline\"\n >\n {tr(\"auth.users.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div\n id={errorId}\n role=\"alert\"\n className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\n <AlertIcon\n className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline\"\n >\n {tr(\"auth.users.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"mb-6 p-4 rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"flex flex-wrap gap-4 items-end\">\n {/* Visually hidden labels satisfy WCAG — placeholders are not labels */}\n <div className=\"flex-1 min-w-[200px]\">\n <label htmlFor={searchId} className=\"sr-only\">\n {tr(\"auth.users.searchLabel\", \"Search users\")}\n </label>\n <input\n id={searchId}\n type=\"search\"\n placeholder={tr(\n \"auth.users.searchPlaceholder\",\n \"Search by email, username, or name...\",\n )}\n value={searchQuery}\n onChange={(e) => {\n setSearchQuery(e.target.value);\n setCurrentPage(0);\n }}\n className=\"w-full px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n <div>\n <label htmlFor={roleFilterId} className=\"sr-only\">\n {tr(\"auth.users.filterRoleLabel\", \"Filter by role\")}\n </label>\n <select\n id={roleFilterId}\n value={filterRole}\n onChange={(e) => {\n setFilterRole(e.target.value as UserRole | \"\");\n setCurrentPage(0);\n }}\n className=\"px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"\">\n {tr(\"auth.users.allRoles\", \"All Roles\")}\n </option>\n {USER_ROLES.map((role) => (\n <option key={role} value={role}>\n {role.replace(\"_\", \" \")}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor={statusFilterId} className=\"sr-only\">\n {tr(\"auth.users.filterStatusLabel\", \"Filter by status\")}\n </label>\n <select\n id={statusFilterId}\n value={filterStatus}\n onChange={(e) => {\n setFilterStatus(e.target.value as UserStatus | \"\");\n setCurrentPage(0);\n }}\n className=\"px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"\">\n {tr(\"auth.users.allStatuses\", \"All Statuses\")}\n </option>\n {USER_STATUSES.map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n\n {isLoading ? (\n <div\n aria-live=\"polite\"\n aria-busy=\"true\"\n className=\"flex items-center justify-center py-12\"\n >\n <SpinnerIcon\n className=\"w-8 h-8 text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.users.loadingUsers\", \"Loading users...\")}\n </span>\n </div>\n ) : users.length === 0 ? (\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-bg-sunken flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z\"\n />\n </svg>\n </div>\n <p className=\"text-text-secondary\">\n {tr(\"auth.users.noUsersFound\", \"No users found\")}\n </p>\n </div>\n ) : (\n <>\n {/* Users Table */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface overflow-hidden shadow-sm\">\n <div className=\"overflow-x-auto\">\n <table\n className=\"w-full min-w-[800px]\"\n aria-label={tr(\"auth.users.tableAriaLabel\", \"Users table\")}\n >\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-canvas\">\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[280px]\"\n >\n {tr(\"auth.users.columnUser\", \"User\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[130px]\"\n >\n {tr(\"auth.users.columnRole\", \"Role\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[100px]\"\n >\n {tr(\"auth.users.columnStatus\", \"Status\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[80px]\"\n >\n {tr(\"auth.users.columnVerified\", \"Verified\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[100px]\"\n >\n {tr(\"auth.users.columnLastLogin\", \"Last Login\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-right py-4 px-4 text-sm font-medium text-text-secondary w-[180px]\"\n >\n {tr(\"auth.users.columnActions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {users.map((user) => (\n <tr\n key={user.id}\n className=\"border-b border-border-subtle last:border-b-0 hover:bg-bg-sunken/50 transition-colors\"\n >\n <td className=\"py-4 px-4\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"auth-brand-badge flex h-10 w-10 shrink-0 items-center justify-center rounded-full font-medium\">\n {(user.name || user.username || user.email)\n .charAt(0)\n .toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-text-primary truncate\">\n {user.name || user.username}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">\n {user.email}\n </p>\n </div>\n </div>\n </td>\n <td className=\"py-4 px-4\">\n <span\n className={`inline-block px-2.5 py-1 rounded-full text-xs font-medium whitespace-nowrap ${getRoleColor(user.role)}`}\n >\n {user.role.replace(\"_\", \" \")}\n </span>\n </td>\n <td className=\"py-4 px-4\">\n <span\n className={`inline-block px-2.5 py-1 rounded-full text-xs font-medium whitespace-nowrap ${getStatusColor(user.status)}`}\n >\n {user.status}\n </span>\n </td>\n <td className=\"py-4 px-4\">\n {user.emailVerified ? (\n <span className=\"inline-flex items-center gap-1 text-status-success-text whitespace-nowrap\">\n <svg\n className=\"w-4 h-4 flex-shrink-0\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <span className=\"text-sm\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-status-warning-text whitespace-nowrap\">\n <svg\n className=\"w-4 h-4 flex-shrink-0\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <span className=\"text-sm\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n </span>\n )}\n </td>\n <td className=\"py-4 px-4 text-sm text-text-secondary whitespace-nowrap\">\n {user.lastLoginAt\n ? new Date(user.lastLoginAt).toLocaleDateString()\n : tr(\"auth.users.lastLoginNever\", \"Never\")}\n </td>\n <td className=\"py-4 px-4\">\n <div className=\"flex justify-end gap-1.5 flex-nowrap\">\n <button\n type=\"button\"\n onClick={() => navigate(`/auth/users/${user.id}`)}\n aria-label={`${tr(\"auth.users.actionView\", \"View\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionView\", \"View\")}\n </button>\n {canUpdateUsers && (\n <button\n type=\"button\"\n onClick={() => startEdit(user)}\n aria-label={`${tr(\"auth.users.actionEdit\", \"Edit\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-status-info-border text-text-link bg-bg-surface hover:bg-status-info-bg-subtle transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionEdit\", \"Edit\")}\n </button>\n )}\n {canDeleteUsers && user.status !== \"DELETED\" && (\n <button\n type=\"button\"\n onClick={() =>\n setPendingAction({ type: \"deactivate\", user })\n }\n aria-label={`${tr(\"auth.users.actionDelete\", \"Delete\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-status-error-border text-status-error-text bg-bg-surface hover:bg-status-error-bg-subtle transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionDelete\", \"Delete\")}\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n\n {/* Pagination */}\n <div className=\"mt-6 flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"auth.users.showing\", \"Showing\")}{\" \"}\n {currentPage * pageSize + 1} {tr(\"auth.users.to\", \"to\")}{\" \"}\n {Math.min((currentPage + 1) * pageSize, totalCount)}{\" \"}\n {tr(\"auth.users.of\", \"of\")} {totalCount}{\" \"}\n {tr(\"auth.users.paginationUsers\", \"users\")}\n </p>\n <nav\n aria-label={tr(\n \"auth.users.paginationAriaLabel\",\n \"User list pagination\",\n )}\n >\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() =>\n setCurrentPage((prev) => Math.max(0, prev - 1))\n }\n disabled={currentPage === 0}\n aria-label={tr(\n \"auth.users.previousPageAriaLabel\",\n \"Go to previous page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.previousPage\", \"Previous\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setCurrentPage((prev) => prev + 1)}\n disabled={!hasMore}\n aria-label={tr(\n \"auth.users.nextPageAriaLabel\",\n \"Go to next page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.nextPage\", \"Next\")}\n </button>\n </div>\n </nav>\n </div>\n </>\n )}\n </div>\n );\n }\n\n // View details\n if (viewMode === \"view\" && selectedUser) {\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {pendingActionDialog}\n <button\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"mb-6 flex items-center gap-2 text-text-link hover:underline font-medium\"\n >\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\"auth.users.backToUsers\", \"Back to Users\")}\n </button>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <div className=\"flex items-center gap-4 mb-8\">\n <div className=\"auth-brand-badge flex h-20 w-20 items-center justify-center rounded-full text-3xl font-semibold\">\n {(\n selectedUser.name ||\n selectedUser.username ||\n selectedUser.email\n )\n .charAt(0)\n .toUpperCase()}\n </div>\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {selectedUser.name || selectedUser.username}\n </h1>\n <p className=\"text-text-secondary\">{selectedUser.email}</p>\n <div className=\"flex items-center gap-2 mt-2\">\n <span\n className={`px-2.5 py-1 rounded-full text-xs font-medium ${getRoleColor(selectedUser.role)}`}\n >\n {selectedUser.role.replace(\"_\", \" \")}\n </span>\n <span\n className={`px-2.5 py-1 rounded-full text-xs font-medium ${getStatusColor(selectedUser.status)}`}\n >\n {selectedUser.status}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-6\">\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsUsername\", \"Username\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.username}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsEmail\", \"Email\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.email}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsEmailVerified\", \"Email Verified\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.emailVerified ? (\n <span className=\"text-status-success-text\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n ) : (\n <span className=\"text-status-warning-text\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsMfaEnabled\", \"MFA Enabled\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.mfaEnabled ? (\n <span className=\"text-status-success-text\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n ) : (\n <span className=\"text-text-secondary\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n )}\n </p>\n </div>\n\n {selectedUser.phoneNumber && (\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsPhoneNumber\", \"Phone Number\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.phoneNumber}\n </p>\n </div>\n )}\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsLastLogin\", \"Last Login\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.lastLoginAt\n ? new Date(selectedUser.lastLoginAt).toLocaleString()\n : tr(\"auth.users.lastLoginNever\", \"Never\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsCreated\", \"Created\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {new Date(selectedUser.createdAt).toLocaleString()}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsLastUpdated\", \"Last Updated\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {new Date(selectedUser.updatedAt).toLocaleString()}\n </p>\n </div>\n </div>\n\n <div className=\"mt-8 pt-6 border-t border-border-subtle flex gap-3\">\n <button\n onClick={() => startEdit(selectedUser)}\n className=\"auth-primary-button px-4 py-2.5 font-medium\"\n >\n {tr(\"auth.users.editUser\", \"Edit User\")}\n </button>\n {selectedUser.status !== \"DELETED\" && (\n <button\n onClick={() =>\n setPendingAction({ type: \"deactivate\", user: selectedUser })\n }\n className=\"px-4 py-2.5 rounded-xl border border-status-error-border text-status-error-text font-medium hover:bg-status-error-bg-subtle transition-colors\"\n >\n {tr(\"auth.users.deleteUser\", \"Delete User\")}\n </button>\n )}\n {canDeleteUsers &&\n selectedUser.status === \"DELETED\" &&\n currentUser?.role === \"SUPER_ADMIN\" && (\n <button\n onClick={() =>\n setPendingAction({\n type: \"hard-delete\",\n user: selectedUser,\n })\n }\n className=\"px-4 py-2.5 rounded-xl bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover transition-colors\"\n >\n {tr(\"auth.users.permanentlyDelete\", \"Permanently Delete\")}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n // Edit form\n return (\n <div className=\"max-w-2xl mx-auto p-6\">\n {pendingActionDialog}\n <button\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"mb-6 flex items-center gap-2 text-text-link hover:underline font-medium\"\n >\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\"auth.users.backToUsers\", \"Back to Users\")}\n </button>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <h1 className=\"text-2xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.editUser\", \"Edit User\")}\n </h1>\n\n {selectedUser && (\n <p className=\"text-text-secondary mb-6\">\n {tr(\"auth.users.editingUser\", \"Editing:\")}{\" \"}\n <strong>{selectedUser.email}</strong>\n </p>\n )}\n\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n </div>\n </div>\n )}\n\n <form\n onSubmit={handleUpdate}\n className=\"space-y-6\"\n aria-describedby={error ? errorId : undefined}\n noValidate\n >\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-username\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldUsername\", \"Username\")}\n </label>\n <input\n id=\"edit-username\"\n type=\"text\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"edit-name\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldName\", \"Name\")}\n </label>\n <input\n id=\"edit-name\"\n type=\"text\"\n value={formData.name}\n onChange={(e) =>\n setFormData({ ...formData, name: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-firstName\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldFirstName\", \"First Name\")}\n </label>\n <input\n id=\"edit-firstName\"\n type=\"text\"\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"edit-lastName\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldLastName\", \"Last Name\")}\n </label>\n <input\n id=\"edit-lastName\"\n type=\"text\"\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n </div>\n\n <div>\n <label\n htmlFor=\"edit-phoneNumber\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldPhoneNumber\", \"Phone Number\")}\n </label>\n <input\n id=\"edit-phoneNumber\"\n type=\"tel\"\n value={formData.phoneNumber}\n onChange={(e) =>\n setFormData({ ...formData, phoneNumber: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-role\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldRole\", \"Role\")}\n </label>\n <select\n id=\"edit-role\"\n value={formData.role}\n onChange={(e) =>\n setFormData({ ...formData, role: e.target.value as UserRole })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n {USER_ROLES.map((role) => (\n <option key={role} value={role}>\n {role.replace(\"_\", \" \")}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label\n htmlFor=\"edit-status\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldStatus\", \"Status\")}\n </label>\n <select\n id=\"edit-status\"\n value={formData.status}\n onChange={(e) =>\n setFormData({\n ...formData,\n status: e.target.value as UserStatus,\n })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n {USER_STATUSES.map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 p-4 rounded-xl bg-bg-canvas/50\">\n <input\n type=\"checkbox\"\n id=\"emailVerified\"\n checked={formData.emailVerified}\n onChange={(e) =>\n setFormData({ ...formData, emailVerified: e.target.checked })\n }\n className=\"w-5 h-5 rounded border-border-default text-text-link focus:ring-action-primary-bg\"\n />\n <label\n htmlFor=\"emailVerified\"\n className=\"text-sm font-medium text-text-primary\"\n >\n {tr(\"auth.users.fieldEmailVerified\", \"Email Verified\")}\n </label>\n </div>\n\n <div className=\"flex gap-3 pt-4\">\n <button\n type=\"submit\"\n disabled={isLoading}\n className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-4 h-4 animate-spin\" />\n {tr(\"auth.users.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.users.saveChanges\", \"Save Changes\")\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UsersPage.js","names":[],"sources":["../../../src/auth/pages/UsersPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useId } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuthPermissions, useUserOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { ConfirmActionDialog } from \"../components/ConfirmActionDialog\";\nimport type {\n User,\n UserRole,\n UserStatus,\n UserFilterInput,\n PaginationInput,\n} from \"../types\";\nimport { SpinnerIcon, AlertIcon } from \"../components/AuthIcons\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\ntype ViewMode = \"list\" | \"edit\" | \"view\";\n\ninterface FormData {\n username: string;\n firstName: string;\n lastName: string;\n name: string;\n phoneNumber: string;\n role: UserRole;\n status: UserStatus;\n emailVerified: boolean;\n}\n\nconst USER_ROLES: UserRole[] = [\n \"SUPER_ADMIN\",\n \"TENANT_ADMIN\",\n \"ORG_ADMIN\",\n \"WORKSPACE_ADMIN\",\n \"MEMBER\",\n \"GUEST\",\n];\n\nconst USER_STATUSES: UserStatus[] = [\n \"ACTIVE\",\n \"INACTIVE\",\n \"SUSPENDED\",\n \"DELETED\",\n];\n\n/**\n * Users CRUDL page for managing users (admin only)\n */\nexport function UsersPage() {\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const currentUser = useAuthStore((state) => state.user);\n const {\n canViewUsers,\n canUpdateUsers,\n canDeleteUsers,\n isLoading: permissionsLoading,\n } = useAuthPermissions();\n const { listUsers, updateUser, deleteUser, hardDeleteUser, isLoading } =\n useUserOperations();\n\n // Stable IDs for ARIA associations (accessibility)\n const searchId = useId();\n const roleFilterId = useId();\n const statusFilterId = useId();\n const errorId = useId();\n const successId = useId();\n\n const [isExporting, setIsExporting] = useState(false);\n\n const handleExport = async () => {\n setIsExporting(true);\n try {\n const filter: UserFilterInput = {};\n if (searchQuery) filter.search = searchQuery;\n if (filterRole) filter.role = filterRole;\n if (filterStatus) filter.status = filterStatus;\n\n const result = await listUsers(filter, { offset: 0, limit: 10000 });\n const rows = result.users;\n\n const headers = [\n \"ID\",\n \"Email\",\n \"Username\",\n \"First Name\",\n \"Last Name\",\n \"Phone\",\n \"Role\",\n \"Status\",\n \"Email Verified\",\n \"MFA Enabled\",\n \"Last Login\",\n \"Created At\",\n ];\n\n const escape = (v: string | undefined | null) => {\n if (v == null) return \"\";\n const s = String(v);\n return s.includes(\",\") || s.includes('\"') || s.includes(\"\\n\")\n ? `\"${s.replace(/\"/g, '\"\"')}\"`\n : s;\n };\n\n const lines = [\n headers.join(\",\"),\n ...rows.map((u) =>\n [\n escape(u.id),\n escape(u.email),\n escape(u.username),\n escape(u.firstName),\n escape(u.lastName),\n escape(u.phoneNumber),\n escape(u.role),\n escape(u.status),\n escape(String(u.emailVerified)),\n escape(String(u.mfaEnabled)),\n escape(u.lastLoginAt),\n escape(u.createdAt),\n ].join(\",\"),\n ),\n ];\n\n const blob = new Blob([lines.join(\"\\n\")], {\n type: \"text/csv;charset=utf-8;\",\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `users-${new Date().toISOString().slice(0, 10)}.csv`;\n a.click();\n URL.revokeObjectURL(url);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to export users\");\n } finally {\n setIsExporting(false);\n }\n };\n\n const [users, setUsers] = useState<User[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [viewMode, setViewMode] = useState<ViewMode>(\"list\");\n const [selectedUser, setSelectedUser] = useState<User | null>(null);\n const [formData, setFormData] = useState<FormData>({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n role: \"MEMBER\",\n status: \"ACTIVE\",\n emailVerified: false,\n });\n const [error, setError] = useState<string | null>(null);\n const [isUnauthorized, setIsUnauthorized] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [pendingAction, setPendingAction] = useState<{\n type: \"deactivate\" | \"hard-delete\";\n user: User;\n } | null>(null);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [filterRole, setFilterRole] = useState<UserRole | \"\">(\"\");\n const [filterStatus, setFilterStatus] = useState<UserStatus | \"\">(\"\");\n const [currentPage, setCurrentPage] = useState(0);\n const pageSize = 10;\n\n const fetchUsers = useCallback(async () => {\n if (!isAuthenticated) return;\n\n try {\n setIsUnauthorized(false);\n const filter: UserFilterInput = {};\n if (searchQuery) filter.search = searchQuery;\n if (filterRole) filter.role = filterRole;\n if (filterStatus) filter.status = filterStatus;\n\n const pagination: PaginationInput = {\n offset: currentPage * pageSize,\n limit: pageSize,\n };\n\n const result = await listUsers(filter, pagination);\n setUsers(result.users);\n setTotalCount(result.totalCount);\n setHasMore(result.hasMore);\n setError(null);\n } catch (err) {\n // Ignore abort errors - they happen during component unmount/re-render\n if (\n err instanceof Error &&\n (err.name === \"AbortError\" || err.message.includes(\"aborted\"))\n ) {\n return;\n }\n const errorMessage =\n err instanceof Error ? err.message : \"Failed to fetch users\";\n // Check if it's an authorization error\n if (\n errorMessage.toLowerCase().includes(\"not authorized\") ||\n errorMessage.toLowerCase().includes(\"forbidden\")\n ) {\n setIsUnauthorized(true);\n setError(null);\n } else {\n setError(errorMessage);\n }\n }\n }, [\n listUsers,\n searchQuery,\n filterRole,\n filterStatus,\n currentPage,\n isAuthenticated,\n ]);\n\n useEffect(() => {\n fetchUsers();\n }, [fetchUsers]);\n\n const resetForm = () => {\n setFormData({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n role: \"MEMBER\",\n status: \"ACTIVE\",\n emailVerified: false,\n });\n setSelectedUser(null);\n setError(null);\n setSuccessMessage(null);\n };\n\n const handleUpdate = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!selectedUser) return;\n setError(null);\n\n try {\n await updateUser(selectedUser.id, {\n username: formData.username || undefined,\n firstName: formData.firstName || undefined,\n lastName: formData.lastName || undefined,\n name: formData.name || undefined,\n phoneNumber: formData.phoneNumber || undefined,\n role: formData.role,\n status: formData.status,\n emailVerified: formData.emailVerified,\n });\n setSuccessMessage(\n tr(\"auth.users.updateSuccess\", \"User updated successfully!\"),\n );\n setViewMode(\"list\");\n resetForm();\n fetchUsers();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to update user\");\n }\n };\n\n const handleDelete = async (user: User) => {\n void nativeImpact(\"medium\");\n try {\n const result = await deleteUser(user.id);\n if (result.success) {\n void nativeNotify(\"success\");\n setSuccessMessage(\n tr(\n \"auth.users.userDeactivated\",\n `User \"${user.email}\" has been deactivated.`,\n ),\n );\n setPendingAction(null);\n fetchUsers();\n } else {\n void nativeNotify(\"error\");\n setError(result.message);\n }\n } catch (err) {\n void nativeNotify(\"error\");\n setError(err instanceof Error ? err.message : \"Failed to delete user\");\n }\n };\n\n const handleHardDelete = async (user: User) => {\n try {\n const result = await hardDeleteUser(user.id);\n if (result.success) {\n setSuccessMessage(\n tr(\n \"auth.users.userPermanentlyDeleted\",\n `User \"${user.email}\" has been permanently deleted.`,\n ),\n );\n setPendingAction(null);\n fetchUsers();\n } else {\n setError(result.message);\n }\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to hard delete user\",\n );\n }\n };\n\n const startEdit = (user: User) => {\n setSelectedUser(user);\n setFormData({\n username: user.username || \"\",\n firstName: user.firstName || \"\",\n lastName: user.lastName || \"\",\n name: user.name || \"\",\n phoneNumber: user.phoneNumber || \"\",\n role: user.role,\n status: user.status,\n emailVerified: user.emailVerified,\n });\n setViewMode(\"edit\");\n setError(null);\n };\n\n const pendingActionDialog = (\n <ConfirmActionDialog\n open={pendingAction !== null}\n onOpenChange={(open) => {\n if (!open) {\n setPendingAction(null);\n }\n }}\n title={\n pendingAction?.type === \"hard-delete\"\n ? tr(\"auth.users.hardDeleteTitle\", \"Permanently delete user?\")\n : tr(\"auth.users.deactivateTitle\", \"Deactivate user?\")\n }\n description={\n pendingAction?.type === \"hard-delete\"\n ? pendingAction\n ? tr(\n \"auth.users.hardDeleteDesc\",\n `This permanently deletes \"${pendingAction.user.email}\" and cannot be undone.`,\n )\n : \"\"\n : pendingAction\n ? tr(\n \"auth.users.deactivateDesc\",\n `\"${pendingAction.user.email}\" will be prevented from signing in until reactivated.`,\n )\n : \"\"\n }\n confirmText={\n pendingAction?.type === \"hard-delete\"\n ? tr(\"auth.users.hardDeleteConfirm\", \"Delete permanently\")\n : tr(\"auth.users.deactivateConfirm\", \"Deactivate user\")\n }\n variant={pendingAction?.type === \"hard-delete\" ? \"danger\" : \"warning\"}\n onConfirm={async () => {\n if (!pendingAction) return;\n if (pendingAction.type === \"hard-delete\") {\n await handleHardDelete(pendingAction.user);\n return;\n }\n await handleDelete(pendingAction.user);\n }}\n />\n );\n\n const getRoleColor = (role: UserRole) => {\n switch (role) {\n case \"SUPER_ADMIN\":\n return \"bg-accent-purple-subtle text-accent-purple\";\n case \"TENANT_ADMIN\":\n return \"bg-status-info-bg-subtle text-status-info-text\";\n case \"ORG_ADMIN\":\n return \"bg-accent-indigo-subtle text-accent-indigo\";\n case \"WORKSPACE_ADMIN\":\n return \"bg-accent-cyan-subtle text-accent-cyan\";\n case \"MEMBER\":\n return \"bg-status-success-bg-subtle text-status-success-text\";\n case \"GUEST\":\n return \"bg-bg-sunken text-text-primary\";\n default:\n return \"bg-bg-sunken text-text-primary\";\n }\n };\n\n const getStatusColor = (status: UserStatus) => {\n switch (status) {\n case \"ACTIVE\":\n return \"bg-status-success-bg-subtle text-status-success-text\";\n case \"INACTIVE\":\n return \"bg-status-warning-bg-subtle text-status-warning-text\";\n case \"SUSPENDED\":\n return \"bg-status-warning-bg-subtle text-status-warning-text\";\n case \"DELETED\":\n return \"bg-status-error-bg-subtle text-status-error-text\";\n default:\n return \"bg-bg-sunken text-text-primary\";\n }\n };\n\n // Authentication check\n if (!isAuthenticated) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-warning-bg-subtle flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-status-warning-text\" />\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\"auth.users.signInToManage\", \"Please sign in to manage users\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Role-based guard — only admin roles may access this page\n const ALLOWED_ROLES: UserRole[] = [\n \"SUPER_ADMIN\",\n \"TENANT_ADMIN\",\n \"ORG_ADMIN\",\n ];\n if (currentUser && !ALLOWED_ROLES.includes(currentUser.role)) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636\"\n />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\n \"auth.users.notAllowed\",\n \"You are not allowed to access this page\",\n )}\n </h2>\n <p className=\"text-text-secondary\">\n {tr(\n \"auth.users.notAllowedDesc\",\n \"This page is restricted to administrators only. Contact your admin if you need access.\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading permissions\n if (permissionsLoading) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16\">\n <SpinnerIcon className=\"w-8 h-8 mx-auto text-text-secondary animate-spin\" />\n <p className=\"mt-4 text-text-secondary\">\n {tr(\"auth.users.loadingPermissions\", \"Loading permissions...\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Authorization check - user needs user:read permission\n if (!canViewUsers || isUnauthorized) {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636\"\n />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.adminAccessRequired\", \"Admin Access Required\")}\n </h2>\n <p className=\"text-text-secondary mb-4\">\n {tr(\n \"auth.users.adminAccessDesc\",\n \"You need administrator privileges to view and manage users.\",\n )}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"auth.users.requiredRoles\",\n \"Required roles: Super Admin, Tenant Admin, or Org Admin\",\n )}\n </p>\n </div>\n </div>\n );\n }\n\n // List view\n if (viewMode === \"list\") {\n return (\n <div className=\"max-w-6xl mx-auto p-6\">\n {pendingActionDialog}\n {/* Header */}\n <div className=\"flex items-center justify-between mb-8\">\n <div>\n <h1 className=\"text-3xl font-semibold text-text-primary\">\n {tr(\"auth.users.title\", \"Users\")}\n </h1>\n <p className=\"text-text-secondary mt-2\">\n {tr(\"auth.users.subtitle\", \"Manage users in your organization\")} (\n {totalCount} {tr(\"auth.users.paginationUsers\", \"total\")})\n </p>\n </div>\n {/* Export button */}\n <button\n type=\"button\"\n onClick={() => void handleExport()}\n disabled={isExporting}\n aria-label={tr(\"auth.users.exportAriaLabel\", \"Export user list\")}\n className=\"flex items-center gap-2 px-4 py-2.5 rounded-xl border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {isExporting ? (\n <>\n <SpinnerIcon\n className=\"w-4 h-4 animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\"auth.users.exporting\", \"Exporting...\")}\n </>\n ) : (\n <>\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n {tr(\"auth.users.export\", \"Export\")}\n </>\n )}\n </button>\n </div>\n\n {/* Live region for status announcements */}\n <div aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {successMessage}\n </div>\n <div\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {error}\n </div>\n\n {/* Success Message */}\n {successMessage && (\n <div\n id={successId}\n role=\"status\"\n className=\"mb-6 p-4 rounded-xl bg-status-success-bg-subtle border border-status-success-border\"\n >\n <p className=\"text-status-success-text\">{successMessage}</p>\n <button\n type=\"button\"\n onClick={() => setSuccessMessage(null)}\n className=\"mt-2 text-sm text-status-success-text hover:underline\"\n >\n {tr(\"auth.users.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div\n id={errorId}\n role=\"alert\"\n className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\"\n >\n <AlertIcon\n className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n <button\n type=\"button\"\n onClick={() => setError(null)}\n className=\"mt-2 text-sm text-status-error-text hover:underline\"\n >\n {tr(\"auth.users.dismiss\", \"Dismiss\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"mb-6 p-4 rounded-xl border border-border-subtle bg-bg-surface\">\n <div className=\"flex flex-wrap gap-4 items-end\">\n {/* Visually hidden labels satisfy WCAG — placeholders are not labels */}\n <div className=\"flex-1 min-w-[200px]\">\n <label htmlFor={searchId} className=\"sr-only\">\n {tr(\"auth.users.searchLabel\", \"Search users\")}\n </label>\n <input\n id={searchId}\n type=\"search\"\n placeholder={tr(\n \"auth.users.searchPlaceholder\",\n \"Search by email, username, or name...\",\n )}\n value={searchQuery}\n onChange={(e) => {\n setSearchQuery(e.target.value);\n setCurrentPage(0);\n }}\n className=\"w-full px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n <div>\n <label htmlFor={roleFilterId} className=\"sr-only\">\n {tr(\"auth.users.filterRoleLabel\", \"Filter by role\")}\n </label>\n <select\n id={roleFilterId}\n value={filterRole}\n onChange={(e) => {\n setFilterRole(e.target.value as UserRole | \"\");\n setCurrentPage(0);\n }}\n className=\"px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"\">\n {tr(\"auth.users.allRoles\", \"All Roles\")}\n </option>\n {USER_ROLES.map((role) => (\n <option key={role} value={role}>\n {role.replace(\"_\", \" \")}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor={statusFilterId} className=\"sr-only\">\n {tr(\"auth.users.filterStatusLabel\", \"Filter by status\")}\n </label>\n <select\n id={statusFilterId}\n value={filterStatus}\n onChange={(e) => {\n setFilterStatus(e.target.value as UserStatus | \"\");\n setCurrentPage(0);\n }}\n className=\"px-4 py-2.5 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n <option value=\"\">\n {tr(\"auth.users.allStatuses\", \"All Statuses\")}\n </option>\n {USER_STATUSES.map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n\n {isLoading ? (\n <div\n aria-live=\"polite\"\n aria-busy=\"true\"\n className=\"flex items-center justify-center py-12\"\n >\n <SpinnerIcon\n className=\"w-8 h-8 text-text-link animate-spin\"\n aria-hidden=\"true\"\n />\n <span className=\"ml-3 text-text-secondary\">\n {tr(\"auth.users.loadingUsers\", \"Loading users...\")}\n </span>\n </div>\n ) : users.length === 0 ? (\n <div className=\"text-center py-16 border-2 border-dashed border-border-subtle rounded-xl\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-bg-sunken flex items-center justify-center\">\n <svg\n className=\"w-8 h-8 text-text-tertiary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z\"\n />\n </svg>\n </div>\n <p className=\"text-text-secondary\">\n {tr(\"auth.users.noUsersFound\", \"No users found\")}\n </p>\n </div>\n ) : (\n <>\n {/* Users Table */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface overflow-hidden shadow-sm\">\n <div className=\"overflow-x-auto\">\n <table\n className=\"w-full min-w-[800px]\"\n aria-label={tr(\"auth.users.tableAriaLabel\", \"Users table\")}\n >\n <thead>\n <tr className=\"border-b border-border-subtle bg-bg-canvas\">\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[280px]\"\n >\n {tr(\"auth.users.columnUser\", \"User\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[130px]\"\n >\n {tr(\"auth.users.columnRole\", \"Role\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[100px]\"\n >\n {tr(\"auth.users.columnStatus\", \"Status\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[80px]\"\n >\n {tr(\"auth.users.columnVerified\", \"Verified\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-left py-4 px-4 text-sm font-medium text-text-secondary w-[100px]\"\n >\n {tr(\"auth.users.columnLastLogin\", \"Last Login\")}\n </th>\n <th\n scope=\"col\"\n className=\"text-right py-4 px-4 text-sm font-medium text-text-secondary w-[180px]\"\n >\n {tr(\"auth.users.columnActions\", \"Actions\")}\n </th>\n </tr>\n </thead>\n <tbody>\n {users.map((user) => (\n <tr\n key={user.id}\n className=\"border-b border-border-subtle last:border-b-0 hover:bg-bg-sunken/50 transition-colors\"\n >\n <td className=\"py-4 px-4\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"auth-brand-badge flex h-10 w-10 shrink-0 items-center justify-center rounded-full font-medium\">\n {(user.name || user.username || user.email)\n .charAt(0)\n .toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-text-primary truncate\">\n {user.name || user.username}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">\n {user.email}\n </p>\n </div>\n </div>\n </td>\n <td className=\"py-4 px-4\">\n <span\n className={`inline-block px-2.5 py-1 rounded-full text-xs font-medium whitespace-nowrap ${getRoleColor(user.role)}`}\n >\n {user.role.replace(\"_\", \" \")}\n </span>\n </td>\n <td className=\"py-4 px-4\">\n <span\n className={`inline-block px-2.5 py-1 rounded-full text-xs font-medium whitespace-nowrap ${getStatusColor(user.status)}`}\n >\n {user.status}\n </span>\n </td>\n <td className=\"py-4 px-4\">\n {user.emailVerified ? (\n <span className=\"inline-flex items-center gap-1 text-status-success-text whitespace-nowrap\">\n <svg\n className=\"w-4 h-4 flex-shrink-0\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <span className=\"text-sm\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-status-warning-text whitespace-nowrap\">\n <svg\n className=\"w-4 h-4 flex-shrink-0\"\n fill=\"currentColor\"\n viewBox=\"0 0 20 20\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <span className=\"text-sm\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n </span>\n )}\n </td>\n <td className=\"py-4 px-4 text-sm text-text-secondary whitespace-nowrap\">\n {user.lastLoginAt\n ? new Date(user.lastLoginAt).toLocaleDateString()\n : tr(\"auth.users.lastLoginNever\", \"Never\")}\n </td>\n <td className=\"py-4 px-4\">\n <div className=\"flex justify-end gap-1.5 flex-nowrap\">\n <button\n type=\"button\"\n onClick={() => navigate(`/auth/users/${user.id}`)}\n aria-label={`${tr(\"auth.users.actionView\", \"View\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-border-default text-text-primary bg-bg-surface hover:bg-bg-sunken transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionView\", \"View\")}\n </button>\n {canUpdateUsers && (\n <button\n type=\"button\"\n onClick={() => startEdit(user)}\n aria-label={`${tr(\"auth.users.actionEdit\", \"Edit\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-status-info-border text-text-link bg-bg-surface hover:bg-status-info-bg-subtle transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionEdit\", \"Edit\")}\n </button>\n )}\n {canDeleteUsers && user.status !== \"DELETED\" && (\n <button\n type=\"button\"\n onClick={() =>\n setPendingAction({ type: \"deactivate\", user })\n }\n aria-label={`${tr(\"auth.users.actionDelete\", \"Delete\")} ${user.name || user.username || user.email}`}\n className=\"px-2.5 py-1.5 rounded-lg text-xs font-medium border border-status-error-border text-status-error-text bg-bg-surface hover:bg-status-error-bg-subtle transition-colors whitespace-nowrap flex-shrink-0\"\n >\n {tr(\"auth.users.actionDelete\", \"Delete\")}\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n\n {/* Pagination */}\n <div className=\"mt-6 flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\"auth.users.showing\", \"Showing\")}{\" \"}\n {currentPage * pageSize + 1} {tr(\"auth.users.to\", \"to\")}{\" \"}\n {Math.min((currentPage + 1) * pageSize, totalCount)}{\" \"}\n {tr(\"auth.users.of\", \"of\")} {totalCount}{\" \"}\n {tr(\"auth.users.paginationUsers\", \"users\")}\n </p>\n <nav\n aria-label={tr(\n \"auth.users.paginationAriaLabel\",\n \"User list pagination\",\n )}\n >\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() =>\n setCurrentPage((prev) => Math.max(0, prev - 1))\n }\n disabled={currentPage === 0}\n aria-label={tr(\n \"auth.users.previousPageAriaLabel\",\n \"Go to previous page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.previousPage\", \"Previous\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setCurrentPage((prev) => prev + 1)}\n disabled={!hasMore}\n aria-label={tr(\n \"auth.users.nextPageAriaLabel\",\n \"Go to next page\",\n )}\n className=\"px-4 py-2 rounded-lg border border-border-default text-text-primary bg-bg-surface disabled:opacity-50 disabled:cursor-not-allowed hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.nextPage\", \"Next\")}\n </button>\n </div>\n </nav>\n </div>\n </>\n )}\n </div>\n );\n }\n\n // View details\n if (viewMode === \"view\" && selectedUser) {\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {pendingActionDialog}\n <button\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"mb-6 flex items-center gap-2 text-text-link hover:underline font-medium\"\n >\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\"auth.users.backToUsers\", \"Back to Users\")}\n </button>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <div className=\"flex items-center gap-4 mb-8\">\n <div className=\"auth-brand-badge flex h-20 w-20 items-center justify-center rounded-full text-3xl font-semibold\">\n {(\n selectedUser.name ||\n selectedUser.username ||\n selectedUser.email\n )\n .charAt(0)\n .toUpperCase()}\n </div>\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">\n {selectedUser.name || selectedUser.username}\n </h1>\n <p className=\"text-text-secondary\">{selectedUser.email}</p>\n <div className=\"flex items-center gap-2 mt-2\">\n <span\n className={`px-2.5 py-1 rounded-full text-xs font-medium ${getRoleColor(selectedUser.role)}`}\n >\n {selectedUser.role.replace(\"_\", \" \")}\n </span>\n <span\n className={`px-2.5 py-1 rounded-full text-xs font-medium ${getStatusColor(selectedUser.status)}`}\n >\n {selectedUser.status}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-6\">\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsUsername\", \"Username\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.username}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsEmail\", \"Email\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.email}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsEmailVerified\", \"Email Verified\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.emailVerified ? (\n <span className=\"text-status-success-text\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n ) : (\n <span className=\"text-status-warning-text\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsMfaEnabled\", \"MFA Enabled\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.mfaEnabled ? (\n <span className=\"text-status-success-text\">\n {tr(\"auth.users.verifiedYes\", \"Yes\")}\n </span>\n ) : (\n <span className=\"text-text-secondary\">\n {tr(\"auth.users.verifiedNo\", \"No\")}\n </span>\n )}\n </p>\n </div>\n\n {selectedUser.phoneNumber && (\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsPhoneNumber\", \"Phone Number\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.phoneNumber}\n </p>\n </div>\n )}\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsLastLogin\", \"Last Login\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {selectedUser.lastLoginAt\n ? new Date(selectedUser.lastLoginAt).toLocaleString()\n : tr(\"auth.users.lastLoginNever\", \"Never\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsCreated\", \"Created\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {new Date(selectedUser.createdAt).toLocaleString()}\n </p>\n </div>\n\n <div className=\"p-4 rounded-lg bg-bg-canvas/50\">\n <label className=\"block text-sm font-medium text-text-secondary mb-1\">\n {tr(\"auth.users.viewDetailsLastUpdated\", \"Last Updated\")}\n </label>\n <p className=\"text-text-primary font-medium\">\n {new Date(selectedUser.updatedAt).toLocaleString()}\n </p>\n </div>\n </div>\n\n <div className=\"mt-8 pt-6 border-t border-border-subtle flex gap-3\">\n <button\n onClick={() => startEdit(selectedUser)}\n className=\"auth-primary-button px-4 py-2.5 font-medium\"\n >\n {tr(\"auth.users.editUser\", \"Edit User\")}\n </button>\n {selectedUser.status !== \"DELETED\" && (\n <button\n onClick={() =>\n setPendingAction({ type: \"deactivate\", user: selectedUser })\n }\n className=\"px-4 py-2.5 rounded-xl border border-status-error-border text-status-error-text font-medium hover:bg-status-error-bg-subtle transition-colors\"\n >\n {tr(\"auth.users.deleteUser\", \"Delete User\")}\n </button>\n )}\n {canDeleteUsers &&\n selectedUser.status === \"DELETED\" &&\n currentUser?.role === \"SUPER_ADMIN\" && (\n <button\n onClick={() =>\n setPendingAction({\n type: \"hard-delete\",\n user: selectedUser,\n })\n }\n className=\"px-4 py-2.5 rounded-xl bg-status-error-bg text-white font-medium hover:bg-status-error-bg-hover transition-colors\"\n >\n {tr(\"auth.users.permanentlyDelete\", \"Permanently Delete\")}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n // Edit form\n return (\n <div className=\"max-w-2xl mx-auto p-6\">\n {pendingActionDialog}\n <button\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"mb-6 flex items-center gap-2 text-text-link hover:underline font-medium\"\n >\n <svg\n className=\"w-4 h-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M10 19l-7-7m0 0l7-7m-7 7h18\"\n />\n </svg>\n {tr(\"auth.users.backToUsers\", \"Back to Users\")}\n </button>\n\n <div className=\"p-6 rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <h1 className=\"text-2xl font-semibold text-text-primary mb-2\">\n {tr(\"auth.users.editUser\", \"Edit User\")}\n </h1>\n\n {selectedUser && (\n <p className=\"text-text-secondary mb-6\">\n {tr(\"auth.users.editingUser\", \"Editing:\")}{\" \"}\n <strong>{selectedUser.email}</strong>\n </p>\n )}\n\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-status-error-bg-subtle border border-status-error-border\">\n <AlertIcon className=\"w-5 h-5 text-status-error-text flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n </div>\n </div>\n )}\n\n <form\n onSubmit={handleUpdate}\n className=\"space-y-6\"\n aria-describedby={error ? errorId : undefined}\n noValidate\n >\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-username\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldUsername\", \"Username\")}\n </label>\n <input\n id=\"edit-username\"\n type=\"text\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"edit-name\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldName\", \"Name\")}\n </label>\n <input\n id=\"edit-name\"\n type=\"text\"\n value={formData.name}\n onChange={(e) =>\n setFormData({ ...formData, name: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-firstName\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldFirstName\", \"First Name\")}\n </label>\n <input\n id=\"edit-firstName\"\n type=\"text\"\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div>\n <label\n htmlFor=\"edit-lastName\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldLastName\", \"Last Name\")}\n </label>\n <input\n id=\"edit-lastName\"\n type=\"text\"\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n </div>\n\n <div>\n <label\n htmlFor=\"edit-phoneNumber\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldPhoneNumber\", \"Phone Number\")}\n </label>\n <input\n id=\"edit-phoneNumber\"\n type=\"tel\"\n value={formData.phoneNumber}\n onChange={(e) =>\n setFormData({ ...formData, phoneNumber: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"edit-role\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldRole\", \"Role\")}\n </label>\n <select\n id=\"edit-role\"\n value={formData.role}\n onChange={(e) =>\n setFormData({ ...formData, role: e.target.value as UserRole })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n {USER_ROLES.map((role) => (\n <option key={role} value={role}>\n {role.replace(\"_\", \" \")}\n </option>\n ))}\n </select>\n </div>\n\n <div>\n <label\n htmlFor=\"edit-status\"\n className=\"block text-sm font-medium text-text-primary mb-2\"\n >\n {tr(\"auth.users.fieldStatus\", \"Status\")}\n </label>\n <select\n id=\"edit-status\"\n value={formData.status}\n onChange={(e) =>\n setFormData({\n ...formData,\n status: e.target.value as UserStatus,\n })\n }\n className=\"block w-full px-4 py-3 border border-border-default rounded-xl bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all\"\n >\n {USER_STATUSES.map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 p-4 rounded-xl bg-bg-canvas/50\">\n <input\n type=\"checkbox\"\n id=\"emailVerified\"\n checked={formData.emailVerified}\n onChange={(e) =>\n setFormData({ ...formData, emailVerified: e.target.checked })\n }\n className=\"w-5 h-5 rounded border-border-default text-text-link focus:ring-action-primary-bg\"\n />\n <label\n htmlFor=\"emailVerified\"\n className=\"text-sm font-medium text-text-primary\"\n >\n {tr(\"auth.users.fieldEmailVerified\", \"Email Verified\")}\n </label>\n </div>\n\n <div className=\"flex gap-3 pt-4\">\n <button\n type=\"submit\"\n disabled={isLoading}\n className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-4 h-4 animate-spin\" />\n {tr(\"auth.users.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.users.saveChanges\", \"Save Changes\")\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setViewMode(\"list\");\n resetForm();\n }}\n className=\"px-6 py-3 rounded-xl border border-border-default text-text-primary font-medium hover:bg-bg-sunken transition-colors\"\n >\n {tr(\"auth.users.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|