@vtex/faststore-plugin-buyer-portal 1.3.4 → 1.3.6
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/CHANGELOG.md +22 -3
- package/cypress/constants.ts +2 -0
- package/cypress/integration/organizational-units.test.ts +1 -1
- package/cypress/integration/{collections.test.ts → product-assortment.test.ts} +54 -50
- package/cypress/integration/profile.test.ts +1 -1
- package/cypress/integration/users.test.ts +9 -0
- package/package.json +1 -1
- package/plugin.config.js +2 -2
- package/src/features/budgets/components/BudgetRemainingBalance/BudgetRemainingBalance.tsx +1 -1
- package/src/features/{collections/clients/CollectionsClient.ts → product-assortment/clients/ProductAssortmentClient.ts} +18 -20
- package/src/features/product-assortment/components/AddProductAssortmentDrawer/AddProductAssortmentDrawer.tsx +144 -0
- package/src/features/{collections/components/AddCollectionsDrawer/add-collections-drawer.scss → product-assortment/components/AddProductAssortmentDrawer/add-product-assortment-drawer.scss} +9 -10
- package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx +99 -0
- package/src/features/product-assortment/components/ProductAssortmentTable/product-assortment-table.scss +45 -0
- package/src/features/{collections/components/RemoveCollectionDrawer/RemoveCollectionDrawer.tsx → product-assortment/components/RemoveProductAssortmentDrawer/RemoveProductAssortmentDrawer.tsx} +21 -20
- package/src/features/product-assortment/components/RemoveProductAssortmentDrawer/remove-product-assortment-drawer.scss +9 -0
- package/src/features/product-assortment/components/index.tsx +2 -0
- package/src/features/{collections/components/table/AddCollectionsDrawerTable.tsx → product-assortment/components/table/AddProductAssortmentDrawerTable.tsx} +9 -9
- package/src/features/product-assortment/components/table/add-product-assortment-drawer-table.scss +14 -0
- package/src/features/product-assortment/hooks/useAddProductAssortmentToScope.ts +25 -0
- package/src/features/product-assortment/hooks/useRemoveProductAssortmentFromScope.ts +26 -0
- package/src/features/{collections/layouts/CollectionsLayout/CollectionsLayout.tsx → product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx} +43 -49
- package/src/features/{collections/layouts/CollectionsLayout/collections-layout.scss → product-assortment/layouts/ProductAssortmentLayout/product-assortment-layout.scss} +7 -7
- package/src/features/product-assortment/layouts/index.ts +1 -0
- package/src/features/product-assortment/services/add-product-assortment-to-scope.service.ts +16 -0
- package/src/features/product-assortment/services/get-product-assortment-from-contract.service.ts +13 -0
- package/src/features/product-assortment/services/get-product-assortment-from-scope.service.ts +28 -0
- package/src/features/product-assortment/services/remove-product-assortment-from-scope.ts +9 -0
- package/src/features/product-assortment/types/index.ts +80 -0
- package/src/features/shared/utils/buyerPortalRoutes.ts +5 -2
- package/src/features/shared/utils/constants.ts +1 -1
- package/src/features/shared/utils/getContractSettingsLinks.ts +2 -2
- package/src/features/shared/utils/routeLayoutMapping.ts +2 -2
- package/src/features/users/clients/UsersClient.ts +2 -0
- package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +19 -2
- package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +31 -5
- package/src/features/users/components/UserDropdownMenu/UserDropdownMenu.tsx +1 -1
- package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +8 -0
- package/src/features/users/services/add-user-to-org-unit.service.ts +1 -0
- package/src/features/users/services/get-user-by-id.service.ts +2 -1
- package/src/features/users/services/update-user.service.ts +3 -0
- package/src/features/users/types/UserData.ts +1 -0
- package/src/features/users/types/UserDataService.ts +1 -0
- package/src/pages/{collections.tsx → productAssortment.tsx} +30 -51
- package/src/themes/layouts.scss +2 -2
- package/src/features/collections/components/AddCollectionsDrawer/AddCollectionsDrawer.tsx +0 -146
- package/src/features/collections/components/CollectionsTable/CollectionsTable.tsx +0 -94
- package/src/features/collections/components/CollectionsTable/collections-table.scss +0 -140
- package/src/features/collections/components/RemoveCollectionDrawer/remove-collection-drawer.scss +0 -15
- package/src/features/collections/components/index.tsx +0 -5
- package/src/features/collections/components/table/add-collections-drawer-table.scss +0 -71
- package/src/features/collections/hooks/useAddCollectionsToScope.ts +0 -23
- package/src/features/collections/hooks/useGetCollectionsFromContract.ts +0 -26
- package/src/features/collections/hooks/useGetCollectionsFromScope.ts +0 -27
- package/src/features/collections/hooks/useRemoveCollectionsFromScope.ts +0 -26
- package/src/features/collections/layouts/index.ts +0 -4
- package/src/features/collections/services/add-collections-to-scope.service.ts +0 -15
- package/src/features/collections/services/get-collections-from-contract.service.ts +0 -9
- package/src/features/collections/services/get-collections-from-scope.service.ts +0 -24
- package/src/features/collections/services/remove-collections-from-scope.ts +0 -7
- package/src/features/collections/types/index.ts +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.6] - 2025-10-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Collections to Product assortment
|
|
15
|
+
- Rename CSS files and data attributes
|
|
16
|
+
- Rename labels, titles and messages
|
|
17
|
+
- Rename files and folders
|
|
18
|
+
- Rename code
|
|
19
|
+
- Rename routes
|
|
20
|
+
|
|
21
|
+
## [1.3.5] - 2025-10-17
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Budget Screen showing `remaining` ammount when it should have been showing `total`
|
|
26
|
+
|
|
10
27
|
## [1.3.4] - 2025-10-16
|
|
11
28
|
|
|
12
29
|
- Error boundary:
|
|
@@ -120,12 +137,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
120
137
|
- Add CHANGELOG file
|
|
121
138
|
- Add README file
|
|
122
139
|
|
|
123
|
-
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/1.3.
|
|
140
|
+
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/1.3.6...HEAD
|
|
124
141
|
[1.2.3]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.2.2...1.2.3
|
|
125
142
|
[1.2.3]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.2.3
|
|
126
143
|
[1.2.4]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.2.4
|
|
127
144
|
[1.3.2]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.2
|
|
128
|
-
|
|
129
145
|
[1.3.3]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.3
|
|
130
|
-
|
|
131
146
|
[1.3.4]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.4
|
|
147
|
+
|
|
148
|
+
[1.3.5]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.5
|
|
149
|
+
|
|
150
|
+
[1.3.6]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.6
|
package/cypress/constants.ts
CHANGED
|
@@ -50,11 +50,13 @@ export const TEST_DATA = {
|
|
|
50
50
|
NEW_USER: {
|
|
51
51
|
NAME: "New User",
|
|
52
52
|
EMAIL: "new_user+e2e_test@vtex.com",
|
|
53
|
+
PHONE: "(555) 555-5555",
|
|
53
54
|
ROLE: "Buyer",
|
|
54
55
|
},
|
|
55
56
|
USER_FROM_OTHER_ORG_UNIT: {
|
|
56
57
|
NAME: "User from other unit",
|
|
57
58
|
EMAIL: "rodrigo.tavares+devb2b@vtex.com",
|
|
59
|
+
PHONE: "(000) 000-0000",
|
|
58
60
|
ROLE: "Order Approver",
|
|
59
61
|
},
|
|
60
62
|
},
|
|
@@ -155,7 +155,7 @@ describe("Organizational Units", { retries: 2 }, () => {
|
|
|
155
155
|
cy.contains("Addresses").should("be.visible");
|
|
156
156
|
cy.contains("Payment methods").should("be.visible");
|
|
157
157
|
cy.contains("Credit cards").should("be.visible");
|
|
158
|
-
cy.contains("
|
|
158
|
+
cy.contains("Product assortment").should("be.visible");
|
|
159
159
|
cy.contains("PO numbers").should("be.visible");
|
|
160
160
|
cy.contains("Cost centers").should("be.visible");
|
|
161
161
|
cy.contains("Releases").should("be.visible");
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { TEST_CONFIG } from "../constants";
|
|
2
2
|
|
|
3
|
-
function
|
|
3
|
+
function visitProductAssortmentPage() {
|
|
4
4
|
// Visit the homepage
|
|
5
5
|
cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
|
|
6
6
|
|
|
7
|
-
// Navigate to
|
|
7
|
+
// Navigate to product assortment page
|
|
8
8
|
cy.get("[data-fs-vertical-nav-menu-item]")
|
|
9
|
-
.contains("
|
|
9
|
+
.contains("Product assortment")
|
|
10
10
|
.click({ timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD });
|
|
11
11
|
|
|
12
12
|
cy.wait(1000);
|
|
@@ -15,25 +15,27 @@ function visitCollectionsPage() {
|
|
|
15
15
|
timeout: TEST_CONFIG.TIMEOUTS.LONG_DELAY,
|
|
16
16
|
}).should("not.exist");
|
|
17
17
|
|
|
18
|
-
cy.get("[data-fs-bp-
|
|
18
|
+
cy.get("[data-fs-bp-product-assortment-layout]").as(
|
|
19
|
+
"productAssortmentLayout"
|
|
20
|
+
);
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
describe(
|
|
22
|
-
"
|
|
24
|
+
"Product assortment",
|
|
23
25
|
{
|
|
24
26
|
retries: 2,
|
|
25
27
|
},
|
|
26
28
|
() => {
|
|
27
|
-
const
|
|
29
|
+
const PRODUCT_ASSORTMENT_UNDER_TEST = "Product Assortment Demo";
|
|
28
30
|
|
|
29
31
|
beforeEach(() => {
|
|
30
32
|
cy.login();
|
|
31
33
|
});
|
|
32
34
|
|
|
33
|
-
it("Should show empty state when unit has no
|
|
35
|
+
it("Should show empty state when unit has no assortment", () => {
|
|
34
36
|
cy.intercept(
|
|
35
37
|
"GET",
|
|
36
|
-
"/_next/data/**/pvt/organization-account/
|
|
38
|
+
"/_next/data/**/pvt/organization-account/product-assortment/**",
|
|
37
39
|
(req) => {
|
|
38
40
|
req.reply((res) => {
|
|
39
41
|
res.body.pageProps.data.isContractEmpty = true;
|
|
@@ -41,34 +43,34 @@ describe(
|
|
|
41
43
|
}
|
|
42
44
|
);
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
visitProductAssortmentPage();
|
|
45
47
|
|
|
46
|
-
cy.get("@
|
|
47
|
-
.find("[data-fs-bp-
|
|
48
|
+
cy.get("@productAssortmentLayout")
|
|
49
|
+
.find("[data-fs-bp-product-assortment-content]")
|
|
48
50
|
.should("not.exist");
|
|
49
|
-
cy.get("@
|
|
51
|
+
cy.get("@productAssortmentLayout")
|
|
50
52
|
.find("[data-fs-empty-state-section]")
|
|
51
53
|
.should("be.visible");
|
|
52
54
|
});
|
|
53
55
|
|
|
54
|
-
it("Should list and filter
|
|
55
|
-
|
|
56
|
+
it("Should list and filter Product Assortment correctly", () => {
|
|
57
|
+
visitProductAssortmentPage();
|
|
56
58
|
|
|
57
|
-
// Wait for
|
|
59
|
+
// Wait for product assortment section to be visible
|
|
58
60
|
cy.get("[data-fs-bp-header-inside-title]")
|
|
59
|
-
.contains("
|
|
61
|
+
.contains("Product assortment")
|
|
60
62
|
.should("be.visible");
|
|
61
63
|
|
|
62
|
-
// Wait for
|
|
63
|
-
cy.get("[data-fs-bp-
|
|
64
|
+
// Wait for product assortment table to be loaded
|
|
65
|
+
cy.get("[data-fs-bp-product-assortment-table]", {
|
|
64
66
|
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
65
67
|
}).should("exist");
|
|
66
68
|
|
|
67
69
|
cy.get("[data-fs-bp-table-row-title]")
|
|
68
70
|
.eq(0)
|
|
69
71
|
.then(($firstTitle) => {
|
|
70
|
-
cy.get("@
|
|
71
|
-
.find("[data-fs-
|
|
72
|
+
cy.get("@productAssortmentLayout")
|
|
73
|
+
.find("[data-fs-product-assortment-filter] input")
|
|
72
74
|
.as("searchInput")
|
|
73
75
|
.should("be.visible")
|
|
74
76
|
.lazyType($firstTitle.text());
|
|
@@ -77,8 +79,8 @@ describe(
|
|
|
77
79
|
// Wait for list to update
|
|
78
80
|
cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
|
|
79
81
|
|
|
80
|
-
// Check if the resulted
|
|
81
|
-
cy.get("[data-fs-bp-
|
|
82
|
+
// Check if the resulted product assortment is visible
|
|
83
|
+
cy.get("[data-fs-bp-product-assortment-table]", {
|
|
82
84
|
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
83
85
|
}).should("exist");
|
|
84
86
|
|
|
@@ -91,34 +93,34 @@ describe(
|
|
|
91
93
|
cy.get("[data-fs-bp-table] [data-fs-bp-table-row]").should("not.exist");
|
|
92
94
|
});
|
|
93
95
|
|
|
94
|
-
it("Should add a new
|
|
95
|
-
|
|
96
|
+
it("Should add a new Product Assortment correctly", () => {
|
|
97
|
+
visitProductAssortmentPage();
|
|
96
98
|
|
|
97
99
|
// Check if drawer is present on screen
|
|
98
|
-
cy.get("[data-fs-bp-add-
|
|
100
|
+
cy.get("[data-fs-bp-add-product-assortment-drawer]").should("not.exist");
|
|
99
101
|
|
|
100
102
|
// Click on add button to open drawer
|
|
101
|
-
cy.get("@
|
|
102
|
-
.find("[aria-label='Add
|
|
103
|
+
cy.get("@productAssortmentLayout")
|
|
104
|
+
.find("[aria-label='Add product assortment']")
|
|
103
105
|
.should("be.visible")
|
|
104
106
|
.click();
|
|
105
107
|
|
|
106
108
|
// Check if drawer was opened
|
|
107
|
-
cy.get("[data-fs-bp-add-
|
|
109
|
+
cy.get("[data-fs-bp-add-product-assortment-drawer]")
|
|
108
110
|
.as("addDrawer")
|
|
109
111
|
.should("be.visible");
|
|
110
112
|
cy.get("@addDrawer")
|
|
111
113
|
.find("[data-fs-bp-basic-drawer-heading]")
|
|
112
|
-
.contains("Add
|
|
114
|
+
.contains("Add product assortment")
|
|
113
115
|
.should("be.visible");
|
|
114
116
|
|
|
115
|
-
// Check if
|
|
117
|
+
// Check if product assortment was listed correclty and submit button is disable
|
|
116
118
|
cy.get("@addDrawer")
|
|
117
119
|
.find("[data-fs-bp-basic-drawer-button-variant='confirm']")
|
|
118
120
|
.as("submitButton")
|
|
119
121
|
.should("be.disabled");
|
|
120
122
|
cy.get("@addDrawer")
|
|
121
|
-
.find("[data-fs-bp-add-
|
|
123
|
+
.find("[data-fs-bp-add-product-assortment-drawer-table] tbody tr")
|
|
122
124
|
.as("results");
|
|
123
125
|
|
|
124
126
|
// Check if empty state is visibile when a search returns no results
|
|
@@ -127,20 +129,20 @@ describe(
|
|
|
127
129
|
.as("input")
|
|
128
130
|
.type("foo bar");
|
|
129
131
|
cy.get("@addDrawer")
|
|
130
|
-
.find("[data-fs-bp-add-
|
|
132
|
+
.find("[data-fs-bp-add-product-assortment-drawer-empty-state]")
|
|
131
133
|
.as("emptyState")
|
|
132
134
|
.should("be.visible");
|
|
133
135
|
cy.get("@results").should("not.exist");
|
|
134
136
|
|
|
135
137
|
// Check if results is updated when search results is not empty
|
|
136
|
-
cy.get("@input").clear().type(
|
|
138
|
+
cy.get("@input").clear().type(PRODUCT_ASSORTMENT_UNDER_TEST);
|
|
137
139
|
cy.get("@emptyState").should("not.exist");
|
|
138
140
|
cy.get("@results").should("have.length", 1);
|
|
139
141
|
|
|
140
|
-
// Select first
|
|
142
|
+
// Select first Product Assortment
|
|
141
143
|
cy.get("@addDrawer")
|
|
142
144
|
.find(
|
|
143
|
-
"[data-fs-bp-add-
|
|
145
|
+
"[data-fs-bp-add-product-assortment-drawer-table] tbody td [data-fs-checkbox]"
|
|
144
146
|
)
|
|
145
147
|
.first()
|
|
146
148
|
.check();
|
|
@@ -151,38 +153,40 @@ describe(
|
|
|
151
153
|
// Wait for page refresh
|
|
152
154
|
cy.wait(TEST_CONFIG.TIMEOUTS.RETRY_DELAY);
|
|
153
155
|
|
|
154
|
-
cy.get("[data-fs-bp-
|
|
156
|
+
cy.get("[data-fs-bp-product-assortment-table]", {
|
|
155
157
|
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
156
158
|
}).within(() => {
|
|
157
|
-
cy.contains(
|
|
159
|
+
cy.contains(PRODUCT_ASSORTMENT_UNDER_TEST);
|
|
158
160
|
});
|
|
159
161
|
});
|
|
160
162
|
|
|
161
|
-
it("Should remove
|
|
162
|
-
|
|
163
|
+
it("Should remove Product Assortment correctly", () => {
|
|
164
|
+
visitProductAssortmentPage();
|
|
163
165
|
|
|
164
166
|
// Check if delete drawer is not visible
|
|
165
|
-
cy.get("[data-fs-bp-remove-
|
|
167
|
+
cy.get("[data-fs-bp-remove-product-assortment-drawer]").should(
|
|
168
|
+
"not.exist"
|
|
169
|
+
);
|
|
166
170
|
|
|
167
|
-
// Count current
|
|
168
|
-
cy.get("[data-fs-bp-
|
|
171
|
+
// Count current product assortment list before remove one
|
|
172
|
+
cy.get("[data-fs-bp-product-assortment-table]", {
|
|
169
173
|
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
170
174
|
}).should("exist");
|
|
171
175
|
|
|
172
|
-
// Find remove
|
|
176
|
+
// Find remove product assortment icon button and click it
|
|
173
177
|
cy.get("[data-fs-bp-table] [data-fs-bp-table-row]")
|
|
174
|
-
.contains(
|
|
178
|
+
.contains(PRODUCT_ASSORTMENT_UNDER_TEST)
|
|
175
179
|
.closest("[data-fs-bp-table-row]")
|
|
176
|
-
.find("[aria-label='Remove
|
|
180
|
+
.find("[aria-label='Remove product assortment']")
|
|
177
181
|
.click();
|
|
178
182
|
|
|
179
183
|
// Check if delete drawer was opened
|
|
180
|
-
cy.get("[data-fs-bp-remove-
|
|
184
|
+
cy.get("[data-fs-bp-remove-product-assortment-drawer]")
|
|
181
185
|
.as("deleteDrawer")
|
|
182
186
|
.should("be.visible");
|
|
183
187
|
cy.get("@deleteDrawer")
|
|
184
188
|
.find("[data-fs-bp-basic-drawer-heading]")
|
|
185
|
-
.contains("Remove
|
|
189
|
+
.contains("Remove product assortment from unit")
|
|
186
190
|
.should("be.visible");
|
|
187
191
|
|
|
188
192
|
// Find remove confirmation button and click it
|
|
@@ -194,13 +198,13 @@ describe(
|
|
|
194
198
|
// Wait for page refresh
|
|
195
199
|
cy.wait(TEST_CONFIG.TIMEOUTS.RETRY_DELAY);
|
|
196
200
|
|
|
197
|
-
// Check if the list was updated without removed
|
|
201
|
+
// Check if the list was updated without removed product assortment
|
|
198
202
|
cy.get("@deleteDrawer").should("not.exist");
|
|
199
|
-
cy.get("[data-fs-bp-
|
|
203
|
+
cy.get("[data-fs-bp-product-assortment-table]", {
|
|
200
204
|
timeout: TEST_CONFIG.TIMEOUTS.PAGE_LOAD,
|
|
201
205
|
})
|
|
202
206
|
.should("exist")
|
|
203
|
-
.contains(
|
|
207
|
+
.contains(PRODUCT_ASSORTMENT_UNDER_TEST)
|
|
204
208
|
.should("not.exist");
|
|
205
209
|
});
|
|
206
210
|
}
|
|
@@ -29,7 +29,7 @@ describe("Profile", () => {
|
|
|
29
29
|
cy.contains("Addresses").should("be.visible");
|
|
30
30
|
cy.contains("Payment methods").should("be.visible");
|
|
31
31
|
cy.contains("Credit cards").should("be.visible");
|
|
32
|
-
cy.contains("
|
|
32
|
+
cy.contains("Product assortment").should("be.visible");
|
|
33
33
|
cy.contains("PO numbers").should("be.visible");
|
|
34
34
|
cy.contains("Cost centers").should("be.visible");
|
|
35
35
|
cy.contains("Releases").should("be.visible");
|
|
@@ -62,6 +62,13 @@ const fillUserForm = (
|
|
|
62
62
|
.clear()
|
|
63
63
|
.type(userData.EMAIL);
|
|
64
64
|
|
|
65
|
+
cy.get("label")
|
|
66
|
+
.contains("Phone number")
|
|
67
|
+
.parent()
|
|
68
|
+
.find("[data-fs-bp-input-text-input]")
|
|
69
|
+
.clear()
|
|
70
|
+
.type(userData.PHONE);
|
|
71
|
+
|
|
65
72
|
cy.wait(500);
|
|
66
73
|
// Fill the user role
|
|
67
74
|
cy.get('[data-fs-bp-create-user-roles="true"]')
|
|
@@ -189,6 +196,7 @@ describe("Users", { retries: 2 }, () => {
|
|
|
189
196
|
// Verify labels and buttons are present
|
|
190
197
|
cy.contains("Name").should("be.visible");
|
|
191
198
|
cy.contains("Email").should("be.visible");
|
|
199
|
+
cy.contains("Phone number").should("be.visible");
|
|
192
200
|
cy.contains("Role").should("be.visible");
|
|
193
201
|
cy.contains("Organizational Unit").should("be.visible");
|
|
194
202
|
cy.contains("Edit").should("be.visible");
|
|
@@ -261,6 +269,7 @@ describe("Users", { retries: 2 }, () => {
|
|
|
261
269
|
const updatedUserData = {
|
|
262
270
|
NAME: `${USER_NAME} Updated`,
|
|
263
271
|
EMAIL: USER_EMAIL,
|
|
272
|
+
PHONE: "(888) 888-8888",
|
|
264
273
|
ROLE: TEST_DATA.USERS.NEW_USER.ROLE,
|
|
265
274
|
};
|
|
266
275
|
|
package/package.json
CHANGED
package/plugin.config.js
CHANGED
|
@@ -36,8 +36,8 @@ module.exports = {
|
|
|
36
36
|
path: "/pvt/organization-account/credit-cards/[orgUnitId]/[contractId]",
|
|
37
37
|
appLayout: false,
|
|
38
38
|
},
|
|
39
|
-
|
|
40
|
-
path: "/pvt/organization-account/
|
|
39
|
+
productAssortment: {
|
|
40
|
+
path: "/pvt/organization-account/product-assortment/[orgUnitId]/[contractId]",
|
|
41
41
|
appLayout: false,
|
|
42
42
|
},
|
|
43
43
|
"po-numbers": {
|
|
@@ -22,7 +22,7 @@ export const BudgetRemainingBalance = ({
|
|
|
22
22
|
<span data-fs-bp-budget-remaining-balance-label-used>
|
|
23
23
|
{formatCurrency(Math.abs(used))}{" "}
|
|
24
24
|
<span data-fs-bp-budget-remaining-balance-label-used-total>
|
|
25
|
-
of {formatCurrency(
|
|
25
|
+
of {formatCurrency(total)} used
|
|
26
26
|
</span>
|
|
27
27
|
</span>
|
|
28
28
|
<BudgetProgressBar
|
|
@@ -2,9 +2,10 @@ import { Client } from "../../shared/clients/Client";
|
|
|
2
2
|
import { getApiUrl } from "../../shared/utils";
|
|
3
3
|
|
|
4
4
|
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
AddProductAssortmentPayload,
|
|
6
|
+
AddProductAssortmentResponse,
|
|
7
|
+
GetProductAssortmentFromContractResponse,
|
|
8
|
+
GetProductAssortmentFromScopeResponse,
|
|
8
9
|
} from "../types";
|
|
9
10
|
|
|
10
11
|
type DefaultArgs = {
|
|
@@ -13,18 +14,15 @@ type DefaultArgs = {
|
|
|
13
14
|
unitId: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
export
|
|
17
|
-
export type AddCollectionsPayload = Array<{ name: string }>;
|
|
18
|
-
|
|
19
|
-
export class CollectionsClient extends Client {
|
|
17
|
+
export class ProductAssortmentClient extends Client {
|
|
20
18
|
constructor() {
|
|
21
19
|
super(getApiUrl());
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
getProductAssortmentFromContract(args: DefaultArgs & { name?: string }) {
|
|
25
23
|
const { contractId, cookie, name, unitId } = args;
|
|
26
24
|
|
|
27
|
-
return this.get<
|
|
25
|
+
return this.get<GetProductAssortmentFromContractResponse["collections"]>(
|
|
28
26
|
`customers/${contractId}/units/${unitId}/collections`,
|
|
29
27
|
{
|
|
30
28
|
headers: { Cookie: cookie },
|
|
@@ -33,7 +31,7 @@ export class CollectionsClient extends Client {
|
|
|
33
31
|
);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
getProductAssortmentListInScope(
|
|
37
35
|
args: DefaultArgs & {
|
|
38
36
|
unitId: string;
|
|
39
37
|
name?: string;
|
|
@@ -43,7 +41,7 @@ export class CollectionsClient extends Client {
|
|
|
43
41
|
) {
|
|
44
42
|
const { contractId, cookie, name, unitId, filterByScope } = args;
|
|
45
43
|
|
|
46
|
-
return this.get<
|
|
44
|
+
return this.get<GetProductAssortmentFromScopeResponse["collections"]>(
|
|
47
45
|
`customers/${contractId}/units/${unitId}/collections`,
|
|
48
46
|
{
|
|
49
47
|
headers: { Cookie: cookie },
|
|
@@ -56,12 +54,12 @@ export class CollectionsClient extends Client {
|
|
|
56
54
|
);
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
args: DefaultArgs & { unitId: string; data:
|
|
57
|
+
addProductAssortmentToScope(
|
|
58
|
+
args: DefaultArgs & { unitId: string; data: AddProductAssortmentPayload }
|
|
61
59
|
) {
|
|
62
60
|
const { contractId, cookie, unitId, data } = args;
|
|
63
61
|
|
|
64
|
-
return this.post<
|
|
62
|
+
return this.post<AddProductAssortmentResponse, AddProductAssortmentPayload>(
|
|
65
63
|
`/customers/${contractId}/units/${unitId}/collections`,
|
|
66
64
|
data,
|
|
67
65
|
{
|
|
@@ -70,13 +68,13 @@ export class CollectionsClient extends Client {
|
|
|
70
68
|
);
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
args: DefaultArgs & { unitId: string;
|
|
71
|
+
removeProductAssortmentFromScope(
|
|
72
|
+
args: DefaultArgs & { unitId: string; productAssortmentId: string }
|
|
75
73
|
) {
|
|
76
|
-
const { contractId, unitId, cookie,
|
|
74
|
+
const { contractId, unitId, cookie, productAssortmentId } = args;
|
|
77
75
|
|
|
78
76
|
return this.delete(
|
|
79
|
-
`/customers/${contractId}/units/${unitId}/collections/${
|
|
77
|
+
`/customers/${contractId}/units/${unitId}/collections/${productAssortmentId}`,
|
|
80
78
|
undefined,
|
|
81
79
|
{
|
|
82
80
|
headers: { Cookie: cookie },
|
|
@@ -85,5 +83,5 @@ export class CollectionsClient extends Client {
|
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
|
|
88
|
-
const
|
|
89
|
-
export {
|
|
86
|
+
const productAssortmentClient = new ProductAssortmentClient();
|
|
87
|
+
export { productAssortmentClient };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/router";
|
|
4
|
+
|
|
5
|
+
import { Link, useUI } from "@faststore/ui";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
BasicDrawer,
|
|
9
|
+
Icon,
|
|
10
|
+
InternalSearch,
|
|
11
|
+
Paginator,
|
|
12
|
+
} from "../../../shared/components";
|
|
13
|
+
import { useBuyerPortal } from "../../../shared/hooks";
|
|
14
|
+
import { useAddProductAssortmentToScope } from "../../hooks/useAddProductAssortmentToScope";
|
|
15
|
+
import { AddProductAssortmentDrawerTable } from "../table/AddProductAssortmentDrawerTable";
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
AddProductAssortmentDrawerProps,
|
|
19
|
+
ProductAssortmentSummary,
|
|
20
|
+
} from "../../types";
|
|
21
|
+
|
|
22
|
+
export const PAGE_SIZE = 10;
|
|
23
|
+
|
|
24
|
+
export const AddProductAssortmentDrawer = ({
|
|
25
|
+
close,
|
|
26
|
+
productAssortment,
|
|
27
|
+
...props
|
|
28
|
+
}: AddProductAssortmentDrawerProps) => {
|
|
29
|
+
const { pushToast } = useUI();
|
|
30
|
+
const [drawerSearch, setDrawerSearch] = useState("");
|
|
31
|
+
const { currentOrgUnit, currentContract } = useBuyerPortal();
|
|
32
|
+
const { reload } = useRouter();
|
|
33
|
+
|
|
34
|
+
const unitId = currentOrgUnit?.id;
|
|
35
|
+
const contractId = currentContract?.id;
|
|
36
|
+
const isLoading = false;
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setDrawerSearch("");
|
|
40
|
+
}, [props.isOpen]);
|
|
41
|
+
|
|
42
|
+
const drawerProductAssortment = useMemo(() => {
|
|
43
|
+
return productAssortment.filter((p) =>
|
|
44
|
+
p.name.toLowerCase().includes(drawerSearch.toLowerCase())
|
|
45
|
+
);
|
|
46
|
+
}, [productAssortment, drawerSearch]);
|
|
47
|
+
|
|
48
|
+
const addProductAssortmentMutation = useAddProductAssortmentToScope();
|
|
49
|
+
|
|
50
|
+
const [selectedAssortment, setSelectedAssortment] = useState<
|
|
51
|
+
ProductAssortmentSummary[]
|
|
52
|
+
>([]);
|
|
53
|
+
|
|
54
|
+
const handleSuccess = async () => {
|
|
55
|
+
await addProductAssortmentMutation.mutate({
|
|
56
|
+
unitId: unitId ?? "",
|
|
57
|
+
contractId: contractId ?? "",
|
|
58
|
+
data: selectedAssortment.map((s) => ({ name: s.name })),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
pushToast({
|
|
62
|
+
message: "Product assortment added successfully",
|
|
63
|
+
status: "INFO",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
close();
|
|
67
|
+
reload();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<BasicDrawer
|
|
72
|
+
data-fs-bp-add-product-assortment-drawer
|
|
73
|
+
id="basicDrawer"
|
|
74
|
+
close={close}
|
|
75
|
+
{...props}
|
|
76
|
+
>
|
|
77
|
+
<BasicDrawer.Heading title="Add product assortment" onClose={close} />
|
|
78
|
+
|
|
79
|
+
<BasicDrawer.Body>
|
|
80
|
+
<span data-fs-bp-add-product-assortment-text-drawer>
|
|
81
|
+
Add product assortment to <Link href="#">{currentOrgUnit?.name}</Link>
|
|
82
|
+
</span>
|
|
83
|
+
|
|
84
|
+
<div data-fs-bp-add-product-assortment-wrapper>
|
|
85
|
+
<InternalSearch
|
|
86
|
+
textSearch={(searchTerm) => {
|
|
87
|
+
setDrawerSearch(searchTerm);
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<Paginator.Counter
|
|
92
|
+
total={drawerProductAssortment.length}
|
|
93
|
+
itemsLength={drawerProductAssortment.length}
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
<section>
|
|
97
|
+
{drawerProductAssortment.length ? (
|
|
98
|
+
<div>
|
|
99
|
+
<AddProductAssortmentDrawerTable
|
|
100
|
+
data={drawerProductAssortment}
|
|
101
|
+
onChange={setSelectedAssortment}
|
|
102
|
+
/>
|
|
103
|
+
{drawerProductAssortment.length > 0 && (
|
|
104
|
+
<div data-fs-bp-drawer-product-assortment-paginator>
|
|
105
|
+
{drawerProductAssortment.length > 0 ? (
|
|
106
|
+
<Paginator.NextPageButton>
|
|
107
|
+
{isLoading ? "Loading" : "Load More"}
|
|
108
|
+
</Paginator.NextPageButton>
|
|
109
|
+
) : (
|
|
110
|
+
<span />
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
<Paginator.Counter
|
|
114
|
+
total={drawerProductAssortment.length}
|
|
115
|
+
itemsLength={drawerProductAssortment.length}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
) : (
|
|
121
|
+
<div data-fs-bp-add-product-assortment-drawer-empty-state>
|
|
122
|
+
<Icon name="Shapes" />
|
|
123
|
+
<p>No product assortment found</p>
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
</section>
|
|
127
|
+
</BasicDrawer.Body>
|
|
128
|
+
<BasicDrawer.Footer data-fs-bp-add-product-assortment-drawer-footer>
|
|
129
|
+
<BasicDrawer.Button variant="ghost" onClick={close}>
|
|
130
|
+
Cancel
|
|
131
|
+
</BasicDrawer.Button>
|
|
132
|
+
<BasicDrawer.Button
|
|
133
|
+
variant="confirm"
|
|
134
|
+
disabled={selectedAssortment.length === 0}
|
|
135
|
+
onClick={handleSuccess}
|
|
136
|
+
isLoading={addProductAssortmentMutation.isLoading}
|
|
137
|
+
>
|
|
138
|
+
Add
|
|
139
|
+
{selectedAssortment.length > 0 && `(${selectedAssortment.length})`}
|
|
140
|
+
</BasicDrawer.Button>
|
|
141
|
+
</BasicDrawer.Footer>
|
|
142
|
+
</BasicDrawer>
|
|
143
|
+
);
|
|
144
|
+
};
|