@vtex/faststore-plugin-buyer-portal 2.0.29 → 2.0.31
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/package.json +3 -1
- package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +1 -1
- package/src/features/addresses/components/AddressesCard/AddressesCard.tsx +1 -1
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingFieldCriteriaSelector.tsx +5 -2
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingValueCriteriaSelector.tsx +8 -3
- package/src/features/buying-policies/components/BudgetCriteriaSelector/BudgetCriteriaSelector.tsx +5 -2
- package/src/features/contracts/components/AddContractsDrawer/AddContractsDrawer.tsx +12 -1
- package/src/features/contracts/components/ContractListItem/ContractListItem.tsx +19 -11
- package/src/features/contracts/components/ContractListItem/__tests__/contractListItemMenu.test.ts +32 -0
- package/src/features/contracts/components/ContractListItem/contractListItemMenu.ts +17 -0
- package/src/features/contracts/components/ContractSelectionList/ContractSelectionListSkeleton.tsx +35 -0
- package/src/features/contracts/components/ContractSwitchOverlay/ContractSwitchOverlay.tsx +9 -1
- package/src/features/contracts/components/UnableToRemoveContractsDrawer/UnableToRemoveContractsDrawer.tsx +1 -0
- package/src/features/contracts/components/index.ts +2 -0
- package/src/features/contracts/hooks/useSwitchContract.ts +6 -4
- package/src/features/contracts/layouts/ContractInformationLayout/ContractInformationLayout.tsx +9 -12
- package/src/features/contracts/layouts/ContractListingLayout/ContractListingLayout.tsx +90 -41
- package/src/features/contracts/layouts/ContractListingLayout/__tests__/utils.test.ts +40 -1
- package/src/features/contracts/layouts/ContractListingLayout/contract-listing-layout.scss +10 -2
- package/src/features/contracts/layouts/ContractListingLayout/utils.ts +25 -0
- package/src/features/contracts/utils/__tests__/clearPersistedSessionState.test.ts +32 -0
- package/src/features/contracts/utils/__tests__/resolveSwitchRedirect.test.ts +21 -0
- package/src/features/contracts/utils/clearPersistedSessionState.ts +43 -5
- package/src/features/contracts/utils/resolveSwitchRedirect.ts +15 -0
- package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumb.tsx +21 -31
- package/src/features/org-units/components/OrgUnitBreadcrumb/__tests__/buildBreadcrumbItems.test.ts +64 -0
- package/src/features/org-units/components/OrgUnitBreadcrumb/buildBreadcrumbItems.ts +36 -0
- package/src/features/org-units/components/OrgUnitDetailsNavbar/OrgUnitDetailsNavbar.tsx +67 -27
- package/src/features/org-units/components/OrgUnitDetailsNavbar/org-unit-details-navbar.scss +22 -1
- package/src/features/org-units/components/OrgUnitHeaderNav/OrgUnitHeaderNav.tsx +112 -0
- package/src/features/org-units/components/OrgUnitHeaderNav/__tests__/getOrgUnitHeaderNavItems.test.ts +83 -0
- package/src/features/org-units/components/OrgUnitHeaderNav/getOrgUnitHeaderNavItems.ts +36 -0
- package/src/features/org-units/components/OrgUnitHeaderNav/org-unit-header-nav.scss +129 -0
- package/src/features/org-units/components/index.ts +4 -0
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss +1 -0
- package/src/features/org-units/types/OrgUnitBreadcrumbTypes.ts +8 -0
- package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +8 -31
- package/src/features/shared/components/LocalizationEslintIgnore/LocalizationEslintIgnore.tsx +12 -0
- package/src/features/shared/components/index.ts +4 -0
- package/src/features/shared/hooks/index.ts +1 -0
- package/src/features/shared/hooks/useRefreshPageData.ts +35 -0
- package/src/features/shared/layouts/BaseTabsLayout/about-drawer/__tests__/aboutQueryParam.test.ts +23 -0
- package/src/features/shared/layouts/BaseTabsLayout/about-drawer/aboutQueryParam.ts +13 -0
- package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +2 -2
- package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +6 -1
- package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +35 -2
- package/src/features/shared/layouts/SumaPageLayout/FullSidebarNav.tsx +33 -12
- package/src/features/shared/layouts/SumaPageLayout/SumaPageLayout.tsx +4 -2
- package/src/features/shared/layouts/SumaPageLayout/SumaSidebar.tsx +27 -18
- package/src/features/shared/layouts/SumaPageLayout/__tests__/resolveOrgLinkContractId.test.ts +16 -0
- package/src/features/shared/layouts/SumaPageLayout/__tests__/sumaSidebarConfig.test.ts +27 -0
- package/src/features/shared/layouts/SumaPageLayout/resolveOrgLinkContractId.ts +13 -0
- package/src/features/shared/layouts/SumaPageLayout/sumaSidebarConfig.ts +37 -0
- package/src/features/shared/utils/__tests__/getContractSettingsLinks.test.ts +18 -0
- package/src/features/shared/utils/__tests__/getSumaListingSidebarLinks.test.ts +43 -0
- package/src/features/shared/utils/__tests__/routeLayoutMapping.test.ts +34 -0
- package/src/features/shared/utils/constants.ts +1 -1
- package/src/features/shared/utils/getContractSettingsLinks.ts +6 -1
- package/src/features/shared/utils/routeLayoutMapping.ts +9 -1
- package/src/pages/contract-information.tsx +9 -1
- package/src/pages/contracts.tsx +5 -0
- package/src/pages/home.tsx +25 -19
- package/src/pages/org-unit-details.tsx +10 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtex/faststore-plugin-buyer-portal",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.31",
|
|
4
4
|
"description": "A plugin for faststore with buyer portal",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"test": "vitest run",
|
|
17
17
|
"test:watch": "vitest",
|
|
18
18
|
"test:coverage": "vitest run --coverage",
|
|
19
|
+
"i18n:check": "node scripts/check-localization-keys.mjs check --base=main",
|
|
20
|
+
"i18n:refresh": "node scripts/check-localization-keys.mjs refresh",
|
|
19
21
|
"prepare": "husky",
|
|
20
22
|
"release": "yarn release:stable",
|
|
21
23
|
"release:stable": "yarn check --integrity && yarn release-it -c .release-it.json --ci --no-npm",
|
|
@@ -192,7 +192,7 @@ ${t("shared.messages.changesTimeout")}`,
|
|
|
192
192
|
<BasicDropdownMenu data-fs-bp-dropdown-menu>
|
|
193
193
|
<DropdownItem onClick={handleOpenNewTab}>
|
|
194
194
|
<Icon name="OpenNewTab" {...sizeProps} />
|
|
195
|
-
|
|
195
|
+
{t("shared.buttons.open")}
|
|
196
196
|
</DropdownItem>
|
|
197
197
|
{!isAddressEditingRestricted && (
|
|
198
198
|
<>
|
|
@@ -4,6 +4,7 @@ import { useUI } from "@faststore/ui";
|
|
|
4
4
|
|
|
5
5
|
import { useListAccountingFields } from "../../../accounting-fields/hooks";
|
|
6
6
|
import { CustomDropdown } from "../../../shared/components/CustomDropdown/CustomDropdown";
|
|
7
|
+
import { LocalizationEslintIgnore } from "../../../shared/components/LocalizationEslintIgnore/LocalizationEslintIgnore";
|
|
7
8
|
import { useBuyerPortal } from "../../../shared/hooks";
|
|
8
9
|
import { useLocalization } from "../../../shared/localization/LocalizationContext";
|
|
9
10
|
import {
|
|
@@ -91,7 +92,9 @@ export const AccountingFieldCriteriaSelector = ({
|
|
|
91
92
|
<div data-fs-bp-accounting-field-criteria-selector>
|
|
92
93
|
<div data-fs-bp-accounting-fields-criteria-string>
|
|
93
94
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
94
|
-
|
|
95
|
+
<LocalizationEslintIgnore>
|
|
96
|
+
$exists(customData.customFields.fields[customFieldId="
|
|
97
|
+
</LocalizationEslintIgnore>
|
|
95
98
|
</span>
|
|
96
99
|
|
|
97
100
|
<div onClick={handleFieldClick} style={{ display: "inline-block" }}>
|
|
@@ -115,7 +118,7 @@ export const AccountingFieldCriteriaSelector = ({
|
|
|
115
118
|
</div>
|
|
116
119
|
|
|
117
120
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
118
|
-
"].value)
|
|
121
|
+
<LocalizationEslintIgnore>"].value)</LocalizationEslintIgnore>
|
|
119
122
|
</span>
|
|
120
123
|
</div>
|
|
121
124
|
</div>
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
useListAccountingValues,
|
|
9
9
|
} from "../../../accounting-fields/hooks";
|
|
10
10
|
import { CustomDropdown } from "../../../shared/components/CustomDropdown/CustomDropdown";
|
|
11
|
+
import { LocalizationEslintIgnore } from "../../../shared/components/LocalizationEslintIgnore/LocalizationEslintIgnore";
|
|
11
12
|
import { useBuyerPortal, useDebounce } from "../../../shared/hooks";
|
|
12
13
|
import { useLocalization } from "../../../shared/localization/LocalizationContext";
|
|
13
14
|
import {
|
|
@@ -216,7 +217,9 @@ export const AccountingValueCriteriaSelector = ({
|
|
|
216
217
|
<div data-fs-bp-accounting-field-criteria-selector>
|
|
217
218
|
<div data-fs-bp-accounting-fields-criteria-string>
|
|
218
219
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
219
|
-
|
|
220
|
+
<LocalizationEslintIgnore>
|
|
221
|
+
customData.customFields.fields[customFieldId="
|
|
222
|
+
</LocalizationEslintIgnore>
|
|
220
223
|
</span>
|
|
221
224
|
|
|
222
225
|
<div onClick={handleFieldClick} style={{ display: "inline-block" }}>
|
|
@@ -244,7 +247,9 @@ export const AccountingValueCriteriaSelector = ({
|
|
|
244
247
|
</div>
|
|
245
248
|
|
|
246
249
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
247
|
-
|
|
250
|
+
<LocalizationEslintIgnore>
|
|
251
|
+
"].customFieldValueId="
|
|
252
|
+
</LocalizationEslintIgnore>
|
|
248
253
|
</span>
|
|
249
254
|
|
|
250
255
|
<div onClick={handleValueClick} style={{ display: "inline-block" }}>
|
|
@@ -275,7 +280,7 @@ export const AccountingValueCriteriaSelector = ({
|
|
|
275
280
|
</div>
|
|
276
281
|
|
|
277
282
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
278
|
-
"
|
|
283
|
+
<LocalizationEslintIgnore>"</LocalizationEslintIgnore>
|
|
279
284
|
</span>
|
|
280
285
|
</div>
|
|
281
286
|
</div>
|
package/src/features/buying-policies/components/BudgetCriteriaSelector/BudgetCriteriaSelector.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
2
|
|
|
3
3
|
import { CustomDropdown } from "../../../shared/components/CustomDropdown/CustomDropdown";
|
|
4
|
+
import { LocalizationEslintIgnore } from "../../../shared/components/LocalizationEslintIgnore/LocalizationEslintIgnore";
|
|
4
5
|
import { useBuyerPortal } from "../../../shared/hooks";
|
|
5
6
|
import { useLocalization } from "../../../shared/localization/LocalizationContext";
|
|
6
7
|
import { useGetBudgets } from "../../hooks/useGetBudgets";
|
|
@@ -90,7 +91,9 @@ export const BudgetCriteriaSelector = ({
|
|
|
90
91
|
<div data-fs-bp-budget-criteria-selector>
|
|
91
92
|
<div data-fs-bp-budget-criteria-string>
|
|
92
93
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
93
|
-
|
|
94
|
+
<LocalizationEslintIgnore>
|
|
95
|
+
$exists(budgetData.budgets[id="
|
|
96
|
+
</LocalizationEslintIgnore>
|
|
94
97
|
</span>
|
|
95
98
|
|
|
96
99
|
<div onClick={handleBudgetValueClick}>
|
|
@@ -115,7 +118,7 @@ export const BudgetCriteriaSelector = ({
|
|
|
115
118
|
</div>
|
|
116
119
|
|
|
117
120
|
<span onClick={handleEditablePartClick} data-fs-bp-editable-part>
|
|
118
|
-
"])
|
|
121
|
+
<LocalizationEslintIgnore>"])</LocalizationEslintIgnore>
|
|
119
122
|
</span>
|
|
120
123
|
</div>
|
|
121
124
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo, useState } from "react";
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { useUI } from "@faststore/ui";
|
|
4
4
|
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
buildRangeSet,
|
|
16
16
|
buildToggleSet,
|
|
17
17
|
} from "../../hooks/contractSelectionHelpers";
|
|
18
|
+
import { pluralSuffixArgs } from "../../layouts/ContractListingLayout/utils";
|
|
18
19
|
|
|
19
20
|
export type AddContractsDrawerProps = Omit<BasicDrawerProps, "children"> & {
|
|
20
21
|
orgUnitId: string;
|
|
@@ -43,10 +44,19 @@ export const AddContractsDrawer = ({
|
|
|
43
44
|
fetchAvailableContracts,
|
|
44
45
|
} = useListAvailableContracts(orgUnitId);
|
|
45
46
|
|
|
47
|
+
const pendingAddCountRef = useRef(0);
|
|
48
|
+
|
|
46
49
|
const { addContracts, isAddContractsLoading } = useAddContracts({
|
|
47
50
|
onSuccess: () => {
|
|
48
51
|
onSuccess();
|
|
49
52
|
drawerProps.onDismiss?.();
|
|
53
|
+
pushToast({
|
|
54
|
+
message: t(
|
|
55
|
+
"contracts.toasts.addSuccess",
|
|
56
|
+
pluralSuffixArgs(pendingAddCountRef.current)
|
|
57
|
+
),
|
|
58
|
+
status: "INFO",
|
|
59
|
+
});
|
|
50
60
|
},
|
|
51
61
|
onError: () => {
|
|
52
62
|
drawerProps.onDismiss?.();
|
|
@@ -129,6 +139,7 @@ export const AddContractsDrawer = ({
|
|
|
129
139
|
};
|
|
130
140
|
|
|
131
141
|
const handleConfirm = () => {
|
|
142
|
+
pendingAddCountRef.current = selectedIds.size;
|
|
132
143
|
addContracts({
|
|
133
144
|
orgUnitId,
|
|
134
145
|
ids: Array.from(selectedIds),
|
|
@@ -6,6 +6,8 @@ import { useLocalization } from "../../../shared/localization/LocalizationContex
|
|
|
6
6
|
import { useSwitchContract } from "../../hooks";
|
|
7
7
|
import { ContractSwitchOverlay } from "../ContractSwitchOverlay/ContractSwitchOverlay";
|
|
8
8
|
|
|
9
|
+
import { getContractMenuState } from "./contractListItemMenu";
|
|
10
|
+
|
|
9
11
|
import type { ContractData } from "../../types";
|
|
10
12
|
|
|
11
13
|
export type ContractListItemProps = {
|
|
@@ -30,6 +32,10 @@ export const ContractListItem = ({
|
|
|
30
32
|
const { pushToast } = useUI();
|
|
31
33
|
const { switchContract, loading } = useSwitchContract();
|
|
32
34
|
const isRemovable = contract.isAttached !== false;
|
|
35
|
+
const menuState = getContractMenuState({
|
|
36
|
+
isDefault: contract.isDefault,
|
|
37
|
+
isRemovable,
|
|
38
|
+
});
|
|
33
39
|
|
|
34
40
|
const handleCheckboxClick = (event: React.MouseEvent) => {
|
|
35
41
|
event.stopPropagation();
|
|
@@ -97,18 +103,20 @@ export const ContractListItem = ({
|
|
|
97
103
|
<Dropdown>
|
|
98
104
|
<BasicDropdownMenu.Trigger />
|
|
99
105
|
<BasicDropdownMenu>
|
|
100
|
-
{
|
|
101
|
-
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
{menuState.showSetDefault && (
|
|
107
|
+
<>
|
|
108
|
+
<DropdownItem
|
|
109
|
+
onClick={
|
|
110
|
+
menuState.setDefaultEnabled ? onSetDefault : undefined
|
|
111
|
+
}
|
|
112
|
+
disabled={!menuState.setDefaultEnabled}
|
|
113
|
+
>
|
|
114
|
+
<Icon name="StarOutline" width={16} height={16} />
|
|
115
|
+
{t("contracts.actions.setAsDefault")}
|
|
116
|
+
</DropdownItem>
|
|
117
|
+
<BasicDropdownMenu.Separator />
|
|
118
|
+
</>
|
|
110
119
|
)}
|
|
111
|
-
<BasicDropdownMenu.Separator />
|
|
112
120
|
<DropdownItem
|
|
113
121
|
data-fs-bp-dropdown-menu-item-mode="danger"
|
|
114
122
|
disabled={!isRemovable}
|
package/src/features/contracts/components/ContractListItem/__tests__/contractListItemMenu.test.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { getContractMenuState } from "../contractListItemMenu";
|
|
4
|
+
|
|
5
|
+
describe("getContractMenuState", () => {
|
|
6
|
+
it("hides 'Set as default' when the contract is already the default", () => {
|
|
7
|
+
expect(
|
|
8
|
+
getContractMenuState({ isDefault: true, isRemovable: true })
|
|
9
|
+
).toEqual({
|
|
10
|
+
showSetDefault: false,
|
|
11
|
+
setDefaultEnabled: false,
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("shows and enables 'Set as default' for a removable non-default contract", () => {
|
|
16
|
+
expect(
|
|
17
|
+
getContractMenuState({ isDefault: false, isRemovable: true })
|
|
18
|
+
).toEqual({
|
|
19
|
+
showSetDefault: true,
|
|
20
|
+
setDefaultEnabled: true,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("shows but disables 'Set as default' for a legacy (non-attached) contract", () => {
|
|
25
|
+
expect(
|
|
26
|
+
getContractMenuState({ isDefault: undefined, isRemovable: false })
|
|
27
|
+
).toEqual({
|
|
28
|
+
showSetDefault: true,
|
|
29
|
+
setDefaultEnabled: false,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ContractMenuState = {
|
|
2
|
+
/** The default contract never offers "Set as default" (AS-8). */
|
|
3
|
+
showSetDefault: boolean;
|
|
4
|
+
/** Legacy non-attached contracts keep the item visible but disabled. */
|
|
5
|
+
setDefaultEnabled: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const getContractMenuState = ({
|
|
9
|
+
isDefault,
|
|
10
|
+
isRemovable,
|
|
11
|
+
}: {
|
|
12
|
+
isDefault?: boolean;
|
|
13
|
+
isRemovable: boolean;
|
|
14
|
+
}): ContractMenuState => ({
|
|
15
|
+
showSetDefault: !isDefault,
|
|
16
|
+
setDefaultEnabled: !isDefault && isRemovable,
|
|
17
|
+
});
|
package/src/features/contracts/components/ContractSelectionList/ContractSelectionListSkeleton.tsx
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Skeleton } from "@faststore/ui";
|
|
2
|
+
|
|
3
|
+
export type ContractSelectionListSkeletonProps = {
|
|
4
|
+
/** Number of placeholder rows; defaults to a typical page. */
|
|
5
|
+
rows?: number;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Placeholder rows shaped like `ContractListItem`, shown while the listing
|
|
10
|
+
* loads (route transition) or refreshes after adding/removing contracts.
|
|
11
|
+
*/
|
|
12
|
+
export const ContractSelectionListSkeleton = ({
|
|
13
|
+
rows = 4,
|
|
14
|
+
}: ContractSelectionListSkeletonProps) => (
|
|
15
|
+
<div
|
|
16
|
+
data-fs-bp-contract-selection-list
|
|
17
|
+
data-fs-bp-contract-selection-list-skeleton
|
|
18
|
+
aria-busy="true"
|
|
19
|
+
aria-live="polite"
|
|
20
|
+
>
|
|
21
|
+
<div data-fs-bp-contract-selection-list-rows>
|
|
22
|
+
{Array.from({ length: Math.max(rows, 1) }, (_, index) => (
|
|
23
|
+
<div
|
|
24
|
+
data-fs-bp-contract-list-item
|
|
25
|
+
data-fs-bp-contract-list-item-skeleton
|
|
26
|
+
key={`contract-skeleton-${index}`}
|
|
27
|
+
>
|
|
28
|
+
<Skeleton size={{ width: "1.25rem", height: "1.25rem" }} />
|
|
29
|
+
<Skeleton size={{ width: "2rem", height: "2rem" }} />
|
|
30
|
+
<Skeleton size={{ width: "14rem", height: "1.25rem" }} />
|
|
31
|
+
</div>
|
|
32
|
+
))}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useBuyerPortal } from "../../../shared/hooks";
|
|
1
2
|
import { ContractTabsLayout } from "../../../shared/layouts/ContractTabsLayout/ContractTabsLayout";
|
|
2
3
|
import { LoadingTabsLayoutContent } from "../../../shared/layouts/LoadingTabsLayout/LoadingTabsLayout";
|
|
3
4
|
import { useLocalization } from "../../../shared/localization/LocalizationContext";
|
|
@@ -21,6 +22,7 @@ export const ContractSwitchOverlay = ({
|
|
|
21
22
|
contractId,
|
|
22
23
|
}: ContractSwitchOverlayProps) => {
|
|
23
24
|
const { t } = useLocalization();
|
|
25
|
+
const { featureFlags } = useBuyerPortal();
|
|
24
26
|
|
|
25
27
|
return (
|
|
26
28
|
<div data-fs-bp-contract-switch-overlay role="alert" aria-busy="true">
|
|
@@ -32,7 +34,13 @@ export const ContractSwitchOverlay = ({
|
|
|
32
34
|
pageName={t("layouts.tabs.contract")}
|
|
33
35
|
loading
|
|
34
36
|
>
|
|
35
|
-
<LoadingTabsLayoutContent
|
|
37
|
+
<LoadingTabsLayoutContent
|
|
38
|
+
title={t(
|
|
39
|
+
featureFlags?.suma
|
|
40
|
+
? "layouts.navigation.basicInformation"
|
|
41
|
+
: "layouts.titles.profile"
|
|
42
|
+
)}
|
|
43
|
+
/>
|
|
36
44
|
</ContractTabsLayout>
|
|
37
45
|
</div>
|
|
38
46
|
);
|
|
@@ -37,6 +37,7 @@ export const UnableToRemoveContractsDrawer = ({
|
|
|
37
37
|
</p>
|
|
38
38
|
<p>
|
|
39
39
|
{t("contracts.removeDrawer.unableDeselectHint", [
|
|
40
|
+
// eslint-disable-next-line no-restricted-syntax -- legacy hardcoded string, pending migration (see specs/custom-localization-system.md#out-of-scope)
|
|
40
41
|
<strong key="organizationalUnit">organizational unit</strong>,
|
|
41
42
|
])}
|
|
42
43
|
</p>
|
|
@@ -3,6 +3,8 @@ export { ContractListItem } from "./ContractListItem/ContractListItem";
|
|
|
3
3
|
export type { ContractListItemProps } from "./ContractListItem/ContractListItem";
|
|
4
4
|
export { ContractSelectionList } from "./ContractSelectionList/ContractSelectionList";
|
|
5
5
|
export type { ContractSelectionListProps } from "./ContractSelectionList/ContractSelectionList";
|
|
6
|
+
export { ContractSelectionListSkeleton } from "./ContractSelectionList/ContractSelectionListSkeleton";
|
|
7
|
+
export type { ContractSelectionListSkeletonProps } from "./ContractSelectionList/ContractSelectionListSkeleton";
|
|
6
8
|
export { ConfirmRemoveDrawer } from "./ConfirmRemoveDrawer/ConfirmRemoveDrawer";
|
|
7
9
|
export type { ConfirmRemoveDrawerProps } from "./ConfirmRemoveDrawer/ConfirmRemoveDrawer";
|
|
8
10
|
export { ErrorRemoveDrawer } from "./ErrorRemoveDrawer/ErrorRemoveDrawer";
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
|
|
3
|
-
import { buyerPortalRoutes } from "../../shared/utils/buyerPortalRoutes";
|
|
4
3
|
import {
|
|
5
4
|
ContractSwitchError,
|
|
6
5
|
changeContractToken,
|
|
7
6
|
} from "../utils/changeContractToken";
|
|
8
7
|
import { clearPersistedSessionState } from "../utils/clearPersistedSessionState";
|
|
8
|
+
import { resolveSwitchRedirect } from "../utils/resolveSwitchRedirect";
|
|
9
9
|
|
|
10
10
|
import { useContractSwitchChannel } from "./useContractSwitchChannel";
|
|
11
11
|
|
|
12
12
|
export type SwitchContractParams = {
|
|
13
13
|
orgUnitId: string;
|
|
14
|
+
/** Where to land after the switch. Defaults to the contract's Profile page. */
|
|
15
|
+
redirectTo?: string;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export type UseSwitchContractReturn = {
|
|
@@ -28,7 +30,7 @@ export type UseSwitchContractReturn = {
|
|
|
28
30
|
* 1. POST switch-properties with the target contract id and apply the returned auth cookie.
|
|
29
31
|
* 2. Clear persisted host session state.
|
|
30
32
|
* 3. Broadcast to other tabs so they reload under the new context.
|
|
31
|
-
* 4. Full-navigate to the contract's profile page so SSR re-runs with the new cookie.
|
|
33
|
+
* 4. Full-navigate to `redirectTo` (default: the contract's profile page) so SSR re-runs with the new cookie.
|
|
32
34
|
*
|
|
33
35
|
* On failure the previous contract stays active and `switchContract` resolves to `false`.
|
|
34
36
|
*/
|
|
@@ -39,7 +41,7 @@ export function useSwitchContract(): UseSwitchContractReturn {
|
|
|
39
41
|
|
|
40
42
|
const switchContract = async (
|
|
41
43
|
contractId: string,
|
|
42
|
-
{ orgUnitId }: SwitchContractParams
|
|
44
|
+
{ orgUnitId, redirectTo }: SwitchContractParams
|
|
43
45
|
): Promise<boolean> => {
|
|
44
46
|
setLoading(true);
|
|
45
47
|
setError(null);
|
|
@@ -52,7 +54,7 @@ export function useSwitchContract(): UseSwitchContractReturn {
|
|
|
52
54
|
|
|
53
55
|
if (typeof window !== "undefined") {
|
|
54
56
|
window.location.assign(
|
|
55
|
-
|
|
57
|
+
resolveSwitchRedirect({ orgUnitId, contractId, redirectTo })
|
|
56
58
|
);
|
|
57
59
|
}
|
|
58
60
|
|
package/src/features/contracts/layouts/ContractInformationLayout/ContractInformationLayout.tsx
CHANGED
|
@@ -21,6 +21,7 @@ import { ConfirmRemoveDrawer } from "../../components/ConfirmRemoveDrawer/Confir
|
|
|
21
21
|
import { ErrorRemoveDrawer } from "../../components/ErrorRemoveDrawer/ErrorRemoveDrawer";
|
|
22
22
|
import { useContractSwitchChannel, useSetDefaultContract } from "../../hooks";
|
|
23
23
|
import { removeContractService } from "../../services";
|
|
24
|
+
import { pluralSuffixArgs } from "../ContractListingLayout/utils";
|
|
24
25
|
|
|
25
26
|
import type { OrgUnitBasicData } from "../../../org-units/types";
|
|
26
27
|
import type { FeatureFlags } from "../../../shared/components/BuyerPortalProvider/BuyerPortalProvider";
|
|
@@ -125,6 +126,7 @@ export const ContractInformationLayout = ({
|
|
|
125
126
|
const router = useRouter();
|
|
126
127
|
const { broadcast } = useContractSwitchChannel();
|
|
127
128
|
const { featureFlags } = useBuyerPortal();
|
|
129
|
+
const { pushToast } = useUI();
|
|
128
130
|
|
|
129
131
|
const contract = contracts.find((c) => c.id === contractId);
|
|
130
132
|
const isSingleContract = contracts.length <= 1;
|
|
@@ -144,8 +146,12 @@ export const ContractInformationLayout = ({
|
|
|
144
146
|
|
|
145
147
|
const handleRemoveSuccess = useCallback(() => {
|
|
146
148
|
broadcast({ type: "contract-removed", contractId });
|
|
149
|
+
pushToast({
|
|
150
|
+
message: t("contracts.toasts.removeSuccess", pluralSuffixArgs(1)),
|
|
151
|
+
status: "INFO",
|
|
152
|
+
});
|
|
147
153
|
router.push(buyerPortalRoutes.contracts({ orgUnitId: orgUnit.id }));
|
|
148
|
-
}, [broadcast, contractId, orgUnit.id, router]);
|
|
154
|
+
}, [broadcast, contractId, orgUnit.id, router, pushToast, t]);
|
|
149
155
|
|
|
150
156
|
const handleRemoveError = useCallback(() => {
|
|
151
157
|
confirmDrawerProps.close();
|
|
@@ -173,7 +179,6 @@ export const ContractInformationLayout = ({
|
|
|
173
179
|
openConfirmDrawer();
|
|
174
180
|
};
|
|
175
181
|
|
|
176
|
-
const { pushToast } = useUI();
|
|
177
182
|
const { setDefaultContract, isSetDefaultContractLoading } =
|
|
178
183
|
useSetDefaultContract({
|
|
179
184
|
onSuccess: () => {
|
|
@@ -224,7 +229,7 @@ export const ContractInformationLayout = ({
|
|
|
224
229
|
<Link
|
|
225
230
|
href={contractsUrl}
|
|
226
231
|
data-fs-bp-contract-information-back-link
|
|
227
|
-
aria-label="
|
|
232
|
+
aria-label={t("layouts.navigation.contracts")}
|
|
228
233
|
>
|
|
229
234
|
<Icon name="ArrowPointLeft" width={16} height={16} />
|
|
230
235
|
{t("layouts.navigation.contracts")}
|
|
@@ -239,15 +244,7 @@ export const ContractInformationLayout = ({
|
|
|
239
244
|
<Dropdown>
|
|
240
245
|
<BasicDropdownMenu.Trigger />
|
|
241
246
|
<BasicDropdownMenu>
|
|
242
|
-
{contract
|
|
243
|
-
<DropdownItem
|
|
244
|
-
data-fs-bp-contract-information-more-menu-set-default
|
|
245
|
-
disabled
|
|
246
|
-
>
|
|
247
|
-
<Icon name="Star" width={16} height={16} />
|
|
248
|
-
{t("contracts.actions.setAsDefault")}
|
|
249
|
-
</DropdownItem>
|
|
250
|
-
) : (
|
|
247
|
+
{contract && !contract.isDefault && (
|
|
251
248
|
<DropdownItem
|
|
252
249
|
data-fs-bp-contract-information-more-menu-set-default
|
|
253
250
|
onClick={handleSetDefault}
|