@vtex/faststore-plugin-buyer-portal 2.0.12 → 2.0.13

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 (27) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/package.json +1 -1
  3. package/src/features/accounting-fields/components/CreateAccountingValueDrawer/CreateAccountingValueDrawer.tsx +1 -0
  4. package/src/features/accounting-fields/hooks/useDetailsAccountingField.ts +5 -4
  5. package/src/features/accounting-fields/hooks/useDetailsAccountingValue.ts +5 -4
  6. package/src/features/accounting-fields/hooks/useListAccountingFields.ts +4 -4
  7. package/src/features/accounting-fields/hooks/useListAccountingValues.ts +5 -3
  8. package/src/features/accounting-fields/layouts/AccountingFieldLayout/AccountingFieldLayout.tsx +1 -0
  9. package/src/features/budgets/components/CreateBudgetAllocationDrawer/CreateBudgetAllocationDrawer.tsx +1 -1
  10. package/src/features/budgets/components/CreateBudgetDrawer/CreateBudgetDrawer.tsx +1 -1
  11. package/src/features/budgets/hooks/useGetAllocations.ts +1 -0
  12. package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingFieldCriteriaSelector.tsx +5 -2
  13. package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingValueCriteriaSelector.tsx +7 -2
  14. package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +2 -0
  15. package/src/features/contracts/layouts/ContractListingLayout/ContractListingLayout.tsx +9 -3
  16. package/src/features/contracts/layouts/ContractListingLayout/__tests__/utils.test.ts +40 -0
  17. package/src/features/contracts/layouts/ContractListingLayout/utils.ts +13 -0
  18. package/src/features/org-units/components/CreateOrgUnitDrawer/CreateOrgUnitDrawer.tsx +9 -1
  19. package/src/features/org-units/components/DeleteOrgUnitDrawer/DeleteOrgUnitDrawer.tsx +8 -1
  20. package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumb.tsx +13 -3
  21. package/src/features/org-units/components/OrgUnitsHierarchyTree/OrgUnitsHierarchyTree.tsx +14 -1
  22. package/src/features/org-units/components/UpdateOrgUnitDrawer/UpdateOrgUnitDrawer.tsx +9 -1
  23. package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +4 -1
  24. package/src/features/shared/layouts/SumaPageLayout/FullSidebarNav.tsx +1 -1
  25. package/src/features/shared/utils/buyerPortalRoutes.ts +14 -4
  26. package/src/features/shared/utils/constants.ts +1 -1
  27. package/src/pages/org-unit-details.tsx +3 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.0.13] - 2026-07-21
11
+
12
+ ### Fixed
13
+
14
+ - Navigating between organizational units (hierarchy tree, breadcrumbs, and the "View" links after creating/editing/deleting a unit) now carries the currently viewed contract's id through, instead of dropping it — this previously caused the `suma`-flag redirect on `/org-unit/[orgUnitId]` to land on the target org unit's default contract instead of the one being viewed. The Contract Listing page now also honors a `contractId` carried in the URL when it belongs to the org unit's attached contracts, falling back to the org unit's default contract otherwise
15
+ - Accounting Fields data (sidebar list, Buying Policy criteria selectors, the Accounting Field details page, and Budget allocation drawers) was fetched using the session's active contract instead of the contract actually being viewed — noticeable when navigating straight to a page for a non-active contract (e.g. from Contract Listing) without first "switching" to it. All accounting-fields read hooks now take an explicit `contractId` instead of silently substituting the session's customerId
16
+
10
17
  ## [2.0.12] - 2026-07-17
11
18
 
12
19
  ### Fixed
@@ -763,7 +770,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
763
770
  - Add CHANGELOG file
764
771
  - Add README file
765
772
 
766
- [unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.12...HEAD
773
+ [unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.13...HEAD
767
774
  [1.3.55]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.54...v1.3.55
768
775
  [1.3.54]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.53...v1.3.54
769
776
  [1.3.53]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.52...v1.3.53
@@ -861,5 +868,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
861
868
  [2.0.10]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.9...v2.0.10
862
869
  [2.0.9]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/2.0.9
863
870
 
871
+ [2.0.13]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.12...v2.0.13
864
872
  [2.0.12]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v2.0.11...v2.0.12
865
873
  [2.0.11]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/2.0.11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "2.0.12",
3
+ "version": "2.0.13",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -133,6 +133,7 @@ export const CreateAccountingValueDrawer = ({
133
133
  const { listAccountingValuesData } = useListAccountingValues({
134
134
  accountingFieldId: accountingField.id,
135
135
  orgUnitId,
136
+ contractId: contract?.id ?? "",
136
137
  page: 1,
137
138
  search,
138
139
  filterByUnit: false,
@@ -6,17 +6,18 @@ export const useDetailsAccountingField = (
6
6
  {
7
7
  accountingFieldId,
8
8
  orgUnitId,
9
- }: Omit<DetailsAccountingFieldParams, "cookie" | "contractId">,
9
+ contractId,
10
+ }: Omit<DetailsAccountingFieldParams, "cookie">,
10
11
  options?: QueryOptions<AwaitedType<typeof detailsAccoutingFieldService>>
11
12
  ) => {
12
13
  const { data, error, isLoading, refetch } = useQuery(
13
- `accounting-fields/${accountingFieldId}/details`,
14
- ({ cookie, customerId }) =>
14
+ `accounting-fields/${accountingFieldId}/details/${contractId}`,
15
+ ({ cookie }) =>
15
16
  detailsAccoutingFieldService({
16
17
  orgUnitId,
17
18
  accountingFieldId,
18
19
  cookie,
19
- contractId: customerId,
20
+ contractId,
20
21
  }),
21
22
  options
22
23
  );
@@ -8,18 +8,19 @@ export const useDetailsAccountingValue = (
8
8
  accountingFieldId,
9
9
  accountingValueId,
10
10
  orgUnitId,
11
- }: Omit<DetailsAccountingValueParams, "cookie" | "contractId">,
11
+ contractId,
12
+ }: Omit<DetailsAccountingValueParams, "cookie">,
12
13
  options?: QueryOptions<AwaitedType<typeof detailsAccountingValueService>>
13
14
  ) => {
14
15
  const { data, error, isLoading, refetch } = useQuery(
15
- `accounting-values/${accountingValueId}/details`,
16
- ({ cookie, customerId }) =>
16
+ `accounting-values/${accountingValueId}/details/${contractId}`,
17
+ ({ cookie }) =>
17
18
  detailsAccountingValueService({
18
19
  orgUnitId,
19
20
  accountingFieldId,
20
21
  accountingValueId,
21
22
  cookie,
22
- contractId: customerId,
23
+ contractId,
23
24
  }),
24
25
  options
25
26
  );
@@ -3,14 +3,14 @@ import { listAccountingFielsdService } from "../services";
3
3
  import { AccountingFieldsParams } from "../types";
4
4
 
5
5
  export const useListAccountingFields = (
6
- { orgUnitId }: Omit<AccountingFieldsParams, "cookie" | "contractId">,
6
+ { orgUnitId, contractId }: Omit<AccountingFieldsParams, "cookie">,
7
7
  options?: QueryOptions<AwaitedType<typeof listAccountingFielsdService>>
8
8
  ) => {
9
9
  const { data, error, isLoading, refetch } = useQuery(
10
- ["api", "accounting-fields", orgUnitId].join("/"),
11
- ({ cookie, customerId }) =>
10
+ ["api", "accounting-fields", orgUnitId, contractId].join("/"),
11
+ ({ cookie }) =>
12
12
  listAccountingFielsdService({
13
- contractId: customerId,
13
+ contractId,
14
14
  orgUnitId,
15
15
  cookie,
16
16
  }),
@@ -6,12 +6,13 @@ import type { ListAccountingValuesParams } from "../types";
6
6
  export const useListAccountingValues = (
7
7
  {
8
8
  orgUnitId,
9
+ contractId,
9
10
  accountingFieldId,
10
11
  page,
11
12
  search,
12
13
  budgetId,
13
14
  filterByUnit,
14
- }: Omit<ListAccountingValuesParams, "cookie" | "contractId">,
15
+ }: Omit<ListAccountingValuesParams, "cookie">,
15
16
  options?: QueryOptions<AwaitedType<typeof listAccountingValuesdService>>,
16
17
  key?: string
17
18
  ) => {
@@ -21,13 +22,14 @@ export const useListAccountingValues = (
21
22
  "api",
22
23
  "accounting-field-values",
23
24
  orgUnitId,
25
+ contractId,
24
26
  accountingFieldId,
25
27
  `page=${page}`,
26
28
  `search=${search}`,
27
29
  ].join("/"),
28
- ({ cookie, customerId }) =>
30
+ ({ cookie }) =>
29
31
  listAccountingValuesdService({
30
- contractId: customerId,
32
+ contractId,
31
33
  cookie,
32
34
  orgUnitId,
33
35
  accountingFieldId,
@@ -96,6 +96,7 @@ export const AccountingFieldLayout = ({
96
96
  } = useListAccountingValues({
97
97
  accountingFieldId: accountingField?.id ?? "",
98
98
  orgUnitId: orgUnit?.id ?? "",
99
+ contractId: contract?.id ?? "",
99
100
  page,
100
101
  search: debouncedSearch,
101
102
  });
@@ -42,7 +42,7 @@ export const CreateBudgetAllocationDrawer = ({
42
42
  const { pushToast } = useUI();
43
43
 
44
44
  const { listAccountingFieldData, listAccountingFieldLoading } =
45
- useListAccountingFields({ orgUnitId });
45
+ useListAccountingFields({ orgUnitId, contractId });
46
46
 
47
47
  const dynamicSortingOptions = useMemo<Dictionary<string>>(() => {
48
48
  const accountingFieldsOptions =
@@ -92,7 +92,7 @@ export const CreateBudgetDrawer = ({
92
92
  });
93
93
 
94
94
  const { listAccountingFieldData, listAccountingFieldLoading } =
95
- useListAccountingFields({ orgUnitId: unitId });
95
+ useListAccountingFields({ orgUnitId: unitId, contractId });
96
96
 
97
97
  const dynamicSortingOptions = useMemo<Dictionary<string>>(() => {
98
98
  const accountingFieldsOptions =
@@ -129,6 +129,7 @@ export function useGetAllocations({
129
129
  budgetId,
130
130
  accountingFieldId: selectedAllocationOption,
131
131
  orgUnitId: unitId,
132
+ contractId,
132
133
  page: filter.page,
133
134
  search: debouncedSearch,
134
135
  filterByUnit: true,
@@ -29,10 +29,13 @@ export const AccountingFieldCriteriaSelector = ({
29
29
  const dropdownRef = useRef<HTMLDivElement>(null);
30
30
 
31
31
  const { pushToast } = useUI();
32
- const { currentOrgUnit } = useBuyerPortal();
32
+ const { currentOrgUnit, currentContract } = useBuyerPortal();
33
33
  const { listAccountingFieldData, listAccountingFieldLoading } =
34
34
  useListAccountingFields(
35
- { orgUnitId: currentOrgUnit?.id ?? "" },
35
+ {
36
+ orgUnitId: currentOrgUnit?.id ?? "",
37
+ contractId: currentContract?.id ?? "",
38
+ },
36
39
  {
37
40
  onError: () => {
38
41
  pushToast({
@@ -44,10 +44,13 @@ export const AccountingValueCriteriaSelector = ({
44
44
 
45
45
  const debouncedSearch = useDebounce(search, 300);
46
46
  const { pushToast } = useUI();
47
- const { currentOrgUnit } = useBuyerPortal();
47
+ const { currentOrgUnit, currentContract } = useBuyerPortal();
48
48
  const { listAccountingFieldData, listAccountingFieldLoading } =
49
49
  useListAccountingFields(
50
- { orgUnitId: currentOrgUnit?.id ?? "" },
50
+ {
51
+ orgUnitId: currentOrgUnit?.id ?? "",
52
+ contractId: currentContract?.id ?? "",
53
+ },
51
54
  {
52
55
  onError: () => {
53
56
  pushToast({
@@ -66,6 +69,7 @@ export const AccountingValueCriteriaSelector = ({
66
69
  {
67
70
  accountingFieldId: fieldId ?? "",
68
71
  orgUnitId: currentOrgUnit?.id ?? "",
72
+ contractId: currentContract?.id ?? "",
69
73
  search: debouncedSearch,
70
74
  },
71
75
  {
@@ -85,6 +89,7 @@ export const AccountingValueCriteriaSelector = ({
85
89
  accountingFieldId: initialFieldIdRef.current,
86
90
  accountingValueId: initialValueIdRef.current,
87
91
  orgUnitId: currentOrgUnit?.id ?? "",
92
+ contractId: currentContract?.id ?? "",
88
93
  },
89
94
  {
90
95
  lazy:
@@ -43,6 +43,7 @@ export const BuyingPolicyDetailsLayout = ({
43
43
  {
44
44
  accountingFieldId,
45
45
  orgUnitId: currentOrgUnit?.id ?? "",
46
+ contractId: currentContract?.id ?? "",
46
47
  },
47
48
  {
48
49
  lazy: !accountFieldCriteria,
@@ -55,6 +56,7 @@ export const BuyingPolicyDetailsLayout = ({
55
56
  accountingFieldId,
56
57
  accountingValueId,
57
58
  orgUnitId: currentOrgUnit?.id ?? "",
59
+ contractId: currentContract?.id ?? "",
58
60
  },
59
61
  {
60
62
  lazy: !accountFieldCriteria || !accountingValueId,
@@ -39,7 +39,7 @@ import {
39
39
  } from "../../hooks";
40
40
 
41
41
  import { buildContractSettingsNavItems } from "./ContractSettingsNav";
42
- import { getDefaultContractId } from "./utils";
42
+ import { getDefaultContractId, resolveViewedContractId } from "./utils";
43
43
 
44
44
  import type { OrgUnitBasicData } from "../../../org-units/types";
45
45
  import type { UserData } from "../../../users/types";
@@ -77,7 +77,10 @@ export const ContractListingLayout = ({
77
77
  const { pushToast } = useUI();
78
78
  const { subscribe } = useContractSwitchChannel();
79
79
 
80
- const defaultContractId = getDefaultContractId(contracts);
80
+ const queryContractId = Array.isArray(router.query.contractId)
81
+ ? router.query.contractId[0]
82
+ : router.query.contractId;
83
+ const defaultContractId = resolveViewedContractId(contracts, queryContractId);
81
84
  const singleContract = contracts[0];
82
85
  const displayName =
83
86
  singleContract?.name ?? singleContract?.email ?? orgUnit.name;
@@ -86,7 +89,10 @@ export const ContractListingLayout = ({
86
89
  listAccountingFieldData,
87
90
  listAccountingFieldLoading,
88
91
  listAccountingFieldRefresh,
89
- } = useListAccountingFields({ orgUnitId: orgUnit.id });
92
+ } = useListAccountingFields({
93
+ orgUnitId: orgUnit.id,
94
+ contractId: defaultContractId,
95
+ });
90
96
 
91
97
  const {
92
98
  open: openAccountingFieldDrawer,
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { getDefaultContractId, resolveViewedContractId } from "../utils";
4
+
5
+ import type { ContractData } from "../../../types";
6
+
7
+ const contracts = [
8
+ { id: "contract-a", isDefault: false },
9
+ { id: "contract-b", isDefault: true },
10
+ ] as ContractData[];
11
+
12
+ describe("getDefaultContractId", () => {
13
+ it("prefers the contract flagged as default", () => {
14
+ expect(getDefaultContractId(contracts)).toBe("contract-b");
15
+ });
16
+
17
+ it("falls back to the first contract when none is flagged as default", () => {
18
+ expect(getDefaultContractId([contracts[0]])).toBe("contract-a");
19
+ });
20
+
21
+ it("returns an empty string when there are no contracts", () => {
22
+ expect(getDefaultContractId([])).toBe("");
23
+ });
24
+ });
25
+
26
+ describe("resolveViewedContractId", () => {
27
+ it("uses the query contractId when it belongs to this org unit's contracts", () => {
28
+ expect(resolveViewedContractId(contracts, "contract-a")).toBe("contract-a");
29
+ });
30
+
31
+ it("falls back to the default contract when the query contractId isn't attached here", () => {
32
+ expect(resolveViewedContractId(contracts, "contract-from-elsewhere")).toBe(
33
+ "contract-b"
34
+ );
35
+ });
36
+
37
+ it("falls back to the default contract when no query contractId is given", () => {
38
+ expect(resolveViewedContractId(contracts, undefined)).toBe("contract-b");
39
+ });
40
+ });
@@ -2,3 +2,16 @@ import type { ContractData } from "../../types";
2
2
 
3
3
  export const getDefaultContractId = (contracts: ContractData[]) =>
4
4
  contracts.find((c) => c.isDefault)?.id ?? contracts[0]?.id ?? "";
5
+
6
+ /**
7
+ * Contracts aren't attached uniformly across the org unit hierarchy, so a
8
+ * contractId carried over from another org unit (e.g. via URL) may not apply
9
+ * here — fall back to this org unit's own default contract when that happens.
10
+ */
11
+ export const resolveViewedContractId = (
12
+ contracts: ContractData[],
13
+ queryContractId?: string
14
+ ) =>
15
+ contracts.some((c) => c.id === queryContractId)
16
+ ? (queryContractId as string)
17
+ : getDefaultContractId(contracts);
@@ -12,10 +12,11 @@ import {
12
12
  InputText,
13
13
  Icon,
14
14
  } from "../../../shared/components";
15
- import { useAnalytics } from "../../../shared/hooks";
15
+ import { useAnalytics, useBuyerPortal } from "../../../shared/hooks";
16
16
  import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
17
17
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
18
18
  import { CHANGES_TIMEOUT_MESSAGE } from "../../../shared/utils/constants";
19
+ import { resolveContractId } from "../../../shared/utils/resolveContractId";
19
20
  import { useCreateNewOrgUnit } from "../../hooks";
20
21
 
21
22
  import type { createNewOrgUnitService } from "../../services";
@@ -37,6 +38,12 @@ export const CreateOrgUnitDrawer = ({
37
38
  }: CreateOrgUnitDrawerProps) => {
38
39
  const { pushToast } = useUI();
39
40
  const router = useRouter();
41
+ const { currentContract, currentOrgUnit } = useBuyerPortal();
42
+ const contractId = resolveContractId({
43
+ queryContractId: router.query.contractId,
44
+ currentContract,
45
+ currentOrgUnit,
46
+ });
40
47
  const { trackEntityCreated, trackEntityCreateError } = useAnalytics({
41
48
  entityType: "org_unit",
42
49
  defaultTimerName: "org_unit_creation",
@@ -70,6 +77,7 @@ export const CreateOrgUnitDrawer = ({
70
77
  router.push(
71
78
  buyerPortalRoutes.orgUnitDetails({
72
79
  orgUnitId: data.id,
80
+ contractId,
73
81
  })
74
82
  )
75
83
  }
@@ -15,6 +15,7 @@ import { useBuyerPortal, useAnalytics } from "../../../shared/hooks";
15
15
  import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
16
16
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
17
17
  import { CHANGES_TIMEOUT_MESSAGE } from "../../../shared/utils/constants";
18
+ import { resolveContractId } from "../../../shared/utils/resolveContractId";
18
19
  import { useGetUserByOrgUnitId } from "../../../users/hooks/useGetUserByOrgUnitId";
19
20
  import { useChildrenOrgUnits } from "../../hooks";
20
21
  import { useDeleteOrgUnit } from "../../hooks/useDeleteOrgUnit";
@@ -34,7 +35,12 @@ export const DeleteOrgUnitDrawer = ({
34
35
  ...props
35
36
  }: DeleteOrgUnitDrawerProps) => {
36
37
  const router = useRouter();
37
- const { currentOrgUnit } = useBuyerPortal();
38
+ const { currentOrgUnit, currentContract } = useBuyerPortal();
39
+ const contractId = resolveContractId({
40
+ queryContractId: router.query.contractId,
41
+ currentContract,
42
+ currentOrgUnit,
43
+ });
38
44
  const { childrenOrgUnits } = useChildrenOrgUnits(id, name);
39
45
  const { users } = useGetUserByOrgUnitId(id);
40
46
  const { pushToast } = useUI();
@@ -80,6 +86,7 @@ export const DeleteOrgUnitDrawer = ({
80
86
  const parentId = ids[ids.length - 2];
81
87
  const redirectUrl = buyerPortalRoutes.orgUnitDetails({
82
88
  orgUnitId: parentId,
89
+ contractId,
83
90
  });
84
91
  router.replace(redirectUrl);
85
92
  } else {
@@ -1,6 +1,9 @@
1
+ import { useRouter } from "next/router";
2
+
1
3
  import { Icon } from "../../../shared/components";
2
4
  import { useBuyerPortal } from "../../../shared/hooks";
3
5
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
6
+ import { resolveContractId } from "../../../shared/utils/resolveContractId";
4
7
  import { USER_ROLES } from "../../../users/types";
5
8
  import { useOrgUnitByUser } from "../../hooks";
6
9
 
@@ -19,8 +22,15 @@ export const OrgUnitBreadcrumb = ({
19
22
  userId,
20
23
  userRoles,
21
24
  }: OrgUnitBreadcrumbProps) => {
22
- const { currentContract } = useBuyerPortal();
25
+ const { currentContract, currentOrgUnit } = useBuyerPortal();
23
26
  const { orgUnit: userUnit } = useOrgUnitByUser(userId);
27
+ const router = useRouter();
28
+
29
+ const contractId = resolveContractId({
30
+ queryContractId: router.query.contractId,
31
+ currentContract,
32
+ currentOrgUnit,
33
+ });
24
34
 
25
35
  const orgUnitList = orgUnit?.path.ids.split("/").slice(1) ?? [];
26
36
 
@@ -36,7 +46,7 @@ export const OrgUnitBreadcrumb = ({
36
46
  ) {
37
47
  acc.push({
38
48
  unitId: orgUnitId,
39
- item: buyerPortalRoutes.orgUnitDetails({ orgUnitId }),
49
+ item: buyerPortalRoutes.orgUnitDetails({ orgUnitId, contractId }),
40
50
  name: orgUnit?.path.names.split("/")[index] ?? "",
41
51
  position: index + 1,
42
52
  enabled: true,
@@ -68,7 +78,7 @@ export const OrgUnitBreadcrumb = ({
68
78
  {Boolean(inBreadcrumb.length) && divider}
69
79
 
70
80
  <OrgUnitBreadcrumbPath
71
- contractId={currentContract?.id ?? ""}
81
+ contractId={contractId}
72
82
  items={sortedByPosition.slice(offset)}
73
83
  divider={divider}
74
84
  hasDropdown={hasDropdown}
@@ -1,4 +1,5 @@
1
1
  import Link from "next/link";
2
+ import { useRouter } from "next/router";
2
3
 
3
4
  import { Dropdown } from "@faststore/ui";
4
5
 
@@ -8,7 +9,9 @@ import {
8
9
  HierarchyTree,
9
10
  Icon,
10
11
  } from "../../../shared/components";
12
+ import { useBuyerPortal } from "../../../shared/hooks";
11
13
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
14
+ import { resolveContractId } from "../../../shared/utils/resolveContractId";
12
15
  import { useChildrenOrgUnits, useOrgUnitStructure } from "../../hooks";
13
16
 
14
17
  import type { OrgUnitHierarchyData } from "../../types";
@@ -25,6 +28,13 @@ export const OrgUnitsHierarchyTree = ({
25
28
  enableChildren = true,
26
29
  }: OrgUnitsHierarchyTreeProps) => {
27
30
  const { structure, setNode } = useOrgUnitStructure(orgUnitHierarchyData);
31
+ const router = useRouter();
32
+ const { currentContract, currentOrgUnit } = useBuyerPortal();
33
+ const contractId = resolveContractId({
34
+ queryContractId: router.query.contractId,
35
+ currentContract,
36
+ currentOrgUnit,
37
+ });
28
38
 
29
39
  return (
30
40
  <HierarchyTree
@@ -48,7 +58,10 @@ export const OrgUnitsHierarchyTree = ({
48
58
  {!readonly && (
49
59
  <Link
50
60
  data-fs-org-unit-item-click-area
51
- href={buyerPortalRoutes.orgUnitDetails({ orgUnitId: id })}
61
+ href={buyerPortalRoutes.orgUnitDetails({
62
+ orgUnitId: id,
63
+ contractId,
64
+ })}
52
65
  />
53
66
  )}
54
67
  {enableChildren && (
@@ -10,10 +10,11 @@ import {
10
10
  ErrorMessage,
11
11
  InputText,
12
12
  } from "../../../shared/components";
13
- import { useAnalytics } from "../../../shared/hooks";
13
+ import { useAnalytics, useBuyerPortal } from "../../../shared/hooks";
14
14
  import { ANALYTICS_EVENTS } from "../../../shared/services/logger/analytics/constants";
15
15
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
16
16
  import { CHANGES_TIMEOUT_MESSAGE } from "../../../shared/utils/constants";
17
+ import { resolveContractId } from "../../../shared/utils/resolveContractId";
17
18
  import { useUpdateOrgUnit } from "../../hooks";
18
19
 
19
20
  export type UpdateOrgUnitDrawerProps = Omit<BasicDrawerProps, "children"> & {
@@ -33,6 +34,12 @@ export const UpdateOrgUnitDrawer = ({
33
34
  }: UpdateOrgUnitDrawerProps) => {
34
35
  const router = useRouter();
35
36
  const { pushToast } = useUI();
37
+ const { currentContract, currentOrgUnit } = useBuyerPortal();
38
+ const contractId = resolveContractId({
39
+ queryContractId: router.query.contractId,
40
+ currentContract,
41
+ currentOrgUnit,
42
+ });
36
43
  const { trackEntityEdited, trackEntityEditError } = useAnalytics({
37
44
  entityType: "org_unit",
38
45
  entityId: id,
@@ -61,6 +68,7 @@ export const UpdateOrgUnitDrawer = ({
61
68
  router.push(
62
69
  buyerPortalRoutes.orgUnitDetails({
63
70
  orgUnitId: id,
71
+ contractId,
64
72
  })
65
73
  )
66
74
  }
@@ -102,7 +102,10 @@ export const OrgUnitsDetailsLayout = ({
102
102
  listAccountingFieldData,
103
103
  listAccountingFieldLoading,
104
104
  listAccountingFieldRefresh,
105
- } = useListAccountingFields({ orgUnitId: orgUnit.id });
105
+ } = useListAccountingFields({
106
+ orgUnitId: orgUnit.id,
107
+ contractId: linkParams.contractId,
108
+ });
106
109
 
107
110
  const organizationMenu = getOrganizationSettingsLinks({
108
111
  orgUnitId: orgUnit.id,
@@ -66,7 +66,7 @@ export const FullSidebarNav = ({
66
66
  listAccountingFieldData,
67
67
  listAccountingFieldRefresh,
68
68
  } = useListAccountingFields(
69
- { orgUnitId: resolvedOrgUnitId },
69
+ { orgUnitId: resolvedOrgUnitId, contractId: resolvedContractId },
70
70
  { lazy: loading }
71
71
  );
72
72
 
@@ -105,8 +105,13 @@ export const buyerPortalRoutes = {
105
105
  userDetails: (params: { orgUnitId: string; userId: string }) =>
106
106
  replaceParams(`${base}/user/[orgUnitId]/[userId]`, params),
107
107
 
108
- orgUnitDetails: (params: { orgUnitId: string }) =>
109
- replaceParams(`${base}/org-unit/[orgUnitId]`, params),
108
+ orgUnitDetails: (params: { orgUnitId: string; contractId?: string }) =>
109
+ appendContractIdParam(
110
+ replaceParams(`${base}/org-unit/[orgUnitId]`, {
111
+ orgUnitId: params.orgUnitId,
112
+ }),
113
+ params.contractId
114
+ ),
110
115
 
111
116
  accountingFields: (params: {
112
117
  orgUnitId: string;
@@ -118,8 +123,13 @@ export const buyerPortalRoutes = {
118
123
  params
119
124
  ),
120
125
 
121
- contracts: (params: { orgUnitId: string }) =>
122
- replaceParams(`${base}/contracts/[orgUnitId]`, params),
126
+ contracts: (params: { orgUnitId: string; contractId?: string }) =>
127
+ appendContractIdParam(
128
+ replaceParams(`${base}/contracts/[orgUnitId]`, {
129
+ orgUnitId: params.orgUnitId,
130
+ }),
131
+ params.contractId
132
+ ),
123
133
 
124
134
  contractInformation: (params: { orgUnitId: string; contractId: string }) =>
125
135
  replaceParams(
@@ -22,7 +22,7 @@ export const SCOPE_KEYS = {
22
22
  CREDIT_CARDS: "creditCards",
23
23
  } as const;
24
24
 
25
- export const CURRENT_VERSION = "2.0.12";
25
+ export const CURRENT_VERSION = "2.0.13";
26
26
 
27
27
  export const CHANGES_TIMEOUT_MESSAGE =
28
28
  "Changes may take up to 10 minutes to apply.";
@@ -51,12 +51,13 @@ export type OrgUnitDetailsPageData = {
51
51
 
52
52
  type OrgUnitDetailsPageQuery = {
53
53
  orgUnitId: string;
54
+ contractId?: string;
54
55
  };
55
56
 
56
57
  const loaderFunction = async (
57
58
  data: LoaderData<OrgUnitDetailsPageQuery>
58
59
  ): Promise<AuthRouteProps<OrgUnitDetailsPageData>> => {
59
- const { orgUnitId } = data.query;
60
+ const { orgUnitId, contractId } = data.query;
60
61
 
61
62
  if (!orgUnitId) {
62
63
  throw new Error(`Missing required query param: orgUnitId=${orgUnitId}`);
@@ -66,7 +67,7 @@ const loaderFunction = async (
66
67
  const featureFlags = await getBuyerPortalFeatureFlags(cookie);
67
68
 
68
69
  if (featureFlags?.suma) {
69
- const location = buyerPortalRoutes.contracts({ orgUnitId });
70
+ const location = buyerPortalRoutes.contracts({ orgUnitId, contractId });
70
71
 
71
72
  data.res?.writeHead(302, { Location: location });
72
73
  data.res?.end();