@vtex/faststore-plugin-buyer-portal 1.3.47 → 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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.48] - 2025-12-19
11
+
12
+ - Adjustment from merge to Collections to Products Assortment
13
+ - Change Products Assortment to client side
14
+
10
15
  ## [1.3.47] - 2025-12-19
11
16
 
12
17
  - Alternative Login Keys:
@@ -406,7 +411,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
406
411
  - Add CHANGELOG file
407
412
  - Add README file
408
413
 
409
- [unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.47...HEAD
414
+ [unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.48...HEAD
410
415
  [1.2.3]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.2.2...1.2.3
411
416
  [1.2.3]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.2.3
412
417
  [1.2.4]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.2.4
@@ -456,6 +461,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
456
461
  [1.3.36]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.35...v1.3.36
457
462
  [1.3.35]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.35
458
463
 
464
+ [1.3.48]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.47...v1.3.48
459
465
  [1.3.47]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.46...v1.3.47
460
466
  [1.3.46]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.45...v1.3.46
461
467
  [1.3.45]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.44...v1.3.45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.3.47",
3
+ "version": "1.3.48",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -8,7 +8,10 @@ export const useOrgUnitByUser = (
8
8
  const { data, error, isLoading, refetch } = useQuery(
9
9
  `api/org-unit-by-user-id/${userId}`,
10
10
  ({ cookie }) => getOrgUnitByUserIdService({ cookie, userId }),
11
- options
11
+ {
12
+ ...options,
13
+ lazy: !userId || options?.lazy,
14
+ }
12
15
  );
13
16
  return {
14
17
  orgUnit: data,
@@ -0,0 +1,52 @@
1
+ import { type QueryOptions, useQuery } from "../../shared/hooks";
2
+ import { getProductAssortmentFromScopeService } from "../services/get-product-assortment-from-scope.service";
3
+
4
+ export const useGetProductAssortment = ({
5
+ contractId,
6
+ orgUnitId,
7
+ search = "",
8
+ filterByScope = false,
9
+ page = 1,
10
+ options,
11
+ }: {
12
+ contractId: string;
13
+ orgUnitId: string;
14
+ filterByScope?: boolean;
15
+ search?: string;
16
+ page?: number;
17
+ options?: QueryOptions<
18
+ AwaitedType<typeof getProductAssortmentFromScopeService>
19
+ >;
20
+ }) => {
21
+ const { data, error, isLoading, refetch } = useQuery(
22
+ `customers/${contractId}/units/${orgUnitId}/collections`,
23
+ ({ cookie }) =>
24
+ getProductAssortmentFromScopeService({
25
+ args: {
26
+ cookie,
27
+ contractId,
28
+ unitId: orgUnitId,
29
+ filterByScope,
30
+ name: search,
31
+ page,
32
+ },
33
+ }),
34
+ { ...options }
35
+ );
36
+
37
+ return {
38
+ data: {
39
+ items: data?.items ?? [],
40
+ paging: {
41
+ page: data?.paging?.page ?? 1,
42
+ total: data?.paging?.total ?? 0,
43
+ pages: data?.paging?.pages ?? 0,
44
+ limit: data?.paging?.limit ?? 10,
45
+ perPage: data?.paging?.perPage ?? 10,
46
+ },
47
+ },
48
+ hasError: !!error,
49
+ isProductAssortmentLoading: isLoading,
50
+ refetchProductAssortment: refetch,
51
+ };
52
+ };
@@ -0,0 +1,35 @@
1
+ import { type QueryOptions, useQuery } from "../../shared/hooks";
2
+ import { getProductAssortmentFromContractService } from "../services/get-product-assortment-from-contract.service";
3
+
4
+ export const useGetProductAssortmentFromContract = ({
5
+ contractId,
6
+ orgUnitId,
7
+ search = "",
8
+ options,
9
+ }: {
10
+ contractId: string;
11
+ orgUnitId: string;
12
+ search?: string;
13
+ options?: QueryOptions<
14
+ AwaitedType<typeof getProductAssortmentFromContractService>
15
+ >;
16
+ }) => {
17
+ const { data, error, isLoading, refetch } = useQuery(
18
+ `customers/${contractId}/units/${orgUnitId}/collections`,
19
+ ({ cookie }) =>
20
+ getProductAssortmentFromContractService({
21
+ cookie,
22
+ contractId,
23
+ unitId: orgUnitId,
24
+ name: search,
25
+ }),
26
+ { ...options }
27
+ );
28
+
29
+ return {
30
+ data,
31
+ hasError: !!error,
32
+ isProductAssortmentFromContractLoading: isLoading,
33
+ refetchProductAssortmentFromContract: refetch,
34
+ };
35
+ };
@@ -1,3 +1,5 @@
1
+ import { useMemo } from "react";
2
+
1
3
  import { Tooltip } from "@faststore/ui";
2
4
 
3
5
  import {
@@ -6,11 +8,16 @@ import {
6
8
  Paginator,
7
9
  } from "../../../shared/components";
8
10
  import { EmptyState } from "../../../shared/components/EmptyState/EmptyState";
9
- import { useBuyerPortal, usePageItems } from "../../../shared/hooks";
10
- import { useDrawerProps } from "../../../shared/hooks";
11
+ import {
12
+ useBuyerPortal,
13
+ useDrawerProps,
14
+ usePageItems,
15
+ } from "../../../shared/hooks";
11
16
  import { ContractTabsLayout, GlobalLayout } from "../../../shared/layouts";
12
17
  import { AddProductAssortmentDrawer } from "../../components";
13
18
  import { ProductAssortmentTable } from "../../components/ProductAssortmentTable/ProductAssortmentTable";
19
+ import { useGetProductAssortment } from "../../hooks/useGetProductAssortment";
20
+ import { useGetProductAssortmentFromContract } from "../../hooks/useGetProductAssortmentFromContract";
14
21
 
15
22
  import type {
16
23
  ProductAssortmentLayoutProps,
@@ -18,11 +25,10 @@ import type {
18
25
  } from "../../types";
19
26
 
20
27
  export const ProductAssortmentLayout = ({
21
- initialProductAssortment,
22
- drawerProductAssortment,
23
- isContractEmpty,
24
28
  page,
25
29
  search,
30
+ orgUnitId,
31
+ contractId,
26
32
  }: ProductAssortmentLayoutProps) => {
27
33
  const {
28
34
  currentOrgUnit: orgUnit,
@@ -30,6 +36,39 @@ export const ProductAssortmentLayout = ({
30
36
  currentContract: contract,
31
37
  } = useBuyerPortal();
32
38
 
39
+ const { data: drawerProductAssortment } = useGetProductAssortment({
40
+ contractId,
41
+ orgUnitId,
42
+ });
43
+ const { data: contractAssortment } = useGetProductAssortmentFromContract({
44
+ contractId,
45
+ orgUnitId,
46
+ });
47
+ const { data: initialProductAssortment, isProductAssortmentLoading } =
48
+ useGetProductAssortment({
49
+ filterByScope: true,
50
+ contractId,
51
+ orgUnitId,
52
+ search,
53
+ page,
54
+ });
55
+
56
+ const isContractEmpty = !contractAssortment || contractAssortment.total === 0;
57
+
58
+ const itemsKey = useMemo(
59
+ () =>
60
+ initialProductAssortment.items
61
+ .map((item) => item.id)
62
+ .sort()
63
+ .join(","),
64
+ [initialProductAssortment.items]
65
+ );
66
+
67
+ const memoizedInitialItems = useMemo(
68
+ () => initialProductAssortment.items,
69
+ [itemsKey]
70
+ );
71
+
33
72
  const {
34
73
  isLoading,
35
74
  items: productAssortment,
@@ -38,7 +77,7 @@ export const ProductAssortmentLayout = ({
38
77
  increasePage,
39
78
  decreasePage,
40
79
  } = usePageItems<ProductAssortmentWithAdditionalInformation>({
41
- initialItems: initialProductAssortment.items,
80
+ initialItems: memoizedInitialItems,
42
81
  search,
43
82
  page,
44
83
  });
@@ -53,7 +92,6 @@ export const ProductAssortmentLayout = ({
53
92
  ...addProductAssortmentDrawerProps
54
93
  } = useDrawerProps();
55
94
 
56
- //const enabledAssortment = productAssortment.filter((p) => p.isEnabled);
57
95
  const hasAllAssortment = drawerProductAssortment.items.length === 0;
58
96
  const isEmpty = productAssortment.length === 0;
59
97
 
@@ -72,7 +110,7 @@ export const ProductAssortmentLayout = ({
72
110
  <GlobalLayout>
73
111
  <ContractTabsLayout
74
112
  orgUnitName={orgUnit?.name ?? ""}
75
- orgUnitId={orgUnit?.id ?? ""}
113
+ orgUnitId={orgUnitId ?? orgUnit?.id ?? ""}
76
114
  contractName={contract?.name ?? ""}
77
115
  contractId={contract?.id ?? ""}
78
116
  pageName="Contract"
@@ -80,6 +118,7 @@ export const ProductAssortmentLayout = ({
80
118
  image: undefined,
81
119
  name: user?.name ?? "",
82
120
  role: user?.role ?? "",
121
+ id: user?.id ?? "",
83
122
  }}
84
123
  >
85
124
  <section data-fs-bp-product-assortment-container>
@@ -140,9 +179,11 @@ export const ProductAssortmentLayout = ({
140
179
  {initialProductAssortment.paging.page > 1 ? (
141
180
  <Paginator.NextPageButton
142
181
  onClick={decreasePage}
143
- disabled={isLoading}
182
+ disabled={isLoading || isProductAssortmentLoading}
144
183
  >
145
- {isLoading ? "Loading" : "Previous Page"}
184
+ {isLoading || isProductAssortmentLoading
185
+ ? "Loading"
186
+ : "Previous Page"}
146
187
  </Paginator.NextPageButton>
147
188
  ) : (
148
189
  <></>
@@ -150,9 +191,11 @@ export const ProductAssortmentLayout = ({
150
191
  {!isLastPage && !isEmpty ? (
151
192
  <Paginator.NextPageButton
152
193
  onClick={increasePage}
153
- disabled={isLoading}
194
+ disabled={isLoading || isProductAssortmentLoading}
154
195
  >
155
- {isLoading ? "Loading" : "Next Page"}
196
+ {isLoading || isProductAssortmentLoading
197
+ ? "Loading"
198
+ : "Next Page"}
156
199
  </Paginator.NextPageButton>
157
200
  ) : (
158
201
  <></>
@@ -95,4 +95,4 @@
95
95
  margin-top: var(--fs-spacing-0);
96
96
  padding: var(--fs-spacing-2) 0;
97
97
  }
98
- }
98
+ }
@@ -1,8 +1,5 @@
1
- import type { ContractData } from "../../contracts/types";
2
- import type { OrgUnitBasicData } from "../../org-units/types";
3
1
  import type { BasicDrawerProps } from "../../shared/components";
4
2
  import type { ErrorBoundaryProps } from "../../shared/components/ErrorBoundary/types";
5
- import type { ClientContext } from "../../shared/utils";
6
3
 
7
4
  export type ProductAssortmentSummary = {
8
5
  id: string;
@@ -55,24 +52,19 @@ export interface ProductAssortmentSelectedProps {
55
52
  }
56
53
 
57
54
  export type ProductAssortmentLayoutProps = {
58
- initialProductAssortment: GetProductAssortmentFromContractResponse;
59
- drawerProductAssortment: GetProductAssortmentFromContractResponse;
55
+ userId?: string;
56
+ orgUnitId: string;
57
+ contractId: string;
60
58
  page: number;
61
59
  search: string;
62
- isContractEmpty: boolean;
63
60
  };
64
61
 
65
62
  export type ProductAssortmentData = {
66
- productAssortment: GetProductAssortmentFromContractResponse;
67
- drawerProductAssortment: GetProductAssortmentFromContractResponse;
68
- isContractEmpty: boolean;
63
+ userId: string;
64
+ orgUnitId: string;
65
+ contractId: string;
69
66
  search: string;
70
67
  page: number;
71
- context: {
72
- clientContext: ClientContext;
73
- currentOrgUnit: OrgUnitBasicData;
74
- currentContract: ContractData | null;
75
- };
76
68
  hasError?: boolean;
77
69
  error?: ErrorBoundaryProps;
78
70
  };
@@ -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;
@@ -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.47";
25
+ export const CURRENT_VERSION = "1.3.48";
@@ -1,80 +1,80 @@
1
1
  import { getContractDetailsService } from "../features/contracts/services";
2
2
  import { getOrgUnitBasicDataService } from "../features/org-units/services";
3
3
  import { ProductAssortmentLayout } from "../features/product-assortment/layouts";
4
- import { getProductAssortmentFromContractService } from "../features/product-assortment/services/get-product-assortment-from-contract.service";
5
- import { getProductAssortmentFromScopeService } from "../features/product-assortment/services/get-product-assortment-from-scope.service";
6
4
  import { withErrorBoundary } from "../features/shared/components";
5
+ import { ErrorBoundaryProps } from "../features/shared/components/ErrorBoundary/types";
7
6
  import { ErrorTabsLayout } from "../features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout";
8
7
  import {
8
+ type ClientContext,
9
9
  getValidPage,
10
- withLoaderErrorBoundary,
11
10
  withAuthLoader,
11
+ withLoaderErrorBoundary,
12
12
  withProviders,
13
13
  } from "../features/shared/utils";
14
+ import { getUserByIdService } from "../features/users/services";
14
15
 
15
- import type {
16
- ProductAssortmentData,
17
- ProductAssortmentQuery,
18
- } from "../features/product-assortment/types";
16
+ import type { ContractData } from "../features/contracts/types";
17
+ import type { OrgUnitBasicData } from "../features/org-units/types";
18
+ import type { ProductAssortmentQuery } from "../features/product-assortment/types";
19
19
  import type { AuthRouteProps, LoaderData } from "../features/shared/types";
20
+ import type { UserData } from "../features/users/types";
21
+
22
+ export type ProductAssortmentPageData = {
23
+ data: {
24
+ orgUnitId: string;
25
+ contractId: string;
26
+ userId: string;
27
+ search: string;
28
+ page: number;
29
+ };
30
+ context: {
31
+ clientContext: ClientContext;
32
+ currentOrgUnit: OrgUnitBasicData;
33
+ currentContract: ContractData | null;
34
+ currentUser: UserData | null;
35
+ };
36
+ hasError?: boolean;
37
+ error?: ErrorBoundaryProps;
38
+ };
20
39
 
21
40
  const loaderFunction = async (
22
41
  data: LoaderData<ProductAssortmentQuery>
23
- ): Promise<AuthRouteProps<ProductAssortmentData>> => {
42
+ ): Promise<AuthRouteProps<ProductAssortmentPageData>> => {
24
43
  const { contractId, orgUnitId, search = "", page: pageString } = data.query;
25
44
 
26
- const page = getValidPage(pageString);
27
-
28
- return withAuthLoader(data, async ({ cookie, ...clientContext }) => {
29
- const [currentOrgUnit, contract] = await Promise.all([
30
- getOrgUnitBasicDataService({ id: orgUnitId, cookie }),
31
- getContractDetailsService({ contractId, cookie, unitId: orgUnitId }),
32
- ]);
33
-
34
- const [enabledAssortment, notAddedAssortments, contractAssortment] =
35
- await Promise.all([
36
- getProductAssortmentFromScopeService({
37
- args: {
38
- cookie,
39
- contractId,
40
- unitId: orgUnitId,
41
- filterByScope: true,
42
- name: search,
43
- page,
44
- },
45
- }),
46
- getProductAssortmentFromScopeService({
47
- args: {
48
- cookie,
49
- contractId,
50
- unitId: orgUnitId,
51
- filterByScope: false,
52
- page: 1,
53
- },
45
+ return withAuthLoader(
46
+ data,
47
+ async ({ customerId, cookie, userId, ...clientContext }) => {
48
+ const [orgUnit, contract, user] = await Promise.all([
49
+ getOrgUnitBasicDataService({
50
+ id: orgUnitId,
51
+ cookie,
54
52
  }),
55
- getProductAssortmentFromContractService({
53
+ getContractDetailsService({
56
54
  contractId,
57
- cookie,
58
55
  unitId: orgUnitId,
56
+ cookie,
59
57
  }),
58
+ getUserByIdService({ orgUnitId, userId, cookie }),
60
59
  ]);
61
60
 
62
- const isContractEmpty =
63
- !contractAssortment || contractAssortment.total === 0;
64
-
65
- return {
66
- productAssortment: enabledAssortment,
67
- drawerProductAssortment: notAddedAssortments,
68
- isContractEmpty,
69
- search,
70
- page,
71
- context: {
72
- clientContext: { cookie, ...clientContext },
73
- currentContract: contract,
74
- currentOrgUnit,
75
- },
76
- };
77
- });
61
+ return {
62
+ data: {
63
+ orgUnitId,
64
+ contractId,
65
+ userId,
66
+ search,
67
+ page: getValidPage(pageString),
68
+ },
69
+ context: {
70
+ clientContext: { customerId, cookie, userId, ...clientContext },
71
+ currentOrgUnit: orgUnit,
72
+ currentContract: contract,
73
+ currentUser: user,
74
+ },
75
+ };
76
+ }
77
+ );
78
78
  };
79
79
 
80
80
  export const loader = withLoaderErrorBoundary(loaderFunction, {
@@ -83,24 +83,20 @@ export const loader = withLoaderErrorBoundary(loaderFunction, {
83
83
  });
84
84
 
85
85
  const ProductAssortmentPage = ({
86
- productAssortment,
87
- drawerProductAssortment,
88
- isContractEmpty,
89
- page,
90
- search,
86
+ data,
91
87
  hasError,
92
88
  error,
93
- }: ProductAssortmentData) => (
89
+ }: ProductAssortmentPageData) => (
94
90
  <>
95
91
  {hasError ? (
96
92
  <ErrorTabsLayout error={error} />
97
93
  ) : (
98
94
  <ProductAssortmentLayout
99
- page={page}
100
- search={search}
101
- initialProductAssortment={productAssortment}
102
- drawerProductAssortment={drawerProductAssortment}
103
- isContractEmpty={isContractEmpty}
95
+ page={data.page}
96
+ search={data.search}
97
+ userId={data.userId}
98
+ orgUnitId={data.orgUnitId}
99
+ contractId={data.contractId}
104
100
  />
105
101
  )}
106
102
  </>