@vtex/faststore-plugin-buyer-portal 1.3.64 → 1.3.66
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 +23 -3
- package/package.json +1 -1
- package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +6 -1
- package/src/features/addresses/components/CreateAddressSettingsDrawer/CreateAddressSettingsDrawer.tsx +13 -11
- package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +19 -1
- package/src/features/custom-fields/layouts/CustomFieldsLayout/CustomFieldsLayout.tsx +15 -0
- package/src/features/payment-methods/components/PaymentMethodSettingsDrawer/PaymentMethodSettingsDrawer.tsx +3 -0
- package/src/features/payment-methods/components/RemoveMethodButton/RemoveMethodButton.tsx +4 -1
- package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +30 -1
- package/src/features/payment-methods/layouts/PaymentMethodsLayout/payment-methods-layout.scss +1 -0
- package/src/features/product-assortment/components/CollectionsSettingsDrawer/CollectionsSettingsDrawer.tsx +3 -0
- package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx +8 -2
- package/src/features/product-assortment/components/ProductAssortmentTable/product-assortment-table.scss +43 -37
- package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx +36 -9
- package/src/features/shared/components/BasicDropdownMenu/basic-dropdown-menu.scss +10 -3
- package/src/features/shared/components/CustomField/table/CustomFieldTable.tsx +4 -0
- package/src/features/shared/hooks/useGetScopeConfig.ts +3 -0
- package/src/features/shared/layouts/CustomFieldLayout/CustomFieldLayout.tsx +3 -0
- package/src/features/shared/utils/constants.ts +1 -1
- package/src/features/shared/utils/cookie.ts +7 -9
package/CHANGELOG.md
CHANGED
|
@@ -7,17 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.66] - 2026-02-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Disable "Remove from Unit" actions in sync mode instead of hiding them across Addresses, Payment Methods, Product Assortment, and Custom Fields
|
|
15
|
+
- Fix address settings drawer to allow saving when only changing list type without requiring default address selection
|
|
16
|
+
- Fix automatic UI refresh after switching between Synchronized List and Custom List modes (no F5 needed)
|
|
17
|
+
- Fix stale sync mode state after scope config changes by refetching scope config on updates
|
|
18
|
+
- Fix Product Assortment remove button sizing to remain square when disabled
|
|
19
|
+
|
|
20
|
+
## [1.3.65] - 2026-02-11
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fix cookie encoding on string transformation
|
|
25
|
+
|
|
10
26
|
## [1.3.64] - 2026-02-11
|
|
11
27
|
|
|
12
28
|
### Fixed
|
|
13
|
-
|
|
29
|
+
|
|
30
|
+
- Fix build error on import invalid type in `OrgUnitBreadcrumbDropdown`
|
|
14
31
|
|
|
15
32
|
## [1.3.63] - 2026-02-10
|
|
16
33
|
|
|
17
34
|
### Added
|
|
35
|
+
|
|
18
36
|
- Include `Super Buyer Admin` role validation on mount breadcrumb path
|
|
19
37
|
|
|
20
38
|
### Changed
|
|
39
|
+
|
|
21
40
|
- Remove unused `person` property from Layout components
|
|
22
41
|
|
|
23
42
|
## [1.3.62] - 2026-02-06
|
|
@@ -468,7 +487,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
468
487
|
- Add CHANGELOG file
|
|
469
488
|
- Add README file
|
|
470
489
|
|
|
471
|
-
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/
|
|
490
|
+
[unreleased]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.66...HEAD
|
|
472
491
|
[1.3.55]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.54...v1.3.55
|
|
473
492
|
[1.3.54]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.53...v1.3.54
|
|
474
493
|
[1.3.53]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.52...v1.3.53
|
|
@@ -531,5 +550,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
531
550
|
[1.3.60]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.59...v1.3.60
|
|
532
551
|
[1.3.59]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.58...v1.3.59
|
|
533
552
|
[1.3.58]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.58
|
|
534
|
-
|
|
553
|
+
[1.3.66]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.65...v1.3.66
|
|
554
|
+
[1.3.65]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.64...v1.3.65
|
|
535
555
|
[1.3.64]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.64
|
package/package.json
CHANGED
|
@@ -23,12 +23,14 @@ export type AddressDropdownMenuProps = {
|
|
|
23
23
|
onOpen?: () => void;
|
|
24
24
|
onCreate?: () => void;
|
|
25
25
|
isComplete?: boolean;
|
|
26
|
+
isSyncMode?: boolean;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
export const AddressDropdownMenu = ({
|
|
29
30
|
currentAddress,
|
|
30
31
|
onUpdate,
|
|
31
32
|
onOpen,
|
|
33
|
+
isSyncMode = false,
|
|
32
34
|
}: AddressDropdownMenuProps) => {
|
|
33
35
|
const router = useRouter();
|
|
34
36
|
const { pushToast } = useUI();
|
|
@@ -179,7 +181,10 @@ export const AddressDropdownMenu = ({
|
|
|
179
181
|
)}
|
|
180
182
|
|
|
181
183
|
<BasicDropdownMenu.Separator />
|
|
182
|
-
<DropdownItem
|
|
184
|
+
<DropdownItem
|
|
185
|
+
onClick={openRemoveAddressDrawer}
|
|
186
|
+
data-fs-bp-dropdown-menu-item-disabled={isSyncMode}
|
|
187
|
+
>
|
|
183
188
|
<UIIcon name="MinusCircle" {...sizeProps} />
|
|
184
189
|
Remove from Unit
|
|
185
190
|
</DropdownItem>
|
|
@@ -123,10 +123,6 @@ export const CreateAddressSettingsDrawer = ({
|
|
|
123
123
|
},
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
const isConfirmButtonEnabled = Boolean(
|
|
127
|
-
shippingAddress?.id || billingAddress?.id
|
|
128
|
-
);
|
|
129
|
-
|
|
130
126
|
function getFormData() {
|
|
131
127
|
const data = [];
|
|
132
128
|
if (shippingAddress?.id) {
|
|
@@ -153,12 +149,19 @@ export const CreateAddressSettingsDrawer = ({
|
|
|
153
149
|
type: listType,
|
|
154
150
|
});
|
|
155
151
|
|
|
156
|
-
// Set default addresses
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
// Set default addresses only if at least one is selected
|
|
153
|
+
const formData = getFormData();
|
|
154
|
+
if (formData.length > 0) {
|
|
155
|
+
setDefaultAddresses({
|
|
156
|
+
orgUnitId: router.query.orgUnitId as string,
|
|
157
|
+
customerId: router.query.contractId as string,
|
|
158
|
+
data: formData,
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
// Close drawer and trigger update when only list type changed
|
|
162
|
+
onUpdate?.();
|
|
163
|
+
close();
|
|
164
|
+
}
|
|
162
165
|
};
|
|
163
166
|
|
|
164
167
|
return (
|
|
@@ -170,7 +173,6 @@ export const CreateAddressSettingsDrawer = ({
|
|
|
170
173
|
isPrimaryButtonLoading={
|
|
171
174
|
isSetDefaultAddressesLoading || isSetScopeConfigLoading
|
|
172
175
|
}
|
|
173
|
-
isPrimaryButtonDisabled={!isConfirmButtonEnabled}
|
|
174
176
|
scopeName={SCOPE_KEYS.ADDRESSES}
|
|
175
177
|
onDismiss={close}
|
|
176
178
|
data-fs-bp-create-address-settings-drawer
|
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
import { EmptyState } from "../../../shared/components/EmptyState/EmptyState";
|
|
12
12
|
import { Table } from "../../../shared/components/Table/Table";
|
|
13
13
|
import { getTableColumns } from "../../../shared/components/Table/utils/tableColumns";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
useBuyerPortal,
|
|
16
|
+
useDrawerProps,
|
|
17
|
+
useGetScopeConfig,
|
|
18
|
+
SCOPE_KEYS,
|
|
19
|
+
} from "../../../shared/hooks";
|
|
15
20
|
import { usePageItems } from "../../../shared/hooks/usePageItems";
|
|
16
21
|
import { ContractTabsLayout, GlobalLayout } from "../../../shared/layouts";
|
|
17
22
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
@@ -74,6 +79,7 @@ export const AddressLayout = ({
|
|
|
74
79
|
|
|
75
80
|
const handleRefetchAddresses = () => {
|
|
76
81
|
setIsLoading(true);
|
|
82
|
+
refetchScopeConfig();
|
|
77
83
|
refetchSearchedAddresses();
|
|
78
84
|
};
|
|
79
85
|
|
|
@@ -92,6 +98,17 @@ export const AddressLayout = ({
|
|
|
92
98
|
const { currentOrgUnit: orgUnit, currentContract: contract } =
|
|
93
99
|
useBuyerPortal();
|
|
94
100
|
|
|
101
|
+
const { isSyncMode, refetchScopeConfig } = useGetScopeConfig(
|
|
102
|
+
{
|
|
103
|
+
customerId: router.query.contractId as string,
|
|
104
|
+
unitId: router.query.orgUnitId as string,
|
|
105
|
+
scopeName: SCOPE_KEYS.ADDRESSES,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
lazy: !router.query.contractId || !router.query.orgUnitId,
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
|
|
95
112
|
const columns = getTableColumns({
|
|
96
113
|
nameColumnSize: "18.125rem",
|
|
97
114
|
actionsLength: 2,
|
|
@@ -184,6 +201,7 @@ export const AddressLayout = ({
|
|
|
184
201
|
id,
|
|
185
202
|
...address,
|
|
186
203
|
}}
|
|
204
|
+
isSyncMode={isSyncMode}
|
|
187
205
|
onUpdate={handleRefetchAddresses}
|
|
188
206
|
onOpen={() => {
|
|
189
207
|
const url = buyerPortalRoutes.addressDetails({
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
useBuyerPortal,
|
|
11
11
|
useDebounce,
|
|
12
12
|
useDrawerProps,
|
|
13
|
+
useGetScopeConfig,
|
|
13
14
|
} from "../../../shared/hooks";
|
|
14
15
|
import {
|
|
15
16
|
useAddDefaultValue,
|
|
@@ -63,6 +64,18 @@ export const CustomFieldsLayout = ({
|
|
|
63
64
|
const unitId = orgUnit?.id ?? "";
|
|
64
65
|
const cookie = clientContext?.cookie ?? "";
|
|
65
66
|
const debouncedSearchValue = useDebounce(filter.search, 500);
|
|
67
|
+
const customFieldScopeName = `custom-fields/${customField}`;
|
|
68
|
+
|
|
69
|
+
const { isSyncMode, refetchScopeConfig } = useGetScopeConfig(
|
|
70
|
+
{
|
|
71
|
+
customerId: contractId,
|
|
72
|
+
unitId: unitId,
|
|
73
|
+
scopeName: customFieldScopeName,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
lazy: !contractId || !unitId,
|
|
77
|
+
}
|
|
78
|
+
);
|
|
66
79
|
|
|
67
80
|
useEffect(() => {
|
|
68
81
|
const isNewSearchValue = lastSearchValue.current !== filter.search;
|
|
@@ -188,6 +201,7 @@ export const CustomFieldsLayout = ({
|
|
|
188
201
|
function restartRequest() {
|
|
189
202
|
setIsRefetchingAfterMutation(true);
|
|
190
203
|
setCustomFieldValuesOnUnitScope([]);
|
|
204
|
+
refetchScopeConfig();
|
|
191
205
|
|
|
192
206
|
if (filter.page !== 1) {
|
|
193
207
|
return setFilter((curr) => ({ ...curr, page: 1 }));
|
|
@@ -224,6 +238,7 @@ export const CustomFieldsLayout = ({
|
|
|
224
238
|
data={customFieldValuesOnUnitScope ?? []}
|
|
225
239
|
customFieldlabel={customField}
|
|
226
240
|
isLoading={loadingTable || isRefetchingAfterMutation}
|
|
241
|
+
isSyncMode={isSyncMode}
|
|
227
242
|
onSearch={(value) =>
|
|
228
243
|
setFilter((curr) => ({ ...curr, search: value }))
|
|
229
244
|
}
|
|
@@ -16,6 +16,7 @@ export type PaymentMethodSettingsDrawerProps = Omit<
|
|
|
16
16
|
"children"
|
|
17
17
|
> & {
|
|
18
18
|
readonly?: boolean;
|
|
19
|
+
onUpdate?: () => void;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const PAYMENT_METHOD_LIST_TYPE_OPTIONS =
|
|
@@ -23,6 +24,7 @@ const PAYMENT_METHOD_LIST_TYPE_OPTIONS =
|
|
|
23
24
|
|
|
24
25
|
export const PaymentMethodSettingsDrawer = ({
|
|
25
26
|
close,
|
|
27
|
+
onUpdate,
|
|
26
28
|
...otherProps
|
|
27
29
|
}: PaymentMethodSettingsDrawerProps) => {
|
|
28
30
|
const { pushToast } = useUI();
|
|
@@ -36,6 +38,7 @@ export const PaymentMethodSettingsDrawer = ({
|
|
|
36
38
|
message: "Scope configuration updated successfully",
|
|
37
39
|
status: "INFO",
|
|
38
40
|
});
|
|
41
|
+
onUpdate?.();
|
|
39
42
|
close();
|
|
40
43
|
},
|
|
41
44
|
onError: () => {
|
|
@@ -7,12 +7,14 @@ import { Icon } from "../../../shared/components";
|
|
|
7
7
|
export type RemoveMethodButtonProps = {
|
|
8
8
|
isLoading: boolean;
|
|
9
9
|
disabled: boolean;
|
|
10
|
+
disabledTooltipContent?: string;
|
|
10
11
|
onClick?: () => void;
|
|
11
12
|
} & ComponentProps<"button">;
|
|
12
13
|
|
|
13
14
|
export const RemoveMethodButton = ({
|
|
14
15
|
isLoading,
|
|
15
16
|
disabled,
|
|
17
|
+
disabledTooltipContent,
|
|
16
18
|
onClick,
|
|
17
19
|
...props
|
|
18
20
|
}: RemoveMethodButtonProps) => {
|
|
@@ -22,7 +24,8 @@ export const RemoveMethodButton = ({
|
|
|
22
24
|
placement={disabled ? "left-center" : "top-center"}
|
|
23
25
|
content={
|
|
24
26
|
disabled
|
|
25
|
-
?
|
|
27
|
+
? disabledTooltipContent ??
|
|
28
|
+
"This payment method can't be removed. Each unit must have at least one active payment method. Add another one to proceed with the removal."
|
|
26
29
|
: "Remove from unit"
|
|
27
30
|
}
|
|
28
31
|
>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
|
|
3
|
+
import { useRouter } from "next/router";
|
|
4
|
+
|
|
3
5
|
import {
|
|
4
6
|
HeaderInside,
|
|
5
7
|
InternalSearch,
|
|
@@ -13,6 +15,8 @@ import {
|
|
|
13
15
|
useBuyerPortal,
|
|
14
16
|
useDrawerProps,
|
|
15
17
|
usePageItems,
|
|
18
|
+
useGetScopeConfig,
|
|
19
|
+
SCOPE_KEYS,
|
|
16
20
|
} from "../../../shared/hooks";
|
|
17
21
|
import { ContractTabsLayout, GlobalLayout } from "../../../shared/layouts";
|
|
18
22
|
import {
|
|
@@ -38,6 +42,7 @@ export const PaymentMethodsLayout = ({
|
|
|
38
42
|
totalPaymentMethods,
|
|
39
43
|
page = 1,
|
|
40
44
|
}: PaymentMethodsLayoutProps) => {
|
|
45
|
+
const router = useRouter();
|
|
41
46
|
const [selectedMethod, setSelectedMethod] = useState<
|
|
42
47
|
PaymentMethodData | undefined
|
|
43
48
|
>(undefined);
|
|
@@ -61,6 +66,17 @@ export const PaymentMethodsLayout = ({
|
|
|
61
66
|
page,
|
|
62
67
|
});
|
|
63
68
|
|
|
69
|
+
const { isSyncMode, refetchScopeConfig } = useGetScopeConfig(
|
|
70
|
+
{
|
|
71
|
+
customerId: router.query.contractId as string,
|
|
72
|
+
unitId: router.query.orgUnitId as string,
|
|
73
|
+
scopeName: SCOPE_KEYS.PAYMENT_SYSTEMS,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
lazy: !router.query.contractId || !router.query.orgUnitId,
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
64
80
|
const {
|
|
65
81
|
open: openAddDrawer,
|
|
66
82
|
isOpen: isAddPaymentMethodDrawerOpen,
|
|
@@ -83,6 +99,8 @@ export const PaymentMethodsLayout = ({
|
|
|
83
99
|
useBuyerPortal();
|
|
84
100
|
|
|
85
101
|
const isSinglePaymentMethod = paymentMethods.length <= 1;
|
|
102
|
+
const isRemoveDisabled =
|
|
103
|
+
isSyncMode || isSinglePaymentMethod || isRemovingPaymentMethod;
|
|
86
104
|
const allPaymentMethodsSelected =
|
|
87
105
|
paymentMethods.length === totalPaymentMethods;
|
|
88
106
|
|
|
@@ -105,6 +123,11 @@ export const PaymentMethodsLayout = ({
|
|
|
105
123
|
/>
|
|
106
124
|
);
|
|
107
125
|
|
|
126
|
+
const handleScopeConfigUpdate = () => {
|
|
127
|
+
refetchScopeConfig();
|
|
128
|
+
router.replace(router.asPath);
|
|
129
|
+
};
|
|
130
|
+
|
|
108
131
|
const renderTableRows = () =>
|
|
109
132
|
paymentMethods.map((method) => (
|
|
110
133
|
<Table.Row
|
|
@@ -117,7 +140,12 @@ export const PaymentMethodsLayout = ({
|
|
|
117
140
|
<RemoveMethodButton
|
|
118
141
|
isLoading={isRemovingPaymentMethod}
|
|
119
142
|
onClick={() => onRemoveClick(method)}
|
|
120
|
-
disabled={
|
|
143
|
+
disabled={isRemoveDisabled}
|
|
144
|
+
disabledTooltipContent={
|
|
145
|
+
isSyncMode
|
|
146
|
+
? "Cannot remove items while using synchronized list"
|
|
147
|
+
: undefined
|
|
148
|
+
}
|
|
121
149
|
/>
|
|
122
150
|
}
|
|
123
151
|
/>
|
|
@@ -234,6 +262,7 @@ export const PaymentMethodsLayout = ({
|
|
|
234
262
|
{isPaymentMethodSettingsDrawerOpen && (
|
|
235
263
|
<PaymentMethodSettingsDrawer
|
|
236
264
|
isOpen={isPaymentMethodSettingsDrawerOpen}
|
|
265
|
+
onUpdate={handleScopeConfigUpdate}
|
|
237
266
|
{...paymentMethodSettingsDrawerProps}
|
|
238
267
|
/>
|
|
239
268
|
)}
|
|
@@ -16,12 +16,14 @@ export type CollectionsSettingsDrawerProps = Omit<
|
|
|
16
16
|
"children"
|
|
17
17
|
> & {
|
|
18
18
|
readonly?: boolean;
|
|
19
|
+
onUpdate?: () => void;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const COLLECTIONS_LIST_TYPE_OPTIONS = createListTypeOptions("collections");
|
|
22
23
|
|
|
23
24
|
export const CollectionsSettingsDrawer = ({
|
|
24
25
|
close,
|
|
26
|
+
onUpdate,
|
|
25
27
|
...otherProps
|
|
26
28
|
}: CollectionsSettingsDrawerProps) => {
|
|
27
29
|
const { pushToast } = useUI();
|
|
@@ -35,6 +37,7 @@ export const CollectionsSettingsDrawer = ({
|
|
|
35
37
|
message: "Scope configuration updated successfully",
|
|
36
38
|
status: "INFO",
|
|
37
39
|
});
|
|
40
|
+
onUpdate?.();
|
|
38
41
|
close();
|
|
39
42
|
},
|
|
40
43
|
onError: () => {
|
package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx
CHANGED
|
@@ -16,8 +16,10 @@ import type {
|
|
|
16
16
|
|
|
17
17
|
export function ProductAssortmentTable({
|
|
18
18
|
productAssortment,
|
|
19
|
+
isSyncMode = false,
|
|
19
20
|
}: {
|
|
20
21
|
productAssortment: ProductAssortmentWithAdditionalInformation[];
|
|
22
|
+
isSyncMode?: boolean;
|
|
21
23
|
}) {
|
|
22
24
|
const [assortmentSelected, setAssortmentSelected] =
|
|
23
25
|
useState<ProductAssortmentSelectedProps | null>();
|
|
@@ -66,14 +68,18 @@ export function ProductAssortmentTable({
|
|
|
66
68
|
searchTerm={searchTerm ?? undefined}
|
|
67
69
|
actionIcons={
|
|
68
70
|
<Tooltip
|
|
69
|
-
content={
|
|
71
|
+
content={
|
|
72
|
+
isSyncMode
|
|
73
|
+
? "Cannot remove items while using synchronized list"
|
|
74
|
+
: removeTooltipContent
|
|
75
|
+
}
|
|
70
76
|
placement={"left-center"}
|
|
71
77
|
>
|
|
72
78
|
<IconButton
|
|
73
79
|
data-fs-product-assortment-row-action-button
|
|
74
80
|
icon={<Icon name={"MinusCircle"} width={20} height={20} />}
|
|
75
81
|
aria-label="Remove product assortment"
|
|
76
|
-
disabled={removeDisabled}
|
|
82
|
+
disabled={isSyncMode || removeDisabled}
|
|
77
83
|
onClick={() =>
|
|
78
84
|
handleRemoveSelectedAssortment({
|
|
79
85
|
id: item.id,
|
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
[data-fs-bp-product-assortment-table] {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
@import "@faststore/ui/src/components/molecules/Tooltip/styles.scss";
|
|
3
|
+
@import "../AddProductAssortmentDrawer/add-product-assortment-drawer.scss";
|
|
4
|
+
@import "../../../shared/components/Table/table.scss";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
width: 100%;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
[data-fs-tooltip] {
|
|
9
|
+
--fs-tooltip-background: #1f1f1f;
|
|
10
|
+
border-bottom: none;
|
|
11
|
+
text-wrap: balance;
|
|
12
|
+
text-align: justify;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
[data-fs-tooltip-placement="left-center"] {
|
|
15
|
+
[data-fs-tooltip-indicator="true"] {
|
|
16
|
+
margin-left: -0.1%;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
[data-fs-tooltip-placement="top-center"] {
|
|
20
|
+
[data-fs-tooltip-indicator="true"] {
|
|
21
|
+
margin-top: -1%;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
[data-fs-product-assortment-row-action-button] {
|
|
27
|
+
width: var(--fs-spacing-6);
|
|
28
|
+
height: var(--fs-spacing-6);
|
|
29
|
+
padding: 0;
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
border-radius: var(--fs-border-radius-pill);
|
|
32
|
+
justify-content: center;
|
|
33
|
+
align-items: center;
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
&:hover:not(:disabled) {
|
|
36
|
+
background-color: #ebebeb;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
&:disabled {
|
|
41
|
+
opacity: 0.4;
|
|
42
|
+
cursor: not-allowed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[data-fs-button-icon] {
|
|
46
|
+
display: block;
|
|
47
|
+
width: calc(var(--fs-spacing-4) - var(--fs-spacing-0));
|
|
48
|
+
height: calc(var(--fs-spacing-4) - var(--fs-spacing-0));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
45
51
|
}
|
package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
useBuyerPortal,
|
|
13
13
|
useDrawerProps,
|
|
14
14
|
usePageItems,
|
|
15
|
+
useGetScopeConfig,
|
|
16
|
+
SCOPE_KEYS,
|
|
15
17
|
} from "../../../shared/hooks";
|
|
16
18
|
import { ContractTabsLayout, GlobalLayout } from "../../../shared/layouts";
|
|
17
19
|
import {
|
|
@@ -36,7 +38,21 @@ export const ProductAssortmentLayout = ({
|
|
|
36
38
|
const { currentOrgUnit: orgUnit, currentContract: contract } =
|
|
37
39
|
useBuyerPortal();
|
|
38
40
|
|
|
39
|
-
const {
|
|
41
|
+
const { isSyncMode, refetchScopeConfig } = useGetScopeConfig(
|
|
42
|
+
{
|
|
43
|
+
customerId: contractId ?? "",
|
|
44
|
+
unitId: orgUnitId ?? "",
|
|
45
|
+
scopeName: SCOPE_KEYS.COLLECTIONS,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
lazy: !contractId || !orgUnitId,
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
data: drawerProductAssortment,
|
|
54
|
+
refetchProductAssortment: refetchDrawerAssortment,
|
|
55
|
+
} = useGetProductAssortment({
|
|
40
56
|
contractId,
|
|
41
57
|
orgUnitId,
|
|
42
58
|
});
|
|
@@ -44,14 +60,23 @@ export const ProductAssortmentLayout = ({
|
|
|
44
60
|
contractId,
|
|
45
61
|
orgUnitId,
|
|
46
62
|
});
|
|
47
|
-
const {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
const {
|
|
64
|
+
data: initialProductAssortment,
|
|
65
|
+
isProductAssortmentLoading,
|
|
66
|
+
refetchProductAssortment,
|
|
67
|
+
} = useGetProductAssortment({
|
|
68
|
+
filterByScope: true,
|
|
69
|
+
contractId,
|
|
70
|
+
orgUnitId,
|
|
71
|
+
search,
|
|
72
|
+
page,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const handleScopeConfigUpdate = () => {
|
|
76
|
+
refetchScopeConfig();
|
|
77
|
+
refetchProductAssortment();
|
|
78
|
+
refetchDrawerAssortment();
|
|
79
|
+
};
|
|
55
80
|
|
|
56
81
|
const isContractEmpty = !contractAssortment || contractAssortment.total === 0;
|
|
57
82
|
|
|
@@ -178,6 +203,7 @@ export const ProductAssortmentLayout = ({
|
|
|
178
203
|
<section>
|
|
179
204
|
<ProductAssortmentTable
|
|
180
205
|
productAssortment={productAssortment}
|
|
206
|
+
isSyncMode={isSyncMode}
|
|
181
207
|
/>
|
|
182
208
|
|
|
183
209
|
<div data-fs-bp-product-assortment-paginator>
|
|
@@ -231,6 +257,7 @@ export const ProductAssortmentLayout = ({
|
|
|
231
257
|
{isCollectionsSettingsDrawerOpen && (
|
|
232
258
|
<CollectionsSettingsDrawer
|
|
233
259
|
isOpen={isCollectionsSettingsDrawerOpen}
|
|
260
|
+
onUpdate={handleScopeConfigUpdate}
|
|
234
261
|
{...collectionsSettingsDrawerProps}
|
|
235
262
|
/>
|
|
236
263
|
)}
|
|
@@ -11,15 +11,16 @@
|
|
|
11
11
|
&:hover {
|
|
12
12
|
background-color: var(--fs-bp-color-transparent-0);
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
&:active,
|
|
14
|
+
|
|
15
|
+
&:active,
|
|
16
|
+
&[aria-expanded="true"] {
|
|
16
17
|
background-color: var(--fs-bp-color-transparent-1);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
[data-fs-dropdown-menu] {
|
|
21
22
|
&[data-fs-bp-basic-dropdown-menu] {
|
|
22
|
-
|
|
23
|
+
--fs-dropdown-menu-box-shadow: var(--fs-bp-elevation-dropdown);
|
|
23
24
|
width: auto;
|
|
24
25
|
background-color: #fff;
|
|
25
26
|
padding: var(--fs-spacing-1) 0;
|
|
@@ -53,6 +54,12 @@
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
&[data-fs-bp-dropdown-menu-item-disabled="true"] {
|
|
58
|
+
opacity: 0.4;
|
|
59
|
+
cursor: not-allowed;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
&[data-fs-bp-dropdown-menu-item-mode="danger"] {
|
|
57
64
|
color: #d31a15;
|
|
58
65
|
|
|
@@ -32,6 +32,7 @@ interface CustomFieldTableProps {
|
|
|
32
32
|
data: CustomFieldData[];
|
|
33
33
|
actions: TableActions;
|
|
34
34
|
searchTerm?: string;
|
|
35
|
+
isSyncMode?: boolean;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export const CustomFieldTable = ({
|
|
@@ -40,6 +41,7 @@ export const CustomFieldTable = ({
|
|
|
40
41
|
loading,
|
|
41
42
|
actions,
|
|
42
43
|
searchTerm,
|
|
44
|
+
isSyncMode = false,
|
|
43
45
|
}: CustomFieldTableProps) => {
|
|
44
46
|
const { pushToast } = useUI();
|
|
45
47
|
|
|
@@ -122,9 +124,11 @@ export const CustomFieldTable = ({
|
|
|
122
124
|
actions.itemToSelect(option);
|
|
123
125
|
actions.isOnlyDeleting(false);
|
|
124
126
|
}}
|
|
127
|
+
data-fs-bp-dropdown-menu-item-disabled={isSyncMode}
|
|
125
128
|
>
|
|
126
129
|
<Icon name="CircleRemove" /> <span>Remove from unit</span>
|
|
127
130
|
</DropdownItem>
|
|
131
|
+
<BasicDropdownMenu.Separator />
|
|
128
132
|
<DropdownItem
|
|
129
133
|
data-fs-bp-dropdown-menu-item-mode="danger"
|
|
130
134
|
onClick={() => {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
export interface CustomFieldLayoutProps {
|
|
14
14
|
data: CustomFieldData[];
|
|
15
15
|
isLoading?: boolean;
|
|
16
|
+
isSyncMode?: boolean;
|
|
16
17
|
tableActions: TableActions;
|
|
17
18
|
customFieldlabel: string;
|
|
18
19
|
pagination: {
|
|
@@ -27,6 +28,7 @@ export interface CustomFieldLayoutProps {
|
|
|
27
28
|
export const CustomFieldLayout = ({
|
|
28
29
|
data,
|
|
29
30
|
isLoading,
|
|
31
|
+
isSyncMode = false,
|
|
30
32
|
tableActions,
|
|
31
33
|
customFieldlabel,
|
|
32
34
|
pagination,
|
|
@@ -88,6 +90,7 @@ export const CustomFieldLayout = ({
|
|
|
88
90
|
actions={tableActions}
|
|
89
91
|
loading={isLoading}
|
|
90
92
|
searchTerm={searchValue}
|
|
93
|
+
isSyncMode={isSyncMode}
|
|
91
94
|
/>
|
|
92
95
|
<Pagination
|
|
93
96
|
data-fs-bp-custom-field-bottom-pagination
|
|
@@ -36,7 +36,7 @@ export function getCookieWithoutSessionObjects(cookie: string) {
|
|
|
36
36
|
const newCookie: Record<string, string> = {};
|
|
37
37
|
|
|
38
38
|
for (const key in mappedCookie) {
|
|
39
|
-
if (!valuesToRemove.includes(key)) {
|
|
39
|
+
if (!valuesToRemove.includes(key.toLocaleLowerCase())) {
|
|
40
40
|
newCookie[key] = mappedCookie[key];
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -80,14 +80,12 @@ export function getUserIdFromCookieServerSide(data: LoaderData): string {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
export function getCookieAsString(cookie: Record<string, string>): string {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
.replace(/,/g, ";") ?? ""
|
|
90
|
-
);
|
|
83
|
+
let cookieString = "";
|
|
84
|
+
Object.keys(cookie).forEach((cookieKey) => {
|
|
85
|
+
cookieString += `${cookieKey}=${encodeURIComponent(cookie[cookieKey])};`;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return cookieString.slice(0, cookieString.length - 1);
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
function parseJwt(token: string): ParsedCookie {
|