@datatechsolutions/ui 2.11.86 → 2.11.88

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.
Files changed (75) hide show
  1. package/dist/billing-panel-DsHhhJqG.d.mts +18 -0
  2. package/dist/billing-panel-DsHhhJqG.d.ts +18 -0
  3. package/dist/chunk-4667D2ZT.mjs +61 -0
  4. package/dist/chunk-4667D2ZT.mjs.map +1 -0
  5. package/dist/chunk-5HXDJBVX.mjs +1330 -0
  6. package/dist/chunk-5HXDJBVX.mjs.map +1 -0
  7. package/dist/chunk-DJ33CSGJ.mjs +126 -0
  8. package/dist/chunk-DJ33CSGJ.mjs.map +1 -0
  9. package/dist/chunk-F4TOOARV.mjs +503 -0
  10. package/dist/chunk-F4TOOARV.mjs.map +1 -0
  11. package/dist/chunk-GEUGFYLO.mjs +237 -0
  12. package/dist/chunk-GEUGFYLO.mjs.map +1 -0
  13. package/dist/chunk-LBALE4JX.js +1342 -0
  14. package/dist/chunk-LBALE4JX.js.map +1 -0
  15. package/dist/chunk-MXFEU7A6.js +148 -0
  16. package/dist/chunk-MXFEU7A6.js.map +1 -0
  17. package/dist/chunk-NBCOVUQP.mjs +142 -0
  18. package/dist/chunk-NBCOVUQP.mjs.map +1 -0
  19. package/dist/chunk-P4RVGMZL.js +128 -0
  20. package/dist/chunk-P4RVGMZL.js.map +1 -0
  21. package/dist/chunk-Q2MG7S2E.js +239 -0
  22. package/dist/chunk-Q2MG7S2E.js.map +1 -0
  23. package/dist/chunk-RV555OEO.mjs +1009 -0
  24. package/dist/chunk-RV555OEO.mjs.map +1 -0
  25. package/dist/chunk-SAYVWIMJ.js +63 -0
  26. package/dist/chunk-SAYVWIMJ.js.map +1 -0
  27. package/dist/chunk-SUHNSUMH.mjs +1021 -0
  28. package/dist/chunk-SUHNSUMH.mjs.map +1 -0
  29. package/dist/chunk-TOEMSC4P.mjs +99 -0
  30. package/dist/chunk-TOEMSC4P.mjs.map +1 -0
  31. package/dist/chunk-UUHV5KHF.js +505 -0
  32. package/dist/chunk-UUHV5KHF.js.map +1 -0
  33. package/dist/chunk-UVEPTYZC.js +101 -0
  34. package/dist/chunk-UVEPTYZC.js.map +1 -0
  35. package/dist/chunk-X2KCCQPL.js +1049 -0
  36. package/dist/chunk-X2KCCQPL.js.map +1 -0
  37. package/dist/chunk-ZARCUQA6.js +1015 -0
  38. package/dist/chunk-ZARCUQA6.js.map +1 -0
  39. package/dist/platform/admin/index.d.mts +17 -0
  40. package/dist/platform/admin/index.d.ts +17 -0
  41. package/dist/platform/admin/index.js +39 -0
  42. package/dist/platform/admin/index.js.map +1 -0
  43. package/dist/platform/admin/index.mjs +10 -0
  44. package/dist/platform/admin/index.mjs.map +1 -0
  45. package/dist/platform/auth/index.d.mts +73 -0
  46. package/dist/platform/auth/index.d.ts +73 -0
  47. package/dist/platform/auth/index.js +107 -0
  48. package/dist/platform/auth/index.js.map +1 -0
  49. package/dist/platform/auth/index.mjs +10 -0
  50. package/dist/platform/auth/index.mjs.map +1 -0
  51. package/dist/platform/billing/index.d.mts +29 -0
  52. package/dist/platform/billing/index.d.ts +29 -0
  53. package/dist/platform/billing/index.js +22 -0
  54. package/dist/platform/billing/index.js.map +1 -0
  55. package/dist/platform/billing/index.mjs +9 -0
  56. package/dist/platform/billing/index.mjs.map +1 -0
  57. package/dist/platform/impersonation/index.d.mts +19 -0
  58. package/dist/platform/impersonation/index.d.ts +19 -0
  59. package/dist/platform/impersonation/index.js +17 -0
  60. package/dist/platform/impersonation/index.js.map +1 -0
  61. package/dist/platform/impersonation/index.mjs +8 -0
  62. package/dist/platform/impersonation/index.mjs.map +1 -0
  63. package/dist/platform/index.d.mts +45 -2
  64. package/dist/platform/index.d.ts +45 -2
  65. package/dist/platform/index.js +4850 -0
  66. package/dist/platform/index.js.map +1 -1
  67. package/dist/platform/index.mjs +4716 -3
  68. package/dist/platform/index.mjs.map +1 -1
  69. package/dist/platform/settings/index.d.mts +31 -0
  70. package/dist/platform/settings/index.d.ts +31 -0
  71. package/dist/platform/settings/index.js +21 -0
  72. package/dist/platform/settings/index.js.map +1 -0
  73. package/dist/platform/settings/index.mjs +12 -0
  74. package/dist/platform/settings/index.mjs.map +1 -0
  75. package/package.json +26 -1
@@ -0,0 +1,1015 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkMXFEU7A6_js = require('./chunk-MXFEU7A6.js');
5
+ var chunkKNXAOJAK_js = require('./chunk-KNXAOJAK.js');
6
+ var chunkUZ3CMNUJ_js = require('./chunk-UZ3CMNUJ.js');
7
+ var chunkYXN2K77G_js = require('./chunk-YXN2K77G.js');
8
+ var react = require('react');
9
+ var outline = require('@heroicons/react/24/outline');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ var PAGE_SIZE = 20;
13
+ function AdminUserList({ client, onUserSelect }) {
14
+ const t = chunkYXN2K77G_js.useTranslations("windsock");
15
+ const format = chunkYXN2K77G_js.useFormatter();
16
+ const [users, setUsers] = react.useState([]);
17
+ const [total, setTotal] = react.useState(0);
18
+ const [isLoading, setIsLoading] = react.useState(true);
19
+ const [search, setSearch] = react.useState("");
20
+ const [offset, setOffset] = react.useState(0);
21
+ const [deleteTarget, setDeleteTarget] = react.useState(null);
22
+ const [isDeletingUser, setIsDeletingUser] = react.useState(false);
23
+ const fetchUsers = react.useCallback(async (searchQuery, pageOffset) => {
24
+ setIsLoading(true);
25
+ try {
26
+ const result = await client.listUsers({
27
+ search: searchQuery || void 0,
28
+ limit: PAGE_SIZE,
29
+ offset: pageOffset
30
+ });
31
+ setUsers(result.items);
32
+ setTotal(result.total);
33
+ } catch {
34
+ } finally {
35
+ setIsLoading(false);
36
+ }
37
+ }, [client]);
38
+ react.useEffect(() => {
39
+ fetchUsers(search, offset);
40
+ }, [fetchUsers, search, offset]);
41
+ const handleSearch = react.useCallback((value) => {
42
+ setSearch(value);
43
+ setOffset(0);
44
+ }, []);
45
+ const handleNextPage = react.useCallback(() => {
46
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
47
+ setOffset((previous) => previous + PAGE_SIZE);
48
+ }, []);
49
+ const handlePreviousPage = react.useCallback(() => {
50
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
51
+ setOffset((previous) => Math.max(0, previous - PAGE_SIZE));
52
+ }, []);
53
+ const handleDeleteRequest = react.useCallback((user) => {
54
+ chunkUZ3CMNUJ_js.triggerHaptic("warning");
55
+ setDeleteTarget(user);
56
+ }, []);
57
+ const handleDeleteConfirm = react.useCallback(async () => {
58
+ if (!deleteTarget) return;
59
+ setIsDeletingUser(true);
60
+ chunkUZ3CMNUJ_js.triggerHaptic("medium");
61
+ try {
62
+ await client.deleteUser(deleteTarget.id);
63
+ setDeleteTarget(null);
64
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
65
+ fetchUsers(search, offset);
66
+ } catch {
67
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
68
+ } finally {
69
+ setIsDeletingUser(false);
70
+ }
71
+ }, [deleteTarget, client, fetchUsers, search, offset]);
72
+ const handleDeleteCancel = react.useCallback(() => {
73
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
74
+ setDeleteTarget(null);
75
+ }, []);
76
+ const handleUserClick = react.useCallback((user) => {
77
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
78
+ onUserSelect?.(user);
79
+ }, [onUserSelect]);
80
+ const totalPages = Math.ceil(total / PAGE_SIZE);
81
+ const currentPage = Math.floor(offset / PAGE_SIZE) + 1;
82
+ const roleBadgeColor = (role) => {
83
+ if (role === "owner" || role === "super_admin") return "purple";
84
+ if (role === "admin") return "blue";
85
+ if (role === "manager") return "amber";
86
+ return "zinc";
87
+ };
88
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
89
+ /* @__PURE__ */ jsxRuntime.jsxs(
90
+ chunkKNXAOJAK_js.SectionCard,
91
+ {
92
+ header: {
93
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.UsersIcon, { className: "h-5 w-5 text-white" }),
94
+ title: t("admin.users.title"),
95
+ subtitle: t("admin.users.subtitle"),
96
+ gradient: "from-blue-500 via-indigo-500 to-violet-500"
97
+ },
98
+ padded: false,
99
+ children: [
100
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200/60 p-4 dark:border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx(
101
+ chunkKNXAOJAK_js.SearchInput,
102
+ {
103
+ value: search,
104
+ onChange: (event) => handleSearch(event.target.value),
105
+ placeholder: t("admin.users.searchPlaceholder")
106
+ }
107
+ ) }),
108
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 p-8 text-sm text-gray-500 dark:text-gray-400", children: [
109
+ /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.InlineSpinner, {}),
110
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("admin.users.loading") })
111
+ ] }) : users.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 sm:p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
112
+ chunkKNXAOJAK_js.EmptyState,
113
+ {
114
+ message: t("admin.users.emptyMessage"),
115
+ description: t("admin.users.emptyDescription"),
116
+ icon: outline.UsersIcon,
117
+ variant: "card"
118
+ }
119
+ ) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
120
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-sm", children: [
121
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-gray-200/60 dark:border-white/10", children: [
122
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.users.columnUser") }),
123
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.users.columnRole") }),
124
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.users.columnStatus") }),
125
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 sm:table-cell", children: t("admin.users.columnSecurity") }),
126
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 md:table-cell", children: t("admin.users.columnLastLogin") }),
127
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.users.columnActions") })
128
+ ] }) }),
129
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-200/60 dark:divide-white/10", children: users.map((user) => /* @__PURE__ */ jsxRuntime.jsxs(
130
+ "tr",
131
+ {
132
+ className: "cursor-pointer transition-colors hover:bg-white/40 dark:hover:bg-white/5",
133
+ onClick: () => handleUserClick(user),
134
+ children: [
135
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
136
+ /* @__PURE__ */ jsxRuntime.jsx(
137
+ chunkKNXAOJAK_js.Avatar,
138
+ {
139
+ src: user.image ?? void 0,
140
+ initials: (user.name ?? user.email).slice(0, 2).toUpperCase(),
141
+ alt: user.name ?? user.email
142
+ }
143
+ ),
144
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
145
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium text-gray-900 dark:text-white", children: user.name ?? user.email }),
146
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-xs text-gray-500 dark:text-gray-400", children: user.email })
147
+ ] })
148
+ ] }) }),
149
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.Badge, { color: roleBadgeColor(user.role), children: user.role }) }),
150
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
151
+ chunkKNXAOJAK_js.StatusBadge,
152
+ {
153
+ status: user.status === "active" ? "active" : "inactive",
154
+ label: user.status,
155
+ size: "sm"
156
+ }
157
+ ) }),
158
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 sm:table-cell", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
159
+ user.mfaEnabled && /* @__PURE__ */ jsxRuntime.jsx("span", { title: t("admin.users.mfaEnabled"), children: /* @__PURE__ */ jsxRuntime.jsx(outline.ShieldCheckIcon, { className: "h-4 w-4 text-emerald-500" }) }),
160
+ user.emailVerified && /* @__PURE__ */ jsxRuntime.jsx("span", { title: t("admin.users.emailVerified"), children: /* @__PURE__ */ jsxRuntime.jsx(outline.KeyIcon, { className: "h-4 w-4 text-blue-500" }) })
161
+ ] }) }),
162
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 text-gray-500 dark:text-gray-400 md:table-cell", children: user.lastLoginAt ? format.relativeTime(new Date(user.lastLoginAt)) : t("admin.users.neverLoggedIn") }),
163
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(
164
+ chunkKNXAOJAK_js.Button,
165
+ {
166
+ size: "sm",
167
+ color: "ios-glass-red",
168
+ onClick: (event) => {
169
+ event.stopPropagation();
170
+ handleDeleteRequest(user);
171
+ },
172
+ children: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-3.5 w-3.5" })
173
+ }
174
+ ) })
175
+ ]
176
+ },
177
+ user.id
178
+ )) })
179
+ ] }) }),
180
+ totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-t border-gray-200/60 px-4 py-3 dark:border-white/10", children: [
181
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("admin.users.pagination", { current: currentPage, total: totalPages, count: total }) }),
182
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx(
184
+ chunkKNXAOJAK_js.Button,
185
+ {
186
+ size: "sm",
187
+ outline: true,
188
+ onClick: handlePreviousPage,
189
+ disabled: offset === 0,
190
+ children: t("admin.users.previousPage")
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsxRuntime.jsx(
194
+ chunkKNXAOJAK_js.Button,
195
+ {
196
+ size: "sm",
197
+ outline: true,
198
+ onClick: handleNextPage,
199
+ disabled: offset + PAGE_SIZE >= total,
200
+ children: t("admin.users.nextPage")
201
+ }
202
+ )
203
+ ] })
204
+ ] })
205
+ ] })
206
+ ]
207
+ }
208
+ ),
209
+ /* @__PURE__ */ jsxRuntime.jsx(
210
+ chunkKNXAOJAK_js.DynamicIslandConfirm,
211
+ {
212
+ open: deleteTarget !== null,
213
+ onClose: handleDeleteCancel,
214
+ onConfirm: handleDeleteConfirm,
215
+ title: t("admin.users.deleteConfirmTitle", { name: deleteTarget?.name ?? deleteTarget?.email ?? "" }),
216
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-5 w-5 text-white" }),
217
+ iconBackground: "bg-ios-red",
218
+ confirmLabel: t("admin.users.deleteConfirmButton"),
219
+ cancelLabel: t("admin.users.deleteCancelButton")
220
+ }
221
+ )
222
+ ] });
223
+ }
224
+ var DEFAULT_ROLES = ["viewer", "member", "operator", "analyst", "manager", "admin", "owner"];
225
+ function AdminUserForm({
226
+ open,
227
+ onClose,
228
+ onSubmit,
229
+ roles = DEFAULT_ROLES
230
+ }) {
231
+ const t = chunkYXN2K77G_js.useTranslations("windsock");
232
+ const [email, setEmail] = react.useState("");
233
+ const [name, setName] = react.useState("");
234
+ const [password, setPassword] = react.useState("");
235
+ const [selectedRole, setSelectedRole] = react.useState("viewer");
236
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
237
+ const [error, setError] = react.useState(null);
238
+ const resetForm = react.useCallback(() => {
239
+ setEmail("");
240
+ setName("");
241
+ setPassword("");
242
+ setSelectedRole("viewer");
243
+ setError(null);
244
+ }, []);
245
+ const handleClose = react.useCallback(() => {
246
+ resetForm();
247
+ onClose();
248
+ }, [resetForm, onClose]);
249
+ const handleSubmit = react.useCallback(async () => {
250
+ if (!email.trim()) {
251
+ setError(t("admin.userForm.errorEmailRequired"));
252
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
253
+ return;
254
+ }
255
+ setError(null);
256
+ setIsSubmitting(true);
257
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
258
+ try {
259
+ const data = {
260
+ email: email.trim().toLowerCase(),
261
+ name: name.trim() || void 0,
262
+ password: password || void 0,
263
+ role: selectedRole
264
+ };
265
+ await onSubmit(data);
266
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
267
+ resetForm();
268
+ onClose();
269
+ } catch {
270
+ setError(t("admin.userForm.errorCreateFailed"));
271
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
272
+ } finally {
273
+ setIsSubmitting(false);
274
+ }
275
+ }, [email, name, password, selectedRole, onSubmit, onClose, resetForm, t]);
276
+ return /* @__PURE__ */ jsxRuntime.jsx(
277
+ chunkKNXAOJAK_js.GlassModal,
278
+ {
279
+ open,
280
+ onClose: handleClose,
281
+ title: t("admin.userForm.title"),
282
+ subtitle: t("admin.userForm.subtitle"),
283
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.UserPlusIcon, { className: "h-5 w-5 text-white" }),
284
+ maxWidth: "md",
285
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
286
+ "form",
287
+ {
288
+ onSubmit: (event) => {
289
+ event.preventDefault();
290
+ handleSubmit();
291
+ },
292
+ className: "space-y-4 p-4 sm:p-6",
293
+ children: [
294
+ /* @__PURE__ */ jsxRuntime.jsx(
295
+ chunkKNXAOJAK_js.Input,
296
+ {
297
+ label: t("admin.userForm.emailLabel"),
298
+ type: "email",
299
+ value: email,
300
+ onChange: (event) => setEmail(event.target.value),
301
+ placeholder: t("admin.userForm.emailPlaceholder"),
302
+ disabled: isSubmitting,
303
+ autoComplete: "email",
304
+ autoFocus: true
305
+ }
306
+ ),
307
+ /* @__PURE__ */ jsxRuntime.jsx(
308
+ chunkKNXAOJAK_js.Input,
309
+ {
310
+ label: t("admin.userForm.nameLabel"),
311
+ value: name,
312
+ onChange: (event) => setName(event.target.value),
313
+ placeholder: t("admin.userForm.namePlaceholder"),
314
+ disabled: isSubmitting,
315
+ autoComplete: "name"
316
+ }
317
+ ),
318
+ /* @__PURE__ */ jsxRuntime.jsx(
319
+ chunkKNXAOJAK_js.PasswordInput,
320
+ {
321
+ label: t("admin.userForm.passwordLabel"),
322
+ value: password,
323
+ onChange: (event) => setPassword(event.target.value),
324
+ placeholder: t("admin.userForm.passwordPlaceholder"),
325
+ disabled: isSubmitting,
326
+ autoComplete: "new-password"
327
+ }
328
+ ),
329
+ password && /* @__PURE__ */ jsxRuntime.jsx(chunkMXFEU7A6_js.PasswordStrengthMeter, { password }),
330
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
331
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-1.5 block text-sm font-medium text-gray-900 dark:text-white", children: t("admin.userForm.roleLabel") }),
332
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2 sm:grid-cols-4", children: roles.map((role) => /* @__PURE__ */ jsxRuntime.jsx(
333
+ "button",
334
+ {
335
+ type: "button",
336
+ onClick: () => {
337
+ setSelectedRole(role);
338
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
339
+ },
340
+ className: `rounded-xl border px-2 py-2 text-xs font-semibold backdrop-blur-xl transition ${selectedRole === role ? "border-indigo-400/80 bg-gradient-to-br from-indigo-100/85 via-white/80 to-sky-100/75 text-slate-900 dark:border-indigo-300/70 dark:bg-[linear-gradient(140deg,rgba(99,102,241,0.32)_0%,rgba(30,41,59,0.72)_100%)] dark:text-indigo-100" : "border-white/55 bg-gradient-to-br from-white/82 via-white/66 to-slate-100/62 text-slate-700 hover:from-white/92 hover:to-sky-100/72 dark:border-white/15 dark:bg-[linear-gradient(140deg,rgba(30,41,59,0.72)_0%,rgba(15,23,42,0.62)_100%)] dark:text-slate-100 dark:hover:bg-[linear-gradient(140deg,rgba(51,65,85,0.76)_0%,rgba(30,41,59,0.68)_100%)]"}`,
341
+ children: role
342
+ },
343
+ role
344
+ )) })
345
+ ] }),
346
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: "alert", children: error }),
347
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 pt-2", children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx(
349
+ chunkKNXAOJAK_js.Button,
350
+ {
351
+ type: "button",
352
+ outline: true,
353
+ onClick: handleClose,
354
+ disabled: isSubmitting,
355
+ className: "flex-1",
356
+ children: t("admin.userForm.cancelButton")
357
+ }
358
+ ),
359
+ /* @__PURE__ */ jsxRuntime.jsx(
360
+ chunkKNXAOJAK_js.Button,
361
+ {
362
+ type: "submit",
363
+ color: "ios-glass-blue",
364
+ loading: isSubmitting,
365
+ disabled: isSubmitting || !email.trim(),
366
+ className: "flex-1",
367
+ children: t("admin.userForm.createButton")
368
+ }
369
+ )
370
+ ] })
371
+ ]
372
+ }
373
+ )
374
+ }
375
+ );
376
+ }
377
+ function AdminOrganizationList({ client, onOrganizationSelect }) {
378
+ const t = chunkYXN2K77G_js.useTranslations("windsock");
379
+ const format = chunkYXN2K77G_js.useFormatter();
380
+ const [organizations, setOrganizations] = react.useState([]);
381
+ const [filteredOrganizations, setFilteredOrganizations] = react.useState([]);
382
+ const [isLoading, setIsLoading] = react.useState(true);
383
+ const [search, setSearch] = react.useState("");
384
+ const [deleteTarget, setDeleteTarget] = react.useState(null);
385
+ const [isDeleting, setIsDeleting] = react.useState(false);
386
+ const fetchOrganizations = react.useCallback(async () => {
387
+ setIsLoading(true);
388
+ try {
389
+ const result = await client.listOrganizations();
390
+ setOrganizations(result);
391
+ } catch {
392
+ } finally {
393
+ setIsLoading(false);
394
+ }
395
+ }, [client]);
396
+ react.useEffect(() => {
397
+ fetchOrganizations();
398
+ }, [fetchOrganizations]);
399
+ react.useEffect(() => {
400
+ if (!search.trim()) {
401
+ setFilteredOrganizations(organizations);
402
+ return;
403
+ }
404
+ const query = search.toLowerCase();
405
+ setFilteredOrganizations(
406
+ organizations.filter(
407
+ (organization) => organization.name.toLowerCase().includes(query) || organization.displayName?.toLowerCase().includes(query) || organization.description?.toLowerCase().includes(query)
408
+ )
409
+ );
410
+ }, [organizations, search]);
411
+ const handleOrganizationClick = react.useCallback((organization) => {
412
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
413
+ onOrganizationSelect?.(organization);
414
+ }, [onOrganizationSelect]);
415
+ const handleDeleteRequest = react.useCallback((organization) => {
416
+ chunkUZ3CMNUJ_js.triggerHaptic("warning");
417
+ setDeleteTarget(organization);
418
+ }, []);
419
+ const handleDeleteConfirm = react.useCallback(async () => {
420
+ if (!deleteTarget) return;
421
+ setIsDeleting(true);
422
+ chunkUZ3CMNUJ_js.triggerHaptic("medium");
423
+ try {
424
+ await client.deleteOrganization(deleteTarget.id);
425
+ setDeleteTarget(null);
426
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
427
+ fetchOrganizations();
428
+ } catch {
429
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
430
+ } finally {
431
+ setIsDeleting(false);
432
+ }
433
+ }, [deleteTarget, client, fetchOrganizations]);
434
+ const handleDeleteCancel = react.useCallback(() => {
435
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
436
+ setDeleteTarget(null);
437
+ }, []);
438
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
439
+ /* @__PURE__ */ jsxRuntime.jsxs(
440
+ chunkKNXAOJAK_js.SectionCard,
441
+ {
442
+ header: {
443
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.BuildingOffice2Icon, { className: "h-5 w-5 text-white" }),
444
+ title: t("admin.organizations.title"),
445
+ subtitle: t("admin.organizations.subtitle"),
446
+ gradient: "from-emerald-500 via-teal-500 to-cyan-500"
447
+ },
448
+ padded: false,
449
+ children: [
450
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200/60 p-4 dark:border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx(
451
+ chunkKNXAOJAK_js.SearchInput,
452
+ {
453
+ value: search,
454
+ onChange: (event) => setSearch(event.target.value),
455
+ placeholder: t("admin.organizations.searchPlaceholder")
456
+ }
457
+ ) }),
458
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 p-8 text-sm text-gray-500 dark:text-gray-400", children: [
459
+ /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.InlineSpinner, {}),
460
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("admin.organizations.loading") })
461
+ ] }) : filteredOrganizations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 sm:p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
462
+ chunkKNXAOJAK_js.EmptyState,
463
+ {
464
+ message: t("admin.organizations.emptyMessage"),
465
+ description: t("admin.organizations.emptyDescription"),
466
+ icon: outline.BuildingOffice2Icon,
467
+ variant: "card"
468
+ }
469
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-sm", children: [
470
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-gray-200/60 dark:border-white/10", children: [
471
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.organizations.columnName") }),
472
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 sm:table-cell", children: t("admin.organizations.columnDisplayName") }),
473
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.organizations.columnStatus") }),
474
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 md:table-cell", children: t("admin.organizations.columnCreated") }),
475
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.organizations.columnActions") })
476
+ ] }) }),
477
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-200/60 dark:divide-white/10", children: filteredOrganizations.map((organization) => /* @__PURE__ */ jsxRuntime.jsxs(
478
+ "tr",
479
+ {
480
+ className: "cursor-pointer transition-colors hover:bg-white/40 dark:hover:bg-white/5",
481
+ onClick: () => handleOrganizationClick(organization),
482
+ children: [
483
+ /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
484
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: organization.name }),
485
+ organization.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 truncate text-xs text-gray-500 dark:text-gray-400", children: organization.description })
486
+ ] }),
487
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 text-gray-500 dark:text-gray-400 sm:table-cell", children: organization.displayName ?? "\u2014" }),
488
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
489
+ chunkKNXAOJAK_js.StatusBadge,
490
+ {
491
+ status: organization.enabled ? "active" : "inactive",
492
+ label: organization.enabled ? t("admin.organizations.statusEnabled") : t("admin.organizations.statusDisabled"),
493
+ size: "sm"
494
+ }
495
+ ) }),
496
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 text-gray-500 dark:text-gray-400 md:table-cell", children: format.dateTime(new Date(organization.createdAt), {
497
+ year: "numeric",
498
+ month: "short",
499
+ day: "numeric"
500
+ }) }),
501
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(
502
+ chunkKNXAOJAK_js.Button,
503
+ {
504
+ size: "sm",
505
+ color: "ios-glass-red",
506
+ onClick: (event) => {
507
+ event.stopPropagation();
508
+ handleDeleteRequest(organization);
509
+ },
510
+ children: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-3.5 w-3.5" })
511
+ }
512
+ ) })
513
+ ]
514
+ },
515
+ organization.id
516
+ )) })
517
+ ] }) })
518
+ ]
519
+ }
520
+ ),
521
+ /* @__PURE__ */ jsxRuntime.jsx(
522
+ chunkKNXAOJAK_js.DynamicIslandConfirm,
523
+ {
524
+ open: deleteTarget !== null,
525
+ onClose: handleDeleteCancel,
526
+ onConfirm: handleDeleteConfirm,
527
+ title: t("admin.organizations.deleteConfirmTitle", { name: deleteTarget?.displayName ?? deleteTarget?.name ?? "" }),
528
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-5 w-5 text-white" }),
529
+ iconBackground: "bg-ios-red",
530
+ confirmLabel: t("admin.organizations.deleteConfirmButton"),
531
+ cancelLabel: t("admin.organizations.deleteCancelButton")
532
+ }
533
+ )
534
+ ] });
535
+ }
536
+ function AdminOrganizationForm({
537
+ open,
538
+ onClose,
539
+ organization,
540
+ onSubmit
541
+ }) {
542
+ const t = chunkYXN2K77G_js.useTranslations("windsock");
543
+ const isEditing = organization !== null && organization !== void 0;
544
+ const [name, setName] = react.useState("");
545
+ const [displayName, setDisplayName] = react.useState("");
546
+ const [description, setDescription] = react.useState("");
547
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
548
+ const [error, setError] = react.useState(null);
549
+ react.useEffect(() => {
550
+ if (organization) {
551
+ setName(organization.name);
552
+ setDisplayName(organization.displayName ?? "");
553
+ setDescription(organization.description ?? "");
554
+ } else {
555
+ setName("");
556
+ setDisplayName("");
557
+ setDescription("");
558
+ }
559
+ setError(null);
560
+ }, [organization, open]);
561
+ const handleClose = react.useCallback(() => {
562
+ setError(null);
563
+ onClose();
564
+ }, [onClose]);
565
+ const handleSubmit = react.useCallback(async () => {
566
+ if (!name.trim()) {
567
+ setError(t("admin.organizationForm.errorNameRequired"));
568
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
569
+ return;
570
+ }
571
+ setError(null);
572
+ setIsSubmitting(true);
573
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
574
+ try {
575
+ if (isEditing) {
576
+ const data = {
577
+ name: name.trim(),
578
+ displayName: displayName.trim() || null,
579
+ description: description.trim() || null
580
+ };
581
+ await onSubmit(data);
582
+ } else {
583
+ const data = {
584
+ name: name.trim(),
585
+ displayName: displayName.trim() || void 0,
586
+ description: description.trim() || void 0
587
+ };
588
+ await onSubmit(data);
589
+ }
590
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
591
+ onClose();
592
+ } catch {
593
+ setError(
594
+ isEditing ? t("admin.organizationForm.errorUpdateFailed") : t("admin.organizationForm.errorCreateFailed")
595
+ );
596
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
597
+ } finally {
598
+ setIsSubmitting(false);
599
+ }
600
+ }, [name, displayName, description, isEditing, onSubmit, onClose, t]);
601
+ return /* @__PURE__ */ jsxRuntime.jsx(
602
+ chunkKNXAOJAK_js.GlassModal,
603
+ {
604
+ open,
605
+ onClose: handleClose,
606
+ title: isEditing ? t("admin.organizationForm.editTitle") : t("admin.organizationForm.createTitle"),
607
+ subtitle: isEditing ? t("admin.organizationForm.editSubtitle") : t("admin.organizationForm.createSubtitle"),
608
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.BuildingOffice2Icon, { className: "h-5 w-5 text-white" }),
609
+ maxWidth: "md",
610
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
611
+ "form",
612
+ {
613
+ onSubmit: (event) => {
614
+ event.preventDefault();
615
+ handleSubmit();
616
+ },
617
+ className: "space-y-4 p-4 sm:p-6",
618
+ children: [
619
+ /* @__PURE__ */ jsxRuntime.jsx(
620
+ chunkKNXAOJAK_js.Input,
621
+ {
622
+ label: t("admin.organizationForm.nameLabel"),
623
+ value: name,
624
+ onChange: (event) => setName(event.target.value),
625
+ placeholder: t("admin.organizationForm.namePlaceholder"),
626
+ disabled: isSubmitting,
627
+ autoFocus: true
628
+ }
629
+ ),
630
+ /* @__PURE__ */ jsxRuntime.jsx(
631
+ chunkKNXAOJAK_js.Input,
632
+ {
633
+ label: t("admin.organizationForm.displayNameLabel"),
634
+ value: displayName,
635
+ onChange: (event) => setDisplayName(event.target.value),
636
+ placeholder: t("admin.organizationForm.displayNamePlaceholder"),
637
+ disabled: isSubmitting
638
+ }
639
+ ),
640
+ /* @__PURE__ */ jsxRuntime.jsx(
641
+ chunkKNXAOJAK_js.Input,
642
+ {
643
+ label: t("admin.organizationForm.descriptionLabel"),
644
+ value: description,
645
+ onChange: (event) => setDescription(event.target.value),
646
+ placeholder: t("admin.organizationForm.descriptionPlaceholder"),
647
+ disabled: isSubmitting
648
+ }
649
+ ),
650
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: "alert", children: error }),
651
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 pt-2", children: [
652
+ /* @__PURE__ */ jsxRuntime.jsx(
653
+ chunkKNXAOJAK_js.Button,
654
+ {
655
+ type: "button",
656
+ outline: true,
657
+ onClick: handleClose,
658
+ disabled: isSubmitting,
659
+ className: "flex-1",
660
+ children: t("admin.organizationForm.cancelButton")
661
+ }
662
+ ),
663
+ /* @__PURE__ */ jsxRuntime.jsx(
664
+ chunkKNXAOJAK_js.Button,
665
+ {
666
+ type: "submit",
667
+ color: "ios-glass-blue",
668
+ loading: isSubmitting,
669
+ disabled: isSubmitting || !name.trim(),
670
+ className: "flex-1",
671
+ children: isEditing ? t("admin.organizationForm.saveButton") : t("admin.organizationForm.createButton")
672
+ }
673
+ )
674
+ ] })
675
+ ]
676
+ }
677
+ )
678
+ }
679
+ );
680
+ }
681
+ function AdminPermissionList({ client }) {
682
+ const t = chunkYXN2K77G_js.useTranslations("windsock");
683
+ const format = chunkYXN2K77G_js.useFormatter();
684
+ const [permissions, setPermissions] = react.useState([]);
685
+ const [filteredPermissions, setFilteredPermissions] = react.useState([]);
686
+ const [isLoading, setIsLoading] = react.useState(true);
687
+ const [search, setSearch] = react.useState("");
688
+ const [isFormOpen, setIsFormOpen] = react.useState(false);
689
+ const [editingPermission, setEditingPermission] = react.useState(null);
690
+ const [formId, setFormId] = react.useState("");
691
+ const [formName, setFormName] = react.useState("");
692
+ const [formDescription, setFormDescription] = react.useState("");
693
+ const [formResource, setFormResource] = react.useState("");
694
+ const [formAction, setFormAction] = react.useState("");
695
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
696
+ const [formError, setFormError] = react.useState(null);
697
+ const [deleteTarget, setDeleteTarget] = react.useState(null);
698
+ const [isDeleting, setIsDeleting] = react.useState(false);
699
+ const fetchPermissions = react.useCallback(async () => {
700
+ setIsLoading(true);
701
+ try {
702
+ const result = await client.listPermissions();
703
+ setPermissions(result);
704
+ } catch {
705
+ } finally {
706
+ setIsLoading(false);
707
+ }
708
+ }, [client]);
709
+ react.useEffect(() => {
710
+ fetchPermissions();
711
+ }, [fetchPermissions]);
712
+ react.useEffect(() => {
713
+ if (!search.trim()) {
714
+ setFilteredPermissions(permissions);
715
+ return;
716
+ }
717
+ const query = search.toLowerCase();
718
+ setFilteredPermissions(
719
+ permissions.filter(
720
+ (permission) => permission.name.toLowerCase().includes(query) || permission.description?.toLowerCase().includes(query) || permission.resource?.toLowerCase().includes(query) || permission.action?.toLowerCase().includes(query)
721
+ )
722
+ );
723
+ }, [permissions, search]);
724
+ const handleOpenCreate = react.useCallback(() => {
725
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
726
+ setEditingPermission(null);
727
+ setFormId("");
728
+ setFormName("");
729
+ setFormDescription("");
730
+ setFormResource("");
731
+ setFormAction("");
732
+ setFormError(null);
733
+ setIsFormOpen(true);
734
+ }, []);
735
+ const handleOpenEdit = react.useCallback((permission) => {
736
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
737
+ setEditingPermission(permission);
738
+ setFormId(permission.id);
739
+ setFormName(permission.name);
740
+ setFormDescription(permission.description ?? "");
741
+ setFormResource(permission.resource ?? "");
742
+ setFormAction(permission.action ?? "");
743
+ setFormError(null);
744
+ setIsFormOpen(true);
745
+ }, []);
746
+ const handleCloseForm = react.useCallback(() => {
747
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
748
+ setIsFormOpen(false);
749
+ }, []);
750
+ const handleSubmitForm = react.useCallback(async () => {
751
+ const isEditing = editingPermission !== null;
752
+ if (!isEditing && !formId.trim()) {
753
+ setFormError(t("admin.permissions.errorIdRequired"));
754
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
755
+ return;
756
+ }
757
+ if (!formName.trim()) {
758
+ setFormError(t("admin.permissions.errorNameRequired"));
759
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
760
+ return;
761
+ }
762
+ setFormError(null);
763
+ setIsSubmitting(true);
764
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
765
+ try {
766
+ if (isEditing) {
767
+ const data = {
768
+ name: formName.trim(),
769
+ description: formDescription.trim() || void 0,
770
+ resource: formResource.trim() || void 0,
771
+ action: formAction.trim() || void 0
772
+ };
773
+ await client.updatePermission(editingPermission.id, data);
774
+ } else {
775
+ const data = {
776
+ id: formId.trim(),
777
+ name: formName.trim(),
778
+ description: formDescription.trim() || void 0,
779
+ resource: formResource.trim() || void 0,
780
+ action: formAction.trim() || void 0
781
+ };
782
+ await client.createPermission(data);
783
+ }
784
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
785
+ setIsFormOpen(false);
786
+ fetchPermissions();
787
+ } catch {
788
+ setFormError(
789
+ isEditing ? t("admin.permissions.errorUpdateFailed") : t("admin.permissions.errorCreateFailed")
790
+ );
791
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
792
+ } finally {
793
+ setIsSubmitting(false);
794
+ }
795
+ }, [editingPermission, formId, formName, formDescription, formResource, formAction, client, fetchPermissions, t]);
796
+ const handleDeleteRequest = react.useCallback((permission) => {
797
+ chunkUZ3CMNUJ_js.triggerHaptic("warning");
798
+ setDeleteTarget(permission);
799
+ }, []);
800
+ const handleDeleteConfirm = react.useCallback(async () => {
801
+ if (!deleteTarget) return;
802
+ setIsDeleting(true);
803
+ chunkUZ3CMNUJ_js.triggerHaptic("medium");
804
+ try {
805
+ await client.deletePermission(deleteTarget.id);
806
+ setDeleteTarget(null);
807
+ chunkUZ3CMNUJ_js.triggerHaptic("success");
808
+ fetchPermissions();
809
+ } catch {
810
+ chunkUZ3CMNUJ_js.triggerHaptic("error");
811
+ } finally {
812
+ setIsDeleting(false);
813
+ }
814
+ }, [deleteTarget, client, fetchPermissions]);
815
+ const handleDeleteCancel = react.useCallback(() => {
816
+ chunkUZ3CMNUJ_js.triggerHaptic("light");
817
+ setDeleteTarget(null);
818
+ }, []);
819
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
820
+ /* @__PURE__ */ jsxRuntime.jsxs(
821
+ chunkKNXAOJAK_js.SectionCard,
822
+ {
823
+ header: {
824
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.KeyIcon, { className: "h-5 w-5 text-white" }),
825
+ title: t("admin.permissions.title"),
826
+ subtitle: t("admin.permissions.subtitle"),
827
+ gradient: "from-violet-500 via-purple-500 to-pink-500",
828
+ rightContent: /* @__PURE__ */ jsxRuntime.jsxs(chunkKNXAOJAK_js.Button, { size: "sm", color: "ios-glass-blue", onClick: handleOpenCreate, children: [
829
+ /* @__PURE__ */ jsxRuntime.jsx(outline.PlusIcon, { className: "mr-1 h-3.5 w-3.5" }),
830
+ t("admin.permissions.createButton")
831
+ ] })
832
+ },
833
+ padded: false,
834
+ children: [
835
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200/60 p-4 dark:border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx(
836
+ chunkKNXAOJAK_js.SearchInput,
837
+ {
838
+ value: search,
839
+ onChange: (event) => setSearch(event.target.value),
840
+ placeholder: t("admin.permissions.searchPlaceholder")
841
+ }
842
+ ) }),
843
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 p-8 text-sm text-gray-500 dark:text-gray-400", children: [
844
+ /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.InlineSpinner, {}),
845
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("admin.permissions.loading") })
846
+ ] }) : filteredPermissions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 sm:p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
847
+ chunkKNXAOJAK_js.EmptyState,
848
+ {
849
+ message: t("admin.permissions.emptyMessage"),
850
+ description: t("admin.permissions.emptyDescription"),
851
+ icon: outline.KeyIcon,
852
+ action: {
853
+ label: t("admin.permissions.createButton"),
854
+ onClick: handleOpenCreate
855
+ },
856
+ variant: "card"
857
+ }
858
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-sm", children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-gray-200/60 dark:border-white/10", children: [
860
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.permissions.columnName") }),
861
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 sm:table-cell", children: t("admin.permissions.columnResource") }),
862
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 sm:table-cell", children: t("admin.permissions.columnAction") }),
863
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "hidden px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400 md:table-cell", children: t("admin.permissions.columnCreated") }),
864
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 text-right text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("admin.permissions.columnActions") })
865
+ ] }) }),
866
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-gray-200/60 dark:divide-white/10", children: filteredPermissions.map((permission) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "transition-colors hover:bg-white/40 dark:hover:bg-white/5", children: [
867
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
868
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: permission.name }),
869
+ permission.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 truncate text-xs text-gray-500 dark:text-gray-400", children: permission.description })
870
+ ] }) }),
871
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 sm:table-cell", children: permission.resource ? /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.Badge, { color: "blue", children: permission.resource }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400 dark:text-gray-500", children: "\u2014" }) }),
872
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 sm:table-cell", children: permission.action ? /* @__PURE__ */ jsxRuntime.jsx(chunkKNXAOJAK_js.Badge, { color: "amber", children: permission.action }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400 dark:text-gray-500", children: "\u2014" }) }),
873
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "hidden px-4 py-3 text-gray-500 dark:text-gray-400 md:table-cell", children: format.dateTime(new Date(permission.createdAt), {
874
+ year: "numeric",
875
+ month: "short",
876
+ day: "numeric"
877
+ }) }),
878
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1", children: [
879
+ /* @__PURE__ */ jsxRuntime.jsx(
880
+ chunkKNXAOJAK_js.Button,
881
+ {
882
+ size: "sm",
883
+ outline: true,
884
+ onClick: () => handleOpenEdit(permission),
885
+ children: /* @__PURE__ */ jsxRuntime.jsx(outline.PencilSquareIcon, { className: "h-3.5 w-3.5" })
886
+ }
887
+ ),
888
+ /* @__PURE__ */ jsxRuntime.jsx(
889
+ chunkKNXAOJAK_js.Button,
890
+ {
891
+ size: "sm",
892
+ color: "ios-glass-red",
893
+ onClick: () => handleDeleteRequest(permission),
894
+ children: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-3.5 w-3.5" })
895
+ }
896
+ )
897
+ ] }) })
898
+ ] }, permission.id)) })
899
+ ] }) })
900
+ ]
901
+ }
902
+ ),
903
+ /* @__PURE__ */ jsxRuntime.jsx(
904
+ chunkKNXAOJAK_js.Sheet,
905
+ {
906
+ open: isFormOpen,
907
+ onClose: handleCloseForm,
908
+ title: editingPermission ? t("admin.permissions.editSheetTitle") : t("admin.permissions.createSheetTitle"),
909
+ side: "bottom",
910
+ size: "md",
911
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 p-4 sm:p-6", children: [
912
+ !editingPermission && /* @__PURE__ */ jsxRuntime.jsx(
913
+ chunkKNXAOJAK_js.Input,
914
+ {
915
+ label: t("admin.permissions.formIdLabel"),
916
+ value: formId,
917
+ onChange: (event) => setFormId(event.target.value),
918
+ placeholder: t("admin.permissions.formIdPlaceholder"),
919
+ disabled: isSubmitting,
920
+ autoFocus: true
921
+ }
922
+ ),
923
+ /* @__PURE__ */ jsxRuntime.jsx(
924
+ chunkKNXAOJAK_js.Input,
925
+ {
926
+ label: t("admin.permissions.formNameLabel"),
927
+ value: formName,
928
+ onChange: (event) => setFormName(event.target.value),
929
+ placeholder: t("admin.permissions.formNamePlaceholder"),
930
+ disabled: isSubmitting,
931
+ autoFocus: !!editingPermission
932
+ }
933
+ ),
934
+ /* @__PURE__ */ jsxRuntime.jsx(
935
+ chunkKNXAOJAK_js.Input,
936
+ {
937
+ label: t("admin.permissions.formDescriptionLabel"),
938
+ value: formDescription,
939
+ onChange: (event) => setFormDescription(event.target.value),
940
+ placeholder: t("admin.permissions.formDescriptionPlaceholder"),
941
+ disabled: isSubmitting
942
+ }
943
+ ),
944
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
945
+ /* @__PURE__ */ jsxRuntime.jsx(
946
+ chunkKNXAOJAK_js.Input,
947
+ {
948
+ label: t("admin.permissions.formResourceLabel"),
949
+ value: formResource,
950
+ onChange: (event) => setFormResource(event.target.value),
951
+ placeholder: t("admin.permissions.formResourcePlaceholder"),
952
+ disabled: isSubmitting
953
+ }
954
+ ),
955
+ /* @__PURE__ */ jsxRuntime.jsx(
956
+ chunkKNXAOJAK_js.Input,
957
+ {
958
+ label: t("admin.permissions.formActionLabel"),
959
+ value: formAction,
960
+ onChange: (event) => setFormAction(event.target.value),
961
+ placeholder: t("admin.permissions.formActionPlaceholder"),
962
+ disabled: isSubmitting
963
+ }
964
+ )
965
+ ] }),
966
+ formError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 dark:text-red-400", role: "alert", children: formError }),
967
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
968
+ /* @__PURE__ */ jsxRuntime.jsx(
969
+ chunkKNXAOJAK_js.Button,
970
+ {
971
+ outline: true,
972
+ onClick: handleCloseForm,
973
+ disabled: isSubmitting,
974
+ className: "flex-1",
975
+ children: t("admin.permissions.formCancelButton")
976
+ }
977
+ ),
978
+ /* @__PURE__ */ jsxRuntime.jsx(
979
+ chunkKNXAOJAK_js.Button,
980
+ {
981
+ color: "ios-glass-blue",
982
+ onClick: handleSubmitForm,
983
+ loading: isSubmitting,
984
+ disabled: isSubmitting || !formName.trim() || !editingPermission && !formId.trim(),
985
+ className: "flex-1",
986
+ children: editingPermission ? t("admin.permissions.formSaveButton") : t("admin.permissions.formCreateButton")
987
+ }
988
+ )
989
+ ] })
990
+ ] })
991
+ }
992
+ ),
993
+ /* @__PURE__ */ jsxRuntime.jsx(
994
+ chunkKNXAOJAK_js.DynamicIslandConfirm,
995
+ {
996
+ open: deleteTarget !== null,
997
+ onClose: handleDeleteCancel,
998
+ onConfirm: handleDeleteConfirm,
999
+ title: t("admin.permissions.deleteConfirmTitle", { name: deleteTarget?.name ?? "" }),
1000
+ icon: /* @__PURE__ */ jsxRuntime.jsx(outline.TrashIcon, { className: "h-5 w-5 text-white" }),
1001
+ iconBackground: "bg-ios-red",
1002
+ confirmLabel: t("admin.permissions.deleteConfirmButton"),
1003
+ cancelLabel: t("admin.permissions.deleteCancelButton")
1004
+ }
1005
+ )
1006
+ ] });
1007
+ }
1008
+
1009
+ exports.AdminOrganizationForm = AdminOrganizationForm;
1010
+ exports.AdminOrganizationList = AdminOrganizationList;
1011
+ exports.AdminPermissionList = AdminPermissionList;
1012
+ exports.AdminUserForm = AdminUserForm;
1013
+ exports.AdminUserList = AdminUserList;
1014
+ //# sourceMappingURL=chunk-ZARCUQA6.js.map
1015
+ //# sourceMappingURL=chunk-ZARCUQA6.js.map