@vtex/faststore-plugin-buyer-portal 1.3.46 → 1.3.48

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/package.json +1 -1
  3. package/public/buyer-portal-icons.svg +35 -13
  4. package/src/features/org-units/clients/OrgUnitClient.ts +17 -0
  5. package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +2 -2
  6. package/src/features/org-units/components/AuthSetupDrawer/AuthSetupDrawer.tsx +346 -0
  7. package/src/features/org-units/components/AuthSetupDrawer/auth-setup-drawer.scss +138 -0
  8. package/src/features/org-units/components/AuthSetupDrawer/index.ts +1 -0
  9. package/src/features/org-units/components/OrgUnitDetailsDropdownMenu/OrgUnitDetailsDropdownMenu.tsx +80 -0
  10. package/src/features/org-units/components/OrgUnitDetailsDropdownMenu/index.ts +4 -0
  11. package/src/features/org-units/components/OrgUnitsDropdownMenu/OrgUnitsDropdownMenu.tsx +2 -2
  12. package/src/features/org-units/components/index.ts +8 -0
  13. package/src/features/org-units/hooks/index.ts +2 -0
  14. package/src/features/org-units/hooks/useGetOrgUnitSettings.ts +20 -0
  15. package/src/features/org-units/hooks/useOrgUnitByUser.ts +4 -1
  16. package/src/features/org-units/hooks/useUpdateOrgUnitSettings.ts +27 -0
  17. package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +22 -1
  18. package/src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss +1 -0
  19. package/src/features/org-units/services/get-org-unit-settings.service.ts +13 -0
  20. package/src/features/org-units/services/index.ts +8 -0
  21. package/src/features/org-units/services/update-org-unit-settings.service.ts +17 -0
  22. package/src/features/org-units/types/OrgUnitSettings.ts +25 -0
  23. package/src/features/org-units/types/index.ts +2 -0
  24. package/src/features/product-assortment/hooks/useGetProductAssortment.ts +52 -0
  25. package/src/features/product-assortment/hooks/useGetProductAssortmentFromContract.ts +35 -0
  26. package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx +55 -12
  27. package/src/features/product-assortment/layouts/ProductAssortmentLayout/product-assortment-layout.scss +1 -1
  28. package/src/features/product-assortment/types/index.ts +6 -14
  29. package/src/features/shared/components/BuyerPortalProvider/BuyerPortalProvider.tsx +5 -0
  30. package/src/features/shared/components/Toast/Toast.tsx +43 -2
  31. package/src/features/shared/components/Toast/toast.scss +23 -5
  32. package/src/features/shared/components/index.ts +1 -0
  33. package/src/features/shared/hooks/usePageItems.ts +2 -2
  34. package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +1 -0
  35. package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +13 -0
  36. package/src/features/shared/utils/constants.ts +2 -2
  37. package/src/features/shared/utils/withBuyerPortal.tsx +4 -1
  38. package/src/features/users/clients/UsersClient.ts +105 -4
  39. package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +1 -1
  40. package/src/features/users/components/CreateUserDrawerSelector/CreateUserDrawerSelector.tsx +20 -0
  41. package/src/features/users/components/CreateUserDrawerWithUsername/CreateUserDrawerWithUsername.tsx +696 -0
  42. package/src/features/users/components/CreateUserDrawerWithUsername/create-user-drawer-with-username.scss +116 -0
  43. package/src/features/users/components/UserDropdownMenu/user-dropdown-menu.scss +1 -0
  44. package/src/features/users/components/UsersCard/UsersCard.tsx +2 -2
  45. package/src/features/users/components/index.ts +5 -0
  46. package/src/features/users/hooks/index.ts +2 -0
  47. package/src/features/users/hooks/useAddUserToOrgUnit.ts +12 -5
  48. package/src/features/users/hooks/useResetPassword.ts +39 -0
  49. package/src/features/users/hooks/useValidateUsername.ts +38 -0
  50. package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +10 -0
  51. package/src/features/users/layouts/UsersLayout/UsersLayout.tsx +55 -10
  52. package/src/features/users/layouts/UsersLayout/users-layout.scss +19 -0
  53. package/src/features/users/services/add-user-to-org-unit.service.ts +8 -6
  54. package/src/features/users/services/get-users-by-org-unit-id.service.ts +1 -0
  55. package/src/features/users/services/index.ts +10 -0
  56. package/src/features/users/services/reset-password.service.ts +24 -0
  57. package/src/features/users/services/validate-username.service.ts +25 -0
  58. package/src/features/users/types/UserData.ts +1 -0
  59. package/src/features/users/types/UserDataService.ts +1 -0
  60. package/src/pages/org-unit-details.tsx +20 -2
  61. package/src/pages/productAssortment.tsx +61 -65
@@ -4,6 +4,42 @@ import { useUI } from "@faststore/ui";
4
4
 
5
5
  import { Icon } from "../Icon";
6
6
 
7
+ const LINK_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
8
+
9
+ function parseMessageWithLinks(message: string): (string | JSX.Element)[] {
10
+ const parts: (string | JSX.Element)[] = [];
11
+ let lastIndex = 0;
12
+ let match;
13
+
14
+ while ((match = LINK_REGEX.exec(message)) !== null) {
15
+ if (match.index > lastIndex) {
16
+ parts.push(message.slice(lastIndex, match.index));
17
+ }
18
+
19
+ const [, linkText, url] = match;
20
+
21
+ parts.push(
22
+ <a
23
+ key={match.index}
24
+ href={url}
25
+ target="_blank"
26
+ rel="noopener noreferrer"
27
+ data-fs-bp-toast-link
28
+ >
29
+ {linkText}
30
+ </a>
31
+ );
32
+
33
+ lastIndex = match.index + match[0].length;
34
+ }
35
+
36
+ if (lastIndex < message.length) {
37
+ parts.push(message.slice(lastIndex));
38
+ }
39
+
40
+ return parts;
41
+ }
42
+
7
43
  function Toast() {
8
44
  const { toasts, popToast } = useUI();
9
45
  const toast = toasts[toasts.length - 1];
@@ -39,9 +75,14 @@ function Toast() {
39
75
  >
40
76
  <div data-fs-bp-toast-content>
41
77
  {toast.title && <p data-fs-bp-toast-title>{toast.title}</p>}
42
- <p data-fs-bp-toast-message>{toast.message}</p>
78
+ <p
79
+ data-fs-bp-toast-message
80
+ data-fs-bp-toast-message-has-title={!!toast.title}
81
+ >
82
+ {parseMessageWithLinks(toast.message)}
83
+ </p>
84
+ {!!toast.icon && toast.icon}
43
85
  </div>
44
- {!!toast.icon && toast.icon}
45
86
  <button type="button" data-fs-bp-toast-dismiss onClick={popToast}>
46
87
  <Icon name="Close" width={10} height={10} />
47
88
  </button>
@@ -16,7 +16,7 @@
16
16
  --fs-toast-border-color: transparent;
17
17
 
18
18
  --fs-toast-shadow: 0 0.063rem 0.188rem rgba(0, 0, 0, 0.1);
19
- --fs-toast-bkg-color: #000000;
19
+ --fs-toast-bkg-color: #1f1f1f;
20
20
 
21
21
  --fs-toast-transition-property: var(--fs-transition-property);
22
22
  --fs-toast-transition-timing: var(--fs-transition-timing);
@@ -93,6 +93,7 @@
93
93
  [data-fs-bp-toast-content] {
94
94
  display: block;
95
95
  overflow: hidden;
96
+ padding: var(--fs-spacing-1) var(--fs-spacing-2);
96
97
  }
97
98
 
98
99
  [data-fs-icon] {
@@ -115,27 +116,44 @@
115
116
  }
116
117
 
117
118
  [data-fs-bp-toast-view-button] {
118
- color: #ffffff;
119
+ color: var(--fs-bp-color-neutral-0);
119
120
  font-weight: var(--fs-text-weight-semibold);
120
121
  font-size: var(--fs-text-size-1);
121
122
  line-height: calc(var(--fs-spacing-4) - var(--fs-spacing-0));
122
123
  cursor: pointer;
124
+ padding: 0;
125
+ margin-top: var(--fs-spacing-1);
123
126
  }
124
127
 
125
128
  [data-fs-bp-toast-title] {
126
- margin-left: var(--fs-toast-title-margin-left);
127
129
  overflow: hidden;
128
130
  font-size: var(--fs-toast-title-size);
129
131
  font-weight: var(--fs-toast-title-weight);
130
132
  line-height: var(--fs-toast-title-line-height);
133
+ margin-bottom: var(--fs-spacing-0);
131
134
  }
132
135
 
133
136
  [data-fs-bp-toast-message] {
134
- margin-left: var(--fs-toast-message-margin-left);
135
137
  overflow: hidden;
136
- font-weight: 400;
138
+ font-weight: var(--fs-bp-weight-regular);
137
139
  font-size: var(--fs-text-size-1);
138
140
  line-height: calc(var(--fs-spacing-3) + var(--fs-spacing-0));
141
+ color: var(--fs-bp-color-neutral-0);
142
+
143
+ &[data-fs-bp-toast-message-has-title="true"] {
144
+ color: var(--fs-bp-color-neutral-5);
145
+ }
146
+
147
+ [data-fs-bp-toast-link] {
148
+ color: var(--fs-bp-color-neutral-0);
149
+ text-decoration: none;
150
+ transition: opacity var(--fs-toast-transition-timing)
151
+ var(--fs-toast-transition-function);
152
+
153
+ &:hover {
154
+ opacity: 0.8;
155
+ }
156
+ }
139
157
  }
140
158
 
141
159
  [data-fs-bp-toast-dismiss] {
@@ -23,6 +23,7 @@ export {
23
23
  BuyerPortalProvider,
24
24
  type BuyerPortalContextType,
25
25
  type BuyerPortalProviderProps,
26
+ type FeatureFlags,
26
27
  } from "./BuyerPortalProvider/BuyerPortalProvider";
27
28
  export { Card, CardBody, CardFooter, CardHeader } from "./Card";
28
29
  export {
@@ -37,6 +37,8 @@ export const usePageItems = <T>({
37
37
  const [searchTerm, setSearchTerm] = useState(search ?? "");
38
38
  const [isLoading, setIsLoading] = useState(false);
39
39
 
40
+ const { setQueryStrings, setQueryString } = useQueryParams();
41
+
40
42
  useDebounce(searchTerm, DEBOUNCE_TIMEOUT, {
41
43
  onDebounce: (value) => {
42
44
  setIsLoading(true);
@@ -54,8 +56,6 @@ export const usePageItems = <T>({
54
56
  },
55
57
  });
56
58
 
57
- const { setQueryStrings, setQueryString } = useQueryParams();
58
-
59
59
  useEffect(() => {
60
60
  setItems([]);
61
61
  }, [search]);
@@ -18,6 +18,7 @@ export type ContractTabsLayoutProps = {
18
18
  image?: ReactNode;
19
19
  name: string;
20
20
  role?: string;
21
+ id?: string;
21
22
  };
22
23
  loading?: boolean;
23
24
  children?: ReactNode;
@@ -124,6 +124,19 @@ export const LoadingTabsLayout = ({ children }: LoadingTabsLayoutProps) => {
124
124
  name: "",
125
125
  },
126
126
  },
127
+ settings: {
128
+ userIdentification: {
129
+ userName: false,
130
+ email: false,
131
+ phone: false,
132
+ },
133
+ authenticationMethods: {
134
+ method: "PASSWORD",
135
+ },
136
+ "2FA": {
137
+ verificationCode: false,
138
+ },
139
+ },
127
140
  }}
128
141
  />
129
142
  );
@@ -2,7 +2,7 @@ export const AUT_COOKIE_KEY = "VtexIdclientAutCookie";
2
2
  // PROD URL
3
3
  export const API_URL = (checkoutUrl: string, operation?: string) =>
4
4
  `${checkoutUrl}/_v/store-front/${operation}`;
5
- // DEV URL - CHANGE BEFORE MERGE
5
+ // // DEV URL - CHANGE BEFORE MERGE
6
6
  // export const API_URL = (checkoutUrl?: string, operation?: string) =>
7
7
  // `https://{{workspace}}--b2bfaststoredev.myvtex.com/_v/store-front/${operation}`;
8
8
 
@@ -22,4 +22,4 @@ export const SCOPE_KEYS = {
22
22
  CREDIT_CARDS: "creditCards",
23
23
  } as const;
24
24
 
25
- export const CURRENT_VERSION = "1.3.46";
25
+ export const CURRENT_VERSION = "1.3.48";
@@ -16,7 +16,10 @@ export const withBuyerPortal = <T extends Record<string, unknown>>(
16
16
  const { context, ...componentProps } = props;
17
17
 
18
18
  return (
19
- <BuyerPortalProvider {...context}>
19
+ <BuyerPortalProvider
20
+ featureFlags={{ enableUsernameCreation: true }}
21
+ {...context}
22
+ >
20
23
  <Component {...(componentProps as unknown as T)} />
21
24
  </BuyerPortalProvider>
22
25
  );
@@ -57,8 +57,9 @@ class UsersClient extends Client {
57
57
  props: {
58
58
  orgUnitId: string;
59
59
  role: number[];
60
- email: string;
61
- name: string;
60
+ email?: string;
61
+ name?: string;
62
+ userName: string;
62
63
  },
63
64
  cookie: string
64
65
  ) {
@@ -78,8 +79,9 @@ class UsersClient extends Client {
78
79
  {
79
80
  orgUnitId: string;
80
81
  role: number[];
81
- email: string;
82
- name: string;
82
+ email?: string;
83
+ name?: string;
84
+ userName: string;
83
85
  }
84
86
  >(
85
87
  `units/${orgUnitId}/users`,
@@ -96,6 +98,54 @@ class UsersClient extends Client {
96
98
  );
97
99
  }
98
100
 
101
+ addUserToOrgUnitV2(
102
+ props: {
103
+ orgUnitId: string;
104
+ role: number[];
105
+ email?: string;
106
+ name?: string;
107
+ phone?: string;
108
+ userName: string;
109
+ },
110
+ cookie: string
111
+ ) {
112
+ const { orgUnitId, ...data } = props;
113
+
114
+ return this.post<
115
+ {
116
+ message:
117
+ | "User already exists and is attached to a unit"
118
+ | "User Created, Sucessfully attached to Org Unit";
119
+ user: {
120
+ id: string;
121
+ email: string;
122
+ name: string;
123
+ };
124
+ accessToken?: string;
125
+ },
126
+ {
127
+ orgUnitId: string;
128
+ role: number[];
129
+ email?: string;
130
+ name?: string;
131
+ phone?: string;
132
+ userName: string;
133
+ }
134
+ >(
135
+ `v2/units/${orgUnitId}/users`,
136
+ {
137
+ ...data,
138
+ orgUnitId,
139
+ },
140
+ {
141
+ headers: {
142
+ Cookie: cookie,
143
+ },
144
+ ignoreContentType: true,
145
+ }
146
+ );
147
+ }
148
+
99
149
  removeUserFromOrgUnit(
100
150
  props: {
101
151
  orgUnitId: string;
@@ -169,6 +219,57 @@ class UsersClient extends Client {
169
219
  }
170
220
  );
171
221
  }
222
+
223
+ validateUsername(
224
+ props: {
225
+ orgUnitId: string;
226
+ userName: string;
227
+ },
228
+ cookie: string
229
+ ) {
230
+ const { orgUnitId, userName } = props;
231
+
232
+ return this.post<
233
+ {
234
+ valid: boolean;
235
+ userNameSuggestions?: string[];
236
+ },
237
+ {
238
+ userName: string;
239
+ }
240
+ >(
241
+ `units/${orgUnitId}/users/validate`,
242
+ {
243
+ userName,
244
+ },
245
+ {
246
+ headers: {
247
+ Cookie: cookie,
248
+ },
249
+ }
250
+ );
251
+ }
252
+
253
+ resetPassword(
254
+ props: {
255
+ orgUnitId: string;
256
+ userId: string;
257
+ },
258
+ cookie: string
259
+ ) {
260
+ const { orgUnitId, userId } = props;
261
+
262
+ return this.post<
263
+ {
264
+ accessCode: string;
265
+ },
266
+ null
267
+ >(`units/${orgUnitId}/users/${userId}/reset-password`, null, {
268
+ headers: {
269
+ Cookie: cookie,
270
+ },
271
+ });
272
+ }
172
273
  }
173
274
 
174
275
  const usersClient = new UsersClient();
@@ -166,13 +166,13 @@ export const CreateUserDrawer = ({
166
166
  return;
167
167
  }
168
168
 
169
- // Create User
170
169
  addUserToOrgUnit({
171
170
  name,
172
171
  email,
173
172
  phone: phone ?? "",
174
173
  roles,
175
174
  orgUnitId,
175
+ userName: "",
176
176
  });
177
177
  };
178
178
 
@@ -0,0 +1,20 @@
1
+ import { useBuyerPortal } from "../../../shared/hooks";
2
+ import {
3
+ CreateUserDrawer,
4
+ type CreateUserDrawerProps,
5
+ } from "../CreateUserDrawer/CreateUserDrawer";
6
+ import { CreateUserDrawerWithUsername } from "../CreateUserDrawerWithUsername/CreateUserDrawerWithUsername";
7
+
8
+ export type CreateUserDrawerSelectorProps = CreateUserDrawerProps;
9
+
10
+ export const CreateUserDrawerSelector = (
11
+ props: CreateUserDrawerSelectorProps
12
+ ) => {
13
+ const { featureFlags } = useBuyerPortal();
14
+
15
+ if (featureFlags?.enableUsernameCreation) {
16
+ return <CreateUserDrawerWithUsername {...props} />;
17
+ }
18
+
19
+ return <CreateUserDrawer {...props} />;
20
+ };