@mesob/auth-react 0.3.4 → 0.4.0

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 (142) hide show
  1. package/dist/components/auth/auth-layout.d.ts +1 -1
  2. package/dist/components/auth/auth-layout.js +10 -2
  3. package/dist/components/auth/auth-layout.js.map +1 -1
  4. package/dist/components/auth/countdown.js +8 -6
  5. package/dist/components/auth/countdown.js.map +1 -1
  6. package/dist/components/auth/forgot-password.js +21 -19
  7. package/dist/components/auth/forgot-password.js.map +1 -1
  8. package/dist/components/auth/reset-password-form.js +22 -21
  9. package/dist/components/auth/reset-password-form.js.map +1 -1
  10. package/dist/components/auth/set-password.d.ts +9 -0
  11. package/dist/components/auth/set-password.js +527 -0
  12. package/dist/components/auth/set-password.js.map +1 -0
  13. package/dist/components/auth/sign-in.js +45 -26
  14. package/dist/components/auth/sign-in.js.map +1 -1
  15. package/dist/components/auth/sign-up.js +25 -29
  16. package/dist/components/auth/sign-up.js.map +1 -1
  17. package/dist/components/auth/verification-form.js +24 -27
  18. package/dist/components/auth/verification-form.js.map +1 -1
  19. package/dist/components/auth/verify-email.js +40 -31
  20. package/dist/components/auth/verify-email.js.map +1 -1
  21. package/dist/components/auth/verify-phone.js +40 -31
  22. package/dist/components/auth/verify-phone.js.map +1 -1
  23. package/dist/components/authorization/deny.d.ts +11 -0
  24. package/dist/components/authorization/deny.js +52 -0
  25. package/dist/components/authorization/deny.js.map +1 -0
  26. package/dist/components/authorization/grant.d.ts +12 -0
  27. package/dist/components/authorization/grant.js +57 -0
  28. package/dist/components/authorization/grant.js.map +1 -0
  29. package/dist/components/iam/permission-selector.d.ts +19 -0
  30. package/dist/components/iam/permission-selector.js +122 -0
  31. package/dist/components/iam/permission-selector.js.map +1 -0
  32. package/dist/components/iam/permissions.js +21 -33
  33. package/dist/components/iam/permissions.js.map +1 -1
  34. package/dist/components/iam/role-detail-layout.d.ts +11 -0
  35. package/dist/components/iam/role-detail-layout.js +137 -0
  36. package/dist/components/iam/role-detail-layout.js.map +1 -0
  37. package/dist/components/iam/role-detail-page.d.ts +9 -0
  38. package/dist/components/iam/role-detail-page.js +229 -0
  39. package/dist/components/iam/role-detail-page.js.map +1 -0
  40. package/dist/components/iam/role-permissions-page.d.ts +8 -0
  41. package/dist/components/iam/role-permissions-page.js +397 -0
  42. package/dist/components/iam/role-permissions-page.js.map +1 -0
  43. package/dist/components/iam/roles.js +20 -10
  44. package/dist/components/iam/roles.js.map +1 -1
  45. package/dist/components/iam/tenants.js +9 -2
  46. package/dist/components/iam/tenants.js.map +1 -1
  47. package/dist/components/iam/users.js +10 -9
  48. package/dist/components/iam/users.js.map +1 -1
  49. package/dist/components/profile/account.js +110 -19
  50. package/dist/components/profile/account.js.map +1 -1
  51. package/dist/components/profile/change-email-form.js +26 -29
  52. package/dist/components/profile/change-email-form.js.map +1 -1
  53. package/dist/components/profile/change-phone-form.js +26 -29
  54. package/dist/components/profile/change-phone-form.js.map +1 -1
  55. package/dist/components/profile/change-profile.d.ts +2 -1
  56. package/dist/components/profile/change-profile.js +16 -8
  57. package/dist/components/profile/change-profile.js.map +1 -1
  58. package/dist/components/profile/otp-verification-modal.js +24 -27
  59. package/dist/components/profile/otp-verification-modal.js.map +1 -1
  60. package/dist/components/profile/security.js +88 -57
  61. package/dist/components/profile/security.js.map +1 -1
  62. package/dist/components/profile/verify-change-email-form.js +24 -27
  63. package/dist/components/profile/verify-change-email-form.js.map +1 -1
  64. package/dist/components/profile/verify-change-phone-form.js +24 -27
  65. package/dist/components/profile/verify-change-phone-form.js.map +1 -1
  66. package/dist/index.d.ts +9 -1
  67. package/dist/index.js +1897 -821
  68. package/dist/index.js.map +1 -1
  69. package/dist/pages/auth/forgot-password.d.ts +7 -0
  70. package/dist/pages/auth/forgot-password.js +784 -0
  71. package/dist/pages/auth/forgot-password.js.map +1 -0
  72. package/dist/pages/auth/layout.d.ts +8 -0
  73. package/dist/pages/auth/layout.js +562 -0
  74. package/dist/pages/auth/layout.js.map +1 -0
  75. package/dist/pages/auth/reset-password.d.ts +10 -0
  76. package/dist/pages/auth/reset-password.js +913 -0
  77. package/dist/pages/auth/reset-password.js.map +1 -0
  78. package/dist/pages/auth/set-password.d.ts +10 -0
  79. package/dist/pages/auth/set-password.js +946 -0
  80. package/dist/pages/auth/set-password.js.map +1 -0
  81. package/dist/pages/auth/sign-in.d.ts +10 -0
  82. package/dist/pages/auth/sign-in.js +984 -0
  83. package/dist/pages/auth/sign-in.js.map +1 -0
  84. package/dist/pages/auth/sign-up.d.ts +10 -0
  85. package/dist/pages/auth/sign-up.js +940 -0
  86. package/dist/pages/auth/sign-up.js.map +1 -0
  87. package/dist/pages/auth/verify-email.d.ts +10 -0
  88. package/dist/pages/auth/verify-email.js +950 -0
  89. package/dist/pages/auth/verify-email.js.map +1 -0
  90. package/dist/pages/auth/verify-phone.d.ts +10 -0
  91. package/dist/pages/auth/verify-phone.js +964 -0
  92. package/dist/pages/auth/verify-phone.js.map +1 -0
  93. package/dist/pages/iam/permissions.d.ts +5 -0
  94. package/dist/pages/iam/permissions.js +308 -0
  95. package/dist/pages/iam/permissions.js.map +1 -0
  96. package/dist/pages/iam/role-detail-layout.d.ts +12 -0
  97. package/dist/pages/iam/role-detail-layout.js +145 -0
  98. package/dist/pages/iam/role-detail-layout.js.map +1 -0
  99. package/dist/pages/iam/role-detail.d.ts +12 -0
  100. package/dist/pages/iam/role-detail.js +241 -0
  101. package/dist/pages/iam/role-detail.js.map +1 -0
  102. package/dist/pages/iam/role-permissions.d.ts +12 -0
  103. package/dist/pages/iam/role-permissions.js +409 -0
  104. package/dist/pages/iam/role-permissions.js.map +1 -0
  105. package/dist/pages/iam/role-users.d.ts +12 -0
  106. package/dist/pages/iam/role-users.js +825 -0
  107. package/dist/pages/iam/role-users.js.map +1 -0
  108. package/dist/pages/iam/roles.d.ts +5 -0
  109. package/dist/pages/iam/roles.js +684 -0
  110. package/dist/pages/iam/roles.js.map +1 -0
  111. package/dist/pages/iam/sessions.d.ts +5 -0
  112. package/dist/pages/iam/sessions.js +315 -0
  113. package/dist/pages/iam/sessions.js.map +1 -0
  114. package/dist/pages/iam/tenant-detail.d.ts +10 -0
  115. package/dist/pages/iam/tenant-detail.js +186 -0
  116. package/dist/pages/iam/tenant-detail.js.map +1 -0
  117. package/dist/pages/iam/tenants.d.ts +5 -0
  118. package/dist/pages/iam/tenants.js +610 -0
  119. package/dist/pages/iam/tenants.js.map +1 -0
  120. package/dist/pages/iam/user-activity.d.ts +10 -0
  121. package/dist/pages/iam/user-activity.js +850 -0
  122. package/dist/pages/iam/user-activity.js.map +1 -0
  123. package/dist/pages/iam/user-detail-layout.d.ts +12 -0
  124. package/dist/pages/iam/user-detail-layout.js +106 -0
  125. package/dist/pages/iam/user-detail-layout.js.map +1 -0
  126. package/dist/pages/iam/user-detail.d.ts +10 -0
  127. package/dist/pages/iam/user-detail.js +102 -0
  128. package/dist/pages/iam/user-detail.js.map +1 -0
  129. package/dist/pages/iam/users.d.ts +5 -0
  130. package/dist/pages/iam/users.js +1275 -0
  131. package/dist/pages/iam/users.js.map +1 -0
  132. package/dist/pages/profile/account.d.ts +5 -0
  133. package/dist/pages/profile/account.js +182 -0
  134. package/dist/pages/profile/account.js.map +1 -0
  135. package/dist/pages/profile/layout.d.ts +8 -0
  136. package/dist/pages/profile/layout.js +133 -0
  137. package/dist/pages/profile/layout.js.map +1 -0
  138. package/dist/pages/profile/security.d.ts +5 -0
  139. package/dist/pages/profile/security.js +1539 -0
  140. package/dist/pages/profile/security.js.map +1 -0
  141. package/dist/{types-vcfvnAzQ.d.ts → types-g9QcNRxT.d.ts} +13 -7
  142. package/package.json +102 -3
@@ -0,0 +1,850 @@
1
+ // src/pages/iam/users/activity/user-activity-page-content.tsx
2
+ import {
3
+ Card as Card2,
4
+ CardContent as CardContent2,
5
+ CardHeader as CardHeader2,
6
+ CardTitle,
7
+ Section
8
+ } from "@mesob/ui/components";
9
+ import { IconCalendar as IconCalendar3 } from "@tabler/icons-react";
10
+
11
+ // src/pages/iam/users/activity/_components/role-section.tsx
12
+ import {
13
+ Button as Button2,
14
+ EntityEmptyState as EntityEmptyState2,
15
+ EntityLoadingState as EntityLoadingState2,
16
+ EntitySection,
17
+ useEntitySectionState as useEntitySectionState2
18
+ } from "@mesob/ui/components";
19
+ import { IconPlus, IconShield as IconShield3 } from "@tabler/icons-react";
20
+ import { useMemo as useMemo3, useState as useState3 } from "react";
21
+
22
+ // src/pages/iam/roles/_components/role-selector.tsx
23
+ import {
24
+ EntitySelector,
25
+ useEntitySectionState
26
+ } from "@mesob/ui/components";
27
+ import { cn } from "@mesob/ui/lib/utils";
28
+ import { IconCalendar, IconShield } from "@tabler/icons-react";
29
+
30
+ // src/provider.tsx
31
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
32
+ import { deepmerge } from "deepmerge-ts";
33
+ import createFetchClient from "openapi-fetch";
34
+ import createClient from "openapi-react-query";
35
+ import { createContext, useContext, useMemo, useState } from "react";
36
+
37
+ // src/utils/cookie.ts
38
+ var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
39
+
40
+ // src/provider.tsx
41
+ import { jsx } from "react/jsx-runtime";
42
+ var SessionContext = createContext(null);
43
+ var ApiContext = createContext(null);
44
+ var ConfigContext = createContext(null);
45
+ var queryClient = new QueryClient({
46
+ defaultOptions: {
47
+ queries: {
48
+ refetchOnWindowFocus: false
49
+ }
50
+ }
51
+ });
52
+ function useApi() {
53
+ const context = useContext(ApiContext);
54
+ if (!context) {
55
+ throw new Error("useApi must be used within MesobAuthProvider");
56
+ }
57
+ return context;
58
+ }
59
+ function useConfig() {
60
+ const context = useContext(ConfigContext);
61
+ if (!context) {
62
+ throw new Error("useConfig must be used within MesobAuthProvider");
63
+ }
64
+ return context;
65
+ }
66
+
67
+ // src/pages/iam/shared/navigation.tsx
68
+ import { useMesob } from "@mesob/ui/providers";
69
+ import { jsx as jsx2 } from "react/jsx-runtime";
70
+ function AppLink({ href, children, ...props }) {
71
+ const mesob = useMesob();
72
+ const Link2 = mesob?.linkComponent ?? mesob?.navigation?.Link;
73
+ const locale = mesob?.locale;
74
+ if (Link2) {
75
+ return /* @__PURE__ */ jsx2(Link2, { href, ...locale ? { locale } : {}, ...props, children });
76
+ }
77
+ return /* @__PURE__ */ jsx2("a", { href, ...props, children });
78
+ }
79
+ function useNavigate() {
80
+ const { config } = useConfig();
81
+ return (href) => {
82
+ if (config.navigation?.onNavigate) {
83
+ config.navigation.onNavigate(href);
84
+ return;
85
+ }
86
+ if (typeof window !== "undefined") {
87
+ window.location.href = href;
88
+ }
89
+ };
90
+ }
91
+
92
+ // src/lib/query-options.ts
93
+ import { keepPreviousData } from "@tanstack/react-query";
94
+ var defaultEntityQueryOptions = {
95
+ refetchOnMount: false,
96
+ refetchOnWindowFocus: false,
97
+ refetchOnReconnect: false,
98
+ staleTime: 60 * 1e3,
99
+ gcTime: 5 * 60 * 1e3,
100
+ placeholderData: keepPreviousData,
101
+ retry: 1
102
+ };
103
+
104
+ // src/pages/iam/shared/page-helpers.tsx
105
+ import { jsx as jsx3 } from "react/jsx-runtime";
106
+ var authApi$ = {
107
+ useQuery(...args) {
108
+ const { hooks } = useApi();
109
+ return hooks.useQuery(...args);
110
+ },
111
+ useMutation(...args) {
112
+ const { hooks } = useApi();
113
+ return hooks.useMutation(...args);
114
+ }
115
+ };
116
+ function Link(props) {
117
+ return /* @__PURE__ */ jsx3(AppLink, { ...props });
118
+ }
119
+ function useRouter() {
120
+ const navigate = useNavigate();
121
+ return {
122
+ push: navigate
123
+ };
124
+ }
125
+
126
+ // src/pages/iam/roles/_components/role-card.tsx
127
+ import {
128
+ Badge,
129
+ Button,
130
+ Card,
131
+ CardContent,
132
+ CardHeader,
133
+ DropdownMenu,
134
+ DropdownMenuContent,
135
+ DropdownMenuItem,
136
+ DropdownMenuPortal,
137
+ DropdownMenuTrigger
138
+ } from "@mesob/ui/components";
139
+ import { IconDots, IconExternalLink } from "@tabler/icons-react";
140
+
141
+ // src/pages/iam/roles/_components/roles-data.ts
142
+ function str(v) {
143
+ if (v == null) {
144
+ return "";
145
+ }
146
+ if (typeof v === "string") {
147
+ return v;
148
+ }
149
+ if (typeof v === "object" && v !== null && "en" in v) {
150
+ const o = v;
151
+ return o.en ?? o.am ?? "";
152
+ }
153
+ return String(v);
154
+ }
155
+
156
+ // src/pages/iam/roles/_components/role-card.tsx
157
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
158
+ function RoleCard({ role, mode = "navigate" }) {
159
+ const router = useRouter();
160
+ const canNavigate = mode === "navigate";
161
+ return /* @__PURE__ */ jsxs(Card, { className: "group transition-shadow hover:shadow-md", children: [
162
+ /* @__PURE__ */ jsxs(CardHeader, { className: "pb-2", children: [
163
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
164
+ /* @__PURE__ */ jsx4(
165
+ "button",
166
+ {
167
+ type: "button",
168
+ onClick: () => {
169
+ if (canNavigate) {
170
+ router.push(`/iam/roles/${role.id}`);
171
+ }
172
+ },
173
+ className: "text-left font-semibold hover:text-primary hover:underline",
174
+ children: str(role.name) || role.code
175
+ }
176
+ ),
177
+ canNavigate ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
178
+ /* @__PURE__ */ jsx4(
179
+ DropdownMenuTrigger,
180
+ {
181
+ render: /* @__PURE__ */ jsx4(
182
+ Button,
183
+ {
184
+ variant: "ghost",
185
+ size: "icon",
186
+ className: "h-8 w-8 opacity-0 transition-opacity group-hover:opacity-100"
187
+ }
188
+ ),
189
+ children: /* @__PURE__ */ jsx4(IconDots, { className: "h-4 w-4" })
190
+ }
191
+ ),
192
+ /* @__PURE__ */ jsx4(DropdownMenuPortal, { children: /* @__PURE__ */ jsx4(DropdownMenuContent, { children: /* @__PURE__ */ jsxs(
193
+ DropdownMenuItem,
194
+ {
195
+ onClick: () => router.push(`/iam/roles/${role.id}`),
196
+ children: [
197
+ /* @__PURE__ */ jsx4(IconExternalLink, { className: "mr-2 h-4 w-4" }),
198
+ "Open"
199
+ ]
200
+ }
201
+ ) }) })
202
+ ] }) : null
203
+ ] }),
204
+ /* @__PURE__ */ jsx4(Badge, { variant: "outline", className: "text-xs", children: role.code })
205
+ ] }),
206
+ /* @__PURE__ */ jsxs(CardContent, { children: [
207
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex flex-wrap gap-2", children: [
208
+ role.isSystem ? /* @__PURE__ */ jsx4(Badge, { children: "System" }) : null,
209
+ /* @__PURE__ */ jsxs(Badge, { variant: "secondary", children: [
210
+ role.permissionCount ?? role.permissionIds?.length ?? 0,
211
+ " ",
212
+ "permissions"
213
+ ] }),
214
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
215
+ role.userCount ?? 0,
216
+ " users"
217
+ ] })
218
+ ] }),
219
+ str(role.description) && /* @__PURE__ */ jsx4("p", { className: "line-clamp-2 text-sm text-muted-foreground", children: str(role.description) }),
220
+ /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-muted-foreground", children: [
221
+ "Created ",
222
+ new Date(role.createdAt).toLocaleDateString()
223
+ ] })
224
+ ] })
225
+ ] });
226
+ }
227
+
228
+ // src/pages/iam/roles/_components/role-selector.tsx
229
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
230
+ function SelectableRoleCard({
231
+ role,
232
+ selected,
233
+ onToggle
234
+ }) {
235
+ return (
236
+ // biome-ignore lint/a11y/useSemanticElements: div to avoid nested buttons from RoleCard
237
+ /* @__PURE__ */ jsx5(
238
+ "div",
239
+ {
240
+ role: "button",
241
+ tabIndex: 0,
242
+ onClick: onToggle,
243
+ onKeyDown: (e) => {
244
+ if (e.key === "Enter") {
245
+ onToggle();
246
+ }
247
+ },
248
+ className: cn(
249
+ "cursor-pointer rounded-lg transition-shadow focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
250
+ selected && "ring-primary ring-2"
251
+ ),
252
+ children: /* @__PURE__ */ jsx5(RoleCard, { role, mode: "static" })
253
+ }
254
+ )
255
+ );
256
+ }
257
+ var roleColumns = [
258
+ {
259
+ key: "role",
260
+ header: "Role",
261
+ cell: (role) => /* @__PURE__ */ jsxs2(Fragment, { children: [
262
+ /* @__PURE__ */ jsx5("p", { className: "font-medium", children: str(role.name) || role.code }),
263
+ /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: role.code })
264
+ ] })
265
+ },
266
+ {
267
+ key: "description",
268
+ header: "Description",
269
+ cell: (role) => /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground line-clamp-1 max-w-[200px]", children: str(role.description) || "\u2014" })
270
+ },
271
+ {
272
+ key: "created",
273
+ header: "Created",
274
+ cell: (role) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
275
+ /* @__PURE__ */ jsx5(IconCalendar, { className: "h-4 w-4" }),
276
+ new Date(role.createdAt).toLocaleDateString()
277
+ ] })
278
+ }
279
+ ];
280
+ function RoleSelector({
281
+ trigger,
282
+ multiple = true,
283
+ onSelect,
284
+ modalSize = "xl",
285
+ contentClassName
286
+ }) {
287
+ const state = useEntitySectionState({
288
+ defaultSort: "createdAt",
289
+ defaultOrder: "desc",
290
+ defaultPageSize: 10,
291
+ searchParamName: "search"
292
+ });
293
+ const rolesQuery = state.queryConfig;
294
+ const { data, isPending, isFetching } = authApi$.useQuery(
295
+ "get",
296
+ "/roles",
297
+ rolesQuery,
298
+ defaultEntityQueryOptions
299
+ );
300
+ const roles = data?.roles ?? [];
301
+ const config = {
302
+ title: "Select role(s)",
303
+ modalSize,
304
+ contentClassName,
305
+ multiple,
306
+ entityName: "role",
307
+ entityIcon: IconShield,
308
+ columns: roleColumns,
309
+ columnCount: 3,
310
+ getItemLabel: (role) => str(role.name) || role.code,
311
+ searchPlaceholder: "Search roles...",
312
+ wrapHeaderInCard: false,
313
+ filterOptions: [
314
+ { label: "All", value: "" },
315
+ { label: "By Code", value: "code" }
316
+ ],
317
+ sortOptions: [
318
+ { label: "Created", value: "createdAt" },
319
+ { label: "Updated", value: "updatedAt" },
320
+ { label: "Code", value: "code" }
321
+ ],
322
+ showViewToggle: false,
323
+ renderCard: (role, selected, onToggle) => /* @__PURE__ */ jsx5(SelectableRoleCard, { role, selected, onToggle })
324
+ };
325
+ return /* @__PURE__ */ jsx5(
326
+ EntitySelector,
327
+ {
328
+ trigger,
329
+ config,
330
+ onSelect,
331
+ items: roles,
332
+ total: data?.total,
333
+ isLoading: isPending || isFetching,
334
+ state
335
+ }
336
+ );
337
+ }
338
+
339
+ // src/pages/iam/roles/_components/roles-list.tsx
340
+ import {
341
+ Badge as Badge2,
342
+ DataTableAction,
343
+ DataTablePagination,
344
+ DisplayTable,
345
+ EntityEmptyState,
346
+ EntityLoadingState,
347
+ Tbody,
348
+ Td,
349
+ Th,
350
+ Thead,
351
+ Tr
352
+ } from "@mesob/ui/components";
353
+ import { IconCalendar as IconCalendar2, IconShield as IconShield2 } from "@tabler/icons-react";
354
+ import { useState as useState2 } from "react";
355
+
356
+ // src/pages/iam/roles/_components/role-form.tsx
357
+ import { zodResolver } from "@hookform/resolvers/zod";
358
+ import {
359
+ EntityDrawer,
360
+ EntityFormActions,
361
+ Form,
362
+ FormControl,
363
+ FormField,
364
+ FormItem,
365
+ FormLabel,
366
+ FormMessage,
367
+ Input,
368
+ LocaleInputText,
369
+ LocaleInputTextarea,
370
+ Skeleton
371
+ } from "@mesob/ui/components";
372
+ import { useLocaleConfig, useLocaleSchemas } from "@mesob/ui/providers";
373
+ import { useQueryClient } from "@tanstack/react-query";
374
+ import { useEffect, useMemo as useMemo2 } from "react";
375
+ import { useForm, useWatch } from "react-hook-form";
376
+ import { z } from "zod";
377
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
378
+ function RoleForm({
379
+ mode,
380
+ roleId,
381
+ open,
382
+ onClose,
383
+ onSuccess
384
+ }) {
385
+ const qc = useQueryClient();
386
+ const { localeInputDefault, requiredSchema, optionalSchema } = useLocaleSchemas();
387
+ const { defaultLanguage } = useLocaleConfig();
388
+ const schema = useMemo2(
389
+ () => z.object({
390
+ name: requiredSchema,
391
+ code: z.string().min(1, "Code is required"),
392
+ description: optionalSchema,
393
+ permissionIds: z.array(z.string())
394
+ }),
395
+ [requiredSchema, optionalSchema]
396
+ );
397
+ const defaults = useMemo2(
398
+ () => ({
399
+ name: { ...localeInputDefault },
400
+ code: "",
401
+ description: { ...localeInputDefault },
402
+ permissionIds: []
403
+ }),
404
+ [localeInputDefault]
405
+ );
406
+ const { data, isLoading } = authApi$.useQuery(
407
+ "get",
408
+ "/roles/{id}",
409
+ { params: { path: { id: roleId ?? "" } } },
410
+ { enabled: mode === "edit" && !!roleId }
411
+ );
412
+ const create = authApi$.useMutation("post", "/roles", {
413
+ onSuccess: () => qc.invalidateQueries({ queryKey: ["get", "/roles"] })
414
+ });
415
+ const update = authApi$.useMutation("put", "/roles/{id}", {
416
+ onSuccess: () => {
417
+ qc.invalidateQueries({ queryKey: ["get", "/roles"] });
418
+ if (roleId) {
419
+ qc.invalidateQueries({ queryKey: ["get", "/roles/{id}"] });
420
+ }
421
+ }
422
+ });
423
+ const del = authApi$.useMutation("delete", "/roles/{id}", {
424
+ onSuccess: () => qc.invalidateQueries({ queryKey: ["get", "/roles"] })
425
+ });
426
+ const form = useForm({
427
+ resolver: zodResolver(schema),
428
+ defaultValues: defaults
429
+ });
430
+ const { reset, formState, control, register, setValue } = form;
431
+ const nameVal = useWatch({ control, name: "name" });
432
+ const codeVal = useWatch({ control, name: "code" });
433
+ useEffect(() => {
434
+ const nameDefault = typeof nameVal === "object" && nameVal !== null && defaultLanguage in nameVal ? nameVal[defaultLanguage] ?? "" : "";
435
+ if (mode === "new" && typeof nameDefault === "string" && nameDefault.trim().length > 0 && !codeVal) {
436
+ const code = nameDefault.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
437
+ if (code) {
438
+ setValue("code", code);
439
+ }
440
+ }
441
+ }, [mode, nameVal, setValue, codeVal, defaultLanguage]);
442
+ useEffect(() => {
443
+ if (!open) {
444
+ return;
445
+ }
446
+ if (mode === "edit" && data?.role && !isLoading) {
447
+ const r = data.role;
448
+ reset({
449
+ name: r.name ?? {},
450
+ code: r.code,
451
+ description: r.description ?? {},
452
+ permissionIds: r.permissionIds ?? []
453
+ });
454
+ } else {
455
+ reset({ ...defaults, permissionIds: [] });
456
+ }
457
+ }, [mode, data, open, isLoading, reset, defaults]);
458
+ const onSubmit = form.handleSubmit(async (d) => {
459
+ const body = {
460
+ name: d.name,
461
+ code: d.code,
462
+ description: d.description ?? void 0,
463
+ permissionIds: d.permissionIds
464
+ };
465
+ if (mode === "new") {
466
+ await create.mutateAsync({ body });
467
+ } else if (roleId) {
468
+ await update.mutateAsync({
469
+ params: { path: { id: roleId } },
470
+ body
471
+ });
472
+ }
473
+ onSuccess?.();
474
+ onClose();
475
+ });
476
+ const onDelete = async () => {
477
+ if (!roleId) {
478
+ return;
479
+ }
480
+ await del.mutateAsync({ params: { path: { id: roleId } } });
481
+ onSuccess?.();
482
+ onClose();
483
+ };
484
+ const editable = mode === "new" || data?.role?.isEditable !== false;
485
+ return /* @__PURE__ */ jsx6(
486
+ EntityDrawer,
487
+ {
488
+ title: mode === "new" ? "New role" : "Edit role",
489
+ open,
490
+ onClose,
491
+ isDirty: formState.isDirty,
492
+ size: "md",
493
+ form: isLoading ? /* @__PURE__ */ jsx6(FormSkeleton, {}) : /* @__PURE__ */ jsx6(Form, { ...form, children: /* @__PURE__ */ jsxs3("form", { onSubmit, className: "space-y-4", children: [
494
+ /* @__PURE__ */ jsx6(
495
+ LocaleInputText,
496
+ {
497
+ label: "Name",
498
+ field: "name",
499
+ required: true,
500
+ register,
501
+ errors: formState.errors,
502
+ placeholder: "e.g. Administrator",
503
+ disabled: !editable
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsx6(
507
+ FormField,
508
+ {
509
+ control,
510
+ name: "code",
511
+ render: ({ field }) => /* @__PURE__ */ jsxs3(FormItem, { children: [
512
+ /* @__PURE__ */ jsxs3(FormLabel, { children: [
513
+ "Code ",
514
+ /* @__PURE__ */ jsx6("span", { className: "text-destructive", children: "*" })
515
+ ] }),
516
+ /* @__PURE__ */ jsx6(FormControl, { children: /* @__PURE__ */ jsx6(
517
+ Input,
518
+ {
519
+ placeholder: "e.g. admin",
520
+ disabled: !editable,
521
+ ...field
522
+ }
523
+ ) }),
524
+ /* @__PURE__ */ jsx6(FormMessage, {})
525
+ ] })
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsx6(
529
+ LocaleInputTextarea,
530
+ {
531
+ label: "Description",
532
+ field: "description",
533
+ register,
534
+ errors: formState.errors,
535
+ placeholder: "Description",
536
+ rows: 3,
537
+ disabled: !editable
538
+ }
539
+ )
540
+ ] }) }),
541
+ actions: /* @__PURE__ */ jsx6(
542
+ EntityFormActions,
543
+ {
544
+ mode,
545
+ onSubmit,
546
+ onReset: mode === "new" ? () => reset(defaults) : void 0,
547
+ onDelete: mode === "edit" ? onDelete : void 0,
548
+ isSubmitting: create.isPending || update.isPending,
549
+ isDeleting: del.isPending,
550
+ disabled: isLoading || !editable,
551
+ itemName: "role"
552
+ }
553
+ )
554
+ }
555
+ );
556
+ }
557
+ function FormSkeleton() {
558
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
559
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
560
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-4 w-16" }),
561
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-10 w-full" })
562
+ ] }),
563
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
564
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-4 w-14" }),
565
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-10 w-full" })
566
+ ] }),
567
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
568
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-4 w-24" }),
569
+ /* @__PURE__ */ jsx6(Skeleton, { className: "h-20 w-full" })
570
+ ] })
571
+ ] });
572
+ }
573
+
574
+ // src/pages/iam/roles/_components/roles-list.tsx
575
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
576
+ var TABLE_COLUMN_COUNT = 5;
577
+ function RolesList({
578
+ data,
579
+ isLoading,
580
+ view,
581
+ pageIndex,
582
+ pageSize,
583
+ pageCount,
584
+ totalRows,
585
+ onPageChange,
586
+ onPageSizeChange,
587
+ onCreateNew
588
+ }) {
589
+ const [drawerRole, setDrawerRole] = useState2(null);
590
+ if (isLoading) {
591
+ return /* @__PURE__ */ jsx7(
592
+ EntityLoadingState,
593
+ {
594
+ view,
595
+ rowCount: pageSize,
596
+ columnCount: TABLE_COLUMN_COUNT,
597
+ cardCount: pageSize
598
+ }
599
+ );
600
+ }
601
+ if (totalRows === 0) {
602
+ return /* @__PURE__ */ jsx7(
603
+ EntityEmptyState,
604
+ {
605
+ icon: IconShield2,
606
+ entityName: "role",
607
+ title: "No roles yet",
608
+ description: "Create your first role to get started.",
609
+ onAction: onCreateNew
610
+ }
611
+ );
612
+ }
613
+ if (view === "table") {
614
+ return /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
615
+ drawerRole ? /* @__PURE__ */ jsx7(
616
+ RoleForm,
617
+ {
618
+ mode: "edit",
619
+ roleId: drawerRole.id,
620
+ open: true,
621
+ onClose: () => setDrawerRole(null),
622
+ onSuccess: () => setDrawerRole(null)
623
+ }
624
+ ) : null,
625
+ /* @__PURE__ */ jsxs4(DisplayTable, { withTableBorder: true, children: [
626
+ /* @__PURE__ */ jsx7(Thead, { children: /* @__PURE__ */ jsxs4(Tr, { children: [
627
+ /* @__PURE__ */ jsx7(Th, { children: "Role" }),
628
+ /* @__PURE__ */ jsx7(Th, { children: "Description" }),
629
+ /* @__PURE__ */ jsx7(Th, { children: "Access" }),
630
+ /* @__PURE__ */ jsx7(Th, { children: "Created" }),
631
+ /* @__PURE__ */ jsx7(Th, { className: "w-[50px]" })
632
+ ] }) }),
633
+ /* @__PURE__ */ jsx7(Tbody, { children: data.map((role) => /* @__PURE__ */ jsxs4(Tr, { className: "group", children: [
634
+ /* @__PURE__ */ jsx7(Td, { children: /* @__PURE__ */ jsxs4(
635
+ Link,
636
+ {
637
+ href: `/iam/roles/${role.id}`,
638
+ className: "block text-left font-medium hover:text-primary hover:underline cursor-pointer",
639
+ children: [
640
+ /* @__PURE__ */ jsx7("p", { children: str(role.name) || role.code }),
641
+ /* @__PURE__ */ jsx7(Badge2, { variant: "outline", className: "mt-1 text-xs", children: role.code })
642
+ ]
643
+ }
644
+ ) }),
645
+ /* @__PURE__ */ jsx7(Td, { children: /* @__PURE__ */ jsx7("span", { className: "text-muted-foreground line-clamp-1 max-w-[200px]", children: str(role.description) || "\u2014" }) }),
646
+ /* @__PURE__ */ jsx7(Td, { children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap gap-2", children: [
647
+ role.isSystem ? /* @__PURE__ */ jsx7(Badge2, { children: "System" }) : null,
648
+ /* @__PURE__ */ jsxs4(Badge2, { variant: "secondary", children: [
649
+ role.permissionCount ?? role.permissionIds?.length ?? 0,
650
+ " ",
651
+ "permissions"
652
+ ] })
653
+ ] }) }),
654
+ /* @__PURE__ */ jsx7(Td, { children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
655
+ /* @__PURE__ */ jsx7(IconCalendar2, { className: "h-4 w-4" }),
656
+ new Date(role.createdAt).toLocaleDateString()
657
+ ] }) }),
658
+ /* @__PURE__ */ jsx7(Td, { children: /* @__PURE__ */ jsx7(DataTableAction, { onClick: () => setDrawerRole(role) }) })
659
+ ] }, role.id)) })
660
+ ] }),
661
+ /* @__PURE__ */ jsx7(
662
+ DataTablePagination,
663
+ {
664
+ pageIndex,
665
+ pageSize,
666
+ pageCount,
667
+ totalRows,
668
+ onPageChange,
669
+ onPageSizeChange
670
+ }
671
+ )
672
+ ] });
673
+ }
674
+ return /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
675
+ /* @__PURE__ */ jsx7("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: data.map((r) => /* @__PURE__ */ jsx7(RoleCard, { role: r }, r.id)) }),
676
+ /* @__PURE__ */ jsx7(
677
+ DataTablePagination,
678
+ {
679
+ pageIndex,
680
+ pageSize,
681
+ pageCount,
682
+ totalRows,
683
+ onPageChange,
684
+ onPageSizeChange
685
+ }
686
+ )
687
+ ] });
688
+ }
689
+
690
+ // src/pages/iam/users/activity/_components/role-section.tsx
691
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
692
+ var LIMIT = 100;
693
+ var TABLE_COLUMN_COUNT2 = 4;
694
+ function filterAndSort(roles, search, sort, order) {
695
+ let out = roles;
696
+ if (search.trim()) {
697
+ const q = search.trim().toLowerCase();
698
+ out = out.filter(
699
+ (r) => str(r.name).toLowerCase().includes(q) || r.code.toLowerCase().includes(q)
700
+ );
701
+ }
702
+ const mult = order === "asc" ? 1 : -1;
703
+ const by = sort === "code" ? "code" : "createdAt";
704
+ out = [...out].sort(
705
+ (a, b) => by === "code" ? mult * a.code.localeCompare(b.code) : mult * (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
706
+ );
707
+ return out;
708
+ }
709
+ function RoleSection({ userId }) {
710
+ const [open, setOpen] = useState3(false);
711
+ const sectionState = useEntitySectionState2({
712
+ defaultSort: "createdAt",
713
+ defaultOrder: "desc",
714
+ defaultPageSize: 10,
715
+ filterOptions: [
716
+ { label: "All", value: "" },
717
+ { label: "By Code", value: "code" }
718
+ ],
719
+ sortOptions: [
720
+ { label: "Created", value: "createdAt" },
721
+ { label: "Updated", value: "updatedAt" },
722
+ { label: "Code", value: "code" }
723
+ ],
724
+ views: ["table", "card"]
725
+ });
726
+ const { data, isPending, isFetching } = authApi$.useQuery(
727
+ "get",
728
+ "/roles",
729
+ { params: { query: { limit: LIMIT } } },
730
+ { ...defaultEntityQueryOptions, enabled: open }
731
+ );
732
+ const isLoading = isPending || isFetching;
733
+ const roles = data?.roles ?? [];
734
+ const filtered = useMemo3(
735
+ () => filterAndSort(
736
+ roles,
737
+ sectionState.search,
738
+ sectionState.sort,
739
+ sectionState.order
740
+ ),
741
+ [roles, sectionState.search, sectionState.sort, sectionState.order]
742
+ );
743
+ const pageCount = Math.ceil(filtered.length / sectionState.pageSize) || 1;
744
+ const pageIndex = Math.min(sectionState.page - 1, Math.max(0, pageCount - 1));
745
+ const paginated = useMemo3(
746
+ () => filtered.slice(
747
+ pageIndex * sectionState.pageSize,
748
+ pageIndex * sectionState.pageSize + sectionState.pageSize
749
+ ),
750
+ [filtered, pageIndex, sectionState.pageSize]
751
+ );
752
+ return /* @__PURE__ */ jsx8(
753
+ EntitySection,
754
+ {
755
+ title: "Role",
756
+ state: sectionState,
757
+ onOpenChange: setOpen,
758
+ actions: /* @__PURE__ */ jsx8(
759
+ RoleSelector,
760
+ {
761
+ trigger: /* @__PURE__ */ jsxs5(Button2, { variant: "outline", size: "sm", children: [
762
+ /* @__PURE__ */ jsx8(IconPlus, { className: "h-4 w-4" }),
763
+ "Add role"
764
+ ] }),
765
+ multiple: true,
766
+ onSelect: (roles2) => {
767
+ console.log("Selected roles:", userId, roles2);
768
+ }
769
+ }
770
+ ),
771
+ config: {
772
+ searchPlaceholder: "Search roles...",
773
+ filterOptions: sectionState.filterOptions,
774
+ sortOptions: sectionState.sortOptions,
775
+ views: sectionState.views
776
+ },
777
+ children: (state) => /* @__PURE__ */ jsxs5(Fragment2, { children: [
778
+ isLoading && /* @__PURE__ */ jsx8(
779
+ EntityLoadingState2,
780
+ {
781
+ view: state.view,
782
+ rowCount: state.pageSize,
783
+ columnCount: TABLE_COLUMN_COUNT2,
784
+ cardCount: state.pageSize
785
+ }
786
+ ),
787
+ !isLoading && filtered.length === 0 && /* @__PURE__ */ jsx8(
788
+ EntityEmptyState2,
789
+ {
790
+ icon: IconShield3,
791
+ entityName: "role",
792
+ title: "No roles",
793
+ description: roles.length === 0 ? "No roles in tenant." : "No matches."
794
+ }
795
+ ),
796
+ !isLoading && filtered.length > 0 && /* @__PURE__ */ jsx8(
797
+ RolesList,
798
+ {
799
+ data: paginated,
800
+ view: state.view,
801
+ pageIndex,
802
+ pageSize: state.pageSize,
803
+ pageCount,
804
+ totalRows: filtered.length,
805
+ onPageChange: (p) => state.setPage(p + 1),
806
+ onPageSizeChange: (size) => {
807
+ state.setPageSize(size);
808
+ state.setPage(1);
809
+ }
810
+ }
811
+ )
812
+ ] })
813
+ }
814
+ );
815
+ }
816
+
817
+ // src/pages/iam/users/activity/user-activity-page-content.tsx
818
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
819
+ function UserActivityPageContent({
820
+ userId
821
+ }) {
822
+ if (!userId) {
823
+ return null;
824
+ }
825
+ return /* @__PURE__ */ jsxs6("div", { className: "space-y-4", children: [
826
+ /* @__PURE__ */ jsxs6(Card2, { children: [
827
+ /* @__PURE__ */ jsx9(CardHeader2, { children: /* @__PURE__ */ jsx9(CardTitle, { children: "Activity" }) }),
828
+ /* @__PURE__ */ jsxs6(CardContent2, { className: "flex items-center gap-2 text-muted-foreground text-sm", children: [
829
+ /* @__PURE__ */ jsx9(IconCalendar3, { className: "h-4 w-4" }),
830
+ "Activity (placeholder)"
831
+ ] })
832
+ ] }),
833
+ /* @__PURE__ */ jsx9(RoleSection, { userId }),
834
+ /* @__PURE__ */ jsx9(Section, { title: "Permissions", children: "test" }),
835
+ /* @__PURE__ */ jsx9(Section, { title: "Groups", children: "test" })
836
+ ] });
837
+ }
838
+
839
+ // src/pages/iam/user-activity.tsx
840
+ import { jsx as jsx10 } from "react/jsx-runtime";
841
+ async function UserActivityPage({
842
+ params
843
+ }) {
844
+ const { id } = await params;
845
+ return /* @__PURE__ */ jsx10(UserActivityPageContent, { userId: id });
846
+ }
847
+ export {
848
+ UserActivityPage as default
849
+ };
850
+ //# sourceMappingURL=user-activity.js.map