@vtex/faststore-plugin-buyer-portal 1.0.48 → 1.0.49
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/package.json +1 -1
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +3 -3
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +5 -5
- package/src/features/shared/components/Table/Table.tsx +2 -0
- package/src/features/shared/components/Table/TableCell/TableCell.tsx +7 -0
- package/src/features/shared/components/Table/TableHead/TableHead.tsx +1 -1
- package/src/features/shared/components/Table/TableRow/TableRow.tsx +1 -1
- package/src/features/shared/utils/api.ts +5 -4
- package/src/features/users/clients/UsersClient.ts +30 -0
- package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +50 -38
- package/src/features/users/components/CreateUserDrawer/create-user-drawer.scss +27 -0
- package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +214 -0
- package/src/features/users/components/UpdateUserDrawer/update-user-drawer.scss +40 -0
- package/src/features/users/components/UserDropdownMenu/UserDropdownMenu.tsx +18 -3
- package/src/features/users/components/UserDropdownMenu/user-dropdown-menu.scss +1 -0
- package/src/features/users/components/index.ts +4 -0
- package/src/features/users/hooks/index.ts +2 -0
- package/src/features/users/hooks/useGetUserById.ts +20 -0
- package/src/features/users/hooks/useUpdateUser.ts +23 -0
- package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +25 -4
- package/src/features/users/layouts/UserDetailsLayout/user-details-layout.scss +1 -0
- package/src/features/users/layouts/UsersLayout/UsersLayout.tsx +46 -30
- package/src/features/users/layouts/UsersLayout/users-layout.scss +4 -1
- package/src/features/users/mocks/users-data.ts +2 -2
- package/src/features/users/services/add-user-to-org-unit.service.ts +6 -2
- package/src/features/users/services/get-user-by-id.service.ts +2 -2
- package/src/features/users/services/get-users-by-org-unit-id.service.ts +7 -3
- package/src/features/users/services/index.ts +4 -1
- package/src/features/users/services/update-user.service.ts +27 -0
- package/src/features/users/types/UserData.ts +1 -2
- package/src/features/users/utils/index.ts +1 -0
- package/src/features/users/utils/roles.ts +26 -0
- package/src/pages/users.tsx +2 -3
- package/src/features/users/services/get-user-details.service.ts +0 -6
package/package.json
CHANGED
package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx
CHANGED
|
@@ -82,7 +82,7 @@ export const BasicBuyingPolicyDrawer = ({
|
|
|
82
82
|
}));
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
const
|
|
85
|
+
const isAllFieldsFilled = Object.keys(form).every((key) => {
|
|
86
86
|
const value = form[key as keyof typeof form];
|
|
87
87
|
|
|
88
88
|
if (key === "action") {
|
|
@@ -110,7 +110,7 @@ export const BasicBuyingPolicyDrawer = ({
|
|
|
110
110
|
const handleConfirmClick = () => {
|
|
111
111
|
setIsTouched(true);
|
|
112
112
|
|
|
113
|
-
if (!
|
|
113
|
+
if (!isAllFieldsFilled) {
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -160,7 +160,7 @@ export const BasicBuyingPolicyDrawer = ({
|
|
|
160
160
|
});
|
|
161
161
|
};
|
|
162
162
|
|
|
163
|
-
const isConfirmButtonEnabled =
|
|
163
|
+
const isConfirmButtonEnabled = isAllFieldsFilled && !isLoading;
|
|
164
164
|
|
|
165
165
|
return (
|
|
166
166
|
<BasicDrawer data-fs-bp-basic-buying-policy-drawer close={close} {...props}>
|
|
@@ -40,7 +40,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
40
40
|
{/* TODO: Add person here */}
|
|
41
41
|
<OrgUnitDetailsNavbar
|
|
42
42
|
orgName={orgUnit.name}
|
|
43
|
-
person={{ name: user?.name ?? "", role: user?.
|
|
43
|
+
person={{ name: user?.name ?? "", role: user?.roles?.[0] }}
|
|
44
44
|
/>
|
|
45
45
|
<section data-fs-org-units-details-section>
|
|
46
46
|
<HeaderInside title={orgUnit.name}>
|
|
@@ -67,7 +67,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
67
67
|
footerMessage="Manage contract settings"
|
|
68
68
|
footerLink={buyerPortalRoutes.profileDetails({
|
|
69
69
|
orgUnitId: orgUnit.id,
|
|
70
|
-
contractId: contracts[0]
|
|
70
|
+
contractId: contracts[0]?.id ?? "",
|
|
71
71
|
})}
|
|
72
72
|
enableFooter
|
|
73
73
|
>
|
|
@@ -75,7 +75,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
75
75
|
<VerticalNav.Menu title={orgUnit.name}>
|
|
76
76
|
{getContractSettingsLinks({
|
|
77
77
|
orgUnitId: orgUnit.id,
|
|
78
|
-
contractId: contracts[0]
|
|
78
|
+
contractId: contracts[0]?.id ?? "",
|
|
79
79
|
}).map(({ name, link }) => (
|
|
80
80
|
<VerticalNav.Link key={name} link={link}>
|
|
81
81
|
{name}
|
|
@@ -139,14 +139,14 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
139
139
|
footerMessage="Manage finance and compliance settings"
|
|
140
140
|
footerLink={buyerPortalRoutes.buyingPolicies({
|
|
141
141
|
orgUnitId: orgUnit.id,
|
|
142
|
-
contractId: contracts[0]
|
|
142
|
+
contractId: contracts[0]?.id,
|
|
143
143
|
})}
|
|
144
144
|
enableFooter
|
|
145
145
|
>
|
|
146
146
|
<VerticalNav.Menu title="Finance and Compliance">
|
|
147
147
|
{getFinanceSettingsLinks({
|
|
148
148
|
orgUnitId: orgUnit.id,
|
|
149
|
-
contractId: contracts[0]
|
|
149
|
+
contractId: contracts[0]?.id ?? "",
|
|
150
150
|
}).map((option) => (
|
|
151
151
|
<VerticalNav.Link key={option.name} link={option.link}>
|
|
152
152
|
{option.name}
|
|
@@ -2,6 +2,7 @@ import { TableRow } from "./TableRow/TableRow";
|
|
|
2
2
|
import { TableBody } from "./TableBody/TableBody";
|
|
3
3
|
import TableHead from "./TableHead/TableHead";
|
|
4
4
|
import { TableLoading } from "./TableLoading/TableLoading";
|
|
5
|
+
import { TableCell } from "./TableCell/TableCell";
|
|
5
6
|
|
|
6
7
|
export type TableProps = {
|
|
7
8
|
children: React.ReactNode;
|
|
@@ -15,3 +16,4 @@ Table.Head = TableHead;
|
|
|
15
16
|
Table.Body = TableBody;
|
|
16
17
|
Table.Row = TableRow;
|
|
17
18
|
Table.Loading = TableLoading;
|
|
19
|
+
Table.Cell = TableCell;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { API_URL } from "./constants";
|
|
2
2
|
import storeConfig from "discovery.config";
|
|
3
3
|
|
|
4
|
-
export function getApiUrl(operation
|
|
5
|
-
return `${API_URL(
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export function getApiUrl(operation = "", customerId = "") {
|
|
5
|
+
return `${API_URL(
|
|
6
|
+
`https://${storeConfig?.api.storeId}.myvtex.com`,
|
|
7
|
+
operation
|
|
8
|
+
)}${customerId ? `/${customerId}` : ""}`;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function getPostalCodeApiUrl() {
|
|
@@ -121,6 +121,36 @@ class UsersClient extends Client {
|
|
|
121
121
|
},
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
|
+
|
|
125
|
+
updateUser(
|
|
126
|
+
props: {
|
|
127
|
+
orgUnitId: string;
|
|
128
|
+
userId: string;
|
|
129
|
+
name?: string;
|
|
130
|
+
role?: string;
|
|
131
|
+
},
|
|
132
|
+
cookie: string
|
|
133
|
+
) {
|
|
134
|
+
const { orgUnitId, userId, ...data } = props;
|
|
135
|
+
|
|
136
|
+
return this.patch<
|
|
137
|
+
unknown,
|
|
138
|
+
{
|
|
139
|
+
name?: string;
|
|
140
|
+
role?: string;
|
|
141
|
+
}
|
|
142
|
+
>(
|
|
143
|
+
`units/${orgUnitId}/users/${userId}`,
|
|
144
|
+
{
|
|
145
|
+
...data,
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
headers: {
|
|
149
|
+
Cookie: cookie,
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
}
|
|
124
154
|
}
|
|
125
155
|
|
|
126
156
|
const usersClient = new UsersClient();
|
|
@@ -4,14 +4,14 @@ import { useUI } from "@faststore/ui";
|
|
|
4
4
|
import { useRouter } from "next/router";
|
|
5
5
|
import {
|
|
6
6
|
type BasicDrawerProps,
|
|
7
|
-
AutocompleteDropdown,
|
|
8
7
|
BasicDrawer,
|
|
9
8
|
ErrorMessage,
|
|
10
9
|
Icon,
|
|
11
10
|
InputText,
|
|
12
11
|
} from "../../../shared/components";
|
|
13
|
-
import { roles, type Role } from "../../../shared/utils/roles";
|
|
14
12
|
import { useAddUserToOrgUnit } from "../../hooks";
|
|
13
|
+
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
14
|
+
import { rolesOptions } from "../../utils";
|
|
15
15
|
|
|
16
16
|
export type CreateUserDrawerProps = Omit<BasicDrawerProps, "children"> & {
|
|
17
17
|
onCreate?: () => void;
|
|
@@ -45,25 +45,25 @@ export const CreateUserDrawer = ({
|
|
|
45
45
|
const [form, setForm] = useState<{
|
|
46
46
|
name: string;
|
|
47
47
|
email: string;
|
|
48
|
-
|
|
48
|
+
roles: string[];
|
|
49
49
|
}>({
|
|
50
50
|
name: "",
|
|
51
51
|
email: "",
|
|
52
|
-
|
|
52
|
+
roles: [],
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
const [isTouched, setIsTouched] = useState(false);
|
|
56
56
|
|
|
57
|
-
const { name, email,
|
|
57
|
+
const { name, email, roles } = form;
|
|
58
58
|
|
|
59
|
-
const updateField = (field: keyof typeof form, value: string) => {
|
|
59
|
+
const updateField = (field: keyof typeof form, value: string | string[]) => {
|
|
60
60
|
setForm((prev) => ({
|
|
61
61
|
...prev,
|
|
62
62
|
[field]: value,
|
|
63
63
|
}));
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
const handleAddUserSuccess = (
|
|
66
|
+
const handleAddUserSuccess = ({ user }: { user: { id: string } }) => {
|
|
67
67
|
pushToast({
|
|
68
68
|
message: "User successfully added",
|
|
69
69
|
status: "INFO",
|
|
@@ -72,8 +72,12 @@ export const CreateUserDrawer = ({
|
|
|
72
72
|
data-fs-bp-toast-view-button
|
|
73
73
|
type="button"
|
|
74
74
|
onClick={() => {
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
router.push(
|
|
76
|
+
buyerPortalRoutes.userDetails({
|
|
77
|
+
userId: user.id,
|
|
78
|
+
orgUnitId: orgUnitId,
|
|
79
|
+
})
|
|
80
|
+
);
|
|
77
81
|
}}
|
|
78
82
|
>
|
|
79
83
|
View
|
|
@@ -108,14 +112,18 @@ export const CreateUserDrawer = ({
|
|
|
108
112
|
},
|
|
109
113
|
});
|
|
110
114
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
const isAllFieldsFilled = Object.keys(form).every((key) => {
|
|
116
|
+
if (key === "roles") {
|
|
117
|
+
return form[key as keyof typeof form]?.length > 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return (form[key as keyof typeof form] as string)?.trim();
|
|
121
|
+
});
|
|
114
122
|
|
|
115
123
|
const handleConfirmClick = () => {
|
|
116
124
|
setIsTouched(true);
|
|
117
125
|
|
|
118
|
-
if (!
|
|
126
|
+
if (!isAllFieldsFilled) {
|
|
119
127
|
return;
|
|
120
128
|
}
|
|
121
129
|
|
|
@@ -123,12 +131,13 @@ export const CreateUserDrawer = ({
|
|
|
123
131
|
addUserToOrgUnit({
|
|
124
132
|
name,
|
|
125
133
|
email,
|
|
126
|
-
|
|
134
|
+
roles,
|
|
127
135
|
orgUnitId,
|
|
128
136
|
});
|
|
129
137
|
};
|
|
130
138
|
|
|
131
|
-
const isConfirmButtonEnabled =
|
|
139
|
+
const isConfirmButtonEnabled =
|
|
140
|
+
isAllFieldsFilled && !isAddUserToOrgUnitLoading;
|
|
132
141
|
|
|
133
142
|
const backToCreateUser = () => {
|
|
134
143
|
setDrawerState("CREATE_USER");
|
|
@@ -136,7 +145,7 @@ export const CreateUserDrawer = ({
|
|
|
136
145
|
setForm({
|
|
137
146
|
name: "",
|
|
138
147
|
email: "",
|
|
139
|
-
|
|
148
|
+
roles: [],
|
|
140
149
|
});
|
|
141
150
|
};
|
|
142
151
|
|
|
@@ -190,30 +199,33 @@ export const CreateUserDrawer = ({
|
|
|
190
199
|
message="Email is required"
|
|
191
200
|
/>
|
|
192
201
|
|
|
193
|
-
<
|
|
194
|
-
label
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
202
|
+
<div data-fs-bp-create-user-roles>
|
|
203
|
+
<span data-fs-bp-create-user-roles-label>Roles</span>
|
|
204
|
+
{rolesOptions.map((role) => {
|
|
205
|
+
const id = `role-${role.value.toLowerCase().replace(" ", "-")}`;
|
|
206
|
+
return (
|
|
207
|
+
<span data-fs-bp-create-user-role-wrapper key={role.value}>
|
|
208
|
+
<input
|
|
209
|
+
type="checkbox"
|
|
210
|
+
key={role.value}
|
|
211
|
+
value={role.value}
|
|
212
|
+
id={id}
|
|
213
|
+
checked={roles?.includes(role.value)}
|
|
214
|
+
onChange={(event) => {
|
|
215
|
+
const newRoles = event.target.checked
|
|
216
|
+
? [...(roles ?? []), role.value]
|
|
217
|
+
: roles?.filter((r) => r !== role.value) ?? [];
|
|
218
|
+
updateField("roles", newRoles);
|
|
219
|
+
}}
|
|
220
|
+
/>
|
|
221
|
+
<label htmlFor={id}>{role.label}</label>
|
|
222
|
+
</span>
|
|
223
|
+
);
|
|
224
|
+
})}
|
|
225
|
+
</div>
|
|
214
226
|
|
|
215
227
|
<ErrorMessage
|
|
216
|
-
show={isTouched && !
|
|
228
|
+
show={isTouched && !roles?.length}
|
|
217
229
|
message="Role is required"
|
|
218
230
|
/>
|
|
219
231
|
</BasicDrawer.Body>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[data-fs-bp-create-user-drawer] {
|
|
4
4
|
@import "../../../shared/components/InputText/input-text.scss";
|
|
5
5
|
@import "../../../shared/components/ErrorMessage/error-message.scss";
|
|
6
|
+
@import "@faststore/ui/src/components/molecules/CheckboxField/styles.scss";
|
|
6
7
|
|
|
7
8
|
[data-fs-bp-create-user-drawer-back-icon] {
|
|
8
9
|
vertical-align: middle;
|
|
@@ -10,4 +11,30 @@
|
|
|
10
11
|
margin-right: 0.75rem;
|
|
11
12
|
cursor: pointer;
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
[data-fs-bp-create-user-roles] {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: var(--fs-spacing-2);
|
|
19
|
+
margin-bottom: var(--fs-spacing-6);
|
|
20
|
+
margin-top: var(--fs-spacing-5);
|
|
21
|
+
|
|
22
|
+
[data-fs-bp-create-user-roles-label] {
|
|
23
|
+
font-weight: var(--fs-text-weight-regular);
|
|
24
|
+
font-size: var(--fs-text-size-1);
|
|
25
|
+
line-height: var(--fs-text-size-3);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[data-fs-bp-create-user-role-wrapper] {
|
|
29
|
+
input {
|
|
30
|
+
margin-right: var(--fs-spacing-1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
label {
|
|
34
|
+
font-weight: var(--fs-text-weight-regular);
|
|
35
|
+
font-size: var(--fs-text-size-1);
|
|
36
|
+
line-height: var(--fs-text-size-3);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
13
40
|
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Checkbox, CheckboxField, Skeleton, useUI } from "@faststore/ui";
|
|
4
|
+
import {
|
|
5
|
+
type BasicDrawerProps,
|
|
6
|
+
BasicDrawer,
|
|
7
|
+
ErrorMessage,
|
|
8
|
+
InputText,
|
|
9
|
+
} from "../../../shared/components";
|
|
10
|
+
import { useGetUserById, useUpdateUser } from "../../hooks";
|
|
11
|
+
import { rolesOptions } from "../../utils";
|
|
12
|
+
|
|
13
|
+
export type UpdateUserDrawerProps = Omit<BasicDrawerProps, "children"> & {
|
|
14
|
+
onCreate?: () => void;
|
|
15
|
+
orgUnitId: string;
|
|
16
|
+
userId: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const UpdateUserDrawer = ({
|
|
20
|
+
close,
|
|
21
|
+
onCreate,
|
|
22
|
+
userId,
|
|
23
|
+
orgUnitId,
|
|
24
|
+
...props
|
|
25
|
+
}: UpdateUserDrawerProps) => {
|
|
26
|
+
const { pushToast } = useUI();
|
|
27
|
+
|
|
28
|
+
const { isUserLoading, user } = useGetUserById(
|
|
29
|
+
{ orgUnitId, userId },
|
|
30
|
+
{
|
|
31
|
+
onSuccess: (data) => {
|
|
32
|
+
setForm({
|
|
33
|
+
name: data?.name ?? "",
|
|
34
|
+
email: data?.email ?? "",
|
|
35
|
+
roles: data?.roles ? data.roles : [],
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
onError: () => {
|
|
39
|
+
pushToast({
|
|
40
|
+
message: "Failed to fetch user details",
|
|
41
|
+
status: "ERROR",
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const [form, setForm] = useState<{
|
|
48
|
+
name: string;
|
|
49
|
+
email: string;
|
|
50
|
+
roles: string[];
|
|
51
|
+
}>({
|
|
52
|
+
name: "",
|
|
53
|
+
email: "",
|
|
54
|
+
roles: [],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const [isTouched, setIsTouched] = useState(false);
|
|
58
|
+
|
|
59
|
+
const { name, email, roles } = form;
|
|
60
|
+
|
|
61
|
+
const updateField = (field: keyof typeof form, value: string | string[]) => {
|
|
62
|
+
setForm((prev) => ({
|
|
63
|
+
...prev,
|
|
64
|
+
[field]: value,
|
|
65
|
+
}));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleAddUserSuccess = () => {
|
|
69
|
+
pushToast({
|
|
70
|
+
message: "User successfully updated",
|
|
71
|
+
status: "INFO",
|
|
72
|
+
});
|
|
73
|
+
onCreate?.();
|
|
74
|
+
close();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const { updateUser, isUpdateUserLoading } = useUpdateUser({
|
|
78
|
+
onSuccess: handleAddUserSuccess,
|
|
79
|
+
onError: () => {
|
|
80
|
+
pushToast({
|
|
81
|
+
message: "Failed to update user",
|
|
82
|
+
status: "ERROR",
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const isAllFieldsFilled = Object.keys(form).every((key) => {
|
|
88
|
+
if (key === "roles") {
|
|
89
|
+
return form[key as keyof typeof form]?.length > 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (form[key as keyof typeof form] as string)?.trim();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const handleConfirmClick = () => {
|
|
96
|
+
setIsTouched(true);
|
|
97
|
+
|
|
98
|
+
if (!isAllFieldsFilled) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
updateUser({
|
|
103
|
+
userId,
|
|
104
|
+
name,
|
|
105
|
+
roles,
|
|
106
|
+
orgUnitId,
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const isConfirmButtonEnabled = isAllFieldsFilled && !isUpdateUserLoading;
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<BasicDrawer data-fs-bp-update-user-drawer close={close} {...props}>
|
|
114
|
+
<BasicDrawer.Heading title="Edit user details" onClose={close} />
|
|
115
|
+
|
|
116
|
+
<BasicDrawer.Body>
|
|
117
|
+
{isUserLoading ? (
|
|
118
|
+
<Skeleton size={{ width: "100%", height: "3.5rem" }} />
|
|
119
|
+
) : (
|
|
120
|
+
<InputText
|
|
121
|
+
label="Full Name"
|
|
122
|
+
value={name}
|
|
123
|
+
hasError={isTouched && !name?.trim()}
|
|
124
|
+
onChange={(event) => updateField("name", event.target.value)}
|
|
125
|
+
/>
|
|
126
|
+
)}
|
|
127
|
+
|
|
128
|
+
<ErrorMessage
|
|
129
|
+
show={isTouched && !name?.trim()}
|
|
130
|
+
message="Full name is required"
|
|
131
|
+
/>
|
|
132
|
+
|
|
133
|
+
{isUserLoading ? (
|
|
134
|
+
<Skeleton
|
|
135
|
+
size={{ width: "100%", height: "3.5rem" }}
|
|
136
|
+
style={{
|
|
137
|
+
marginTop: "1rem",
|
|
138
|
+
marginBottom: "1rem",
|
|
139
|
+
width: "100%",
|
|
140
|
+
height: "3.5rem",
|
|
141
|
+
}}
|
|
142
|
+
/>
|
|
143
|
+
) : (
|
|
144
|
+
<InputText
|
|
145
|
+
label="Email"
|
|
146
|
+
value={email}
|
|
147
|
+
wrapperProps={{ style: { marginTop: 16, marginBottom: 16 } }}
|
|
148
|
+
hasError={isTouched && !email?.trim()}
|
|
149
|
+
onChange={(event) => updateField("email", event.target.value)}
|
|
150
|
+
readOnly
|
|
151
|
+
disabled
|
|
152
|
+
/>
|
|
153
|
+
)}
|
|
154
|
+
|
|
155
|
+
<ErrorMessage
|
|
156
|
+
show={isTouched && !email?.trim()}
|
|
157
|
+
message="Email is required"
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
<div data-fs-bp-update-user-roles>
|
|
161
|
+
<span data-fs-bp-update-user-roles-label>Roles</span>
|
|
162
|
+
{rolesOptions.map((role) => {
|
|
163
|
+
if (isUserLoading) {
|
|
164
|
+
return (
|
|
165
|
+
<Skeleton
|
|
166
|
+
key={role.value}
|
|
167
|
+
size={{ width: "100%", height: "1.25rem" }}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const id = `role-${role.value.toLowerCase().replace(" ", "-")}`;
|
|
173
|
+
return (
|
|
174
|
+
<span data-fs-bp-update-user-role-wrapper key={role.value}>
|
|
175
|
+
<input
|
|
176
|
+
type="checkbox"
|
|
177
|
+
key={role.value}
|
|
178
|
+
value={role.value}
|
|
179
|
+
id={id}
|
|
180
|
+
checked={roles?.includes(role.value)}
|
|
181
|
+
onChange={(event) => {
|
|
182
|
+
const newRoles = event.target.checked
|
|
183
|
+
? [...(roles ?? []), role.value]
|
|
184
|
+
: roles?.filter((r) => r !== role.value) ?? [];
|
|
185
|
+
updateField("roles", newRoles);
|
|
186
|
+
}}
|
|
187
|
+
/>
|
|
188
|
+
<label htmlFor={id}>{role.label}</label>
|
|
189
|
+
</span>
|
|
190
|
+
);
|
|
191
|
+
})}
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<ErrorMessage
|
|
195
|
+
show={isTouched && !roles?.length}
|
|
196
|
+
message="Role is required"
|
|
197
|
+
/>
|
|
198
|
+
</BasicDrawer.Body>
|
|
199
|
+
<BasicDrawer.Footer>
|
|
200
|
+
<BasicDrawer.Button variant="ghost" onClick={close}>
|
|
201
|
+
Cancel
|
|
202
|
+
</BasicDrawer.Button>
|
|
203
|
+
<BasicDrawer.Button
|
|
204
|
+
variant="confirm"
|
|
205
|
+
disabled={!isConfirmButtonEnabled}
|
|
206
|
+
onClick={handleConfirmClick}
|
|
207
|
+
isLoading={isUpdateUserLoading}
|
|
208
|
+
>
|
|
209
|
+
Save
|
|
210
|
+
</BasicDrawer.Button>
|
|
211
|
+
</BasicDrawer.Footer>
|
|
212
|
+
</BasicDrawer>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@import "../../../shared/components/BasicDrawer/basic-drawer.scss";
|
|
2
|
+
|
|
3
|
+
[data-fs-bp-update-user-drawer] {
|
|
4
|
+
@import "../../../shared/components/InputText/input-text.scss";
|
|
5
|
+
@import "../../../shared/components/ErrorMessage/error-message.scss";
|
|
6
|
+
@import "@faststore/ui/src/components/atoms/Skeleton/styles.scss";
|
|
7
|
+
|
|
8
|
+
[data-fs-bp-update-user-drawer-back-icon] {
|
|
9
|
+
vertical-align: middle;
|
|
10
|
+
margin-left: -3.125rem;
|
|
11
|
+
margin-right: 0.75rem;
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
[data-fs-bp-update-user-roles] {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: var(--fs-spacing-2);
|
|
19
|
+
margin-bottom: var(--fs-spacing-6);
|
|
20
|
+
margin-top: var(--fs-spacing-5);
|
|
21
|
+
|
|
22
|
+
[data-fs-bp-update-user-roles-label] {
|
|
23
|
+
font-weight: var(--fs-text-weight-regular);
|
|
24
|
+
font-size: var(--fs-text-size-1);
|
|
25
|
+
line-height: var(--fs-text-size-3);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[data-fs-bp-update-user-role-wrapper] {
|
|
29
|
+
input {
|
|
30
|
+
margin-right: var(--fs-spacing-1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
label {
|
|
34
|
+
font-weight: var(--fs-text-weight-regular);
|
|
35
|
+
font-size: var(--fs-text-size-1);
|
|
36
|
+
line-height: var(--fs-text-size-3);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -5,6 +5,7 @@ import { ReassignOrgUnitDrawer } from "../ReassignOrgUnitDrawer/ReassignOrgUnitD
|
|
|
5
5
|
import { useBuyerPortal, useDrawerProps } from "../../../shared/hooks";
|
|
6
6
|
import { DeleteUserDrawer } from "../DeleteUserDrawer/DeleteUserDrawer";
|
|
7
7
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
8
|
+
import { UpdateUserDrawer } from "../UpdateUserDrawer/UpdateUserDrawer";
|
|
8
9
|
|
|
9
10
|
export type UserDropdownMenuProps = {
|
|
10
11
|
user: {
|
|
@@ -32,6 +33,12 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
|
|
|
32
33
|
...deleteUserDrawerProps
|
|
33
34
|
} = useDrawerProps();
|
|
34
35
|
|
|
36
|
+
const {
|
|
37
|
+
open: openUpdateUser,
|
|
38
|
+
isOpen: isUpdateUserDrawerOpen,
|
|
39
|
+
...updateUserDrawerProps
|
|
40
|
+
} = useDrawerProps();
|
|
41
|
+
|
|
35
42
|
return (
|
|
36
43
|
<>
|
|
37
44
|
<BasicDropdownMenu>
|
|
@@ -48,9 +55,9 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
|
|
|
48
55
|
<Icon name="OpenInNew" {...sizeProps} />
|
|
49
56
|
Open
|
|
50
57
|
</DropdownItem>
|
|
51
|
-
<DropdownItem>
|
|
52
|
-
<Icon name="
|
|
53
|
-
|
|
58
|
+
<DropdownItem onClick={openUpdateUser}>
|
|
59
|
+
<Icon name="Edit" {...sizeProps} />
|
|
60
|
+
Edit details
|
|
54
61
|
</DropdownItem>
|
|
55
62
|
<DropdownItem onClick={openReassignOrgUnitDrawer}>
|
|
56
63
|
<Icon name="DriveFileMove" {...sizeProps} />
|
|
@@ -79,6 +86,14 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
|
|
|
79
86
|
{...reassignOrgUnitDrawerProps}
|
|
80
87
|
/>
|
|
81
88
|
)}
|
|
89
|
+
{isUpdateUserDrawerOpen && (
|
|
90
|
+
<UpdateUserDrawer
|
|
91
|
+
userId={user.id}
|
|
92
|
+
orgUnitId={currentOrgUnit?.id ?? ""}
|
|
93
|
+
isOpen={isUpdateUserDrawerOpen}
|
|
94
|
+
{...updateUserDrawerProps}
|
|
95
|
+
/>
|
|
96
|
+
)}
|
|
82
97
|
</>
|
|
83
98
|
);
|
|
84
99
|
};
|
|
@@ -3,3 +3,5 @@ export { useRemoveUserFromOrgUnit } from "./useRemoveUserFromOrgUnit";
|
|
|
3
3
|
export { useAddUserToOrgUnit } from "./useAddUserToOrgUnit";
|
|
4
4
|
export { useReassignUser } from "./useReassignUser";
|
|
5
5
|
export { useDebouncedSearchOrgUnit } from "./useDebouncedSearchOrgUnit";
|
|
6
|
+
export { useUpdateUser } from "./useUpdateUser";
|
|
7
|
+
export { useGetUserById } from "./useGetUserById";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type QueryOptions, useQuery } from "../../shared/hooks";
|
|
2
|
+
import { getUserByIdService } from "../services";
|
|
3
|
+
|
|
4
|
+
export const useGetUserById = (
|
|
5
|
+
{ orgUnitId, userId }: { orgUnitId: string; userId: string },
|
|
6
|
+
options?: QueryOptions<AwaitedType<typeof getUserByIdService>>
|
|
7
|
+
) => {
|
|
8
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
9
|
+
`org-unit/user/${orgUnitId}`,
|
|
10
|
+
({ cookie }) => getUserByIdService({ orgUnitId, userId, cookie }),
|
|
11
|
+
options
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
user: data,
|
|
16
|
+
hasUserError: error,
|
|
17
|
+
isUserLoading: isLoading,
|
|
18
|
+
refetchUser: refetch,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type MutationOptions, useMutation } from "../../shared/hooks";
|
|
2
|
+
import { updateUserService, type UpdateUserServiceProps } from "../services";
|
|
3
|
+
|
|
4
|
+
export const useUpdateUser = (
|
|
5
|
+
options?: MutationOptions<AwaitedType<typeof updateUserService>>
|
|
6
|
+
) => {
|
|
7
|
+
const { mutate, isLoading, error } = useMutation<
|
|
8
|
+
AwaitedType<typeof updateUserService>,
|
|
9
|
+
Omit<UpdateUserServiceProps, "cookie">
|
|
10
|
+
>(
|
|
11
|
+
(variables, clientContext) =>
|
|
12
|
+
updateUserService({
|
|
13
|
+
...variables,
|
|
14
|
+
cookie: clientContext.cookie,
|
|
15
|
+
}),
|
|
16
|
+
options
|
|
17
|
+
);
|
|
18
|
+
return {
|
|
19
|
+
updateUser: mutate,
|
|
20
|
+
isUpdateUserLoading: isLoading,
|
|
21
|
+
hasUpdateUserError: error,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Tag,
|
|
8
8
|
} from "../../../shared/components";
|
|
9
9
|
import { GlobalLayout } from "../../../shared/layouts";
|
|
10
|
-
import { ReassignOrgUnitDrawer } from "../../components";
|
|
10
|
+
import { ReassignOrgUnitDrawer, UpdateUserDrawer } from "../../components";
|
|
11
11
|
import { useBuyerPortal, useDrawerProps } from "../../../shared/hooks";
|
|
12
12
|
import { OrgUnitTabsLayout } from "../../../shared/layouts/OrgUnitTabsLayout/OrgUnitTabLayout";
|
|
13
13
|
import { UserDropdownMenu } from "../../components/UserDropdownMenu/UserDropdownMenu";
|
|
@@ -31,6 +31,12 @@ export const UserDetailsLayout = ({
|
|
|
31
31
|
...reassignDrawerProps
|
|
32
32
|
} = useDrawerProps();
|
|
33
33
|
|
|
34
|
+
const {
|
|
35
|
+
open: openUpdateUser,
|
|
36
|
+
isOpen: isUpdateUserDrawerOpen,
|
|
37
|
+
...updateUserDrawerProps
|
|
38
|
+
} = useDrawerProps();
|
|
39
|
+
|
|
34
40
|
return (
|
|
35
41
|
<GlobalLayout>
|
|
36
42
|
{/* // TODO: Add org unit name and id */}
|
|
@@ -49,12 +55,15 @@ export const UserDetailsLayout = ({
|
|
|
49
55
|
user={{ name: user?.name ?? "", id: user?.id ?? "" }}
|
|
50
56
|
/>
|
|
51
57
|
</Dropdown>
|
|
52
|
-
<HeaderInside.Button />
|
|
53
58
|
</HeaderInside>
|
|
54
59
|
<div data-fs-user-details>
|
|
55
60
|
<div data-fs-buyer-portal-user-details-title>
|
|
56
61
|
<span data-fs-buyer-portal-user-details-title-label>Details</span>
|
|
57
|
-
<button
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
data-fs-buyer-portal-user-details-edit
|
|
65
|
+
onClick={openUpdateUser}
|
|
66
|
+
>
|
|
58
67
|
Edit
|
|
59
68
|
</button>
|
|
60
69
|
</div>
|
|
@@ -77,7 +86,11 @@ export const UserDetailsLayout = ({
|
|
|
77
86
|
<div data-fs-user-details-row>
|
|
78
87
|
<span data-fs-user-details-row-label>Role</span>
|
|
79
88
|
<span data-fs-user-details-row-value>
|
|
80
|
-
|
|
89
|
+
{user?.roles?.map((role) => (
|
|
90
|
+
<Tag key={role} data-fs-user-details-row-value-tag>
|
|
91
|
+
{role}
|
|
92
|
+
</Tag>
|
|
93
|
+
))}
|
|
81
94
|
</span>
|
|
82
95
|
</div>
|
|
83
96
|
|
|
@@ -105,6 +118,14 @@ export const UserDetailsLayout = ({
|
|
|
105
118
|
{...reassignDrawerProps}
|
|
106
119
|
/>
|
|
107
120
|
)}
|
|
121
|
+
{isUpdateUserDrawerOpen && (
|
|
122
|
+
<UpdateUserDrawer
|
|
123
|
+
userId={user?.id ?? ""}
|
|
124
|
+
orgUnitId={currentOrgUnit?.id ?? ""}
|
|
125
|
+
isOpen={isUpdateUserDrawerOpen}
|
|
126
|
+
{...updateUserDrawerProps}
|
|
127
|
+
/>
|
|
128
|
+
)}
|
|
108
129
|
</OrgUnitTabsLayout>
|
|
109
130
|
</GlobalLayout>
|
|
110
131
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@import "@faststore/ui/src/components/molecules/Toggle/styles.scss";
|
|
2
2
|
@import "../../components/ReassignOrgUnitDrawer/reassign-org-unit-drawer.scss";
|
|
3
|
+
@import "../../components/UpdateUserDrawer/update-user-drawer.scss";
|
|
3
4
|
@import "../../components/DeleteUserDrawer/delete-user-drawer.scss";
|
|
4
5
|
@import "../../components/UserDropdownMenu/user-dropdown-menu.scss";
|
|
5
6
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { Dropdown, DropdownButton, Link } from "@faststore/ui";
|
|
2
|
-
|
|
3
1
|
import type { UserData } from "../../types";
|
|
4
|
-
import { InternalSearch,
|
|
2
|
+
import { InternalSearch, HeaderInside, Tag } from "../../../shared/components";
|
|
5
3
|
import {
|
|
6
4
|
useBuyerPortal,
|
|
7
5
|
useDrawerProps,
|
|
@@ -9,10 +7,11 @@ import {
|
|
|
9
7
|
} from "../../../shared/hooks";
|
|
10
8
|
import { GlobalLayout } from "../../../shared/layouts";
|
|
11
9
|
import { CreateUserDrawer } from "../../components";
|
|
12
|
-
import { Fragment } from "react";
|
|
13
10
|
import { UserDropdownMenu } from "../../components/UserDropdownMenu/UserDropdownMenu";
|
|
14
11
|
import { OrgUnitTabsLayout } from "../../../shared/layouts/OrgUnitTabsLayout/OrgUnitTabLayout";
|
|
15
12
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
13
|
+
import { Table } from "../../../shared/components/Table/Table";
|
|
14
|
+
import type { TableColumn } from "../../../shared/components/Table/TableHead/TableHead";
|
|
16
15
|
|
|
17
16
|
export type UsersLayoutProps = {
|
|
18
17
|
data: {
|
|
@@ -35,6 +34,28 @@ export const UsersLayout = ({
|
|
|
35
34
|
...createUserDrawerProps
|
|
36
35
|
} = useDrawerProps();
|
|
37
36
|
|
|
37
|
+
const configTable: Array<TableColumn> = [
|
|
38
|
+
{
|
|
39
|
+
key: "name",
|
|
40
|
+
label: "Name",
|
|
41
|
+
align: "left",
|
|
42
|
+
colspan: 2,
|
|
43
|
+
size: "large",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: "role",
|
|
47
|
+
label: "Role",
|
|
48
|
+
align: "left",
|
|
49
|
+
size: "large",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "actions",
|
|
53
|
+
label: "",
|
|
54
|
+
align: "right",
|
|
55
|
+
size: "large",
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
|
|
38
59
|
return (
|
|
39
60
|
<GlobalLayout>
|
|
40
61
|
<OrgUnitTabsLayout pageName="Organization">
|
|
@@ -57,40 +78,35 @@ export const UsersLayout = ({
|
|
|
57
78
|
</div>
|
|
58
79
|
</div>
|
|
59
80
|
|
|
60
|
-
<div data-fs-user-table-heading>
|
|
81
|
+
{/* <div data-fs-user-table-heading>
|
|
61
82
|
<span data-fs-user-table-title>Name</span>
|
|
62
83
|
<span data-fs-user-table-title>Role</span>
|
|
63
84
|
</div>
|
|
64
|
-
<hr data-fs-user-divider />
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
<hr data-fs-user-divider /> */}
|
|
86
|
+
<Table>
|
|
87
|
+
<Table.Head columns={configTable} />
|
|
88
|
+
<Table.Body>
|
|
89
|
+
{users.map((user) => (
|
|
90
|
+
<Table.Row
|
|
91
|
+
key={user.id}
|
|
92
|
+
title={user.name}
|
|
93
|
+
iconName="Profile"
|
|
94
|
+
iconSize={20}
|
|
70
95
|
href={buyerPortalRoutes.userDetails({
|
|
71
96
|
orgUnitId: currentOrgUnit?.id ?? "",
|
|
72
97
|
userId: user.id,
|
|
73
98
|
})}
|
|
74
|
-
|
|
99
|
+
dropdownMenu={<UserDropdownMenu user={user} />}
|
|
75
100
|
>
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
</
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<Icon name="MoreVert" data-fs-menu-action-button />
|
|
86
|
-
</DropdownButton>
|
|
87
|
-
<UserDropdownMenu user={user} />
|
|
88
|
-
</Dropdown>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
<hr data-fs-user-divider />
|
|
92
|
-
</Fragment>
|
|
93
|
-
))}
|
|
101
|
+
<Table.Cell>
|
|
102
|
+
{user.roles?.map((role) => (
|
|
103
|
+
<Tag key={role}>{role}</Tag>
|
|
104
|
+
))}
|
|
105
|
+
</Table.Cell>
|
|
106
|
+
</Table.Row>
|
|
107
|
+
))}
|
|
108
|
+
</Table.Body>
|
|
109
|
+
</Table>
|
|
94
110
|
</div>
|
|
95
111
|
|
|
96
112
|
{isCreateUserDrawerOpen && (
|
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
@import "../../../shared/components/InternalSearch/internal-search.scss";
|
|
12
12
|
@import "../../../shared/components/DropdownFilter/dropdown-filter.scss";
|
|
13
13
|
@import "../../../shared/components/SortFilter/sort-filter.scss";
|
|
14
|
+
@import "../../../shared/components/Tag/tag.scss";
|
|
14
15
|
@import "../../../shared/components/InternalTopbar/internal-top-bar.scss";
|
|
15
16
|
|
|
17
|
+
@import "../../../shared/components/Table/table.scss";
|
|
18
|
+
|
|
16
19
|
--data-fs-users-table-width: 11.875rem;
|
|
17
20
|
|
|
18
21
|
padding: 0 calc(var(--fs-spacing-9) - var(--fs-spacing-0));
|
|
@@ -128,7 +131,7 @@
|
|
|
128
131
|
color: #5c5c5c;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
[data-fs-user-
|
|
134
|
+
[data-fs-user-role] {
|
|
132
135
|
width: 15.625rem;
|
|
133
136
|
font-size: var(--fs-text-size-1);
|
|
134
137
|
font-weight: var(--fs-text-weight-regular);
|
|
@@ -3,7 +3,7 @@ import type { UserData } from "../types";
|
|
|
3
3
|
export const usersData: UserData[] = [
|
|
4
4
|
{
|
|
5
5
|
name: "Everton Ataide",
|
|
6
|
-
|
|
6
|
+
roles: ["Admin"],
|
|
7
7
|
isActive: true,
|
|
8
8
|
id: "1234",
|
|
9
9
|
email: "everton@vtex.com",
|
|
@@ -14,7 +14,7 @@ export const usersData: UserData[] = [
|
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
name: "Arthur Andrade",
|
|
17
|
-
|
|
17
|
+
roles: ["Buyer"],
|
|
18
18
|
isActive: false,
|
|
19
19
|
id: "32141",
|
|
20
20
|
email: "arthur@vtex.com",
|
|
@@ -2,7 +2,7 @@ import { usersClient } from "../clients/UsersClient";
|
|
|
2
2
|
|
|
3
3
|
export type AddUserToOrgUnitServiceProps = {
|
|
4
4
|
orgUnitId: string;
|
|
5
|
-
|
|
5
|
+
roles: string[];
|
|
6
6
|
email: string;
|
|
7
7
|
name: string;
|
|
8
8
|
cookie: string;
|
|
@@ -10,9 +10,13 @@ export type AddUserToOrgUnitServiceProps = {
|
|
|
10
10
|
|
|
11
11
|
export const addUserToOrgUnitService = async ({
|
|
12
12
|
cookie,
|
|
13
|
+
roles,
|
|
13
14
|
...data
|
|
14
15
|
}: AddUserToOrgUnitServiceProps) => {
|
|
15
|
-
const response = await usersClient.addUserToOrgUnit(
|
|
16
|
+
const response = await usersClient.addUserToOrgUnit(
|
|
17
|
+
{ ...data, role: roles.join(",") },
|
|
18
|
+
cookie
|
|
19
|
+
);
|
|
16
20
|
|
|
17
21
|
if (response.message === "User already exists and is attached to a unit") {
|
|
18
22
|
throw new Error(JSON.stringify(response));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { usersClient } from "../clients/UsersClient";
|
|
2
|
+
import type { UserData } from "../types";
|
|
2
3
|
|
|
3
4
|
export type GetUsersByOrgUnitIdServiceProps = {
|
|
4
5
|
orgUnitId: string;
|
|
@@ -8,7 +9,10 @@ export type GetUsersByOrgUnitIdServiceProps = {
|
|
|
8
9
|
export const getUsersByOrgUnitIdService = async ({
|
|
9
10
|
orgUnitId,
|
|
10
11
|
cookie,
|
|
11
|
-
}: GetUsersByOrgUnitIdServiceProps)
|
|
12
|
+
}: GetUsersByOrgUnitIdServiceProps): Promise<{
|
|
13
|
+
users: UserData[];
|
|
14
|
+
total: number;
|
|
15
|
+
}> => {
|
|
12
16
|
const { users, total } = await usersClient.getUsersByOrgUnitId(
|
|
13
17
|
orgUnitId,
|
|
14
18
|
cookie
|
|
@@ -16,9 +20,9 @@ export const getUsersByOrgUnitIdService = async ({
|
|
|
16
20
|
|
|
17
21
|
return {
|
|
18
22
|
users: users.map((user) => ({
|
|
23
|
+
id: user.userId,
|
|
19
24
|
name: user.name,
|
|
20
|
-
|
|
21
|
-
userId: user.userId,
|
|
25
|
+
roles: user.role ? user.role.split(",") : [],
|
|
22
26
|
email: user.email,
|
|
23
27
|
orgUnit: { name: user.orgUnit },
|
|
24
28
|
})),
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { getUserDetailsService } from "./get-user-details.service";
|
|
2
1
|
export {
|
|
3
2
|
getUsersByOrgUnitIdService,
|
|
4
3
|
type GetUsersByOrgUnitIdServiceProps,
|
|
@@ -15,4 +14,8 @@ export {
|
|
|
15
14
|
reassignUserService,
|
|
16
15
|
type ReassignUserServiceProps,
|
|
17
16
|
} from "./reassign-user.service";
|
|
17
|
+
export {
|
|
18
|
+
updateUserService,
|
|
19
|
+
UpdateUserServiceProps,
|
|
20
|
+
} from "./update-user.service";
|
|
18
21
|
export { getUserByIdService } from "./get-user-by-id.service";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { usersClient } from "../clients/UsersClient";
|
|
2
|
+
|
|
3
|
+
export type UpdateUserServiceProps = {
|
|
4
|
+
orgUnitId: string;
|
|
5
|
+
userId: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
roles?: string[];
|
|
8
|
+
cookie: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const updateUserService = async ({
|
|
12
|
+
orgUnitId,
|
|
13
|
+
userId,
|
|
14
|
+
cookie,
|
|
15
|
+
name,
|
|
16
|
+
roles,
|
|
17
|
+
}: UpdateUserServiceProps) => {
|
|
18
|
+
return usersClient.updateUser(
|
|
19
|
+
{
|
|
20
|
+
orgUnitId,
|
|
21
|
+
userId,
|
|
22
|
+
name,
|
|
23
|
+
role: roles?.join(",") || undefined,
|
|
24
|
+
},
|
|
25
|
+
cookie
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { rolesOptions } from "./roles";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const rolesOptions = [
|
|
2
|
+
{
|
|
3
|
+
label: "Organizational Unit Admin",
|
|
4
|
+
value: "Admin",
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
label: "Order Approver",
|
|
8
|
+
value: "Approver",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: "Contract Manager",
|
|
12
|
+
value: "Contract Manager",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: "Organizational Unit Manager",
|
|
16
|
+
value: "Organizational Unit Manager",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: "Contract Viewer",
|
|
20
|
+
value: "Contract Viewer",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: "Address Manager",
|
|
24
|
+
value: "Manager",
|
|
25
|
+
},
|
|
26
|
+
];
|
package/src/pages/users.tsx
CHANGED
|
@@ -13,8 +13,6 @@ import { BuyerPortalProvider } from "../features/shared/components";
|
|
|
13
13
|
import type { LoaderData } from "../features/shared/types";
|
|
14
14
|
import { getOrgUnitBasicDataService } from "../features/org-units/services";
|
|
15
15
|
import type { OrgUnitBasicData } from "../features/org-units/types";
|
|
16
|
-
import { ContractData } from "../features/contracts/types";
|
|
17
|
-
import { getContractDetailsService } from "../features/contracts/services";
|
|
18
16
|
|
|
19
17
|
export type UsersPageData = {
|
|
20
18
|
data: {
|
|
@@ -55,7 +53,8 @@ export async function loader(
|
|
|
55
53
|
|
|
56
54
|
const mappedUsers = users.map((user) => ({
|
|
57
55
|
...user,
|
|
58
|
-
id: user.
|
|
56
|
+
id: user.id,
|
|
57
|
+
name: user.name || user.email,
|
|
59
58
|
}));
|
|
60
59
|
|
|
61
60
|
return {
|