@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,610 @@
1
+ "use client";
2
+
3
+ // src/pages/iam/tenants.tsx
4
+ import {
5
+ EntityDrawerTrigger,
6
+ EntityFilter,
7
+ EntityHeader,
8
+ EntitySearch,
9
+ EntitySort,
10
+ EntityViewToggle,
11
+ PageBody,
12
+ PageContainer,
13
+ useBreadcrumbs,
14
+ useEntityPagination,
15
+ useEntityParams
16
+ } from "@mesob/ui/components";
17
+ import { IconBuilding as IconBuilding2 } from "@tabler/icons-react";
18
+ import { useState as useState4 } from "react";
19
+
20
+ // src/lib/query-options.ts
21
+ import { keepPreviousData } from "@tanstack/react-query";
22
+ var defaultEntityQueryOptions = {
23
+ refetchOnMount: false,
24
+ refetchOnWindowFocus: false,
25
+ refetchOnReconnect: false,
26
+ staleTime: 60 * 1e3,
27
+ gcTime: 5 * 60 * 1e3,
28
+ placeholderData: keepPreviousData,
29
+ retry: 1
30
+ };
31
+
32
+ // src/provider.tsx
33
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
34
+ import { deepmerge } from "deepmerge-ts";
35
+ import createFetchClient from "openapi-fetch";
36
+ import createClient from "openapi-react-query";
37
+ import { createContext, useContext, useMemo, useState } from "react";
38
+
39
+ // src/utils/cookie.ts
40
+ var isProduction = typeof process !== "undefined" && process.env.NODE_ENV === "production";
41
+
42
+ // src/provider.tsx
43
+ import { jsx } from "react/jsx-runtime";
44
+ var SessionContext = createContext(null);
45
+ var ApiContext = createContext(null);
46
+ var ConfigContext = createContext(null);
47
+ var queryClient = new QueryClient({
48
+ defaultOptions: {
49
+ queries: {
50
+ refetchOnWindowFocus: false
51
+ }
52
+ }
53
+ });
54
+ function useApi() {
55
+ const context = useContext(ApiContext);
56
+ if (!context) {
57
+ throw new Error("useApi must be used within MesobAuthProvider");
58
+ }
59
+ return context;
60
+ }
61
+
62
+ // src/pages/iam/tenants/_components/tenant-form.tsx
63
+ import { zodResolver } from "@hookform/resolvers/zod";
64
+ import {
65
+ EntityDrawer,
66
+ EntityFormActions,
67
+ Input,
68
+ Label,
69
+ Skeleton,
70
+ Textarea
71
+ } from "@mesob/ui/components";
72
+ import { useQueryClient } from "@tanstack/react-query";
73
+ import { useEffect } from "react";
74
+ import { useForm } from "react-hook-form";
75
+ import { z } from "zod";
76
+
77
+ // src/pages/iam/shared/navigation.tsx
78
+ import { useMesob } from "@mesob/ui/providers";
79
+ import { jsx as jsx2 } from "react/jsx-runtime";
80
+ function AppLink({ href, children, ...props }) {
81
+ const mesob = useMesob();
82
+ const Link2 = mesob?.linkComponent ?? mesob?.navigation?.Link;
83
+ const locale = mesob?.locale;
84
+ if (Link2) {
85
+ return /* @__PURE__ */ jsx2(Link2, { href, ...locale ? { locale } : {}, ...props, children });
86
+ }
87
+ return /* @__PURE__ */ jsx2("a", { href, ...props, children });
88
+ }
89
+
90
+ // src/pages/iam/shared/page-helpers.tsx
91
+ import { jsx as jsx3 } from "react/jsx-runtime";
92
+ var authApi$ = {
93
+ useQuery(...args) {
94
+ const { hooks } = useApi();
95
+ return hooks.useQuery(...args);
96
+ },
97
+ useMutation(...args) {
98
+ const { hooks } = useApi();
99
+ return hooks.useMutation(...args);
100
+ }
101
+ };
102
+ function Link(props) {
103
+ return /* @__PURE__ */ jsx3(AppLink, { ...props });
104
+ }
105
+
106
+ // src/pages/iam/tenants/_components/tenants-data.ts
107
+ function str(v) {
108
+ if (v == null) {
109
+ return "";
110
+ }
111
+ if (typeof v === "string") {
112
+ return v;
113
+ }
114
+ if (typeof v === "object" && v !== null && "en" in v) {
115
+ const o = v;
116
+ return o.en ?? o.am ?? "";
117
+ }
118
+ return String(v);
119
+ }
120
+
121
+ // src/pages/iam/tenants/_components/tenant-form.tsx
122
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
123
+ var schema = z.object({
124
+ id: z.string().min(1).max(30),
125
+ name: z.string().optional(),
126
+ description: z.string().optional(),
127
+ isActive: z.boolean()
128
+ });
129
+ var defaults = {
130
+ id: "",
131
+ name: "",
132
+ description: "",
133
+ isActive: true
134
+ };
135
+ function TenantForm({
136
+ mode,
137
+ tenantId,
138
+ open,
139
+ onClose,
140
+ onSuccess
141
+ }) {
142
+ const qc = useQueryClient();
143
+ const { data, isLoading } = authApi$.useQuery(
144
+ "get",
145
+ "/tenants/{id}",
146
+ { params: { path: { id: tenantId ?? "" } } },
147
+ { enabled: mode === "edit" && !!tenantId }
148
+ );
149
+ const create = authApi$.useMutation("post", "/tenants", {
150
+ onSuccess: () => qc.invalidateQueries({ queryKey: ["get", "/tenants"] })
151
+ });
152
+ const update = authApi$.useMutation("put", "/tenants/{id}", {
153
+ onSuccess: () => {
154
+ qc.invalidateQueries({ queryKey: ["get", "/tenants"] });
155
+ if (tenantId) {
156
+ qc.invalidateQueries({ queryKey: ["get", "/tenants/{id}"] });
157
+ }
158
+ }
159
+ });
160
+ const del = authApi$.useMutation("delete", "/tenants/{id}", {
161
+ onSuccess: () => qc.invalidateQueries({ queryKey: ["get", "/tenants"] })
162
+ });
163
+ const form = useForm({
164
+ resolver: zodResolver(schema),
165
+ defaultValues: defaults
166
+ });
167
+ const { reset, formState, register } = form;
168
+ useEffect(() => {
169
+ if (!open) {
170
+ return;
171
+ }
172
+ if (mode === "edit" && data?.tenant && !isLoading) {
173
+ const t = data.tenant;
174
+ reset({
175
+ id: t.id,
176
+ name: str(t.name) || "",
177
+ description: str(t.description) || "",
178
+ isActive: t.isActive
179
+ });
180
+ } else {
181
+ reset(defaults);
182
+ }
183
+ }, [mode, data, open, isLoading, reset]);
184
+ const onSubmit = form.handleSubmit(async (d) => {
185
+ const body = {
186
+ id: d.id,
187
+ name: d.name || void 0,
188
+ description: d.description || void 0,
189
+ isActive: d.isActive
190
+ };
191
+ if (mode === "new") {
192
+ await create.mutateAsync({ body });
193
+ } else if (tenantId) {
194
+ await update.mutateAsync({
195
+ params: { path: { id: tenantId } },
196
+ body: {
197
+ name: d.name || void 0,
198
+ description: d.description || void 0,
199
+ isActive: d.isActive
200
+ }
201
+ });
202
+ }
203
+ onSuccess?.();
204
+ onClose();
205
+ });
206
+ const onDelete = async () => {
207
+ if (!tenantId) {
208
+ return;
209
+ }
210
+ await del.mutateAsync({ params: { path: { id: tenantId } } });
211
+ onSuccess?.();
212
+ onClose();
213
+ };
214
+ return /* @__PURE__ */ jsx4(
215
+ EntityDrawer,
216
+ {
217
+ title: mode === "new" ? "New tenant" : "Edit tenant",
218
+ open,
219
+ onClose,
220
+ isDirty: formState.isDirty,
221
+ size: "md",
222
+ form: isLoading ? /* @__PURE__ */ jsx4(FormSkeleton, {}) : /* @__PURE__ */ jsxs("form", { onSubmit, className: "space-y-4", children: [
223
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
224
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "id", children: [
225
+ "ID ",
226
+ /* @__PURE__ */ jsx4("span", { className: "text-destructive", children: "*" })
227
+ ] }),
228
+ /* @__PURE__ */ jsx4(
229
+ Input,
230
+ {
231
+ id: "id",
232
+ placeholder: "e.g. acme",
233
+ ...register("id"),
234
+ disabled: mode === "edit"
235
+ }
236
+ ),
237
+ formState.errors.id && /* @__PURE__ */ jsx4("p", { className: "text-sm text-destructive", children: formState.errors.id.message })
238
+ ] }),
239
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
240
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "name", children: "Name" }),
241
+ /* @__PURE__ */ jsx4(
242
+ Input,
243
+ {
244
+ id: "name",
245
+ placeholder: "Display name",
246
+ ...register("name")
247
+ }
248
+ )
249
+ ] }),
250
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
251
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "description", children: "Description" }),
252
+ /* @__PURE__ */ jsx4(
253
+ Textarea,
254
+ {
255
+ id: "description",
256
+ placeholder: "Description",
257
+ rows: 3,
258
+ ...register("description")
259
+ }
260
+ )
261
+ ] }),
262
+ mode === "edit" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
263
+ /* @__PURE__ */ jsx4(
264
+ "input",
265
+ {
266
+ type: "checkbox",
267
+ id: "isActive",
268
+ ...register("isActive", {
269
+ setValueAs: (v) => v === true || v === "on"
270
+ }),
271
+ className: "h-4 w-4"
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsx4(Label, { htmlFor: "isActive", children: "Active" })
275
+ ] })
276
+ ] }),
277
+ actions: /* @__PURE__ */ jsx4(
278
+ EntityFormActions,
279
+ {
280
+ mode,
281
+ onSubmit,
282
+ onReset: mode === "new" ? () => reset(defaults) : void 0,
283
+ onDelete: mode === "edit" ? onDelete : void 0,
284
+ isSubmitting: create.isPending || update.isPending,
285
+ isDeleting: del.isPending,
286
+ disabled: isLoading,
287
+ itemName: "tenant"
288
+ }
289
+ )
290
+ }
291
+ );
292
+ }
293
+ function FormSkeleton() {
294
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
295
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
296
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-4 w-12" }),
297
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-10 w-full" })
298
+ ] }),
299
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
300
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-4 w-16" }),
301
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-10 w-full" })
302
+ ] }),
303
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
304
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-4 w-24" }),
305
+ /* @__PURE__ */ jsx4(Skeleton, { className: "h-20 w-full" })
306
+ ] })
307
+ ] });
308
+ }
309
+
310
+ // src/pages/iam/tenants/_components/tenants-list.tsx
311
+ import {
312
+ Badge as Badge2,
313
+ DataTableAction,
314
+ DataTablePagination,
315
+ DisplayTable,
316
+ EntityEmptyState,
317
+ EntityLoadingState,
318
+ Tbody,
319
+ Td,
320
+ Th,
321
+ Thead,
322
+ Tr
323
+ } from "@mesob/ui/components";
324
+ import { IconBuilding, IconCalendar } from "@tabler/icons-react";
325
+ import { useState as useState3 } from "react";
326
+
327
+ // src/pages/iam/tenants/_components/tenant-card.tsx
328
+ import {
329
+ Badge,
330
+ Button,
331
+ Card,
332
+ CardContent,
333
+ CardHeader,
334
+ DropdownMenu,
335
+ DropdownMenuContent,
336
+ DropdownMenuItem,
337
+ DropdownMenuPortal,
338
+ DropdownMenuTrigger
339
+ } from "@mesob/ui/components";
340
+ import { IconDots, IconPencil } from "@tabler/icons-react";
341
+ import { useState as useState2 } from "react";
342
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
343
+ function TenantCard({ tenant }) {
344
+ const [editOpen, setEditOpen] = useState2(false);
345
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
346
+ /* @__PURE__ */ jsxs2(Card, { className: "group hover:shadow-md transition-shadow", children: [
347
+ /* @__PURE__ */ jsxs2(CardHeader, { className: "pb-2", children: [
348
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between", children: [
349
+ /* @__PURE__ */ jsx5(
350
+ Link,
351
+ {
352
+ href: `/iam/tenants/${tenant.id}`,
353
+ className: "text-left font-semibold hover:text-primary hover:underline",
354
+ children: str(tenant.name) || tenant.id
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsxs2(DropdownMenu, { children: [
358
+ /* @__PURE__ */ jsx5(
359
+ DropdownMenuTrigger,
360
+ {
361
+ render: /* @__PURE__ */ jsx5(
362
+ Button,
363
+ {
364
+ variant: "ghost",
365
+ size: "icon",
366
+ className: "h-8 w-8 opacity-0 group-hover:opacity-100 transition-opacity"
367
+ }
368
+ ),
369
+ children: /* @__PURE__ */ jsx5(IconDots, { className: "h-4 w-4" })
370
+ }
371
+ ),
372
+ /* @__PURE__ */ jsx5(DropdownMenuPortal, { children: /* @__PURE__ */ jsx5(DropdownMenuContent, { children: /* @__PURE__ */ jsxs2(DropdownMenuItem, { onClick: () => setEditOpen(true), children: [
373
+ /* @__PURE__ */ jsx5(IconPencil, { className: "mr-2 h-4 w-4" }),
374
+ "Edit"
375
+ ] }) }) })
376
+ ] })
377
+ ] }),
378
+ /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: tenant.id })
379
+ ] }),
380
+ /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-2", children: [
381
+ /* @__PURE__ */ jsx5(Badge, { variant: tenant.isActive ? "default" : "secondary", children: tenant.isActive ? "Active" : "Inactive" }),
382
+ str(tenant.description) ? /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground line-clamp-2", children: str(tenant.description) }) : null,
383
+ /* @__PURE__ */ jsxs2("p", { className: "text-xs text-muted-foreground", children: [
384
+ "Created ",
385
+ new Date(tenant.createdAt).toLocaleDateString()
386
+ ] })
387
+ ] })
388
+ ] }),
389
+ editOpen ? /* @__PURE__ */ jsx5(
390
+ TenantForm,
391
+ {
392
+ mode: "edit",
393
+ tenantId: tenant.id,
394
+ open: editOpen,
395
+ onClose: () => setEditOpen(false)
396
+ }
397
+ ) : null
398
+ ] });
399
+ }
400
+
401
+ // src/pages/iam/tenants/_components/tenants-list.tsx
402
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
403
+ var TABLE_COLUMN_COUNT = 5;
404
+ function TenantsList({
405
+ data,
406
+ isLoading,
407
+ view,
408
+ pageIndex,
409
+ pageSize,
410
+ pageCount,
411
+ totalRows,
412
+ onPageChange,
413
+ onPageSizeChange,
414
+ onCreateNew
415
+ }) {
416
+ const [editingTenantId, setEditingTenantId] = useState3(null);
417
+ if (isLoading) {
418
+ return /* @__PURE__ */ jsx6(
419
+ EntityLoadingState,
420
+ {
421
+ view,
422
+ rowCount: pageSize,
423
+ columnCount: TABLE_COLUMN_COUNT,
424
+ cardCount: pageSize
425
+ }
426
+ );
427
+ }
428
+ if (totalRows === 0) {
429
+ return /* @__PURE__ */ jsx6(
430
+ EntityEmptyState,
431
+ {
432
+ icon: IconBuilding,
433
+ entityName: "tenant",
434
+ title: "No tenants yet",
435
+ description: "Create your first tenant to get started.",
436
+ onAction: onCreateNew
437
+ }
438
+ );
439
+ }
440
+ if (view === "table") {
441
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
442
+ editingTenantId && /* @__PURE__ */ jsx6(
443
+ TenantForm,
444
+ {
445
+ mode: "edit",
446
+ tenantId: editingTenantId,
447
+ open: true,
448
+ onClose: () => setEditingTenantId(null)
449
+ }
450
+ ),
451
+ /* @__PURE__ */ jsxs3(DisplayTable, { withTableBorder: true, children: [
452
+ /* @__PURE__ */ jsx6(Thead, { children: /* @__PURE__ */ jsxs3(Tr, { children: [
453
+ /* @__PURE__ */ jsx6(Th, { children: "Tenant" }),
454
+ /* @__PURE__ */ jsx6(Th, { children: "Description" }),
455
+ /* @__PURE__ */ jsx6(Th, { children: "Status" }),
456
+ /* @__PURE__ */ jsx6(Th, { children: "Created" }),
457
+ /* @__PURE__ */ jsx6(Th, { className: "w-[50px]" })
458
+ ] }) }),
459
+ /* @__PURE__ */ jsx6(Tbody, { children: data.map((tenant) => /* @__PURE__ */ jsxs3(Tr, { className: "group", children: [
460
+ /* @__PURE__ */ jsx6(Td, { children: /* @__PURE__ */ jsxs3(
461
+ Link,
462
+ {
463
+ href: `/iam/tenants/${tenant.id}`,
464
+ className: "block text-left font-medium hover:text-primary hover:underline cursor-pointer",
465
+ children: [
466
+ /* @__PURE__ */ jsx6("p", { children: str(tenant.name) || tenant.id }),
467
+ /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: tenant.id })
468
+ ]
469
+ }
470
+ ) }),
471
+ /* @__PURE__ */ jsx6(Td, { children: /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground line-clamp-1 max-w-[200px]", children: str(tenant.description) || "\u2014" }) }),
472
+ /* @__PURE__ */ jsx6(Td, { children: /* @__PURE__ */ jsx6(Badge2, { variant: tenant.isActive ? "default" : "secondary", children: tenant.isActive ? "Active" : "Inactive" }) }),
473
+ /* @__PURE__ */ jsx6(Td, { children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
474
+ /* @__PURE__ */ jsx6(IconCalendar, { className: "h-4 w-4" }),
475
+ new Date(tenant.createdAt).toLocaleDateString()
476
+ ] }) }),
477
+ /* @__PURE__ */ jsx6(Td, { children: /* @__PURE__ */ jsx6(
478
+ DataTableAction,
479
+ {
480
+ onClick: () => setEditingTenantId(tenant.id)
481
+ }
482
+ ) })
483
+ ] }, tenant.id)) })
484
+ ] }),
485
+ /* @__PURE__ */ jsx6(
486
+ DataTablePagination,
487
+ {
488
+ pageIndex,
489
+ pageSize,
490
+ pageCount,
491
+ totalRows,
492
+ onPageChange,
493
+ onPageSizeChange
494
+ }
495
+ )
496
+ ] });
497
+ }
498
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
499
+ /* @__PURE__ */ jsx6("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: data.map((t) => /* @__PURE__ */ jsx6(TenantCard, { tenant: t }, t.id)) }),
500
+ /* @__PURE__ */ jsx6(
501
+ DataTablePagination,
502
+ {
503
+ pageIndex,
504
+ pageSize,
505
+ pageCount,
506
+ totalRows,
507
+ onPageChange,
508
+ onPageSizeChange
509
+ }
510
+ )
511
+ ] });
512
+ }
513
+
514
+ // src/pages/iam/tenants.tsx
515
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
516
+ function TenantsPage() {
517
+ const { hooks } = useApi();
518
+ useBreadcrumbs({
519
+ items: [
520
+ { label: "Home", href: "/dashboard" },
521
+ { label: "IAM", href: "/iam/tenants" },
522
+ { label: "Tenants" }
523
+ ]
524
+ });
525
+ const [createOpen, setCreateOpen] = useState4(false);
526
+ const { queryConfig, params, setParams } = useEntityParams({
527
+ searchKey: "search"
528
+ });
529
+ const tenantsQuery = queryConfig;
530
+ const { data, error, isPending, isFetching } = hooks.useQuery(
531
+ "get",
532
+ "/tenants",
533
+ tenantsQuery,
534
+ defaultEntityQueryOptions
535
+ );
536
+ const isLoading = isPending || isFetching;
537
+ const tenants = data?.tenants ?? [];
538
+ const { total, pageCount } = useEntityPagination({
539
+ items: tenants,
540
+ total: data?.total,
541
+ pageSize: params.pageSize
542
+ });
543
+ const errorStatus = error?.status;
544
+ const hasAccessError = errorStatus === 401 || errorStatus === 403;
545
+ const hasError = Boolean(error) && !isLoading;
546
+ return /* @__PURE__ */ jsx7(PageContainer, { className: "flex flex-1 flex-col gap-4 p-4 pt-0", children: /* @__PURE__ */ jsxs4(PageBody, { className: "px-0", children: [
547
+ /* @__PURE__ */ jsx7(
548
+ EntityHeader,
549
+ {
550
+ icon: /* @__PURE__ */ jsx7(IconBuilding2, { className: "size-5" }),
551
+ title: "Tenants",
552
+ actions: hasAccessError ? null : /* @__PURE__ */ jsx7(
553
+ EntityDrawerTrigger,
554
+ {
555
+ mode: "new",
556
+ entity: "Tenant",
557
+ open: createOpen,
558
+ onOpenChange: setCreateOpen,
559
+ children: (open, onClose) => /* @__PURE__ */ jsx7(TenantForm, { mode: "new", open, onClose })
560
+ }
561
+ ),
562
+ search: hasAccessError ? null : /* @__PURE__ */ jsx7(EntitySearch, { paramKey: "search", placeholder: "Search tenants..." }),
563
+ filter: hasAccessError ? null : /* @__PURE__ */ jsx7(
564
+ EntityFilter,
565
+ {
566
+ options: [
567
+ { label: "All", value: "" },
568
+ { label: "Active", value: "isActive:true" },
569
+ { label: "Inactive", value: "isActive:false" }
570
+ ],
571
+ placeholder: "Filter"
572
+ }
573
+ ),
574
+ sort: hasAccessError ? null : /* @__PURE__ */ jsx7(
575
+ EntitySort,
576
+ {
577
+ options: [
578
+ { label: "Created", value: "createdAt" },
579
+ { label: "Updated", value: "updatedAt" },
580
+ { label: "Name", value: "name" }
581
+ ]
582
+ }
583
+ ),
584
+ view: hasAccessError ? null : /* @__PURE__ */ jsx7(EntityViewToggle, { views: ["table", "card"] })
585
+ }
586
+ ),
587
+ hasError ? /* @__PURE__ */ jsxs4("div", { className: "rounded-[1.75rem] border border-border/60 bg-muted/20 p-8", children: [
588
+ /* @__PURE__ */ jsx7("div", { className: "text-lg font-semibold", children: hasAccessError ? "Tenant access denied" : "Unable to load tenants" }),
589
+ /* @__PURE__ */ jsx7("p", { className: "mt-2 text-sm text-muted-foreground", children: hasAccessError ? "This account does not have permission to view or manage tenants." : "The tenants page returned an unexpected error. Retry after the API is healthy." })
590
+ ] }) : /* @__PURE__ */ jsx7(
591
+ TenantsList,
592
+ {
593
+ data: tenants,
594
+ isLoading,
595
+ view: params.view || "table",
596
+ pageIndex: params.page - 1,
597
+ pageSize: params.pageSize,
598
+ pageCount,
599
+ totalRows: total,
600
+ onCreateNew: () => setCreateOpen(true),
601
+ onPageChange: (p) => setParams({ page: p + 1 }),
602
+ onPageSizeChange: (size) => setParams({ pageSize: size, page: 1 })
603
+ }
604
+ )
605
+ ] }) });
606
+ }
607
+ export {
608
+ TenantsPage as default
609
+ };
610
+ //# sourceMappingURL=tenants.js.map