@vtex/faststore-plugin-buyer-portal 1.1.40 → 1.1.41

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.
@@ -36,6 +36,31 @@ export const TEST_DATA = {
36
36
  TEST_CONTRACT_NAME: "teste_fields",
37
37
  TEST_CONTRACT_ID: "27e05218-d807-11ef-b37f-8dc7bb2ee7fa",
38
38
  },
39
+ USERS: {
40
+ USER_ORG_UNIT_ADMIN: {
41
+ NAME: "User Org Unit Admin",
42
+ ROLE: "Organizational Unit Admin",
43
+ },
44
+ USER_ORG_UNIT_BUYER: {
45
+ NAME: "User Org Unit Buyer",
46
+ ROLE: "Buyer",
47
+ },
48
+ USER_NAME_FOR_ROLES: "User for Test Roles",
49
+ NEW_USER: {
50
+ NAME: `New User ${Date.now().toString(36)}-${Math.random()
51
+ .toString(36)
52
+ .substring(2, 5)}`,
53
+ EMAIL: `new_user+e2e_test${Date.now().toString(36)}-${Math.random()
54
+ .toString(36)
55
+ .substring(2, 5)}@vtex.com`,
56
+ ROLE: "Buyer",
57
+ },
58
+ USER_FROM_OTHER_ORG_UNIT: {
59
+ NAME: "User from other unit",
60
+ EMAIL: "rodrigo.tavares+devb2b@vtex.com",
61
+ ROLE: "Order Approver",
62
+ },
63
+ },
39
64
  BUYING_POLICIES: {
40
65
  NEW_POLICY: {
41
66
  NAME: "Test Buying Policy E2E",
@@ -0,0 +1,551 @@
1
+ import { TEST_CONFIG, TEST_DATA } from "../constants";
2
+
3
+ const navigateToUsers = () => {
4
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
5
+ cy.contains("Users").click();
6
+
7
+ cy.wait(TEST_CONFIG.TIMEOUTS.RETRY_DELAY);
8
+ cy.get("[data-fs-users-section]").should("exist");
9
+ };
10
+
11
+ const verifyUserState = (
12
+ userName: string,
13
+ shouldExist: boolean,
14
+ maxRetries = TEST_CONFIG.RETRY.DEFAULT_MAX_ATTEMPTS
15
+ ) => {
16
+ const verifyAndRetry = (currentRetry = 0) => {
17
+ cy.get("[data-fs-users-section]").should("exist");
18
+ cy.get("[data-fs-bp-base-tabs-layout-content]").scrollTo("bottom");
19
+
20
+ cy.get("body").then(($body) => {
21
+ const exists = $body.text().includes(userName);
22
+ if (exists !== shouldExist && currentRetry < maxRetries) {
23
+ cy.log(`Retry attempt ${currentRetry + 1} of ${maxRetries}`);
24
+ cy.wait(TEST_CONFIG.TIMEOUTS.RETRY_DELAY);
25
+ cy.reload();
26
+ verifyAndRetry(currentRetry + 1);
27
+ } else if (exists !== shouldExist) {
28
+ throw new Error(
29
+ `Failed to verify user state after ${maxRetries} retries`
30
+ );
31
+ }
32
+ });
33
+ };
34
+
35
+ verifyAndRetry();
36
+
37
+ if (shouldExist) {
38
+ cy.contains(userName).should("be.visible");
39
+ } else {
40
+ cy.contains(userName).should("not.exist");
41
+ }
42
+ };
43
+
44
+ const fillUserForm = (
45
+ userData: typeof TEST_DATA.USERS.NEW_USER,
46
+ shouldUpdateEmailAndRole = true
47
+ ) => {
48
+ // Fill the user name
49
+ cy.get("label")
50
+ .contains("Full Name")
51
+ .parent()
52
+ .find("[data-fs-bp-input-text-input]")
53
+ .clear()
54
+ .type(userData.NAME);
55
+
56
+ if (shouldUpdateEmailAndRole) {
57
+ // Fill the user email
58
+ cy.get("label")
59
+ .contains("Email")
60
+ .parent()
61
+ .find("[data-fs-bp-input-text-input]")
62
+ .clear()
63
+ .type(userData.EMAIL);
64
+
65
+ cy.wait(500);
66
+ // Fill the user role
67
+ cy.get('[data-fs-bp-create-user-roles="true"]')
68
+ .contains(userData.ROLE)
69
+ .parents('[data-fs-bp-create-user-role-wrapper="true"]')
70
+ .within(() => {
71
+ cy.get('[type="checkbox"]').check();
72
+ });
73
+ }
74
+ };
75
+
76
+ const openUserDropdown = (userName: string) => {
77
+ cy.get("[data-fs-bp-table-row]")
78
+ .contains(userName)
79
+ .parents("[data-fs-bp-table-row]")
80
+ .within(() => {
81
+ cy.get("[data-fs-bp-basic-dropdown-menu-trigger]").click();
82
+ });
83
+ };
84
+
85
+ const confirmDeletion = (userName: string) => {
86
+ const tryDelete = (attempt = 0) => {
87
+ cy.contains("Delete user").should("be.visible");
88
+ cy.contains("Confirm by typing the user name below:").should("be.visible");
89
+
90
+ cy.get("label")
91
+ .contains("User name")
92
+ .parent()
93
+ .find("[data-fs-bp-input-text-input]")
94
+ .clear()
95
+ .type(userName);
96
+
97
+ cy.contains("button", "Delete").click();
98
+
99
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
100
+
101
+ cy.get("body").then(($body) => {
102
+ const errorOccurred = $body
103
+ .text()
104
+ .includes("An error occurred while deleting the user");
105
+ if (errorOccurred && attempt < TEST_CONFIG.RETRY.DEFAULT_MAX_ATTEMPTS) {
106
+ cy.log(`Retrying delete attempt ${attempt + 1}`);
107
+ cy.wait(TEST_CONFIG.TIMEOUTS.RETRY_DELAY);
108
+ tryDelete(attempt + 1);
109
+ } else if (errorOccurred) {
110
+ throw new Error(
111
+ `Failed to delete user after ${TEST_CONFIG.RETRY.DEFAULT_MAX_ATTEMPTS} retries due to error`
112
+ );
113
+ }
114
+ });
115
+ };
116
+
117
+ tryDelete();
118
+ };
119
+
120
+ describe("Users", () => {
121
+ beforeEach(() => {
122
+ cy.login();
123
+ });
124
+
125
+ it("Should load and display users information correctly (User List)", () => {
126
+ navigateToUsers();
127
+
128
+ // Check that the table columns are present
129
+ cy.contains("Name").should("be.visible");
130
+ cy.contains("Role").should("be.visible");
131
+
132
+ // Check that the expected users are present in the table
133
+ cy.contains(TEST_DATA.USERS.USER_ORG_UNIT_ADMIN.NAME)
134
+ .scrollIntoView()
135
+ .should("be.visible")
136
+ .parent()
137
+ .parent()
138
+ .within(() => {
139
+ cy.contains(TEST_DATA.USERS.USER_ORG_UNIT_ADMIN.ROLE)
140
+ .scrollIntoView()
141
+ .should("be.visible");
142
+ cy.get("[data-fs-bp-basic-dropdown-menu-trigger]")
143
+ .should("be.visible")
144
+ .click();
145
+ });
146
+
147
+ // Check if the menu options are visible
148
+ cy.contains("Open").should("be.visible");
149
+ cy.contains("Edit details").should("be.visible");
150
+ cy.contains("Change organizational unit").should("be.visible");
151
+ cy.contains("Delete").should("be.visible");
152
+ });
153
+
154
+ it("Should load user details page successfully", () => {
155
+ navigateToUsers();
156
+
157
+ // Click on User Test 1 to go to details page
158
+ cy.contains(TEST_DATA.USERS.USER_ORG_UNIT_ADMIN.NAME)
159
+ .scrollIntoView()
160
+ .should("be.visible")
161
+ .parents("[data-fs-bp-table-row]")
162
+ .click();
163
+
164
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
165
+
166
+ // Check that the user details section is visible
167
+ cy.get("[data-fs-user-details-section]").should("exist");
168
+
169
+ // Check that the user's name is displayed in the details
170
+ cy.get("[data-fs-user-details-row-value]")
171
+ .contains(TEST_DATA.USERS.USER_ORG_UNIT_ADMIN.NAME)
172
+ .should("be.visible");
173
+
174
+ cy.get("[data-fs-user-details-row-value]")
175
+ .contains(TEST_DATA.USERS.USER_ORG_UNIT_ADMIN.ROLE)
176
+ .should("be.visible");
177
+
178
+ // Verify labels and buttons are present
179
+ cy.contains("Name").should("be.visible");
180
+ cy.contains("Email").should("be.visible");
181
+ cy.contains("Role").should("be.visible");
182
+ cy.contains("Organizational Unit").should("be.visible");
183
+ cy.contains("Edit").should("be.visible");
184
+ });
185
+
186
+ it("Should add a new user", () => {
187
+ navigateToUsers();
188
+
189
+ // === CREATE USER ===
190
+ cy.log("=== Creating new user ===");
191
+
192
+ // Click to add a new user
193
+ cy.get("[data-fs-header-inside-button]").should("be.visible").click();
194
+
195
+ // Fill user form
196
+ fillUserForm(TEST_DATA.USERS.NEW_USER);
197
+
198
+ // Submit form
199
+ cy.contains("button", "Add").click();
200
+
201
+ // Verify success message
202
+ cy.contains("User successfully added").should("be.visible");
203
+
204
+ // Reload and verify user was created
205
+ verifyUserState(TEST_DATA.USERS.NEW_USER.NAME, true);
206
+ });
207
+
208
+ it("Should view and edit the newly created user", () => {
209
+ navigateToUsers();
210
+
211
+ // === VIEW USER DETAILS ===
212
+ cy.log("=== Viewing user details ===");
213
+ cy.get("[data-fs-bp-base-tabs-layout-content]").scrollTo("bottom");
214
+
215
+ cy.contains(TEST_DATA.USERS.NEW_USER.NAME)
216
+ .should("be.visible")
217
+ .parents("[data-fs-bp-table-row]")
218
+ .click();
219
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
220
+
221
+ // Verify user details page
222
+ cy.get("[data-fs-user-details-section]").should("exist");
223
+ cy.get("[data-fs-user-details-row-value]")
224
+ .contains(TEST_DATA.USERS.NEW_USER.ROLE)
225
+ .should("be.visible");
226
+
227
+ // Go back to users list
228
+ navigateToUsers();
229
+
230
+ // === EDIT USER ===
231
+ cy.log("=== Editing user ===");
232
+
233
+ openUserDropdown(TEST_DATA.USERS.NEW_USER.NAME);
234
+ cy.contains("Edit details").click();
235
+
236
+ // Verify edit drawer is open
237
+ cy.contains("Edit user details").should("be.visible");
238
+
239
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
240
+
241
+ // Update user information
242
+ const updatedUserData = {
243
+ NAME: `${TEST_DATA.USERS.NEW_USER.NAME} Updated`,
244
+ EMAIL: TEST_DATA.USERS.NEW_USER.EMAIL,
245
+ ROLE: TEST_DATA.USERS.NEW_USER.ROLE,
246
+ };
247
+
248
+ fillUserForm(updatedUserData, false);
249
+
250
+ // Save changes
251
+ cy.contains("button", "Save").click();
252
+
253
+ // Verify update
254
+ verifyUserState(updatedUserData.NAME, true);
255
+ });
256
+
257
+ it("Should delete the updated user", () => {
258
+ navigateToUsers();
259
+
260
+ // === DELETE USER ===
261
+ cy.log("=== Deleting user ===");
262
+ cy.get("[data-fs-bp-base-tabs-layout-content]").scrollTo("bottom");
263
+
264
+ const updatedUserData = {
265
+ NAME: `${TEST_DATA.USERS.NEW_USER.NAME} Updated`,
266
+ EMAIL: TEST_DATA.USERS.NEW_USER.EMAIL,
267
+ ROLE: TEST_DATA.USERS.NEW_USER.ROLE,
268
+ };
269
+
270
+ openUserDropdown(updatedUserData.NAME);
271
+ cy.contains("Delete").click();
272
+
273
+ cy.get(`a:contains("${updatedUserData.NAME}")`)
274
+ .invoke("text")
275
+ .then((userNameText) => {
276
+ confirmDeletion(userNameText);
277
+ });
278
+
279
+ // Verify if the user was deleted
280
+ verifyUserState(updatedUserData.NAME, false);
281
+ });
282
+
283
+ it("Should not allow adding a user already in another org unit", () => {
284
+ navigateToUsers();
285
+
286
+ // Click to add a new user
287
+ cy.get("[data-fs-header-inside-button]").should("be.visible").click();
288
+
289
+ // Fill form with existing user data - Org Unit for E2E Tests Child 3
290
+ fillUserForm(TEST_DATA.USERS.USER_FROM_OTHER_ORG_UNIT);
291
+
292
+ // Submit form
293
+ cy.contains("button", "Add").click();
294
+
295
+ // Assert error message is shown
296
+ cy.contains("User cannot be added").should("be.visible");
297
+ cy.contains("This user is assigned to another organizational unit.").should(
298
+ "be.visible"
299
+ );
300
+ cy.contains(
301
+ "Users can only belong to one organizational unit at a time."
302
+ ).should("be.visible");
303
+
304
+ // Close error dialog
305
+ cy.contains("Ok").click();
306
+ });
307
+
308
+ it("Should create a new user add, edit and remove roles", () => {
309
+ // Visit the buyer portal home page
310
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
311
+
312
+ // Click on the "Users" link in the sidebar menu
313
+ cy.get("a[data-fs-vertical-nav-menu-link]").contains("Users").click();
314
+
315
+ // Check that the Users page is rendered
316
+ cy.get('h1[data-fs-bp-header-inside-title="true"]').should(
317
+ "contain",
318
+ "Users"
319
+ );
320
+
321
+ // Check that at least one user row exists
322
+ cy.get('a[data-fs-bp-table-row-link="true"]').should("exist");
323
+
324
+ // Click the add user button at the top
325
+ cy.get('button[data-fs-header-inside-button="true"]').click();
326
+
327
+ // Check that the user creation modal is open
328
+ cy.get(
329
+ 'div[data-fs-modal-content="true"][data-fs-bp-create-user-drawer="true"]'
330
+ ).should("be.visible");
331
+ cy.get('h2[data-fs-bp-basic-drawer-heading-title="true"]').should(
332
+ "contain",
333
+ "Add User"
334
+ );
335
+
336
+ // Fill out the user creation form
337
+ cy.get('input[data-fs-bp-input-text-input="true"]')
338
+ .first()
339
+ .type(TEST_DATA.USERS.USER_NAME_FOR_ROLES); // Full Name
340
+ cy.get('input[data-fs-bp-input-text-input="true"]')
341
+ .eq(1)
342
+ .type("userfortestroles@vtex.com"); // Email
343
+ cy.get('input[type="checkbox"][value="Buyer"]').check(); // Assign Buyer role
344
+
345
+ // Click the "Add" button to submit the form
346
+ cy.get(
347
+ 'button[data-fs-bp-basic-drawer-button="true"][data-fs-bp-basic-drawer-button-variant="confirm"]'
348
+ )
349
+ .should("not.be.disabled")
350
+ .click();
351
+
352
+ cy.wait(3000);
353
+
354
+ // Retry logic to check if user appears in the list
355
+ const checkUserExists = (attempt = 1) => {
356
+ cy.reload();
357
+ cy.get("body").then(($body) => {
358
+ if ($body.text().includes(TEST_DATA.USERS.USER_NAME_FOR_ROLES)) {
359
+ // User found, verify it exists
360
+ cy.contains("td", TEST_DATA.USERS.USER_NAME_FOR_ROLES).should(
361
+ "exist"
362
+ );
363
+ } else if (attempt < 3) {
364
+ cy.log(`User not found, retry attempt ${attempt + 1} of 3`);
365
+ cy.wait(2000);
366
+ checkUserExists(attempt + 1);
367
+ } else {
368
+ throw new Error(
369
+ `User ${TEST_DATA.USERS.USER_NAME_FOR_ROLES} not found after 3 attempts`
370
+ );
371
+ }
372
+ });
373
+ };
374
+
375
+ checkUserExists();
376
+
377
+ // Check that the 'Buyer' badge is present in the same row
378
+ cy.contains(
379
+ 'tr[data-fs-bp-table-row="true"]',
380
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
381
+ )
382
+ .find('span[data-fs-tag="true"]')
383
+ .should("contain.text", "Buyer");
384
+
385
+ // --- Edit user roles: add Organizational Unit Admin ---
386
+ cy.contains(
387
+ 'tr[data-fs-bp-table-row="true"]',
388
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
389
+ )
390
+ .find('button[data-fs-bp-basic-dropdown-menu-trigger="true"]')
391
+ .click();
392
+ cy.get(
393
+ 'div[data-fs-dropdown-menu="true"] button[data-fs-dropdown-item="true"]'
394
+ )
395
+ .contains("Edit details")
396
+ .click();
397
+ cy.get(
398
+ 'div[data-fs-modal-content="true"][data-fs-bp-update-user-drawer="true"]'
399
+ ).should("be.visible");
400
+ cy.get('h2[data-fs-bp-basic-drawer-heading-title="true"]').should(
401
+ "contain",
402
+ "Edit user details"
403
+ );
404
+ cy.get("input#role-organizational-unit\\ admin").check({ force: true });
405
+ cy.get(
406
+ 'button[data-fs-bp-basic-drawer-button="true"][data-fs-bp-basic-drawer-button-variant="confirm"]'
407
+ )
408
+ .should("not.be.disabled")
409
+ .click();
410
+
411
+ cy.wait(1000);
412
+ cy.reload();
413
+ cy.contains(
414
+ 'tr[data-fs-bp-table-row="true"]',
415
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
416
+ )
417
+ .find('span[data-fs-tag="true"]')
418
+ .should("contain.text", "Organizational Unit Admin");
419
+
420
+ // --- Edit user roles: remove Organizational Unit Admin ---
421
+ cy.contains(
422
+ 'tr[data-fs-bp-table-row="true"]',
423
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
424
+ )
425
+ .find('button[data-fs-bp-basic-dropdown-menu-trigger="true"]')
426
+ .click();
427
+ cy.get(
428
+ 'div[data-fs-dropdown-menu="true"] button[data-fs-dropdown-item="true"]'
429
+ )
430
+ .contains("Edit details")
431
+ .click();
432
+ cy.get(
433
+ 'div[data-fs-modal-content="true"][data-fs-bp-update-user-drawer="true"]'
434
+ ).should("be.visible");
435
+ cy.get("input#role-organizational-unit\\ admin").uncheck({ force: true });
436
+ cy.get(
437
+ 'button[data-fs-bp-basic-drawer-button="true"][data-fs-bp-basic-drawer-button-variant="confirm"]'
438
+ )
439
+ .should("not.be.disabled")
440
+ .click();
441
+
442
+ cy.wait(1000);
443
+ cy.reload();
444
+ cy.contains(
445
+ 'tr[data-fs-bp-table-row="true"]',
446
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
447
+ )
448
+ .find('span[data-fs-tag="true"]')
449
+ .should("not.contain.text", "Organizational Unit Admin");
450
+
451
+ // Open the dropdown menu (three dots) for the created user
452
+ cy.contains(
453
+ 'tr[data-fs-bp-table-row="true"]',
454
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
455
+ )
456
+ .find('button[data-fs-bp-basic-dropdown-menu-trigger="true"]')
457
+ .click();
458
+
459
+ // Click the "Delete" option in the dropdown menu
460
+ cy.get(
461
+ 'div[data-fs-dropdown-menu="true"] button[data-fs-dropdown-item="true"]'
462
+ )
463
+ .contains("Delete")
464
+ .click();
465
+
466
+ // Check that the delete user modal is open
467
+ cy.get(
468
+ 'div[data-fs-modal-content="true"][data-fs-bp-delete-user-drawer="true"]'
469
+ ).should("be.visible");
470
+ cy.get('h2[data-fs-bp-basic-drawer-heading-title="true"]').should(
471
+ "contain",
472
+ "Delete user"
473
+ );
474
+
475
+ // Type the user name to confirm deletion
476
+ cy.get('input[data-fs-bp-input-text-input="true"]').type(
477
+ TEST_DATA.USERS.USER_NAME_FOR_ROLES
478
+ );
479
+
480
+ cy.wait(1000);
481
+
482
+ // Click the "Delete" button to confirm
483
+ cy.get(
484
+ 'button[data-fs-bp-basic-drawer-button="true"][data-fs-bp-basic-drawer-button-variant="danger"]'
485
+ )
486
+ .should("not.be.disabled")
487
+ .click();
488
+
489
+ cy.wait(1000);
490
+ // Reload the users page
491
+ cy.reload();
492
+
493
+ // Check that the user no longer exists in the list
494
+ cy.contains("td", TEST_DATA.USERS.USER_NAME_FOR_ROLES).should("not.exist");
495
+ });
496
+
497
+ it("Should allow changing the organizational unit from the list dropdown menu", () => {
498
+ navigateToUsers();
499
+
500
+ // Open dropdown for the test user
501
+ cy.get("[data-fs-header-inside-button]").should("be.visible").click();
502
+ fillUserForm(TEST_DATA.USERS.NEW_USER);
503
+
504
+ cy.contains("button", "Add").click();
505
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
506
+
507
+ verifyUserState(TEST_DATA.USERS.NEW_USER.NAME, true);
508
+
509
+ openUserDropdown(TEST_DATA.USERS.NEW_USER.NAME);
510
+ cy.contains("Change organizational unit").click();
511
+
512
+ // Verify change org unit modal/drawer is open
513
+ cy.contains("Change user organizational unit").should("be.visible");
514
+ cy.contains(
515
+ `Users can belong to only one Organizational Unit. Search and select a new unit for ${TEST_DATA.USERS.NEW_USER.NAME}`
516
+ ).should("be.visible");
517
+
518
+ cy.get('[data-fs-bp-input-text="true"]')
519
+ .should("be.visible")
520
+ .type(TEST_DATA.ORG_UNITS.ROOT, { delay: 1000 });
521
+
522
+ cy.wait(0);
523
+
524
+ // Wait for and click on the option in the dropdown
525
+ cy.get('[data-fs-bp-autocomplete-dropdown-menu="true"]')
526
+ .contains(TEST_DATA.ORG_UNITS.CHILD_2, { timeout: 10000 })
527
+ .should("exist")
528
+ .click();
529
+
530
+ // Confirm change
531
+ cy.contains("button", "Save").click();
532
+
533
+ // Reload and verify user is now in the new org unit
534
+ cy.reload();
535
+
536
+ // Check if the user is not on the same org unit
537
+ verifyUserState(TEST_DATA.USERS.NEW_USER.NAME, false);
538
+ });
539
+
540
+ it.skip("Should not allow deleting the last admin user", () => {
541
+ // TODO: Implement this test
542
+ });
543
+
544
+ it.skip("Should not allow moving the last admin user", () => {
545
+ // TODO: Implement this test
546
+ });
547
+
548
+ it.skip("Should not allow removing the role from the last admin user", () => {
549
+ // TODO: Implement this test
550
+ });
551
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.1.40",
3
+ "version": "1.1.41",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -31,7 +31,7 @@ export const DeleteUserDrawer = ({
31
31
 
32
32
  const handleRemoveSuccess = () => {
33
33
  pushToast({
34
- message: "User successfully edited",
34
+ message: "User successfully deleted",
35
35
  status: "INFO",
36
36
  });
37
37
  onDelete?.();
@@ -49,15 +49,16 @@ export const DeleteUserDrawer = ({
49
49
  });
50
50
  };
51
51
 
52
- const { removeUserFromOrgUnit } = useRemoveUserFromOrgUnit({
53
- onSuccess: handleRemoveSuccess,
54
- onError: () => {
55
- pushToast({
56
- message: "An error occurred while deleting the user",
57
- status: "ERROR",
58
- });
59
- },
60
- });
52
+ const { removeUserFromOrgUnit, isRemoveUserFromOrgUnitLoading } =
53
+ useRemoveUserFromOrgUnit({
54
+ onSuccess: handleRemoveSuccess,
55
+ onError: () => {
56
+ pushToast({
57
+ message: "An error occurred while deleting the user",
58
+ status: "ERROR",
59
+ });
60
+ },
61
+ });
61
62
 
62
63
  const isDeleteButtonEnabled = userNameConfirmation === user.name;
63
64
 
@@ -72,6 +73,7 @@ export const DeleteUserDrawer = ({
72
73
  orgUnitId: orgUnit?.id || "",
73
74
  userId: user.id,
74
75
  })}
76
+ data-fs-bp-delete-user-drawer-user-name
75
77
  >
76
78
  {user.name}
77
79
  </a>
@@ -100,7 +102,8 @@ export const DeleteUserDrawer = ({
100
102
  Cancel
101
103
  </BasicDrawer.Button>
102
104
  <BasicDrawer.Button
103
- variant="confirm"
105
+ variant="danger"
106
+ isLoading={isRemoveUserFromOrgUnitLoading}
104
107
  onClick={handleDeleteClick}
105
108
  disabled={!isDeleteButtonEnabled}
106
109
  >
@@ -43,6 +43,10 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
43
43
  ...updateUserDrawerProps
44
44
  } = useDrawerProps();
45
45
 
46
+ const handleUpdate = () => {
47
+ route.reload();
48
+ };
49
+
46
50
  return (
47
51
  <>
48
52
  <BasicDropdownMenu>
@@ -80,6 +84,7 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
80
84
  <DeleteUserDrawer
81
85
  user={user}
82
86
  isOpen={isDeleteUserDrawerOpen}
87
+ onDelete={handleUpdate}
83
88
  {...deleteUserDrawerProps}
84
89
  />
85
90
  )}
@@ -87,6 +92,7 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
87
92
  <ReassignOrgUnitDrawer
88
93
  user={user}
89
94
  isOpen={isReassignOrgUnitDrawerOpen}
95
+ onReassing={handleUpdate}
90
96
  {...reassignOrgUnitDrawerProps}
91
97
  />
92
98
  )}
@@ -96,6 +102,7 @@ export const UserDropdownMenu = ({ user }: UserDropdownMenuProps) => {
96
102
  userId={user.id}
97
103
  orgUnitId={currentOrgUnit?.id ?? ""}
98
104
  isOpen={isUpdateUserDrawerOpen}
105
+ onCreate={handleUpdate}
99
106
  {...updateUserDrawerProps}
100
107
  />
101
108
  )}
@@ -89,7 +89,10 @@ export const UserDetailsLayout = ({
89
89
 
90
90
  <div data-fs-user-details-row>
91
91
  <span data-fs-user-details-row-label>Role</span>
92
- <span data-fs-user-details-row-value>
92
+ <span
93
+ data-fs-user-details-row-value
94
+ data-fs-user-details-row-value-roles
95
+ >
93
96
  {user?.roles?.map((role) => (
94
97
  <Tag key={role} data-fs-user-details-row-value-tag>
95
98
  {role}
@@ -130,6 +130,7 @@
130
130
  color: #707070;
131
131
  font-size: var(--fs-text-size-1);
132
132
  font-weight: 500;
133
+ min-width: 12.5rem;
133
134
  }
134
135
 
135
136
  [data-fs-user-details-row-value] {
@@ -138,6 +139,12 @@
138
139
  font-weight: 500;
139
140
  }
140
141
 
142
+ [data-fs-user-details-row-value-roles] {
143
+ display: flex;
144
+ flex-wrap: wrap;
145
+ gap: var(--fs-spacing-1);
146
+ }
147
+
141
148
  [data-fs-user-details-change] {
142
149
  margin-left: auto;
143
150
  font-weight: 600;
@@ -103,9 +103,11 @@ export const UsersLayout = ({ data: { users, search } }: UsersLayoutProps) => {
103
103
  dropdownMenu={<UserDropdownMenu user={user} />}
104
104
  >
105
105
  <Table.Cell>
106
- {user.roles?.map((role) => (
107
- <Tag key={role}>{role}</Tag>
108
- ))}
106
+ <div data-fs-bp-table-user-roles>
107
+ {user.roles?.map((role) => (
108
+ <Tag key={role}>{role}</Tag>
109
+ ))}
110
+ </div>
109
111
  </Table.Cell>
110
112
  </Table.Row>
111
113
  ))}
@@ -158,4 +158,16 @@
158
158
  }
159
159
  }
160
160
  }
161
+
162
+ [data-fs-bp-table] {
163
+ margin-bottom: var(--fs-spacing-8);
164
+
165
+ [data-fs-bp-table-row] {
166
+ [data-fs-bp-table-user-roles] {
167
+ display: flex;
168
+ flex-wrap: wrap;
169
+ gap: var(--fs-spacing-1);
170
+ }
171
+ }
172
+ }
161
173
  }