@open-kingdom/shared-frontend-feature-user-management 0.0.2-14 → 0.0.2-17
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.
- package/README.md +136 -4
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +654 -288
- package/dist/lib/components/invitations/AcceptInvitation.component.d.ts.map +1 -1
- package/dist/lib/components/invitations/InvitationList.component.d.ts +2 -0
- package/dist/lib/components/invitations/InvitationList.component.d.ts.map +1 -0
- package/dist/lib/components/invitations/InviteUserModal.component.d.ts.map +1 -1
- package/dist/lib/components/invitations/index.d.ts +1 -0
- package/dist/lib/components/invitations/index.d.ts.map +1 -1
- package/dist/lib/components/roles/RoleList.component.d.ts +2 -0
- package/dist/lib/components/roles/RoleList.component.d.ts.map +1 -0
- package/dist/lib/components/roles/RolePermissionsModal.component.d.ts +11 -0
- package/dist/lib/components/roles/RolePermissionsModal.component.d.ts.map +1 -0
- package/dist/lib/components/roles/index.d.ts +3 -0
- package/dist/lib/components/roles/index.d.ts.map +1 -0
- package/dist/lib/components/shared/ConfirmDialog.component.d.ts.map +1 -1
- package/dist/lib/components/shared/FormField.component.d.ts.map +1 -1
- package/dist/lib/components/shared/RoleBadge.component.d.ts +1 -2
- package/dist/lib/components/shared/RoleBadge.component.d.ts.map +1 -1
- package/dist/lib/components/shared/StatusBadge.component.d.ts +7 -0
- package/dist/lib/components/shared/StatusBadge.component.d.ts.map +1 -0
- package/dist/lib/components/shared/StatusCard.component.d.ts.map +1 -1
- package/dist/lib/components/users/RoleChangeModal.component.d.ts +12 -0
- package/dist/lib/components/users/RoleChangeModal.component.d.ts.map +1 -0
- package/dist/lib/components/users/UserList.component.d.ts.map +1 -1
- package/dist/lib/hooks/useHasPermission.d.ts +2 -0
- package/dist/lib/hooks/useHasPermission.d.ts.map +1 -0
- package/dist/lib/types.d.ts +11 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +24 -1
- package/.babelrc +0 -12
- package/dist/lib/components/shared/ModalOverlay.component.d.ts +0 -9
- package/dist/lib/components/shared/ModalOverlay.component.d.ts.map +0 -1
- package/dist/lib/styles.d.ts +0 -8
- package/dist/lib/styles.d.ts.map +0 -1
- package/jest.config.cts +0 -14
- package/src/index.ts +0 -4
- package/src/lib/components/invitations/AcceptInvitation.component.spec.tsx +0 -154
- package/src/lib/components/invitations/AcceptInvitation.component.tsx +0 -197
- package/src/lib/components/invitations/InviteUserModal.component.spec.tsx +0 -79
- package/src/lib/components/invitations/InviteUserModal.component.tsx +0 -121
- package/src/lib/components/invitations/index.ts +0 -2
- package/src/lib/components/shared/ConfirmDialog.component.spec.tsx +0 -45
- package/src/lib/components/shared/ConfirmDialog.component.tsx +0 -58
- package/src/lib/components/shared/FormField.component.spec.tsx +0 -50
- package/src/lib/components/shared/FormField.component.tsx +0 -34
- package/src/lib/components/shared/ModalOverlay.component.spec.tsx +0 -81
- package/src/lib/components/shared/ModalOverlay.component.tsx +0 -45
- package/src/lib/components/shared/RoleBadge.component.spec.tsx +0 -20
- package/src/lib/components/shared/RoleBadge.component.tsx +0 -25
- package/src/lib/components/shared/StatusCard.component.spec.tsx +0 -44
- package/src/lib/components/shared/StatusCard.component.tsx +0 -47
- package/src/lib/components/users/UserList.component.spec.tsx +0 -216
- package/src/lib/components/users/UserList.component.tsx +0 -153
- package/src/lib/styles.ts +0 -19
- package/src/lib/types.ts +0 -9
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -47
- package/tsconfig.spec.json +0 -27
- package/vite.config.mts +0 -58
package/dist/index.js
CHANGED
|
@@ -1,410 +1,356 @@
|
|
|
1
1
|
import { jsx as e, jsxs as i } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { useDispatch as
|
|
4
|
-
import { useInvitationsControllerInviteMutation as
|
|
5
|
-
import { showSuccessNotification as
|
|
6
|
-
import { DataGrid as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
2
|
+
import { useState as N, useMemo as R, useCallback as W } from "react";
|
|
3
|
+
import { useDispatch as I } from "react-redux";
|
|
4
|
+
import { useInvitationsControllerInviteMutation as X, useRolesControllerFindAllQuery as F, useInvitationsControllerValidateQuery as Z, useInvitationsControllerAcceptMutation as _, useInvitationsControllerFindAllQuery as ee, useInvitationsControllerCancelMutation as te, useUserRolesControllerSetRolesMutation as ne, useAuthControllerGetProfileQuery as ie, useUsersControllerFindAllQuery as ae, useUsersControllerDeleteMutation as se, usePermissionsControllerFindAllQuery as re, useRolesControllerGetPermissionsQuery as le, useRolesControllerSetPermissionsMutation as oe, useRolesControllerDeleteMutation as de } from "@open-kingdom/shared-frontend-data-access-api-client";
|
|
5
|
+
import { showSuccessNotification as A } from "@open-kingdom/shared-frontend-data-access-notifications";
|
|
6
|
+
import { DataGrid as U } from "@open-kingdom/shared-frontend-ui-datagrid";
|
|
7
|
+
import { AlertDialog as ce, AlertDialogContent as ue, AlertDialogHeader as me, AlertDialogTitle as fe, AlertDialogDescription as he, AlertDialogFooter as pe, AlertDialogCancel as ge, AlertDialogAction as ve, Badge as V, Label as be, Dialog as j, DialogContent as E, DialogHeader as O, DialogTitle as G, Input as P, Button as w, Card as M, CardContent as T, DialogDescription as $ } from "@open-kingdom/shared-frontend-ui-primitives";
|
|
8
|
+
import { useForm as B } from "react-hook-form";
|
|
9
|
+
import { zodResolver as q } from "@hookform/resolvers/zod";
|
|
10
|
+
import { z as C } from "zod";
|
|
11
|
+
import { formatDate as z } from "@open-kingdom/shared-poly-util-date";
|
|
12
|
+
import { useDeepCompareEffect as H } from "@react-hookz/web";
|
|
13
|
+
function Q({
|
|
13
14
|
isOpen: t,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
title: n,
|
|
16
|
+
message: s,
|
|
17
|
+
confirmLabel: m = "Confirm",
|
|
18
|
+
onConfirm: f,
|
|
19
|
+
onCancel: b,
|
|
20
|
+
isLoading: d = !1
|
|
17
21
|
}) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
const n = P((l) => {
|
|
22
|
-
l?.focus();
|
|
23
|
-
}, []);
|
|
24
|
-
return t ? /* @__PURE__ */ e(
|
|
25
|
-
"div",
|
|
22
|
+
return /* @__PURE__ */ e(
|
|
23
|
+
ce,
|
|
26
24
|
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
children: /* @__PURE__ */
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
25
|
+
open: t,
|
|
26
|
+
onOpenChange: (l) => !l && b(),
|
|
27
|
+
children: /* @__PURE__ */ i(ue, { children: [
|
|
28
|
+
/* @__PURE__ */ i(me, { children: [
|
|
29
|
+
/* @__PURE__ */ e(fe, { children: n }),
|
|
30
|
+
/* @__PURE__ */ e(he, { children: s })
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ i(pe, { children: [
|
|
33
|
+
/* @__PURE__ */ e(
|
|
34
|
+
ge,
|
|
35
|
+
{
|
|
36
|
+
"data-testid": "confirm-cancel-btn",
|
|
37
|
+
disabled: d,
|
|
38
|
+
onClick: b,
|
|
39
|
+
children: "Cancel"
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
/* @__PURE__ */ e(
|
|
43
|
+
ve,
|
|
44
|
+
{
|
|
45
|
+
"data-testid": "confirm-btn",
|
|
46
|
+
disabled: d,
|
|
47
|
+
onClick: f,
|
|
48
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
49
|
+
children: m
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
] })
|
|
53
|
+
] })
|
|
42
54
|
}
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
const b = "w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-md bg-white dark:bg-neutral-700 text-neutral-900 dark:text-neutral-100", J = "block text-sm font-medium text-neutral-700 dark:text-neutral-300 mb-1", k = "max-w-md mx-auto mt-8 p-6 bg-white dark:bg-neutral-800 rounded-lg shadow-lg", S = "text-neutral-600 dark:text-neutral-400", C = "rounded-md px-4 py-2 text-sm font-medium transition-colors", D = `${C} bg-primary-500 text-white hover:bg-primary-600 disabled:opacity-50`, M = `${C} border border-neutral-300 text-neutral-700 hover:bg-neutral-50 dark:border-neutral-600 dark:text-neutral-300 dark:hover:bg-neutral-700`, K = `${C} bg-error-500 text-white hover:bg-error-600 disabled:opacity-50`;
|
|
46
|
-
function H({
|
|
47
|
-
isOpen: t,
|
|
48
|
-
title: a,
|
|
49
|
-
message: r,
|
|
50
|
-
confirmLabel: s = "Confirm",
|
|
51
|
-
onConfirm: n,
|
|
52
|
-
onCancel: l,
|
|
53
|
-
isLoading: o = !1
|
|
54
|
-
}) {
|
|
55
|
-
const d = "confirm-dialog-title";
|
|
56
|
-
return /* @__PURE__ */ i(j, { isOpen: t, onClose: l, ariaLabelledBy: d, children: [
|
|
57
|
-
/* @__PURE__ */ e(
|
|
58
|
-
"h3",
|
|
59
|
-
{
|
|
60
|
-
id: d,
|
|
61
|
-
className: "text-lg font-semibold text-neutral-900 dark:text-neutral-100",
|
|
62
|
-
children: a
|
|
63
|
-
}
|
|
64
|
-
),
|
|
65
|
-
/* @__PURE__ */ e("p", { className: "mt-2 text-sm text-neutral-600 dark:text-neutral-400", children: r }),
|
|
66
|
-
/* @__PURE__ */ i("div", { className: "mt-6 flex justify-end gap-3", children: [
|
|
67
|
-
/* @__PURE__ */ e(
|
|
68
|
-
"button",
|
|
69
|
-
{
|
|
70
|
-
type: "button",
|
|
71
|
-
"data-testid": "confirm-cancel-btn",
|
|
72
|
-
onClick: l,
|
|
73
|
-
disabled: o,
|
|
74
|
-
className: M,
|
|
75
|
-
children: "Cancel"
|
|
76
|
-
}
|
|
77
|
-
),
|
|
78
|
-
/* @__PURE__ */ e(
|
|
79
|
-
"button",
|
|
80
|
-
{
|
|
81
|
-
type: "button",
|
|
82
|
-
"data-testid": "confirm-btn",
|
|
83
|
-
onClick: n,
|
|
84
|
-
disabled: o,
|
|
85
|
-
className: K,
|
|
86
|
-
children: s
|
|
87
|
-
}
|
|
88
|
-
)
|
|
89
|
-
] })
|
|
90
|
-
] });
|
|
55
|
+
);
|
|
91
56
|
}
|
|
92
|
-
const
|
|
93
|
-
admin: "
|
|
94
|
-
user: "
|
|
95
|
-
guest: "
|
|
57
|
+
const xe = {
|
|
58
|
+
admin: "secondary",
|
|
59
|
+
user: "default",
|
|
60
|
+
guest: "muted"
|
|
96
61
|
};
|
|
97
|
-
function
|
|
62
|
+
function Y({ role: t }) {
|
|
98
63
|
if (!t) return null;
|
|
99
|
-
const
|
|
100
|
-
return /* @__PURE__ */ e(
|
|
101
|
-
"span",
|
|
102
|
-
{
|
|
103
|
-
className: `inline-block rounded-full px-2.5 py-0.5 text-xs font-medium ${W[t]}`,
|
|
104
|
-
children: a
|
|
105
|
-
}
|
|
106
|
-
);
|
|
64
|
+
const n = t.charAt(0).toUpperCase() + t.slice(1);
|
|
65
|
+
return /* @__PURE__ */ e(V, { variant: xe[t] ?? "default", children: n });
|
|
107
66
|
}
|
|
108
|
-
function
|
|
67
|
+
function D({
|
|
109
68
|
label: t,
|
|
110
|
-
htmlFor:
|
|
111
|
-
required:
|
|
112
|
-
error:
|
|
113
|
-
children:
|
|
69
|
+
htmlFor: n,
|
|
70
|
+
required: s,
|
|
71
|
+
error: m,
|
|
72
|
+
children: f
|
|
114
73
|
}) {
|
|
115
74
|
return /* @__PURE__ */ i("div", { children: [
|
|
116
|
-
/* @__PURE__ */ i(
|
|
75
|
+
/* @__PURE__ */ i(be, { htmlFor: n, className: "mb-1", children: [
|
|
117
76
|
t,
|
|
118
77
|
" ",
|
|
119
|
-
|
|
78
|
+
s && /* @__PURE__ */ e("span", { className: "text-destructive", children: "*" })
|
|
120
79
|
] }),
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"p",
|
|
124
|
-
{
|
|
125
|
-
"data-testid": "field-error",
|
|
126
|
-
className: "mt-1 text-sm text-error-600 dark:text-error-400",
|
|
127
|
-
children: s
|
|
128
|
-
}
|
|
129
|
-
)
|
|
80
|
+
f,
|
|
81
|
+
m && /* @__PURE__ */ e("p", { "data-testid": "field-error", className: "mt-1 text-sm text-destructive", children: m })
|
|
130
82
|
] });
|
|
131
83
|
}
|
|
132
|
-
const
|
|
133
|
-
email:
|
|
134
|
-
role:
|
|
84
|
+
const ye = C.object({
|
|
85
|
+
email: C.string().email("Invalid email address"),
|
|
86
|
+
role: C.string().min(1)
|
|
135
87
|
});
|
|
136
|
-
function
|
|
137
|
-
const
|
|
88
|
+
function Ce({ isOpen: t, onClose: n }) {
|
|
89
|
+
const s = I(), [m, { isLoading: f }] = X(), { data: b } = F(), d = b ?? [], {
|
|
138
90
|
register: l,
|
|
139
|
-
handleSubmit:
|
|
140
|
-
reset:
|
|
141
|
-
formState: { errors:
|
|
142
|
-
} =
|
|
143
|
-
resolver:
|
|
91
|
+
handleSubmit: r,
|
|
92
|
+
reset: c,
|
|
93
|
+
formState: { errors: g }
|
|
94
|
+
} = B({
|
|
95
|
+
resolver: q(ye),
|
|
144
96
|
defaultValues: { email: "", role: "guest" }
|
|
145
|
-
}),
|
|
146
|
-
|
|
97
|
+
}), a = () => {
|
|
98
|
+
c(), n();
|
|
147
99
|
};
|
|
148
|
-
return /* @__PURE__ */
|
|
100
|
+
return /* @__PURE__ */ e(
|
|
149
101
|
j,
|
|
150
102
|
{
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
"h3",
|
|
157
|
-
{
|
|
158
|
-
id: h,
|
|
159
|
-
className: "text-lg font-semibold text-neutral-900 dark:text-neutral-100",
|
|
160
|
-
children: "Invite User"
|
|
161
|
-
}
|
|
162
|
-
),
|
|
163
|
-
/* @__PURE__ */ i("form", { onSubmit: o(async (m) => {
|
|
103
|
+
open: t,
|
|
104
|
+
onOpenChange: (u) => !u && a(),
|
|
105
|
+
children: /* @__PURE__ */ i(E, { children: [
|
|
106
|
+
/* @__PURE__ */ e(O, { children: /* @__PURE__ */ e(G, { children: "Invite User" }) }),
|
|
107
|
+
/* @__PURE__ */ i("form", { onSubmit: r(async (u) => {
|
|
164
108
|
try {
|
|
165
|
-
await
|
|
109
|
+
await m({ inviteUserDto: u }).unwrap(), s(A("Invitation sent successfully")), c(), n();
|
|
166
110
|
} catch {
|
|
167
111
|
}
|
|
168
|
-
}), className: "
|
|
112
|
+
}), className: "space-y-4", children: [
|
|
169
113
|
/* @__PURE__ */ e(
|
|
170
|
-
|
|
114
|
+
D,
|
|
171
115
|
{
|
|
172
116
|
label: "Email",
|
|
173
117
|
htmlFor: "invite-email",
|
|
174
118
|
required: !0,
|
|
175
|
-
error:
|
|
119
|
+
error: g.email?.message,
|
|
176
120
|
children: /* @__PURE__ */ e(
|
|
177
|
-
|
|
121
|
+
P,
|
|
178
122
|
{
|
|
179
123
|
id: "invite-email",
|
|
180
124
|
"data-testid": "invite-email-input",
|
|
181
125
|
type: "email",
|
|
182
126
|
placeholder: "user@example.com",
|
|
183
|
-
className: b,
|
|
184
127
|
...l("email")
|
|
185
128
|
}
|
|
186
129
|
)
|
|
187
130
|
}
|
|
188
131
|
),
|
|
189
|
-
/* @__PURE__ */ e(
|
|
132
|
+
/* @__PURE__ */ e(D, { label: "Role", htmlFor: "invite-role", children: /* @__PURE__ */ e(
|
|
190
133
|
"select",
|
|
191
134
|
{
|
|
192
135
|
id: "invite-role",
|
|
193
136
|
"data-testid": "invite-role-select",
|
|
194
|
-
className:
|
|
137
|
+
className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
195
138
|
...l("role"),
|
|
196
|
-
children:
|
|
197
|
-
/* @__PURE__ */ e("option", { value: "guest", children: "Guest" }),
|
|
198
|
-
/* @__PURE__ */ e("option", { value: "user", children: "User" }),
|
|
199
|
-
/* @__PURE__ */ e("option", { value: "admin", children: "Admin" })
|
|
200
|
-
]
|
|
139
|
+
children: d.map((u) => /* @__PURE__ */ e("option", { value: u.name, children: u.name.charAt(0).toUpperCase() + u.name.slice(1) }, u.id))
|
|
201
140
|
}
|
|
202
141
|
) }),
|
|
203
142
|
/* @__PURE__ */ i("div", { className: "flex justify-end gap-3", children: [
|
|
204
143
|
/* @__PURE__ */ e(
|
|
205
|
-
|
|
144
|
+
w,
|
|
206
145
|
{
|
|
207
146
|
type: "button",
|
|
147
|
+
variant: "secondary",
|
|
208
148
|
"data-testid": "invite-cancel-btn",
|
|
209
|
-
onClick:
|
|
210
|
-
disabled:
|
|
211
|
-
className: M,
|
|
149
|
+
onClick: a,
|
|
150
|
+
disabled: f,
|
|
212
151
|
children: "Cancel"
|
|
213
152
|
}
|
|
214
153
|
),
|
|
215
154
|
/* @__PURE__ */ e(
|
|
216
|
-
|
|
155
|
+
w,
|
|
217
156
|
{
|
|
218
157
|
type: "submit",
|
|
219
158
|
"data-testid": "invite-submit-btn",
|
|
220
|
-
disabled:
|
|
221
|
-
|
|
222
|
-
children: n ? "Sending..." : "Send Invitation"
|
|
159
|
+
disabled: f,
|
|
160
|
+
children: f ? "Sending..." : "Send Invitation"
|
|
223
161
|
}
|
|
224
162
|
)
|
|
225
163
|
] })
|
|
226
164
|
] })
|
|
227
|
-
]
|
|
165
|
+
] })
|
|
228
166
|
}
|
|
229
167
|
);
|
|
230
168
|
}
|
|
231
|
-
const
|
|
232
|
-
error: "text-xl font-bold text-
|
|
233
|
-
success: "text-xl font-bold text-success
|
|
169
|
+
const Ne = {
|
|
170
|
+
error: "text-xl font-bold text-destructive",
|
|
171
|
+
success: "text-xl font-bold text-success"
|
|
234
172
|
};
|
|
235
|
-
function
|
|
173
|
+
function k({
|
|
236
174
|
variant: t,
|
|
237
|
-
title:
|
|
238
|
-
message:
|
|
239
|
-
children:
|
|
175
|
+
title: n,
|
|
176
|
+
message: s,
|
|
177
|
+
children: m
|
|
240
178
|
}) {
|
|
241
|
-
return t === "loading" ? /* @__PURE__ */ e("
|
|
242
|
-
|
|
179
|
+
return t === "loading" ? /* @__PURE__ */ e(M, { className: "max-w-md mx-auto mt-8", children: /* @__PURE__ */ e(T, { className: "pt-6", children: /* @__PURE__ */ e("p", { className: "text-center text-muted-foreground", children: s }) }) }) : /* @__PURE__ */ e(
|
|
180
|
+
M,
|
|
243
181
|
{
|
|
244
|
-
className:
|
|
182
|
+
className: "max-w-md mx-auto mt-8",
|
|
245
183
|
role: t === "error" ? "alert" : void 0,
|
|
246
|
-
children: [
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
184
|
+
children: /* @__PURE__ */ i(T, { className: "pt-6", children: [
|
|
185
|
+
n && /* @__PURE__ */ e(
|
|
186
|
+
"h2",
|
|
187
|
+
{
|
|
188
|
+
"data-testid": "status-card-title",
|
|
189
|
+
className: Ne[t],
|
|
190
|
+
children: n
|
|
191
|
+
}
|
|
192
|
+
),
|
|
193
|
+
/* @__PURE__ */ e(
|
|
194
|
+
"p",
|
|
195
|
+
{
|
|
196
|
+
"data-testid": "status-card-message",
|
|
197
|
+
className: "mt-2 text-muted-foreground",
|
|
198
|
+
children: s
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
m
|
|
202
|
+
] })
|
|
251
203
|
}
|
|
252
204
|
);
|
|
253
205
|
}
|
|
254
|
-
const
|
|
255
|
-
firstName:
|
|
256
|
-
lastName:
|
|
257
|
-
password:
|
|
258
|
-
confirmPassword:
|
|
206
|
+
const we = C.object({
|
|
207
|
+
firstName: C.string().optional(),
|
|
208
|
+
lastName: C.string().optional(),
|
|
209
|
+
password: C.string().min(8, "Password must be at least 8 characters"),
|
|
210
|
+
confirmPassword: C.string()
|
|
259
211
|
}).refine((t) => t.password === t.confirmPassword, {
|
|
260
212
|
message: "Passwords do not match",
|
|
261
213
|
path: ["confirmPassword"]
|
|
262
214
|
});
|
|
263
|
-
function
|
|
215
|
+
function Ye({ token: t, loginPath: n }) {
|
|
264
216
|
const {
|
|
265
|
-
data:
|
|
266
|
-
isLoading:
|
|
267
|
-
error:
|
|
268
|
-
} =
|
|
269
|
-
register:
|
|
270
|
-
handleSubmit:
|
|
271
|
-
formState: { errors:
|
|
272
|
-
} =
|
|
273
|
-
resolver:
|
|
217
|
+
data: s,
|
|
218
|
+
isLoading: m,
|
|
219
|
+
error: f
|
|
220
|
+
} = Z({ token: t }), [b, { isLoading: d, isSuccess: l }] = _(), {
|
|
221
|
+
register: r,
|
|
222
|
+
handleSubmit: c,
|
|
223
|
+
formState: { errors: g }
|
|
224
|
+
} = B({
|
|
225
|
+
resolver: q(we),
|
|
274
226
|
defaultValues: {
|
|
275
227
|
firstName: "",
|
|
276
228
|
lastName: "",
|
|
277
229
|
password: "",
|
|
278
230
|
confirmPassword: ""
|
|
279
231
|
}
|
|
280
|
-
}),
|
|
232
|
+
}), a = s?.email ?? "", v = async (u) => {
|
|
281
233
|
try {
|
|
282
|
-
await
|
|
234
|
+
await b({
|
|
283
235
|
acceptInvitationDto: {
|
|
284
236
|
token: t,
|
|
285
|
-
password:
|
|
286
|
-
firstName:
|
|
287
|
-
lastName:
|
|
237
|
+
password: u.password,
|
|
238
|
+
firstName: u.firstName || void 0,
|
|
239
|
+
lastName: u.lastName || void 0
|
|
288
240
|
}
|
|
289
241
|
}).unwrap();
|
|
290
242
|
} catch {
|
|
291
243
|
}
|
|
292
244
|
};
|
|
293
|
-
return
|
|
294
|
-
|
|
245
|
+
return l ? /* @__PURE__ */ e(
|
|
246
|
+
k,
|
|
295
247
|
{
|
|
296
248
|
variant: "success",
|
|
297
249
|
title: "Account Created",
|
|
298
250
|
message: "Your account has been created successfully. You can now log in with your email and password.",
|
|
299
|
-
children:
|
|
251
|
+
children: n && /* @__PURE__ */ e(
|
|
300
252
|
"a",
|
|
301
253
|
{
|
|
302
|
-
href:
|
|
254
|
+
href: n,
|
|
303
255
|
"data-testid": "accept-login-link",
|
|
304
|
-
className: "mt-4 inline-block text-sm font-medium text-primary
|
|
256
|
+
className: "mt-4 inline-block text-sm font-medium text-primary hover:underline",
|
|
305
257
|
children: "Go to login"
|
|
306
258
|
}
|
|
307
259
|
)
|
|
308
260
|
}
|
|
309
|
-
) :
|
|
310
|
-
|
|
261
|
+
) : m ? /* @__PURE__ */ e(k, { variant: "loading", message: "Validating invitation..." }) : f ? /* @__PURE__ */ e(
|
|
262
|
+
k,
|
|
311
263
|
{
|
|
312
264
|
variant: "error",
|
|
313
265
|
title: "Validation Failed",
|
|
314
266
|
message: "Unable to validate this invitation. Please check your connection and try again."
|
|
315
267
|
}
|
|
316
|
-
) :
|
|
268
|
+
) : s?.valid ? /* @__PURE__ */ e(M, { className: "max-w-md mx-auto mt-8", children: /* @__PURE__ */ i(T, { className: "pt-6", children: [
|
|
317
269
|
/* @__PURE__ */ e(
|
|
318
270
|
"h2",
|
|
319
271
|
{
|
|
320
272
|
"data-testid": "accept-heading",
|
|
321
|
-
className: "text-xl font-bold text-
|
|
273
|
+
className: "text-xl font-bold text-foreground",
|
|
322
274
|
children: "Accept Invitation"
|
|
323
275
|
}
|
|
324
276
|
),
|
|
325
|
-
/* @__PURE__ */ i("p", { className:
|
|
326
|
-
"You've been invited
|
|
327
|
-
/* @__PURE__ */ e("strong", { "data-testid": "accept-role", children: m }),
|
|
277
|
+
/* @__PURE__ */ i("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
278
|
+
"You've been invited with email",
|
|
328
279
|
" ",
|
|
329
|
-
"
|
|
330
|
-
/* @__PURE__ */ e("strong", { "data-testid": "accept-email", children: g })
|
|
280
|
+
/* @__PURE__ */ e("strong", { "data-testid": "accept-email", children: a })
|
|
331
281
|
] }),
|
|
332
|
-
/* @__PURE__ */ i("form", { onSubmit:
|
|
333
|
-
/* @__PURE__ */ e(
|
|
334
|
-
|
|
282
|
+
/* @__PURE__ */ i("form", { onSubmit: c(v), className: "mt-4 space-y-4", children: [
|
|
283
|
+
/* @__PURE__ */ e(D, { label: "First Name", htmlFor: "accept-firstName", children: /* @__PURE__ */ e(
|
|
284
|
+
P,
|
|
335
285
|
{
|
|
336
286
|
id: "accept-firstName",
|
|
337
287
|
"data-testid": "accept-first-name-input",
|
|
338
288
|
type: "text",
|
|
339
289
|
placeholder: "John",
|
|
340
|
-
|
|
341
|
-
...c("firstName")
|
|
290
|
+
...r("firstName")
|
|
342
291
|
}
|
|
343
292
|
) }),
|
|
344
|
-
/* @__PURE__ */ e(
|
|
345
|
-
|
|
293
|
+
/* @__PURE__ */ e(D, { label: "Last Name", htmlFor: "accept-lastName", children: /* @__PURE__ */ e(
|
|
294
|
+
P,
|
|
346
295
|
{
|
|
347
296
|
id: "accept-lastName",
|
|
348
297
|
"data-testid": "accept-last-name-input",
|
|
349
298
|
type: "text",
|
|
350
299
|
placeholder: "Doe",
|
|
351
|
-
|
|
352
|
-
...c("lastName")
|
|
300
|
+
...r("lastName")
|
|
353
301
|
}
|
|
354
302
|
) }),
|
|
355
303
|
/* @__PURE__ */ e(
|
|
356
|
-
|
|
304
|
+
D,
|
|
357
305
|
{
|
|
358
306
|
label: "Password",
|
|
359
307
|
htmlFor: "accept-password",
|
|
360
308
|
required: !0,
|
|
361
|
-
error:
|
|
309
|
+
error: g.password?.message,
|
|
362
310
|
children: /* @__PURE__ */ e(
|
|
363
|
-
|
|
311
|
+
P,
|
|
364
312
|
{
|
|
365
313
|
id: "accept-password",
|
|
366
314
|
"data-testid": "accept-password-input",
|
|
367
315
|
type: "password",
|
|
368
316
|
placeholder: "Min. 8 characters",
|
|
369
|
-
|
|
370
|
-
...c("password")
|
|
317
|
+
...r("password")
|
|
371
318
|
}
|
|
372
319
|
)
|
|
373
320
|
}
|
|
374
321
|
),
|
|
375
322
|
/* @__PURE__ */ e(
|
|
376
|
-
|
|
323
|
+
D,
|
|
377
324
|
{
|
|
378
325
|
label: "Confirm Password",
|
|
379
326
|
htmlFor: "accept-confirmPassword",
|
|
380
327
|
required: !0,
|
|
381
|
-
error:
|
|
328
|
+
error: g.confirmPassword?.message,
|
|
382
329
|
children: /* @__PURE__ */ e(
|
|
383
|
-
|
|
330
|
+
P,
|
|
384
331
|
{
|
|
385
332
|
id: "accept-confirmPassword",
|
|
386
333
|
"data-testid": "accept-confirm-password-input",
|
|
387
334
|
type: "password",
|
|
388
335
|
placeholder: "Repeat password",
|
|
389
|
-
|
|
390
|
-
...c("confirmPassword")
|
|
336
|
+
...r("confirmPassword")
|
|
391
337
|
}
|
|
392
338
|
)
|
|
393
339
|
}
|
|
394
340
|
),
|
|
395
341
|
/* @__PURE__ */ e(
|
|
396
|
-
|
|
342
|
+
w,
|
|
397
343
|
{
|
|
398
344
|
type: "submit",
|
|
399
345
|
"data-testid": "accept-submit-btn",
|
|
400
|
-
disabled:
|
|
401
|
-
className:
|
|
402
|
-
children:
|
|
346
|
+
disabled: d,
|
|
347
|
+
className: "w-full",
|
|
348
|
+
children: d ? "Creating account..." : "Create Account"
|
|
403
349
|
}
|
|
404
350
|
)
|
|
405
351
|
] })
|
|
406
|
-
] }) : /* @__PURE__ */ e(
|
|
407
|
-
|
|
352
|
+
] }) }) : /* @__PURE__ */ e(
|
|
353
|
+
k,
|
|
408
354
|
{
|
|
409
355
|
variant: "error",
|
|
410
356
|
title: "Invalid Invitation",
|
|
@@ -412,69 +358,284 @@ function pe({ token: t, loginPath: a }) {
|
|
|
412
358
|
}
|
|
413
359
|
);
|
|
414
360
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
361
|
+
const De = {
|
|
362
|
+
pending: "warning",
|
|
363
|
+
accepted: "success",
|
|
364
|
+
expired: "muted"
|
|
365
|
+
};
|
|
366
|
+
function Se({ status: t }) {
|
|
367
|
+
if (!t) return null;
|
|
368
|
+
const n = t.charAt(0).toUpperCase() + t.slice(1);
|
|
369
|
+
return /* @__PURE__ */ e(V, { variant: De[t], children: n });
|
|
370
|
+
}
|
|
371
|
+
const Re = {
|
|
372
|
+
field: "email",
|
|
373
|
+
headerName: "Email",
|
|
374
|
+
flex: 2
|
|
375
|
+
};
|
|
376
|
+
function Ie(t) {
|
|
377
|
+
return {
|
|
378
|
+
headerName: "Role",
|
|
379
|
+
flex: 1,
|
|
380
|
+
cellRenderer: (n) => n.data ? /* @__PURE__ */ e(Y, { role: t.get(n.data.roleId) ?? null }) : null
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
const Ae = {
|
|
384
|
+
field: "status",
|
|
385
|
+
headerName: "Status",
|
|
386
|
+
flex: 1,
|
|
387
|
+
cellRenderer: (t) => t.data ? /* @__PURE__ */ e(Se, { status: t.data.status }) : null
|
|
388
|
+
}, Pe = {
|
|
389
|
+
headerName: "Invited",
|
|
390
|
+
flex: 1,
|
|
391
|
+
valueGetter: (t) => z(t.data?.invitedAt)
|
|
392
|
+
}, ke = {
|
|
393
|
+
headerName: "Expires",
|
|
394
|
+
flex: 1,
|
|
395
|
+
valueGetter: (t) => z(t.data?.tokenExpiry)
|
|
396
|
+
};
|
|
397
|
+
function Le(t) {
|
|
398
|
+
return {
|
|
399
|
+
headerName: "Actions",
|
|
400
|
+
flex: 1,
|
|
401
|
+
sortable: !1,
|
|
402
|
+
filter: !1,
|
|
403
|
+
cellRenderer: (n) => n.data ? /* @__PURE__ */ e(
|
|
404
|
+
"button",
|
|
405
|
+
{
|
|
406
|
+
onClick: () => n.data && t(n.data),
|
|
407
|
+
className: "text-destructive text-xs font-medium rounded px-2 py-1 transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-40",
|
|
408
|
+
children: "Cancel"
|
|
409
|
+
}
|
|
410
|
+
) : null
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function Fe(t, n) {
|
|
414
|
+
return [
|
|
415
|
+
Re,
|
|
416
|
+
Ie(n),
|
|
417
|
+
Ae,
|
|
418
|
+
Pe,
|
|
419
|
+
ke,
|
|
420
|
+
Le(t)
|
|
421
|
+
];
|
|
422
|
+
}
|
|
423
|
+
function Je() {
|
|
424
|
+
const t = I(), { data: n, isLoading: s, error: m, refetch: f } = ee(), [b, { isLoading: d }] = te(), { data: l } = F(), [r, c] = N(null), g = n ?? [], a = R(() => {
|
|
425
|
+
const y = l ?? [];
|
|
426
|
+
return new Map(y.map((o) => [o.id, o.name]));
|
|
427
|
+
}, [l]);
|
|
428
|
+
async function v() {
|
|
429
|
+
if (r)
|
|
430
|
+
try {
|
|
431
|
+
await b({ id: r.id }).unwrap(), t(A("Invitation cancelled successfully"));
|
|
432
|
+
} catch {
|
|
433
|
+
} finally {
|
|
434
|
+
c(null);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const u = R(
|
|
438
|
+
() => Fe(c, a),
|
|
439
|
+
[a]
|
|
440
|
+
);
|
|
441
|
+
return m ? /* @__PURE__ */ i(
|
|
442
|
+
"div",
|
|
443
|
+
{
|
|
444
|
+
"data-testid": "invitations-error",
|
|
445
|
+
className: "rounded-lg bg-destructive/10 p-6 text-center",
|
|
446
|
+
role: "alert",
|
|
447
|
+
children: [
|
|
448
|
+
/* @__PURE__ */ e("p", { className: "text-destructive", children: "Failed to load invitations." }),
|
|
449
|
+
/* @__PURE__ */ e(
|
|
450
|
+
"button",
|
|
451
|
+
{
|
|
452
|
+
"data-testid": "invitations-retry-btn",
|
|
453
|
+
onClick: f,
|
|
454
|
+
className: "mt-2 text-sm font-medium text-primary hover:underline",
|
|
455
|
+
children: "Try again"
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
]
|
|
459
|
+
}
|
|
460
|
+
) : /* @__PURE__ */ i("div", { children: [
|
|
461
|
+
/* @__PURE__ */ e("div", { className: "mb-4 flex items-center justify-between", children: /* @__PURE__ */ e(
|
|
462
|
+
"h2",
|
|
463
|
+
{
|
|
464
|
+
"data-testid": "invitations-heading",
|
|
465
|
+
className: "text-xl font-semibold text-foreground",
|
|
466
|
+
children: "Invitations"
|
|
467
|
+
}
|
|
468
|
+
) }),
|
|
469
|
+
/* @__PURE__ */ e(
|
|
470
|
+
U,
|
|
471
|
+
{
|
|
472
|
+
rowData: g,
|
|
473
|
+
columnDefs: u,
|
|
474
|
+
loading: s
|
|
475
|
+
}
|
|
476
|
+
),
|
|
477
|
+
/* @__PURE__ */ e(
|
|
478
|
+
Q,
|
|
479
|
+
{
|
|
480
|
+
isOpen: !!r,
|
|
481
|
+
title: "Cancel Invitation",
|
|
482
|
+
message: `Are you sure you want to cancel the invitation for ${r?.email}? This action cannot be undone.`,
|
|
483
|
+
confirmLabel: d ? "Cancelling..." : "Cancel Invitation",
|
|
484
|
+
onConfirm: v,
|
|
485
|
+
onCancel: () => c(null),
|
|
486
|
+
isLoading: d
|
|
487
|
+
}
|
|
488
|
+
)
|
|
489
|
+
] });
|
|
490
|
+
}
|
|
491
|
+
function Me({
|
|
492
|
+
isOpen: t,
|
|
493
|
+
onClose: n,
|
|
494
|
+
user: s
|
|
495
|
+
}) {
|
|
496
|
+
const m = I(), { data: f } = F(), [b, { isLoading: d }] = ne(), l = R(
|
|
497
|
+
() => f ?? [],
|
|
498
|
+
[f]
|
|
499
|
+
), [r, c] = N(null);
|
|
500
|
+
H(() => {
|
|
501
|
+
if (!l.length) return;
|
|
502
|
+
const a = l.find((v) => v.name === s.role);
|
|
503
|
+
c(a?.id ?? null);
|
|
504
|
+
}, [l, s.role]);
|
|
505
|
+
const g = async (a) => {
|
|
506
|
+
if (a.preventDefault(), r !== null)
|
|
507
|
+
try {
|
|
508
|
+
await b({
|
|
509
|
+
userId: s.id,
|
|
510
|
+
updateUserRolesDto: { roleIds: [r] }
|
|
511
|
+
}).unwrap(), m(A("Role updated successfully")), n();
|
|
512
|
+
} catch {
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
return /* @__PURE__ */ e(j, { open: t, onOpenChange: (a) => !a && n(), children: /* @__PURE__ */ i(E, { children: [
|
|
516
|
+
/* @__PURE__ */ i(O, { children: [
|
|
517
|
+
/* @__PURE__ */ e(G, { children: "Change Role" }),
|
|
518
|
+
/* @__PURE__ */ i($, { children: [
|
|
519
|
+
"Changing role for ",
|
|
520
|
+
/* @__PURE__ */ e("strong", { children: s.email })
|
|
521
|
+
] })
|
|
522
|
+
] }),
|
|
523
|
+
/* @__PURE__ */ i("form", { onSubmit: g, className: "space-y-4", children: [
|
|
524
|
+
/* @__PURE__ */ e(D, { label: "Role", htmlFor: "role-select", children: /* @__PURE__ */ e(
|
|
525
|
+
"select",
|
|
526
|
+
{
|
|
527
|
+
id: "role-select",
|
|
528
|
+
"data-testid": "role-select",
|
|
529
|
+
className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
530
|
+
value: r ?? "",
|
|
531
|
+
onChange: (a) => c(Number(a.target.value)),
|
|
532
|
+
children: l.map((a) => /* @__PURE__ */ e("option", { value: a.id, children: a.name.charAt(0).toUpperCase() + a.name.slice(1) }, a.id))
|
|
533
|
+
}
|
|
534
|
+
) }),
|
|
535
|
+
/* @__PURE__ */ i("div", { className: "flex justify-end gap-3", children: [
|
|
536
|
+
/* @__PURE__ */ e(
|
|
537
|
+
w,
|
|
538
|
+
{
|
|
539
|
+
type: "button",
|
|
540
|
+
variant: "secondary",
|
|
541
|
+
"data-testid": "role-change-cancel-btn",
|
|
542
|
+
onClick: n,
|
|
543
|
+
disabled: d,
|
|
544
|
+
children: "Cancel"
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
/* @__PURE__ */ e(
|
|
548
|
+
w,
|
|
549
|
+
{
|
|
550
|
+
type: "submit",
|
|
551
|
+
"data-testid": "role-change-submit-btn",
|
|
552
|
+
disabled: d || r === null,
|
|
553
|
+
children: d ? "Saving..." : "Save"
|
|
554
|
+
}
|
|
555
|
+
)
|
|
556
|
+
] })
|
|
557
|
+
] })
|
|
558
|
+
] }) });
|
|
559
|
+
}
|
|
560
|
+
function L(t, n) {
|
|
561
|
+
const { data: s } = ie();
|
|
562
|
+
return s?.permissions ? s.permissions.includes(`${t}:${n}`) : !1;
|
|
563
|
+
}
|
|
564
|
+
function Ke({ currentUserId: t }) {
|
|
565
|
+
const n = I(), { data: s, isLoading: m, error: f, refetch: b } = ae(), [d, { isLoading: l }] = se(), r = L("users", "delete"), c = L("roles", "update"), [g, a] = N(!1), [v, u] = N(null), [y, o] = N(null), p = s ?? [], h = W(async () => {
|
|
566
|
+
if (v)
|
|
418
567
|
try {
|
|
419
|
-
await
|
|
568
|
+
await d({ id: v.id }).unwrap(), n(A("User deleted successfully"));
|
|
420
569
|
} catch {
|
|
421
570
|
} finally {
|
|
422
|
-
|
|
571
|
+
u(null);
|
|
423
572
|
}
|
|
424
|
-
}, [
|
|
573
|
+
}, [v, d, n]), J = R(
|
|
425
574
|
() => [
|
|
426
575
|
{ field: "email", headerName: "Email", flex: 2 },
|
|
427
576
|
{
|
|
428
577
|
headerName: "Name",
|
|
429
578
|
flex: 2,
|
|
430
|
-
valueGetter: (
|
|
431
|
-
const { firstName:
|
|
432
|
-
return [
|
|
579
|
+
valueGetter: (x) => {
|
|
580
|
+
const { firstName: S, lastName: K } = x.data ?? {};
|
|
581
|
+
return [S, K].filter(Boolean).join(" ") || "—";
|
|
433
582
|
}
|
|
434
583
|
},
|
|
435
584
|
{
|
|
436
585
|
field: "role",
|
|
437
586
|
headerName: "Role",
|
|
438
587
|
flex: 1,
|
|
439
|
-
cellRenderer: (
|
|
588
|
+
cellRenderer: (x) => x.data ? /* @__PURE__ */ e(Y, { role: x.data.role }) : null
|
|
440
589
|
},
|
|
441
590
|
{
|
|
442
591
|
headerName: "Actions",
|
|
443
592
|
flex: 1,
|
|
444
593
|
sortable: !1,
|
|
445
594
|
filter: !1,
|
|
446
|
-
cellRenderer: (
|
|
447
|
-
if (!
|
|
448
|
-
const
|
|
449
|
-
return /* @__PURE__ */
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
595
|
+
cellRenderer: (x) => {
|
|
596
|
+
if (!x.data) return null;
|
|
597
|
+
const S = x.data.id === t;
|
|
598
|
+
return /* @__PURE__ */ i("div", { className: "flex gap-1", children: [
|
|
599
|
+
c && /* @__PURE__ */ e(
|
|
600
|
+
"button",
|
|
601
|
+
{
|
|
602
|
+
onClick: () => x.data && o(x.data),
|
|
603
|
+
disabled: S,
|
|
604
|
+
title: S ? "Cannot change your own role" : "Change user role",
|
|
605
|
+
className: "rounded px-2 py-1 text-xs font-medium text-primary transition-colors hover:bg-primary/10 disabled:cursor-not-allowed disabled:opacity-40",
|
|
606
|
+
children: "Change Role"
|
|
607
|
+
}
|
|
608
|
+
),
|
|
609
|
+
r && /* @__PURE__ */ e(
|
|
610
|
+
"button",
|
|
611
|
+
{
|
|
612
|
+
onClick: () => x.data && u(x.data),
|
|
613
|
+
disabled: S,
|
|
614
|
+
title: S ? "Cannot delete your own account" : "Delete user",
|
|
615
|
+
className: "rounded px-2 py-1 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-40",
|
|
616
|
+
children: "Delete"
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
] });
|
|
459
620
|
}
|
|
460
621
|
}
|
|
461
622
|
],
|
|
462
|
-
[t]
|
|
623
|
+
[t, c, r]
|
|
463
624
|
);
|
|
464
|
-
return
|
|
625
|
+
return f ? /* @__PURE__ */ i(
|
|
465
626
|
"div",
|
|
466
627
|
{
|
|
467
628
|
"data-testid": "users-error",
|
|
468
|
-
className: "rounded-lg bg-
|
|
629
|
+
className: "rounded-lg bg-destructive/10 p-6 text-center",
|
|
469
630
|
role: "alert",
|
|
470
631
|
children: [
|
|
471
|
-
/* @__PURE__ */ e("p", { className: "text-
|
|
632
|
+
/* @__PURE__ */ e("p", { className: "text-destructive", children: "Failed to load users." }),
|
|
472
633
|
/* @__PURE__ */ e(
|
|
473
634
|
"button",
|
|
474
635
|
{
|
|
475
636
|
"data-testid": "users-retry-btn",
|
|
476
|
-
onClick:
|
|
477
|
-
className: "mt-2 text-sm font-medium text-primary
|
|
637
|
+
onClick: b,
|
|
638
|
+
className: "mt-2 text-sm font-medium text-primary hover:underline",
|
|
478
639
|
children: "Try again"
|
|
479
640
|
}
|
|
480
641
|
)
|
|
@@ -486,53 +647,258 @@ function he({ currentUserId: t }) {
|
|
|
486
647
|
"h2",
|
|
487
648
|
{
|
|
488
649
|
"data-testid": "users-heading",
|
|
489
|
-
className: "text-xl font-semibold text-
|
|
650
|
+
className: "text-xl font-semibold text-foreground",
|
|
490
651
|
children: "Users"
|
|
491
652
|
}
|
|
492
653
|
),
|
|
493
654
|
/* @__PURE__ */ e(
|
|
494
|
-
|
|
655
|
+
w,
|
|
495
656
|
{
|
|
496
657
|
"data-testid": "invite-user-btn",
|
|
497
|
-
onClick: () =>
|
|
498
|
-
className: D,
|
|
658
|
+
onClick: () => a(!0),
|
|
499
659
|
children: "Invite User"
|
|
500
660
|
}
|
|
501
661
|
)
|
|
502
662
|
] }),
|
|
663
|
+
/* @__PURE__ */ e(U, { rowData: p, columnDefs: J, loading: m }),
|
|
503
664
|
/* @__PURE__ */ e(
|
|
504
|
-
|
|
665
|
+
Ce,
|
|
505
666
|
{
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
mode: s,
|
|
509
|
-
theme: r,
|
|
510
|
-
loading: l
|
|
667
|
+
isOpen: g,
|
|
668
|
+
onClose: () => a(!1)
|
|
511
669
|
}
|
|
512
670
|
),
|
|
513
671
|
/* @__PURE__ */ e(
|
|
514
|
-
|
|
672
|
+
Me,
|
|
515
673
|
{
|
|
516
|
-
isOpen:
|
|
517
|
-
onClose: () =>
|
|
674
|
+
isOpen: !!y,
|
|
675
|
+
onClose: () => o(null),
|
|
676
|
+
user: {
|
|
677
|
+
id: y?.id ?? 0,
|
|
678
|
+
email: y?.email ?? "",
|
|
679
|
+
role: y?.role ?? ""
|
|
680
|
+
}
|
|
518
681
|
}
|
|
519
682
|
),
|
|
520
683
|
/* @__PURE__ */ e(
|
|
521
|
-
|
|
684
|
+
Q,
|
|
522
685
|
{
|
|
523
|
-
isOpen: !!
|
|
686
|
+
isOpen: !!v,
|
|
524
687
|
title: "Delete User",
|
|
525
|
-
message: `Are you sure you want to delete ${
|
|
526
|
-
confirmLabel:
|
|
527
|
-
onConfirm:
|
|
528
|
-
onCancel: () =>
|
|
529
|
-
isLoading:
|
|
688
|
+
message: `Are you sure you want to delete ${v?.email}? This action cannot be undone.`,
|
|
689
|
+
confirmLabel: l ? "Deleting..." : "Delete",
|
|
690
|
+
onConfirm: h,
|
|
691
|
+
onCancel: () => u(null),
|
|
692
|
+
isLoading: l
|
|
693
|
+
}
|
|
694
|
+
)
|
|
695
|
+
] });
|
|
696
|
+
}
|
|
697
|
+
function Te({
|
|
698
|
+
isOpen: t,
|
|
699
|
+
onClose: n,
|
|
700
|
+
role: s
|
|
701
|
+
}) {
|
|
702
|
+
const m = I(), { data: f } = re(), { data: b } = le(
|
|
703
|
+
{ id: s.id },
|
|
704
|
+
{ skip: !t }
|
|
705
|
+
), [d, { isLoading: l }] = oe(), [r, c] = N(/* @__PURE__ */ new Set()), g = f ?? [], a = b ?? [];
|
|
706
|
+
H(() => {
|
|
707
|
+
c(new Set(a.map((o) => o.id)));
|
|
708
|
+
}, [a]);
|
|
709
|
+
const v = R(() => {
|
|
710
|
+
const o = /* @__PURE__ */ new Map();
|
|
711
|
+
for (const p of g) {
|
|
712
|
+
const h = o.get(p.resource) ?? [];
|
|
713
|
+
h.push(p), o.set(p.resource, h);
|
|
714
|
+
}
|
|
715
|
+
return o;
|
|
716
|
+
}, [g]);
|
|
717
|
+
function u(o) {
|
|
718
|
+
c((p) => {
|
|
719
|
+
const h = new Set(p);
|
|
720
|
+
return h.has(o) ? h.delete(o) : h.add(o), h;
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
async function y(o) {
|
|
724
|
+
o.preventDefault();
|
|
725
|
+
try {
|
|
726
|
+
await d({
|
|
727
|
+
id: s.id,
|
|
728
|
+
setRolePermissionsDto: { permissionIds: [...r] }
|
|
729
|
+
}).unwrap(), m(A("Permissions updated successfully")), n();
|
|
730
|
+
} catch {
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return /* @__PURE__ */ e(j, { open: t, onOpenChange: (o) => !o && n(), children: /* @__PURE__ */ i(E, { children: [
|
|
734
|
+
/* @__PURE__ */ i(O, { children: [
|
|
735
|
+
/* @__PURE__ */ e(G, { children: "Manage Permissions" }),
|
|
736
|
+
/* @__PURE__ */ i($, { children: [
|
|
737
|
+
"Editing permissions for ",
|
|
738
|
+
/* @__PURE__ */ e("strong", { children: s.name })
|
|
739
|
+
] })
|
|
740
|
+
] }),
|
|
741
|
+
/* @__PURE__ */ i("form", { onSubmit: y, className: "mt-4", children: [
|
|
742
|
+
/* @__PURE__ */ e("div", { className: "max-h-64 space-y-4 overflow-y-auto", children: [...v.entries()].map(([o, p]) => /* @__PURE__ */ i("fieldset", { children: [
|
|
743
|
+
/* @__PURE__ */ e("legend", { className: "text-sm font-medium capitalize text-foreground", children: o }),
|
|
744
|
+
/* @__PURE__ */ e("div", { className: "mt-1 space-y-1", children: p.map((h) => /* @__PURE__ */ i(
|
|
745
|
+
"label",
|
|
746
|
+
{
|
|
747
|
+
className: "flex items-center gap-2 text-sm text-muted-foreground",
|
|
748
|
+
children: [
|
|
749
|
+
/* @__PURE__ */ e(
|
|
750
|
+
"input",
|
|
751
|
+
{
|
|
752
|
+
type: "checkbox",
|
|
753
|
+
checked: r.has(h.id),
|
|
754
|
+
onChange: () => u(h.id),
|
|
755
|
+
className: "rounded border-input text-primary focus:ring-ring"
|
|
756
|
+
}
|
|
757
|
+
),
|
|
758
|
+
/* @__PURE__ */ e("span", { children: h.action }),
|
|
759
|
+
h.description && /* @__PURE__ */ i("span", { className: "text-xs text-muted-foreground/70", children: [
|
|
760
|
+
"— ",
|
|
761
|
+
h.description
|
|
762
|
+
] })
|
|
763
|
+
]
|
|
764
|
+
},
|
|
765
|
+
h.id
|
|
766
|
+
)) })
|
|
767
|
+
] }, o)) }),
|
|
768
|
+
/* @__PURE__ */ i("div", { className: "mt-4 flex justify-end gap-3", children: [
|
|
769
|
+
/* @__PURE__ */ e(
|
|
770
|
+
w,
|
|
771
|
+
{
|
|
772
|
+
type: "button",
|
|
773
|
+
variant: "secondary",
|
|
774
|
+
"data-testid": "permissions-cancel-btn",
|
|
775
|
+
onClick: n,
|
|
776
|
+
disabled: l,
|
|
777
|
+
children: "Cancel"
|
|
778
|
+
}
|
|
779
|
+
),
|
|
780
|
+
/* @__PURE__ */ e(
|
|
781
|
+
w,
|
|
782
|
+
{
|
|
783
|
+
type: "submit",
|
|
784
|
+
"data-testid": "permissions-save-btn",
|
|
785
|
+
disabled: l,
|
|
786
|
+
children: l ? "Saving..." : "Save"
|
|
787
|
+
}
|
|
788
|
+
)
|
|
789
|
+
] })
|
|
790
|
+
] })
|
|
791
|
+
] }) });
|
|
792
|
+
}
|
|
793
|
+
function We() {
|
|
794
|
+
const t = I(), { data: n, isLoading: s, error: m, refetch: f } = F(), [b, { isLoading: d }] = de(), l = L("roles", "delete"), r = L("roles", "update"), [c, g] = N(null), [a, v] = N(null), u = n ?? [];
|
|
795
|
+
async function y() {
|
|
796
|
+
if (c)
|
|
797
|
+
try {
|
|
798
|
+
await b({ id: c.id }).unwrap(), t(A("Role deleted successfully"));
|
|
799
|
+
} catch {
|
|
800
|
+
} finally {
|
|
801
|
+
g(null);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const o = R(
|
|
805
|
+
() => [
|
|
806
|
+
{ field: "name", headerName: "Name", flex: 1 },
|
|
807
|
+
{ field: "description", headerName: "Description", flex: 2 },
|
|
808
|
+
{
|
|
809
|
+
headerName: "Type",
|
|
810
|
+
flex: 1,
|
|
811
|
+
valueGetter: (p) => p.data?.isSystem ? "System" : "Custom"
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
headerName: "Actions",
|
|
815
|
+
flex: 1,
|
|
816
|
+
sortable: !1,
|
|
817
|
+
filter: !1,
|
|
818
|
+
cellRenderer: (p) => {
|
|
819
|
+
if (!p.data) return null;
|
|
820
|
+
const h = !!p.data.isSystem;
|
|
821
|
+
return /* @__PURE__ */ i("div", { className: "flex gap-1", children: [
|
|
822
|
+
r && /* @__PURE__ */ e(
|
|
823
|
+
"button",
|
|
824
|
+
{
|
|
825
|
+
onClick: () => p.data && v(p.data),
|
|
826
|
+
className: "rounded px-2 py-1 text-xs font-medium text-primary transition-colors hover:bg-primary/10",
|
|
827
|
+
children: "Permissions"
|
|
828
|
+
}
|
|
829
|
+
),
|
|
830
|
+
l && /* @__PURE__ */ e(
|
|
831
|
+
"button",
|
|
832
|
+
{
|
|
833
|
+
onClick: () => p.data && g(p.data),
|
|
834
|
+
disabled: h,
|
|
835
|
+
title: h ? "Cannot delete a system role" : "Delete role",
|
|
836
|
+
className: "rounded px-2 py-1 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-40",
|
|
837
|
+
children: "Delete"
|
|
838
|
+
}
|
|
839
|
+
)
|
|
840
|
+
] });
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
],
|
|
844
|
+
[r, l]
|
|
845
|
+
);
|
|
846
|
+
return m ? /* @__PURE__ */ i(
|
|
847
|
+
"div",
|
|
848
|
+
{
|
|
849
|
+
"data-testid": "roles-error",
|
|
850
|
+
className: "rounded-lg bg-destructive/10 p-6 text-center",
|
|
851
|
+
role: "alert",
|
|
852
|
+
children: [
|
|
853
|
+
/* @__PURE__ */ e("p", { className: "text-destructive", children: "Failed to load roles." }),
|
|
854
|
+
/* @__PURE__ */ e(
|
|
855
|
+
"button",
|
|
856
|
+
{
|
|
857
|
+
"data-testid": "roles-retry-btn",
|
|
858
|
+
onClick: f,
|
|
859
|
+
className: "mt-2 text-sm font-medium text-primary hover:underline",
|
|
860
|
+
children: "Try again"
|
|
861
|
+
}
|
|
862
|
+
)
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
) : /* @__PURE__ */ i("div", { children: [
|
|
866
|
+
/* @__PURE__ */ e("div", { className: "mb-4 flex items-center justify-between", children: /* @__PURE__ */ e(
|
|
867
|
+
"h2",
|
|
868
|
+
{
|
|
869
|
+
"data-testid": "roles-heading",
|
|
870
|
+
className: "text-xl font-semibold text-foreground",
|
|
871
|
+
children: "Roles & Permissions"
|
|
872
|
+
}
|
|
873
|
+
) }),
|
|
874
|
+
/* @__PURE__ */ e(U, { rowData: u, columnDefs: o, loading: s }),
|
|
875
|
+
/* @__PURE__ */ e(
|
|
876
|
+
Te,
|
|
877
|
+
{
|
|
878
|
+
isOpen: !!a,
|
|
879
|
+
onClose: () => v(null),
|
|
880
|
+
role: a ? { id: a.id, name: a.name } : { id: 0, name: "" }
|
|
881
|
+
}
|
|
882
|
+
),
|
|
883
|
+
/* @__PURE__ */ e(
|
|
884
|
+
Q,
|
|
885
|
+
{
|
|
886
|
+
isOpen: !!c,
|
|
887
|
+
title: "Delete Role",
|
|
888
|
+
message: `Are you sure you want to delete the "${c?.name}" role? This action cannot be undone.`,
|
|
889
|
+
confirmLabel: d ? "Deleting..." : "Delete",
|
|
890
|
+
onConfirm: y,
|
|
891
|
+
onCancel: () => g(null),
|
|
892
|
+
isLoading: d
|
|
530
893
|
}
|
|
531
894
|
)
|
|
532
895
|
] });
|
|
533
896
|
}
|
|
534
897
|
export {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
898
|
+
Ye as AcceptInvitation,
|
|
899
|
+
Je as InvitationList,
|
|
900
|
+
We as RoleList,
|
|
901
|
+
k as StatusCard,
|
|
902
|
+
Ke as UserList,
|
|
903
|
+
L as useHasPermission
|
|
538
904
|
};
|