@shopgate/engage 7.32.0-beta.14 → 7.32.0-beta.16

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 (80) hide show
  1. package/cart/components/CartItem/CartItemQuantityPicker.js +1 -1
  2. package/components/Badge/Badge.d.ts.map +1 -1
  3. package/components/Badge/Badge.js +1 -0
  4. package/components/index.d.ts +1 -0
  5. package/components/index.d.ts.map +1 -1
  6. package/components/index.js +3 -1
  7. package/components/v2/IconButton/IconButton.d.ts +72 -0
  8. package/components/v2/IconButton/IconButton.d.ts.map +1 -0
  9. package/components/v2/IconButton/IconButton.js +169 -0
  10. package/components/v2/IconButton/index.d.ts +3 -0
  11. package/components/v2/IconButton/index.d.ts.map +1 -0
  12. package/components/v2/IconButton/index.js +1 -0
  13. package/components/v2/index.d.ts +1 -0
  14. package/components/v2/index.d.ts.map +1 -1
  15. package/components/v2/index.js +1 -0
  16. package/filter/components/FilterItem/index.js +9 -2
  17. package/filter/components/FilterPageContent/components/ApplyButton/index.d.ts +21 -0
  18. package/filter/components/FilterPageContent/components/ApplyButton/index.d.ts.map +1 -0
  19. package/filter/components/FilterPageContent/components/ApplyButton/index.js +25 -52
  20. package/filter/components/FilterPageContent/components/FilterButtonBar/index.d.ts +8 -0
  21. package/filter/components/FilterPageContent/components/FilterButtonBar/index.d.ts.map +1 -0
  22. package/filter/components/FilterPageContent/components/FilterButtonBar/index.js +63 -0
  23. package/filter/components/FilterPageContent/components/ResetButton/index.d.ts +17 -0
  24. package/filter/components/FilterPageContent/components/ResetButton/index.d.ts.map +1 -0
  25. package/filter/components/FilterPageContent/components/ResetButton/index.js +24 -46
  26. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.d.ts +19 -0
  27. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.d.ts.map +1 -0
  28. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.js +25 -46
  29. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.d.ts +14 -0
  30. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.d.ts.map +1 -0
  31. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.js +13 -46
  32. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.d.ts +25 -0
  33. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.d.ts.map +1 -0
  34. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.js +77 -0
  35. package/filter/components/FilterPageContent/components/Selector/index.d.ts +43 -0
  36. package/filter/components/FilterPageContent/components/Selector/index.d.ts.map +1 -0
  37. package/filter/components/FilterPageContent/components/Selector/index.js +52 -40
  38. package/filter/components/FilterPageContent/index.d.ts +16 -0
  39. package/filter/components/FilterPageContent/index.d.ts.map +1 -0
  40. package/filter/components/FilterPageContent/index.js +51 -57
  41. package/filter/components/PriceSlider/components/Label/index.js +69 -94
  42. package/filter/components/PriceSlider/index.js +43 -33
  43. package/filter/helpers/buildFilterParamsForFetchFiltersRequest.d.ts +8 -0
  44. package/filter/helpers/buildFilterParamsForFetchFiltersRequest.d.ts.map +1 -0
  45. package/filter/helpers/buildInitialFilters.d.ts +7 -0
  46. package/filter/helpers/buildInitialFilters.d.ts.map +1 -0
  47. package/filter/helpers/buildUpdatedFilters.d.ts +7 -0
  48. package/filter/helpers/buildUpdatedFilters.d.ts.map +1 -0
  49. package/filter/helpers/index.d.ts +5 -0
  50. package/filter/helpers/index.d.ts.map +1 -0
  51. package/filter/helpers/translateFilterLabel.d.ts +8 -0
  52. package/filter/helpers/translateFilterLabel.d.ts.map +1 -0
  53. package/filter/providers/FilterPageProvider.context.d.ts +157 -0
  54. package/filter/providers/FilterPageProvider.context.d.ts.map +1 -0
  55. package/filter/providers/FilterPageProvider.d.ts +24 -0
  56. package/filter/providers/FilterPageProvider.d.ts.map +1 -0
  57. package/filter/providers/FilterPageProvider.js +77 -132
  58. package/locations/components/GlobalLocationSwitcher/GlobalLocationSwitcherBar.js +4 -2
  59. package/package.json +7 -7
  60. package/page/widgets/CategoryList/CategoryList.js +2 -1
  61. package/product/components/FilterBar/components/Content/components/FilterButton/index.js +38 -46
  62. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.d.ts +38 -0
  63. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.d.ts.map +1 -0
  64. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.js +88 -0
  65. package/product/components/FilterBar/components/Content/components/FilterChips/index.js +54 -35
  66. package/product/components/FilterBar/components/Content/components/Sort/index.js +1 -1
  67. package/product/components/FilterBar/components/Content/index.js +7 -3
  68. package/product/components/FilterBar/index.js +11 -22
  69. package/product/components/ProductFilters/index.js +2 -6
  70. package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/index.js +0 -1
  71. package/product/components/ProductGridPrice/index.js +1 -1
  72. package/settings/reducers/appSettings.js +1 -1
  73. package/styles/theme/createDefaultThemeOptions/index.d.ts +11 -1
  74. package/styles/theme/createDefaultThemeOptions/index.d.ts.map +1 -1
  75. package/styles/theme/createDefaultThemeOptions/index.js +17 -5
  76. package/styles/theme/createTheme/createComponents.types.d.ts +27 -0
  77. package/styles/theme/createTheme/createComponents.types.d.ts.map +1 -1
  78. package/styles/theme/createTheme/createComponents.types.js +31 -4
  79. package/filter/components/FilterPageContent/components/Selector/components/ValueButton/index.js +0 -69
  80. package/product/components/FilterBar/components/Content/components/FilterChips/connector.js +0 -22
@@ -0,0 +1,157 @@
1
+ export default context;
2
+ export type APIFilterValue = {
3
+ /**
4
+ * Filter value id
5
+ */
6
+ id: string;
7
+ /**
8
+ * Filter value label
9
+ */
10
+ label: string;
11
+ /**
12
+ * Number of hits for the filter value
13
+ */
14
+ hits: number;
15
+ };
16
+ export type APIFilter = {
17
+ /**
18
+ * Filter id
19
+ */
20
+ id: string;
21
+ /**
22
+ * Filter label
23
+ */
24
+ label: string;
25
+ /**
26
+ * Filter type
27
+ */
28
+ type: "range" | "multiselect" | "single_select";
29
+ /**
30
+ * Filter source
31
+ */
32
+ source?: string | undefined;
33
+ /**
34
+ * Minimum value for a range filter
35
+ */
36
+ minimum?: number | undefined;
37
+ /**
38
+ * Maximum value for a range filter
39
+ */
40
+ maximum?: number | undefined;
41
+ values: APIFilterValue[];
42
+ };
43
+ export type RouteFilterValue = {
44
+ /**
45
+ * Filter value id
46
+ */
47
+ id: string;
48
+ /**
49
+ * Filter value label
50
+ */
51
+ label: string;
52
+ };
53
+ export type RouteFilter = {
54
+ /**
55
+ * Filter id
56
+ */
57
+ id: string;
58
+ /**
59
+ * Filter label
60
+ */
61
+ label: string;
62
+ /**
63
+ * Filter source
64
+ */
65
+ source: string;
66
+ /**
67
+ * Filter type
68
+ */
69
+ type: "range" | "multiselect" | "single_select";
70
+ /**
71
+ * Selected values for the filter
72
+ */
73
+ values: RouteFilterValue[];
74
+ };
75
+ /**
76
+ * Object with the active filters for a route with filtered product list
77
+ */
78
+ export type RouteFilters = {
79
+ [x: string]: RouteFilter;
80
+ };
81
+ export type GetSelectedFilterValuesFn = (filterId: string) => any;
82
+ export type UpdateSelectedFilterValuesFn = (filterId: string, selectedValues: string[]) => void;
83
+ export type FilterPageContext = {
84
+ /**
85
+ * Whether the filter selection has changed since the filters page
86
+ * was opened
87
+ */
88
+ hasChanged: boolean;
89
+ /**
90
+ * Whether a reset of the active filters is possible
91
+ */
92
+ resetPossible: boolean;
93
+ /**
94
+ * List of available filters from the API
95
+ */
96
+ apiFilters: APIFilter[];
97
+ /**
98
+ * Object that represents the current state of all filters
99
+ */
100
+ filters: RouteFilters;
101
+ /**
102
+ * Resets all filters which have been changed by the
103
+ * user
104
+ */
105
+ resetAllFilters: () => void;
106
+ /**
107
+ * Resets all filters which have been changed by the
108
+ * user since the filters page was opened
109
+ */
110
+ resetChangedFilters: () => void;
111
+ /**
112
+ * Applies the current filter selection to the parent route
113
+ * with a product list to be filtered
114
+ */
115
+ applyFilters: () => void;
116
+ /**
117
+ * Retrieves a list of currently
118
+ * selected values for a filter
119
+ */
120
+ getSelectedFilterValues: GetSelectedFilterValuesFn;
121
+ /**
122
+ * Updates the selection for a
123
+ * filter
124
+ */
125
+ updateSelectedFilterValues: UpdateSelectedFilterValuesFn;
126
+ };
127
+ /**
128
+ * @callback GetSelectedFilterValuesFn
129
+ * @param {string} filterId The id of the filter
130
+ */
131
+ /**
132
+ * @callback UpdateSelectedFilterValuesFn
133
+ * @param {string} filterId The id of the filter to be updated
134
+ * @param {string[]} selectedValues The updated selected values
135
+ * @returns {void}
136
+ */
137
+ /**
138
+ * @typedef {Object} FilterPageContext
139
+ * @property {boolean} hasChanged Whether the filter selection has changed since the filters page
140
+ * was opened
141
+ * @property {boolean} resetPossible Whether a reset of the active filters is possible
142
+ * @property {APIFilter[]} apiFilters List of available filters from the API
143
+ * @property {RouteFilters} filters Object that represents the current state of all filters
144
+ * @property {function():void} resetAllFilters Resets all filters which have been changed by the
145
+ * user
146
+ * @property {function():void} resetChangedFilters Resets all filters which have been changed by the
147
+ * user since the filters page was opened
148
+ * @property {function():void} applyFilters Applies the current filter selection to the parent route
149
+ * with a product list to be filtered
150
+ * @property {GetSelectedFilterValuesFn} getSelectedFilterValues Retrieves a list of currently
151
+ * selected values for a filter
152
+ * @property {UpdateSelectedFilterValuesFn} updateSelectedFilterValues Updates the selection for a
153
+ * filter
154
+ */
155
+ /** @type {import('react').Context<FilterPageContext>} */
156
+ declare const context: import("react").Context<FilterPageContext>;
157
+ //# sourceMappingURL=FilterPageProvider.context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterPageProvider.context.d.ts","sourceRoot":"","sources":["../../../filter/providers/FilterPageProvider.context.js"],"names":[],"mappings":";;;;;QAKc,MAAM;;;;WACN,MAAM;;;;UACN,MAAM;;;;;;QAMN,MAAM;;;;WACN,MAAM;;;;UACN,OAAO,GAAC,aAAa,GAAC,eAAe;;;;;;;;;;;;;YAIrC,cAAc,EAAE;;;;;;QAMhB,MAAM;;;;WACN,MAAM;;;;;;QAKN,MAAM;;;;WACN,MAAM;;;;YACN,MAAM;;;;UACN,OAAO,GAAC,aAAa,GAAC,eAAe;;;;YACrC,gBAAgB,EAAE;;;;;;;;mDAWrB,MAAM;sDAKN,MAAM,kBACN,MAAM,EAAE,KACN,IAAI;;;;;;gBAIH,OAAO;;;;mBAEP,OAAO;;;;gBACP,SAAS,EAAE;;;;aACX,YAAY;;;;;qBACZ,MAAW,IAAI;;;;;yBAEf,MAAW,IAAI;;;;;kBAEf,MAAW,IAAI;;;;;6BAEf,yBAAyB;;;;;gCAEzB,4BAA4B;;AA1B1C;;;GAGG;AAEH;;;;;GAKG;AACH;;;;;;;;;;;;;;;;;GAiBG;AAEH,yDAAyD;AACzD,uBADW,OAAO,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAWlD"}
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { APIFilter, RouteFilters } from './FilterPageProvider.context';
3
+ interface FilterPageProviderProps {
4
+ /** Array of available filters, injected from Redux. */
5
+ filters?: APIFilter[] | null;
6
+ /** Object with the active filters for a filtered product list. */
7
+ activeFilters?: RouteFilters | null;
8
+ /** Id of the route with the product list that's supposed to be filtered. */
9
+ parentRouteId?: string | null;
10
+ /** Callback invoked when users pressed the apply button. */
11
+ onApply?: (filters: RouteFilters | null) => void;
12
+ /** Provider children. */
13
+ children?: ReactNode;
14
+ }
15
+ declare const _default: import("react-redux").ConnectedComponent<({ filters: filtersProp, activeFilters: activeFiltersProp, parentRouteId, onApply, children, }: FilterPageProviderProps) => import("react").JSX.Element, {
16
+ children?: ReactNode;
17
+ activeFilters?: (RouteFilters | null) | undefined;
18
+ parentRouteId?: string | null | undefined;
19
+ onApply?: ((filters: RouteFilters | null) => void) | undefined;
20
+ context?: import("react-redux/es/components/Context").ReactReduxContextInstance | undefined;
21
+ store?: import("redux").Store | undefined;
22
+ }>;
23
+ export default _default;
24
+ //# sourceMappingURL=FilterPageProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterPageProvider.d.ts","sourceRoot":"","sources":["../../../filter/providers/FilterPageProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAkB,SAAS,EAAE,MAAM,OAAO,CAAC;AASvD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAyC5E,UAAU,uBAAuB;IAC/B,uDAAuD;IACvD,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC7B,kEAAkE;IAClE,aAAa,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,yBAAyB;IACzB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;iKAoCE,uBAAuB;;qBA3CR,YAAY,GAAG,IAAI;oBAEnB,MAAM,GAAG,IAAI;eAEnB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI;;;;AAiQlD,wBAKsB"}
@@ -1,28 +1,40 @@
1
- import React, { useMemo, useState, useEffect, useCallback } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import "core-js/modules/es.array.includes.js";
2
+ import "core-js/modules/es.string.replace.js";
3
+ import { useMemo, useState, useEffect, useCallback } from 'react';
3
4
  import { connect } from 'react-redux';
4
5
  import debounce from 'lodash/debounce';
5
6
  import isEqual from 'lodash/isEqual';
6
7
  import { router } from '@shopgate/engage/core';
8
+ import { useRoute } from '@shopgate/engage/core/hooks';
9
+ import { parseObjectToQueryString } from '@shopgate/engage/core/helpers';
7
10
  import { getFiltersByHash } from '@shopgate/engage/filter';
8
- // eslint-disable-next-line no-unused-vars, import/named
9
- import Context, { APIFilter, RouteFilters } from "./FilterPageProvider.context";
11
+ import Context from "./FilterPageProvider.context";
10
12
  import { buildInitialFilters, buildUpdatedFilters } from "../helpers";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ const FILTER_PATH_SUFFIX = '/filter';
11
15
 
12
16
  /**
13
- * @param {Object} state The application state.
14
- * @param {Object} props The component props.
15
- * @returns {Object}
17
+ * A single stored filter value carrying id and label.
18
+ */
19
+
20
+ /**
21
+ * A filter as kept in the provider's internal state. `value` holds either the selected values of a
22
+ * list filter or the `[min, max]` tuple of a range filter.
23
+ */
24
+
25
+ const buildInitialFiltersTyped = buildInitialFilters;
26
+ const buildUpdatedFiltersTyped = buildUpdatedFilters;
27
+ /**
28
+ * Maps the available filters from the application state onto the provider props.
29
+ * @returns The mapped state props.
16
30
  */
17
- import { jsx as _jsx } from "react/jsx-runtime";
18
31
  const mapStateToProps = (state, props) => ({
19
32
  filters: getFiltersByHash(state, props)
20
33
  });
21
34
 
22
35
  /**
23
- * @param {Object} next The next component props.
24
- * @param {Object} prev The previous component props.
25
- * @returns {boolean}
36
+ * Compares the mapped state props to decide whether the connected component needs to re-render.
37
+ * @returns Whether the state props are considered equal.
26
38
  */
27
39
  const areStatePropsEqual = (next, prev) => {
28
40
  if (!prev.filters && next.filters || !isEqual(prev.filters, next.filters)) {
@@ -34,25 +46,19 @@ const areStatePropsEqual = (next, prev) => {
34
46
  /**
35
47
  * The FilterPageProvider component provides all relevant data and callbacks to represent and modify
36
48
  * the current state of the "filter" page.
37
- * @param {Object} props Provider props
38
- * @param {APIFilter[]} props.filters Array of available filters
39
- * @param {RouteFilters} props.activeFilters Object with the active filters for a filtered product
40
- * list
41
- * @param {string} props.parentRouteId Id of the route with the product list that's supposed to be
42
- * filtered
43
- * @param {Function} [props.onApply] Callback invoked when users pressed the apply button
44
- * @param {string} [props.categoryId] A category to be used for filter selection from Redux
45
- * @param {string} [props.searchPhrase] A search phrase to be used for filter selection from Redux
46
- * @param {NodeList} children Provider children
47
- * @returns {JSX.Element}
49
+ * @returns The rendered component.
48
50
  */
49
51
  const FilterPageProvider = ({
50
- filters: filtersProp,
51
- activeFilters: activeFiltersProp,
52
- parentRouteId,
53
- onApply,
54
- children
52
+ filters: filtersProp = null,
53
+ activeFilters: activeFiltersProp = null,
54
+ parentRouteId = null,
55
+ onApply = () => setTimeout(router.pop, 250),
56
+ children = null
55
57
  }) => {
58
+ const {
59
+ pathname,
60
+ query
61
+ } = useRoute();
56
62
  const [currentFilters, setCurrentFilters] = useState(activeFiltersProp || {});
57
63
 
58
64
  /**
@@ -60,7 +66,7 @@ const FilterPageProvider = ({
60
66
  * It's created from the "filters" array that contains all available filters, and the
61
67
  * "activeFilters" object that represents filters with an active value selection.
62
68
  */
63
- const [initialFilters, setInitialFilters] = useState(buildInitialFilters(filtersProp, activeFiltersProp));
69
+ const [initialFilters, setInitialFilters] = useState(buildInitialFiltersTyped(filtersProp, activeFiltersProp));
64
70
 
65
71
  /**
66
72
  * Storage that hosts an object that represents the a partial state of the filters page with
@@ -82,7 +88,7 @@ const FilterPageProvider = ({
82
88
  if (Object.keys(currentState).length > 0) {
83
89
  return currentState;
84
90
  }
85
- return buildInitialFilters(filtersProp, activeFiltersProp);
91
+ return buildInitialFiltersTyped(filtersProp, activeFiltersProp);
86
92
  });
87
93
  }, [activeFiltersProp, filtersProp]);
88
94
 
@@ -91,37 +97,23 @@ const FilterPageProvider = ({
91
97
  *
92
98
  * Reset is possible whenever filters where selected by the user before, or when filters where
93
99
  * modified since the filters page was opened.
94
- * @type {boolean}
95
100
  */
96
101
  const resetPossible = useMemo(() => !!(Object.keys(currentFilters).length || Object.keys(changedFilters).length), [changedFilters, currentFilters]);
97
102
 
98
103
  /**
99
104
  * Whether the filter selection has changed since the filters page was opened
100
- * @type {boolean}
101
105
  */
102
106
  const hasChanged = useMemo(() => Object.keys(changedFilters).length > 0 || !!(Object.keys(currentFilters).length === 0 && activeFiltersProp), [activeFiltersProp, changedFilters, currentFilters]);
103
-
104
- /**
105
- * Retrieves a list of currently selected values for a filter
106
- * @callback getSelectedFilterValues
107
- * @param {string} filterId The id of the filter
108
- * @returns {string[]}
109
- */
110
- const getSelectedFilterValues = useCallback(
111
- /**
112
- * @param {string} filterId The id of the filter
113
- * @returns {string[]}
114
- */
115
- filterId => {
107
+ const getSelectedFilterValues = useCallback(filterId => {
116
108
  const value = changedFilters[filterId] ? changedFilters[filterId].value : initialFilters[filterId]?.value || [];
117
- return value.map(entry => entry.id || entry);
109
+ return value.map(entry => typeof entry === 'object' ? entry.id : entry);
118
110
  }, [changedFilters, initialFilters]);
119
111
 
120
112
  /**
121
113
  * Resets all filters which have been changed by the user
122
114
  */
123
115
  const resetAllFilters = useCallback(() => {
124
- setInitialFilters(buildInitialFilters(filtersProp, {}));
116
+ setInitialFilters(buildInitialFiltersTyped(filtersProp, {}));
125
117
  setCurrentFilters({});
126
118
  setChangedFilters({});
127
119
  }, [filtersProp]);
@@ -132,77 +124,33 @@ const FilterPageProvider = ({
132
124
  const resetChangedFilters = useCallback(() => {
133
125
  setChangedFilters({});
134
126
  }, []);
135
-
136
- /**
137
- * Adds or updates the selection for a changed filter
138
- * @callback updateChangedFilterInternal
139
- * @param {string} filterId The id of the filter to be updated
140
- * @param {string[]} selectedValues The updated selected values
141
- */
142
- const updateChangedFilterInternal = useCallback(
143
- /**
144
- * @param {string} filterId The id of the filter to be updated
145
- * @param {string[]} selectedValues The updated selected values
146
- */
147
- (filterId, selectedValues) => {
127
+ const updateChangedFilterInternal = useCallback((filterId, selectedValues) => {
148
128
  setChangedFilters(currentState => ({
149
129
  ...currentState,
150
130
  [filterId]: selectedValues
151
131
  }));
152
132
  }, []);
153
-
154
- /**
155
- * Removes a changed filter
156
- * @callback removeChangedFilterInternal
157
- * @param {string} filterId The id of the filter to be updated
158
- * @param {string[]} selectedValues The updated selected values
159
- */
160
- const removeChangedFilterInternal = useCallback(
161
- /**
162
- * @param {string} filterId The id of the filter to be removed
163
- */
164
- filterId => {
133
+ const removeChangedFilterInternal = useCallback(filterId => {
165
134
  setChangedFilters(currentState => {
166
- // Separate the given id from the other set filters.
167
- const {
168
- [filterId]: removed,
169
- ...remainingFilters
170
- } = currentState;
135
+ const remainingFilters = {
136
+ ...currentState
137
+ };
138
+ delete remainingFilters[filterId];
171
139
  return remainingFilters;
172
140
  });
173
141
  }, []);
174
-
175
- /**
176
- * Updates the selection for a filter
177
- *
178
- * @param {string} filterId The id of the filter to be updated
179
- * @param {string[]} selectedValues The updated selected values
180
- */
181
- const updateSelectedFilterValues = useCallback(debounce(
182
- /**
183
- * @param {string} filterId The id of the filter to be updated
184
- * @param {string[]} selectedValues The updated selected values
185
- */
186
- (filterId, selectedValues) => {
187
- // Retrieve data of filter to be updated from the filters array.
188
- const filter = filtersProp.find(entry => entry.id === filterId);
189
-
190
- // Retrieve the values for the updated filter that where set when the filter page was opened
142
+ const updateSelectedFilterValues = useCallback(debounce((filterId, selectedValues) => {
143
+ const filter = (filtersProp || []).find(entry => entry.id === filterId);
144
+ if (!filter) {
145
+ return;
146
+ }
191
147
  const {
192
148
  value: initialValues
193
149
  } = initialFilters[filterId];
194
-
195
- // Prepare the update payload
196
- let stateValue = [].concat(selectedValues);
197
-
198
- /**
199
- * No initial values where set for this filter, and the update contains no values. So we
200
- * can remove the filter from the changedFilters storage.
201
- */
202
- if (initialValues.length === 0 && selectedValues.length === 0) {
203
- removeChangedFilterInternal(filterId);
204
- return;
205
- }
150
+ const hasValueList = Array.isArray(filter.values);
151
+ const orderByFilter = ids => hasValueList ? filter.values.filter(entry => ids.includes(entry.id)).map(entry => entry.id) : ids;
152
+ const selectedValueIds = orderByFilter(selectedValues);
153
+ const initialValueIds = orderByFilter(initialValues.map(entry => typeof entry === 'object' ? entry.id : entry));
206
154
 
207
155
  /**
208
156
  * When the filter update would recreate the state that the filter initially had, we
@@ -210,25 +158,21 @@ const FilterPageProvider = ({
210
158
  *
211
159
  * That enables proper behavior for the "reset" and "update" button states.
212
160
  */
213
- if (initialValues.length !== 0 && selectedValues.length !== 0) {
214
- if (initialValues.every((initial, i) => initial === selectedValues[i])) {
215
- removeChangedFilterInternal(filterId);
216
- return;
217
- }
161
+ if (initialValueIds.length === selectedValueIds.length && initialValueIds.every((initial, i) => initial === selectedValueIds[i])) {
162
+ removeChangedFilterInternal(filterId);
163
+ return;
218
164
  }
219
- if (Array.isArray(filter.values)) {
165
+ let stateValue = [].concat(selectedValueIds);
166
+ if (hasValueList) {
220
167
  /**
221
168
  * The selectedValues array only contains a list of ids.
222
169
  * For the getProducts request that's dispatched after the current filter selection was
223
170
  * applied, id and label is required at the filter values level.
224
171
  */
225
- stateValue = selectedValues.map(valueId => {
226
- const match = filter.values.find(entry => entry.id === valueId);
227
- return {
228
- id: match.id,
229
- label: match.label
230
- };
231
- });
172
+ stateValue = selectedValueIds.map(valueId => filter.values.find(entry => entry.id === valueId)).filter(match => Boolean(match)).map(match => ({
173
+ id: match.id,
174
+ label: match.label
175
+ }));
232
176
  }
233
177
  updateChangedFilterInternal(filterId, {
234
178
  id: filterId,
@@ -242,15 +186,27 @@ const FilterPageProvider = ({
242
186
  }, 50), [filtersProp, initialFilters, removeChangedFilterInternal, updateChangedFilterInternal]);
243
187
 
244
188
  /**
245
- * Applies the current filter selection to the parent route with a product list to be filtered
189
+ * Applies the current filter selection to the parent route with a product list to be filtered.
190
+ * When the filter page was entered directly, no parent route exists in the history stack. In
191
+ * that case the product list route is derived from the current pathname and replaces the
192
+ * filter page.
246
193
  */
247
194
  const applyFilters = useCallback(() => {
248
- const filters = buildUpdatedFilters(currentFilters, changedFilters);
195
+ const filters = buildUpdatedFiltersTyped(currentFilters, changedFilters);
196
+ if (!parentRouteId) {
197
+ router.replace({
198
+ pathname: `${pathname.slice(0, -FILTER_PATH_SUFFIX.length)}${parseObjectToQueryString(query)}`,
199
+ state: {
200
+ filters
201
+ }
202
+ });
203
+ return;
204
+ }
249
205
  router.update(parentRouteId, {
250
206
  filters
251
207
  });
252
208
  onApply(filters);
253
- }, [changedFilters, currentFilters, onApply, parentRouteId]);
209
+ }, [changedFilters, currentFilters, onApply, parentRouteId, pathname, query]);
254
210
  const value = useMemo(() => ({
255
211
  resetPossible,
256
212
  hasChanged,
@@ -267,17 +223,6 @@ const FilterPageProvider = ({
267
223
  children: children
268
224
  });
269
225
  };
270
- FilterPageProvider.defaultProps = {
271
- children: null,
272
- activeFilters: null,
273
- parentRouteId: null,
274
- filters: null,
275
- onApply: () => setTimeout(router.pop, 250)
276
- };
277
-
278
- /**
279
- * @type FilterPageProvider
280
- */
281
226
  export default connect(mapStateToProps, null, null, {
282
227
  areStatePropsEqual
283
228
  })(FilterPageProvider);
@@ -8,7 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const useStyles = makeStyles()(theme => ({
9
9
  wrapper: {
10
10
  color: theme.palette.text.primary,
11
- background: theme.palette.background.emphasized
11
+ background: theme.palette.background.surface
12
12
  },
13
13
  inner: {
14
14
  display: 'flex',
@@ -16,7 +16,8 @@ const useStyles = makeStyles()(theme => ({
16
16
  margin: theme.spacing(0, 2),
17
17
  borderBottom: `1px solid ${theme.components.border.light}`,
18
18
  alignItems: 'center',
19
- height: theme.components.filterBar.height
19
+ height: theme.components.filterBar.height,
20
+ justifyContent: 'space-between'
20
21
  },
21
22
  innerStandalone: {
22
23
  borderBottom: 'none'
@@ -26,6 +27,7 @@ const useStyles = makeStyles()(theme => ({
26
27
  },
27
28
  button: {
28
29
  marginLeft: theme.spacing(2),
30
+ marginTop: theme.spacing(0.5),
29
31
  textTransform: 'none'
30
32
  }
31
33
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.32.0-beta.14",
3
+ "version": "7.32.0-beta.16",
4
4
  "description": "Shopgate's ENGAGE library.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -18,12 +18,12 @@
18
18
  "dependencies": {
19
19
  "@emotion/react": "^11.14.0",
20
20
  "@shopgate/native-modules": "1.0.0-beta.34",
21
- "@shopgate/pwa-common": "7.32.0-beta.14",
22
- "@shopgate/pwa-common-commerce": "7.32.0-beta.14",
23
- "@shopgate/pwa-core": "7.32.0-beta.14",
24
- "@shopgate/pwa-ui-ios": "7.32.0-beta.14",
25
- "@shopgate/pwa-ui-material": "7.32.0-beta.14",
26
- "@shopgate/pwa-ui-shared": "7.32.0-beta.14",
21
+ "@shopgate/pwa-common": "7.32.0-beta.16",
22
+ "@shopgate/pwa-common-commerce": "7.32.0-beta.16",
23
+ "@shopgate/pwa-core": "7.32.0-beta.16",
24
+ "@shopgate/pwa-ui-ios": "7.32.0-beta.16",
25
+ "@shopgate/pwa-ui-material": "7.32.0-beta.16",
26
+ "@shopgate/pwa-ui-shared": "7.32.0-beta.16",
27
27
  "@stripe/react-stripe-js": "^1.16.5",
28
28
  "@stripe/stripe-js": "^1.44.1",
29
29
  "@virtuous/conductor": "~2.5.0",
@@ -6,7 +6,8 @@ import WidgetHeadline from "../../components/WidgetHeadline";
6
6
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  const useStyles = makeStyles()(theme => ({
8
8
  headline: {
9
- paddingBottom: theme.spacing(0)
9
+ paddingBottom: theme.spacing(0),
10
+ background: theme.palette.background.surface
10
11
  }
11
12
  }));
12
13