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

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.
@@ -44,4 +44,14 @@ export const TEST_DATA = {
44
44
  ACTION_TYPE: "Bypass all buying policies",
45
45
  },
46
46
  },
47
+ ADDRESS: {
48
+ EXISTING_ADDRESS: "Existing Test Address",
49
+ NEW_ADDRESS_NAME: "VTEX RJ",
50
+ NEW_ADDRESS_STREET: "Praia de Botafogo, 300",
51
+ EDIT_ADDRESS_STREET: "Praia de Botafogo, 400",
52
+ NEW_ADDRESS_COMPLEMENT: "Segundo Andar",
53
+ NEW_ADDRESS_CITY: "Rio de Janeiro",
54
+ NEW_ADDRESS_STATE: "RJ",
55
+ NEW_ADDRESS_POSTAL_CODE: "22250-905",
56
+ },
47
57
  };
@@ -0,0 +1,275 @@
1
+ import { TEST_CONFIG, TEST_DATA } from "../constants";
2
+ import { clickConfirmButton } from "../shared";
3
+
4
+ function navigateToAddressByName(addressName: string) {
5
+ cy.get("[data-fs-addresses-table]").within(() => {
6
+ cy.contains(addressName).should("be.visible").parent().parent().click();
7
+ });
8
+
9
+ cy.wait(8000);
10
+ }
11
+
12
+ function goToAddressPage() {
13
+ // Navigate to Addresses page
14
+ cy.contains("Addresses").click();
15
+
16
+ // Address Page is loading slowly, custom wait untill we get the request optimized
17
+ cy.wait(10000);
18
+
19
+ // Check to see if the address section loaded
20
+ cy.get("[data-fs-addresses-section]", { timeout: 100000 }).should("exist");
21
+
22
+ // Check to see if contract details loaded correctly
23
+ cy.get("[data-fs-bp-header-inside]").should("exist");
24
+ cy.contains(TEST_DATA.PROFILE.TEST_CONTRACT_NAME).should("be.visible");
25
+ }
26
+
27
+ function openCreateAddressDrawer() {
28
+ cy.get("[data-fs-bp-header-inside]").within(() => {
29
+ cy.get("button").eq(1).click(); // Dropdown triggers
30
+ });
31
+
32
+ cy.get("[data-fs-bp-create-address-drawer]").should("be.visible");
33
+ }
34
+
35
+ function openActionsDropdown(addressName: string) {
36
+ cy.get("[data-fs-addresses-table]")
37
+ .contains(addressName)
38
+ .parent()
39
+ .parent()
40
+ .find("[data-fs-bp-basic-dropdown-menu-trigger]")
41
+ .click();
42
+ }
43
+
44
+ describe("Address Page", () => {
45
+ beforeEach(() => {
46
+ cy.login();
47
+ });
48
+ it("Should load current addresses, create a new one and be able to see it's details", () => {
49
+ // Visit the homepage
50
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
51
+
52
+ goToAddressPage();
53
+
54
+ // Check Existing Address
55
+ cy.get("[data-fs-addresses-table]").within(() => {
56
+ cy.contains(TEST_DATA.ADDRESS.EXISTING_ADDRESS).should("exist");
57
+ });
58
+
59
+ openCreateAddressDrawer();
60
+
61
+ // Fill The Address Form
62
+ // Open Country Selector
63
+ cy.get("[data-fs-bp-autocomplete-dropdown]")
64
+ .eq(0)
65
+ .click()
66
+ .within(() => {
67
+ cy.get("[data-fs-bp-autocomplete-dropdown-option]").eq(0).click();
68
+ });
69
+
70
+ // Address Name
71
+ cy.get("[data-fs-bp-autocomplete-dropdown]")
72
+ .eq(1)
73
+ .type(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
74
+
75
+ // Street
76
+ cy.get("[class=street-address]").type(TEST_DATA.ADDRESS.NEW_ADDRESS_STREET);
77
+
78
+ // Complement
79
+ cy.get("[class=street-address2]").type(
80
+ TEST_DATA.ADDRESS.NEW_ADDRESS_COMPLEMENT
81
+ );
82
+
83
+ // City
84
+ cy.get("[class=address-city]").type(TEST_DATA.ADDRESS.NEW_ADDRESS_CITY);
85
+
86
+ // Rio de Janeiro as State
87
+ cy.get("[data-fs-bp-autocomplete-dropdown]")
88
+ .eq(2)
89
+ .click()
90
+ .within(() => {
91
+ cy.get("[data-fs-bp-autocomplete-dropdown-option]").eq(18).click();
92
+ });
93
+
94
+ // Postal Code
95
+ cy.get("[class=address-postal-code]")
96
+ .click()
97
+ .type(TEST_DATA.ADDRESS.NEW_ADDRESS_POSTAL_CODE);
98
+
99
+ // Mark as Shipping Address
100
+ cy.get("[data-fs-bp-autocomplete-dropdown]")
101
+ .eq(3)
102
+ .click()
103
+ .within(() => {
104
+ cy.get("[data-fs-bp-autocomplete-dropdown-option]").eq(0).click();
105
+ });
106
+
107
+ clickConfirmButton();
108
+
109
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
110
+
111
+ //Sometimes masterdata has cache, the reload helps with that
112
+ cy.reload();
113
+
114
+ // Check to see if address was created
115
+ cy.get("[data-fs-addresses-table]")
116
+ .contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME)
117
+ .should("be.visible");
118
+ });
119
+ it("Should be able to edit street in specific Address via address details", () => {
120
+ // Visit the homepage
121
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
122
+
123
+ // Navigate to Addresses page
124
+ goToAddressPage();
125
+
126
+ // Navigate to Address Details
127
+ navigateToAddressByName(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
128
+
129
+ // // Check if sections are rendered correctly
130
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("be.visible");
131
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_STREET).should("be.visible");
132
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_COMPLEMENT).should("be.visible");
133
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_POSTAL_CODE).should("be.visible");
134
+
135
+ // Open Edit Drawer
136
+ cy.get("[data-fs-address-details-button]").click();
137
+
138
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
139
+
140
+ // Edit street
141
+ cy.get("[class=street-address]")
142
+ .clear()
143
+ .type(TEST_DATA.ADDRESS.EDIT_ADDRESS_STREET);
144
+
145
+ clickConfirmButton();
146
+
147
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
148
+ cy.reload();
149
+
150
+ // Check to see if information is edited
151
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("be.visible");
152
+ cy.contains(TEST_DATA.ADDRESS.EDIT_ADDRESS_STREET).should("be.visible");
153
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_COMPLEMENT).should("be.visible");
154
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_POSTAL_CODE).should("be.visible");
155
+ });
156
+ it("Should be able to edit the address from the address list page", () => {
157
+ // Visit the homepage
158
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
159
+
160
+ // Navigate to Addresses page
161
+ goToAddressPage();
162
+
163
+ openActionsDropdown(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
164
+
165
+ cy.contains("Edit details").click();
166
+
167
+ // Edit street
168
+ cy.get("[class=street-address]")
169
+ .clear()
170
+ .type(TEST_DATA.ADDRESS.NEW_ADDRESS_STREET);
171
+
172
+ clickConfirmButton();
173
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
174
+ });
175
+
176
+ it("Should be able to set the address as default", () => {
177
+ // Visit the homepage
178
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
179
+
180
+ // Navigate to Addresses page
181
+ goToAddressPage();
182
+
183
+ openActionsDropdown(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
184
+
185
+ cy.contains("Set as default").click();
186
+
187
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
188
+
189
+ // Check to see if is set as default
190
+ cy.get("[data-fs-addresses-table]")
191
+ .contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME)
192
+ .parent()
193
+ .parent()
194
+ .get("[data-fs-bp-table-row-default-icon]")
195
+ .should("be.visible");
196
+ });
197
+ it("Should be able to Remove the address from the unit", () => {
198
+ // Visit the homepage
199
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
200
+
201
+ // Navigate to Addresses page
202
+ goToAddressPage();
203
+
204
+ openActionsDropdown(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
205
+
206
+ // Inside the Action dropdown, remove from unit
207
+ cy.contains("Remove from Unit").click();
208
+
209
+ clickConfirmButton();
210
+
211
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
212
+ cy.reload();
213
+
214
+ // Check to see if the address has been removed
215
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("not.exist");
216
+ });
217
+
218
+ it("Should be able to Add existing Address", () => {
219
+ // Visit the homepage
220
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
221
+
222
+ // Navigate to Addresses page
223
+ goToAddressPage();
224
+
225
+ // Check to see if address is really absent
226
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("not.exist");
227
+
228
+ openCreateAddressDrawer();
229
+
230
+ // Address Name with existing address
231
+ cy.get('[data-fs-bp-input-text="true"]')
232
+ .eq(1)
233
+ .should("be.visible")
234
+ .type(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME, { delay: 500 });
235
+
236
+ // Select existing address
237
+ cy.get('[data-fs-bp-autocomplete-dropdown-menu="true"]')
238
+ .contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME)
239
+ .should("exist")
240
+ .click();
241
+
242
+ clickConfirmButton();
243
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
244
+
245
+ cy.reload();
246
+
247
+ // Check to see if address has been added
248
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("be.visible");
249
+ });
250
+
251
+ it("Should be able to delete the address", () => {
252
+ // Visit the homepage
253
+ cy.visit(TEST_CONFIG.ROUTES.BUYER_PORTAL);
254
+
255
+ // Navigate to Addresses page
256
+ goToAddressPage();
257
+
258
+ openActionsDropdown(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME);
259
+
260
+ cy.contains("Delete").click();
261
+
262
+ // Fill check to allow deletion
263
+ cy.get("[class=address-name-confirmation]").type(
264
+ TEST_DATA.ADDRESS.NEW_ADDRESS_NAME
265
+ );
266
+
267
+ cy.get('[data-fs-bp-basic-drawer-button-variant="danger"]').click();
268
+
269
+ cy.wait(TEST_CONFIG.TIMEOUTS.PAGE_LOAD);
270
+ cy.reload();
271
+
272
+ // Check if address has been deleted
273
+ cy.contains(TEST_DATA.ADDRESS.NEW_ADDRESS_NAME).should("not.exist");
274
+ });
275
+ });
@@ -0,0 +1,3 @@
1
+ export function clickConfirmButton() {
2
+ cy.get('[data-fs-bp-basic-drawer-button-variant="confirm"]').click();
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.1.39",
3
+ "version": "1.1.40",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,7 +10,7 @@ import {
10
10
  DeleteAddressDrawer,
11
11
  } from "..";
12
12
  import { BasicDropdownMenu, Icon } from "../../../shared/components";
13
- import { useDrawerProps, useBuyerPortal } from "../../../shared/hooks";
13
+ import { useDrawerProps } from "../../../shared/hooks";
14
14
  import { ADDRESS_MESSAGES } from "../../constants/messages";
15
15
  import { useSetDefaultAddress } from "../../hooks/useSetDefaultAddress";
16
16
  import { useUnsetDefaultAddress } from "../../hooks/useUnsetDefaultAddress";
@@ -28,7 +28,6 @@ export const AddressDropdownMenu = ({
28
28
  currentAddress,
29
29
  onUpdate,
30
30
  }: AddressDropdownMenuProps) => {
31
- const { currentOrgUnit } = useBuyerPortal();
32
31
  const router = useRouter();
33
32
  const { pushToast } = useUI();
34
33
 
@@ -107,9 +106,8 @@ export const AddressDropdownMenu = ({
107
106
  });
108
107
  };
109
108
 
110
- const idsPath = currentOrgUnit?.path?.ids?.split("/") ?? [];
111
-
112
- const isRootLevelOrgUnit = idsPath.length === 2;
109
+ // const idsPath = currentOrgUnit?.path?.ids?.split("/") ?? [];
110
+ // const isRootLevelOrgUnit = idsPath.length === 2;
113
111
 
114
112
  const {
115
113
  open: openEditDrawerProps,
@@ -175,15 +173,16 @@ export const AddressDropdownMenu = ({
175
173
  <UIIcon name="MinusCircle" {...sizeProps} />
176
174
  Remove from Unit
177
175
  </DropdownItem>
178
- {isRootLevelOrgUnit && (
179
- <DropdownItem
180
- onClick={openDeleteAddressDrawer}
181
- data-fs-bp-dropdown-menu-item-mode="danger"
182
- >
183
- <Icon name="Delete" {...sizeProps} data-fs-bp-delete-address />
184
- <span data-fs-bp-delete-address>Delete</span>
185
- </DropdownItem>
186
- )}
176
+ {/* Remove validation while we reevaluate the rule */}
177
+ {/* {isRootLevelOrgUnit && ( */}
178
+ <DropdownItem
179
+ onClick={openDeleteAddressDrawer}
180
+ data-fs-bp-dropdown-menu-item-mode="danger"
181
+ >
182
+ <Icon name="Delete" {...sizeProps} data-fs-bp-delete-address />
183
+ <span data-fs-bp-delete-address>Delete</span>
184
+ </DropdownItem>
185
+ {/* )} */}
187
186
  </BasicDropdownMenu>
188
187
  {isEditDrawerOpen && (
189
188
  <EditAddressDrawer
@@ -11,7 +11,7 @@ import { useBuyerPortal } from "../../../shared/hooks";
11
11
  import { maskPostalCode } from "../../../shared/utils/postalCode";
12
12
  import { CountryOptions } from "../../data/countries";
13
13
  import { states as StateOptions } from "../../data/states";
14
- import { useDebouncedSearchAddressByUnitId } from "../../hooks/useDebouncedSearchAddressByUnitId";
14
+ import { useDebouncedSearchAddress } from "../../hooks/useDebouncedSearchAddress";
15
15
  import { AddressData, AddressInput } from "../../types";
16
16
 
17
17
  export type AddressFormProps = {
@@ -45,10 +45,10 @@ export const AddressForm = ({
45
45
 
46
46
  const [autoCompleteAddressName, setAutoCompleteAddressName] = useState("");
47
47
 
48
- const { searchedAddresses } = useDebouncedSearchAddressByUnitId({
49
- orgUnitId: currentOrgUnit?.id ?? "",
50
- search: autoCompleteAddressName,
51
- });
48
+ const { searchedAddresses } = useDebouncedSearchAddress(
49
+ autoCompleteAddressName,
50
+ currentOrgUnit?.id ?? ""
51
+ );
52
52
 
53
53
  const cleanCompletedAddress = () => {
54
54
  if (setCompletedAddress && setUseExistingAddress) {
@@ -75,6 +75,7 @@ export const AddressForm = ({
75
75
  <AutocompleteDropdown
76
76
  data-fs-bp-create-address-country-selector
77
77
  label="Country"
78
+ className="address-country"
78
79
  value={address.country}
79
80
  options={CountryOptions}
80
81
  onConfirmKeyPress={(option) =>
@@ -110,6 +111,7 @@ export const AddressForm = ({
110
111
  <InputText
111
112
  label="Address Name"
112
113
  value={address.name}
114
+ className="address-name"
113
115
  wrapperProps={{ style: { marginTop: 16 } }}
114
116
  hasError={isTouched && !address.name?.trim()}
115
117
  onChange={(event) =>
@@ -120,6 +122,7 @@ export const AddressForm = ({
120
122
  <AutocompleteDropdown
121
123
  label="Address Name"
122
124
  value={autoCompleteAddressName}
125
+ className="address-name"
123
126
  options={searchedAddresses}
124
127
  onChange={(event) => {
125
128
  setAutoCompleteAddressName(event.currentTarget.value);
@@ -157,6 +160,7 @@ export const AddressForm = ({
157
160
  <InputText
158
161
  label="Street Address"
159
162
  value={address.streetAddress}
163
+ className="street-address"
160
164
  wrapperProps={{ style: { marginTop: 16 } }}
161
165
  hasError={isTouched && !address.streetAddress?.trim()}
162
166
  onChange={(event) =>
@@ -171,6 +175,7 @@ export const AddressForm = ({
171
175
 
172
176
  <InputText
173
177
  label="Apt, Suite, Building (optional)"
178
+ className="street-address2"
174
179
  value={address.streetAddress2}
175
180
  wrapperProps={{ style: { marginTop: 16, marginBottom: 16 } }}
176
181
  onChange={(event) =>
@@ -180,6 +185,7 @@ export const AddressForm = ({
180
185
 
181
186
  <InputText
182
187
  label="City"
188
+ className="address-city"
183
189
  value={address.city}
184
190
  wrapperProps={{ style: { marginTop: 16 } }}
185
191
  hasError={isTouched && !address.city?.trim()}
@@ -191,6 +197,7 @@ export const AddressForm = ({
191
197
  <AutocompleteDropdown
192
198
  data-fs-bp-create-address-state-selector
193
199
  label="State"
200
+ className="address-state"
194
201
  value={address.state}
195
202
  options={
196
203
  address.countryCode ? StateOptions[address.countryCode] : []
@@ -221,6 +228,7 @@ export const AddressForm = ({
221
228
  <InputText
222
229
  label="Postal Code"
223
230
  value={address.zip}
231
+ className="address-postal-code"
224
232
  wrapperProps={{ style: { marginTop: 16, marginBottom: 16 } }}
225
233
  hasError={isTouched && !address.zip?.trim()}
226
234
  onChange={(event) => handleChangePostalCode(event.target.value)}
@@ -252,6 +260,7 @@ export const AddressForm = ({
252
260
  <AutocompleteDropdown
253
261
  label="Address Type"
254
262
  value={address.types}
263
+ className="address-type"
255
264
  options={addressTypeOptions}
256
265
  onConfirmKeyPress={(option) =>
257
266
  setAddress({ ...address, types: [option] })
@@ -77,6 +77,7 @@ export const DeleteAddressDrawer = ({
77
77
  <br />
78
78
  <InputText
79
79
  label="Address name"
80
+ className="address-name-confirmation"
80
81
  value={addressNameConfirmation}
81
82
  onChange={(event) =>
82
83
  setAddressNameConfirmation(event.currentTarget.value)
@@ -1,3 +1,4 @@
1
+ import { scopesClient } from "../../shared/clients/ScopeClient";
1
2
  import { addressesClient } from "../clients/AddressesClient";
2
3
 
3
4
  import type { AddressInput } from "../types";
@@ -8,14 +9,26 @@ export type CreateNewAddressServiceProps = {
8
9
  unitId: string;
9
10
  } & AddressInput;
10
11
 
12
+ type NewAddress = {
13
+ newAddressId: string;
14
+ };
15
+
11
16
  export const createNewAddressService = async ({
12
17
  cookie,
13
18
  ...data
14
19
  }: CreateNewAddressServiceProps) => {
15
- return addressesClient.createNewAddress(
20
+ const newAddress = (await addressesClient.createNewAddress(
16
21
  data,
17
22
  data.unitId,
18
23
  data.customerId,
19
24
  cookie
25
+ )) as NewAddress;
26
+
27
+ await scopesClient.addToScope(
28
+ data.unitId,
29
+ { scopeName: "addresses", ids: [newAddress.newAddressId] },
30
+ cookie
20
31
  );
32
+
33
+ return newAddress;
21
34
  };
@@ -20,8 +20,8 @@ export const searchAddressByNameService = async (
20
20
  }
21
21
 
22
22
  const { addresses } = await addressesClient.searchAddressesByName(
23
- customerId,
24
23
  unitId,
24
+ customerId,
25
25
  name,
26
26
  cookie
27
27
  );
@@ -3,7 +3,7 @@ export type CollectionsSummary = {
3
3
  name: string;
4
4
  };
5
5
 
6
- export type ContractCollection = CollectionsSummary & { inContract: boolean };
6
+ export type ContractCollection = CollectionsSummary & { isEnabled: boolean };
7
7
  export type ScopeCollection = CollectionsSummary & { isEnabled: boolean };
8
8
 
9
9
  export type GetCollectionsFromContractResponse = {
@@ -73,7 +73,7 @@ export async function loader(
73
73
  }),
74
74
  ]);
75
75
 
76
- const isContractEmpty = contractCollections.every((c) => !c.inContract);
76
+ const isContractEmpty = contractCollections.every((c) => !c.isEnabled);
77
77
  const drawerCollections = allCollections.filter((col) => !col.isEnabled);
78
78
 
79
79
  return {