@magento/venia-ui 11.5.0 → 11.6.0-alpha.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 (52) hide show
  1. package/lib/RootComponents/Category/__tests__/__snapshots__/categoryContent.shimmer.spec.js.snap +12 -12
  2. package/lib/RootComponents/Category/categoryContent.js +2 -1
  3. package/lib/components/AuthBar/authBar.js +6 -4
  4. package/lib/components/ButtonTab/button.module.css +123 -0
  5. package/lib/components/ButtonTab/buttonTab.js +99 -0
  6. package/lib/components/ButtonTab/index.js +1 -0
  7. package/lib/components/CartPage/PriceSummary/__tests__/__snapshots__/priceSummary.spec.js.snap +0 -2
  8. package/lib/components/CartPage/PriceSummary/priceSummary.js +1 -0
  9. package/lib/components/CartPage/ProductListing/EditModal/__tests__/__snapshots__/productForm.spec.js.snap +2 -2
  10. package/lib/components/CartPage/__tests__/__snapshots__/cartPage.spec.js.snap +12 -6
  11. package/lib/components/CartPage/cartPage.js +12 -6
  12. package/lib/components/CheckoutPage/ItemsReview/__tests__/__snapshots__/itemsReview.spec.js.snap +3 -3
  13. package/lib/components/CheckoutPage/ItemsReview/itemsReview.js +1 -16
  14. package/lib/components/CheckoutPage/OrderConfirmationPage/__fixtures__/cartItems.js +33 -0
  15. package/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/__snapshots__/orderConfirmationPage.spec.js.snap +135 -1
  16. package/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/orderConfirmationPage.spec.js +40 -3
  17. package/lib/components/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.js +118 -103
  18. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/__tests__/__snapshots__/guestForm.spec.js.snap +12 -36
  19. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/guestForm.js +1 -1
  20. package/lib/components/CheckoutPage/ShippingMethod/__tests__/__snapshots__/shippingMethod.spec.js.snap +8 -16
  21. package/lib/components/CheckoutPage/ShippingMethod/shippingMethod.js +1 -1
  22. package/lib/components/CheckoutPage/__tests__/__snapshots__/checkoutPage.spec.js.snap +1 -1
  23. package/lib/components/CheckoutPage/checkoutPage.js +16 -7
  24. package/lib/components/CreateAccount/__tests__/createAccount.spec.js +30 -0
  25. package/lib/components/CreateAccount/createAccount.js +2 -2
  26. package/lib/components/FilterModal/CurrentFilters/__tests__/currentFilter.spec.js +6 -1
  27. package/lib/components/FilterModal/CurrentFilters/currentFilter.js +12 -2
  28. package/lib/components/FilterModal/FilterList/__tests__/filterList.spec.js +16 -3
  29. package/lib/components/FilterModal/FilterList/filterList.js +81 -31
  30. package/lib/components/FilterModal/filterBlock.js +2 -1
  31. package/lib/components/FilterSidebar/__tests__/filterSidebar.spec.js +51 -19
  32. package/lib/components/FilterSidebar/filterSidebar.js +36 -2
  33. package/lib/components/Gallery/__tests__/__snapshots__/gallery.spec.js.snap +2 -2
  34. package/lib/components/Gallery/__tests__/__snapshots__/item.spec.js.snap +3 -3
  35. package/lib/components/MiniCart/ProductList/__tests__/__snapshots__/item.spec.js.snap +4 -4
  36. package/lib/components/MiniCart/miniCart.js +16 -12
  37. package/lib/components/Newsletter/__tests__/__snapshots__/newsletter.spec.js.snap +4 -4
  38. package/lib/components/Newsletter/newsletter.js +2 -2
  39. package/lib/components/OrderHistoryPage/OrderDetails/__tests__/__snapshots__/item.spec.js.snap +1 -1
  40. package/lib/components/OrderHistoryPage/collapsedImageGallery.js +3 -0
  41. package/lib/components/ProductImageCarousel/__tests__/__snapshots__/carousel.spec.js.snap +7 -7
  42. package/lib/components/ProductImageCarousel/__tests__/__snapshots__/thumbnail.spec.js.snap +4 -4
  43. package/lib/components/RangeSlider/rangeSlider.js +127 -0
  44. package/lib/components/RangeSlider/rangeSlider.module.css +76 -0
  45. package/lib/components/SearchBar/__tests__/__snapshots__/suggestedProduct.spec.js.snap +1 -1
  46. package/lib/components/SignIn/__tests__/__snapshots__/signIn.spec.js.snap +6 -6
  47. package/lib/components/SignIn/__tests__/signIn.spec.js +31 -0
  48. package/lib/components/SignIn/signIn.js +3 -5
  49. package/lib/components/WishlistPage/__tests__/__snapshots__/wishlistItem.spec.js.snap +2 -2
  50. package/lib/defaultRoutes.json +6 -0
  51. package/package.json +4 -4
  52. package/upward.yml +31 -1
@@ -2,14 +2,13 @@ import React, { Fragment, useEffect } from 'react';
2
2
  import { shape, string } from 'prop-types';
3
3
  import { FormattedMessage, useIntl } from 'react-intl';
4
4
  import { AlertCircle as AlertCircleIcon } from 'react-feather';
5
- import { Link } from 'react-router-dom';
5
+ import { Link, useHistory } from 'react-router-dom';
6
6
 
7
7
  import { useWindowSize, useToasts } from '@magento/peregrine';
8
8
  import {
9
9
  CHECKOUT_STEP,
10
10
  useCheckoutPage
11
11
  } from '@magento/peregrine/lib/talons/CheckoutPage/useCheckoutPage';
12
-
13
12
  import { useStyle } from '../../classify';
14
13
  import Button from '../Button';
15
14
  import { StoreTitle } from '../Head';
@@ -25,8 +24,8 @@ import payments from './PaymentInformation/paymentMethodCollection';
25
24
  import PriceAdjustments from './PriceAdjustments';
26
25
  import ShippingMethod from './ShippingMethod';
27
26
  import ShippingInformation from './ShippingInformation';
28
- import OrderConfirmationPage from './OrderConfirmationPage';
29
27
  import ItemsReview from './ItemsReview';
28
+ import OrderConfirmationPage from './OrderConfirmationPage';
30
29
  import GoogleReCaptcha from '../GoogleReCaptcha';
31
30
 
32
31
  import defaultClasses from './checkoutPage.module.css';
@@ -35,6 +34,7 @@ import ScrollAnchor from '../ScrollAnchor/scrollAnchor';
35
34
  const errorIcon = <Icon src={AlertCircleIcon} size={20} />;
36
35
 
37
36
  const CheckoutPage = props => {
37
+ const history = useHistory();
38
38
  const { classes: propClasses } = props;
39
39
  const { formatMessage } = useIntl();
40
40
  const talonProps = useCheckoutPage();
@@ -58,8 +58,8 @@ const CheckoutPage = props => {
58
58
  isGuestCheckout,
59
59
  isLoading,
60
60
  isUpdating,
61
- orderDetailsData,
62
61
  orderDetailsLoading,
62
+ orderDetailsData,
63
63
  orderNumber,
64
64
  placeOrderLoading,
65
65
  placeOrderButtonClicked,
@@ -83,7 +83,15 @@ const CheckoutPage = props => {
83
83
  } = talonProps;
84
84
 
85
85
  const [, { addToast }] = useToasts();
86
-
86
+ const orderCount = localStorage.getItem('orderCount');
87
+ useEffect(() => {
88
+ if (isGuestCheckout && !orderDetailsData) {
89
+ if (orderCount === '1') {
90
+ history.push('/');
91
+ localStorage.setItem('orderCount', '0');
92
+ }
93
+ }
94
+ }, [isGuestCheckout, history, orderDetailsData, orderCount]);
87
95
  useEffect(() => {
88
96
  if (hasError) {
89
97
  const message =
@@ -125,7 +133,7 @@ const CheckoutPage = props => {
125
133
  defaultMessage: 'Checkout'
126
134
  });
127
135
 
128
- if (orderNumber && orderDetailsData) {
136
+ if (isGuestCheckout && orderDetailsData && orderNumber) {
129
137
  return (
130
138
  <OrderConfirmationPage
131
139
  data={orderDetailsData}
@@ -245,6 +253,7 @@ const CheckoutPage = props => {
245
253
  checkoutStep === CHECKOUT_STEP.PAYMENT ? (
246
254
  <Button
247
255
  onClick={handleReviewOrder}
256
+ onTouchStart={handleReviewOrder}
248
257
  onKeyDown={handleReviewOrderEnterKeyPress}
249
258
  priority="high"
250
259
  className={classes.review_order_button}
@@ -265,7 +274,7 @@ const CheckoutPage = props => {
265
274
  const itemsReview =
266
275
  checkoutStep === CHECKOUT_STEP.REVIEW ? (
267
276
  <div className={classes.items_review_container}>
268
- <ItemsReview />
277
+ <ItemsReview items={cartItems} />
269
278
  </div>
270
279
  ) : null;
271
280
 
@@ -4,6 +4,8 @@ import { createTestInstance } from '@magento/peregrine';
4
4
 
5
5
  import CreateAccount from '../createAccount';
6
6
 
7
+ import { useHistory, useLocation } from 'react-router-dom';
8
+
7
9
  jest.mock('@apollo/client', () => ({
8
10
  gql: jest.fn(),
9
11
  useApolloClient: jest.fn().mockImplementation(() => {}),
@@ -24,6 +26,16 @@ jest.mock('@apollo/client', () => ({
24
26
  }))
25
27
  }));
26
28
 
29
+ // Mocking the react-router hooks
30
+
31
+ jest.mock('react-router-dom', () => ({
32
+ ...jest.requireActual('react-router-dom'),
33
+
34
+ useHistory: jest.fn(),
35
+
36
+ useLocation: jest.fn()
37
+ }));
38
+
27
39
  jest.mock('../../../util/formValidators');
28
40
  jest.mock('@magento/peregrine/lib/context/user', () => {
29
41
  const userState = {
@@ -58,6 +70,24 @@ jest.mock('@magento/peregrine/lib/hooks/useAwaitQuery', () => {
58
70
  return { useAwaitQuery };
59
71
  });
60
72
 
73
+ // Mocking useLocation and useHistory for the tests
74
+
75
+ beforeEach(() => {
76
+ useHistory.mockReturnValue({
77
+ push: jest.fn() // mock any methods you need from useHistory
78
+ });
79
+
80
+ useLocation.mockReturnValue({
81
+ pathname: '/mock-path', // mock the location properties
82
+
83
+ search: '',
84
+
85
+ hash: '',
86
+
87
+ state: null
88
+ });
89
+ });
90
+
61
91
  jest.mock('@magento/peregrine/lib/context/eventing', () => ({
62
92
  useEventingContext: jest.fn().mockReturnValue([{}, { dispatch: jest.fn() }])
63
93
  }));
@@ -46,7 +46,7 @@ const CreateAccount = props => {
46
46
  <Button
47
47
  data-cy="CreateAccount-cancelButton"
48
48
  className={classes.cancelButton}
49
- disabled={isDisabled}
49
+ disabled={Boolean(isDisabled)}
50
50
  type="button"
51
51
  priority="low"
52
52
  onClick={handleCancel}
@@ -62,7 +62,7 @@ const CreateAccount = props => {
62
62
  const submitButton = (
63
63
  <Button
64
64
  className={classes.submitButton}
65
- disabled={isDisabled}
65
+ disabled={Boolean(isDisabled)}
66
66
  type="submit"
67
67
  priority="high"
68
68
  onKeyDown={handleEnterKeyPress}
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { act } from 'react-test-renderer';
3
+ import { MemoryRouter } from 'react-router-dom';
3
4
 
4
5
  import { createTestInstance } from '@magento/peregrine';
5
6
 
@@ -19,7 +20,11 @@ jest.mock('../../../Trigger', () => props => <mock-Trigger {...props} />);
19
20
  let inputProps = {};
20
21
 
21
22
  const Component = () => {
22
- return <CurrentFilter {...inputProps} />;
23
+ return (
24
+ <MemoryRouter>
25
+ <CurrentFilter {...inputProps} />
26
+ </MemoryRouter>
27
+ );
23
28
  };
24
29
 
25
30
  const givenDefaultValues = () => {
@@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { shape, string, func } from 'prop-types';
4
4
  import { X as Remove } from 'react-feather';
5
+ import { useHistory, useLocation } from 'react-router-dom';
5
6
 
6
7
  import { useStyle } from '../../../classify';
7
8
  import Icon from '../../Icon';
@@ -12,13 +13,22 @@ const CurrentFilter = props => {
12
13
  const { group, item, removeItem, onRemove } = props;
13
14
  const classes = useStyle(defaultClasses, props.classes);
14
15
  const { formatMessage } = useIntl();
16
+ const location = useLocation();
17
+ const history = useHistory();
15
18
 
16
19
  const handleClick = useCallback(() => {
17
20
  removeItem({ group, item });
18
21
  if (typeof onRemove === 'function') {
19
22
  onRemove(group, item);
20
23
  }
21
- }, [group, item, removeItem, onRemove]);
24
+
25
+ if (group == 'price') {
26
+ // preserve all existing params
27
+ const params = new URLSearchParams(location.search);
28
+ params.delete('price[filter]');
29
+ history.replace({ search: params.toString() });
30
+ }
31
+ }, [group, item, removeItem, onRemove, history, location.search]);
22
32
 
23
33
  const ariaLabel = formatMessage(
24
34
  {
@@ -34,7 +44,7 @@ const CurrentFilter = props => {
34
44
  <span className={classes.root} data-cy="CurrentFilter-root">
35
45
  <Trigger
36
46
  action={handleClick}
37
- ariaLabel={ariaLabel}
47
+ aria-label={ariaLabel}
38
48
  data-cy="CurrentFilter-trigger"
39
49
  >
40
50
  <Icon size={20} src={Remove} />
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { MemoryRouter } from 'react-router-dom';
2
3
 
3
4
  import { createTestInstance } from '@magento/peregrine';
4
5
 
@@ -67,7 +68,11 @@ describe('#FilterList', () => {
67
68
  });
68
69
 
69
70
  it('renders without show more button', () => {
70
- const { root } = createTestInstance(<Component />);
71
+ const { root } = createTestInstance(
72
+ <MemoryRouter>
73
+ <Component />
74
+ </MemoryRouter>
75
+ );
71
76
 
72
77
  expect(root.findAllByType(FilterItem)).toHaveLength(2);
73
78
  expect(() => root.findByType('button')).toThrow();
@@ -76,7 +81,11 @@ describe('#FilterList', () => {
76
81
  it('renders with show more button', () => {
77
82
  givenShowMore();
78
83
 
79
- const { root } = createTestInstance(<Component />);
84
+ const { root } = createTestInstance(
85
+ <MemoryRouter>
86
+ <Component />
87
+ </MemoryRouter>
88
+ );
80
89
 
81
90
  expect(() => root.findByType('button')).not.toThrow();
82
91
  expect(root.findByType('button').children[0]).toBe(mockShowMore);
@@ -86,7 +95,11 @@ describe('#FilterList', () => {
86
95
  givenShowMore();
87
96
  givenExpanded();
88
97
 
89
- const { root } = createTestInstance(<Component />);
98
+ const { root } = createTestInstance(
99
+ <MemoryRouter>
100
+ <Component />
101
+ </MemoryRouter>
102
+ );
90
103
 
91
104
  expect(() => root.findByType('button')).not.toThrow();
92
105
  expect(root.findByType('button').children[0]).toBe(mockShowLess);
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useMemo } from 'react';
1
+ import React, { Fragment, useMemo, useCallback } from 'react';
2
2
  import { array, func, number, shape, string } from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import setValidator from '@magento/peregrine/lib/validators/set';
@@ -8,6 +8,8 @@ import { useStyle } from '../../../classify';
8
8
  import FilterItem from './filterItem';
9
9
  import defaultClasses from './filterList.module.css';
10
10
  import FilterItemRadioGroup from './filterItemRadioGroup';
11
+ import RangeSlider from '../../RangeSlider/rangeSlider';
12
+ import { useHistory, useLocation } from 'react-router-dom';
11
13
 
12
14
  const labels = new WeakMap();
13
15
 
@@ -22,13 +24,46 @@ const FilterList = props => {
22
24
  items,
23
25
  onApply
24
26
  } = props;
27
+ const { pathname, search } = useLocation();
28
+ const history = useHistory();
25
29
  const classes = useStyle(defaultClasses, props.classes);
26
30
  const talonProps = useFilterList({ filterState, items, itemCountToShow });
27
31
  const { isListExpanded, handleListToggle } = talonProps;
28
32
  const { formatMessage } = useIntl();
29
33
 
30
- // memoize item creation
31
- // search value is not referenced, so this array is stable
34
+ if (name === 'Price') {
35
+ var minRange = Number(items[0].value.split('_')[0]);
36
+ var maxRange = Number(items[items.length - 1].value.split('_')[1]);
37
+ if (filterState !== undefined) {
38
+ const filterArray = [...filterState];
39
+ var currentMinVal = Number(filterArray[0].value.split('_')[0]);
40
+ var currentMaxVal = Number(filterArray[0].value.split('_')[1]);
41
+ }
42
+ }
43
+
44
+ const handleChange = useCallback(
45
+ newValue => {
46
+ const test = String(search).split('&');
47
+ const filters = test.filter(element => {
48
+ return !element.includes('price');
49
+ });
50
+ const newSearch = filters.join('&');
51
+ const nextParams = new URLSearchParams(newSearch);
52
+
53
+ const DELIMITER = ',';
54
+ const title = String(newValue.min) + '-' + String(newValue.max);
55
+ const value = String(newValue.min) + '_' + String(newValue.max);
56
+ nextParams.append(
57
+ `${group}[filter]`,
58
+ `${title}${DELIMITER}${value}`
59
+ );
60
+
61
+ history.push({ pathname, search: String(nextParams) });
62
+ },
63
+ [group, history, pathname, search]
64
+ );
65
+
66
+ // Memoize item creation
32
67
  const itemElements = useMemo(() => {
33
68
  if (filterFrontendInput === 'boolean') {
34
69
  const key = `item-${group}`;
@@ -51,36 +86,46 @@ const FilterList = props => {
51
86
  );
52
87
  }
53
88
 
54
- return items.map((item, index) => {
55
- const { title, value } = item;
56
- const key = `item-${group}-${value}`;
57
-
58
- if (!isListExpanded && index >= itemCountToShow) {
59
- return null;
60
- }
61
-
62
- // create an element for each item
63
- const element = (
64
- <li
65
- key={key}
66
- className={classes.item}
67
- data-cy="FilterList-item"
68
- >
69
- <FilterItem
70
- filterApi={filterApi}
71
- filterState={filterState}
72
- group={group}
73
- item={item}
74
- onApply={onApply}
89
+ if (name === 'Price') {
90
+ return (
91
+ <div className={classes.root}>
92
+ <RangeSlider
93
+ min={minRange}
94
+ max={maxRange}
95
+ initialMin={currentMinVal}
96
+ initialMax={currentMaxVal}
97
+ onChange={handleChange}
75
98
  />
76
- </li>
99
+ </div>
77
100
  );
101
+ } else {
102
+ return items.map((item, index) => {
103
+ const { title, value } = item;
104
+ const key = `item-${group}-${value}`;
105
+
106
+ if (!isListExpanded && index >= itemCountToShow) {
107
+ return null;
108
+ }
78
109
 
79
- // associate each element with its normalized title
80
- // titles are not unique, so use the element as the key
81
- labels.set(element, title.toUpperCase());
82
- return element;
83
- });
110
+ const element = (
111
+ <li
112
+ key={key}
113
+ className={classes.item}
114
+ data-cy="FilterList-item"
115
+ >
116
+ <FilterItem
117
+ filterApi={filterApi}
118
+ filterState={filterState}
119
+ group={group}
120
+ item={item}
121
+ onApply={onApply}
122
+ />
123
+ </li>
124
+ );
125
+ labels.set(element, title.toUpperCase());
126
+ return element;
127
+ });
128
+ }
84
129
  }, [
85
130
  classes,
86
131
  filterApi,
@@ -91,7 +136,12 @@ const FilterList = props => {
91
136
  items,
92
137
  isListExpanded,
93
138
  itemCountToShow,
94
- onApply
139
+ onApply,
140
+ minRange,
141
+ maxRange,
142
+ currentMinVal,
143
+ currentMaxVal,
144
+ handleChange
95
145
  ]);
96
146
 
97
147
  const showMoreLessItem = useMemo(() => {
@@ -28,7 +28,8 @@ const FilterBlock = props => {
28
28
  const talonProps = useFilterBlock({
29
29
  filterState,
30
30
  items,
31
- initialOpen
31
+ initialOpen,
32
+ group
32
33
  });
33
34
  const { handleClick, isExpanded } = talonProps;
34
35
  const iconSrc = isExpanded ? ArrowUp : ArrowDown;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { act } from 'react-test-renderer';
3
+ import { MemoryRouter } from 'react-router-dom';
3
4
 
4
5
  import { createTestInstance } from '@magento/peregrine';
5
6
 
@@ -51,6 +52,8 @@ const mockHandleApply = jest.fn();
51
52
 
52
53
  const mockScrollTo = jest.fn();
53
54
 
55
+ const mockFilterOptions = jest.fn();
56
+
54
57
  const mockGetBoundingClientRect = jest.fn();
55
58
 
56
59
  let mockFilterState;
@@ -125,7 +128,8 @@ const Component = () => {
125
128
 
126
129
  const givenDefaultValues = () => {
127
130
  inputProps = {
128
- filters: []
131
+ filters: [],
132
+ setFilterOptions: mockFilterOptions
129
133
  };
130
134
 
131
135
  mockFilterState = new Map();
@@ -133,13 +137,15 @@ const givenDefaultValues = () => {
133
137
 
134
138
  const givenFilters = () => {
135
139
  inputProps = {
136
- filters: mockFilters
140
+ filters: mockFilters,
141
+ setFilterOptions: mockFilterOptions
137
142
  };
138
143
  };
139
144
 
140
145
  const givenSelectedFilters = () => {
141
146
  inputProps = {
142
- filters: mockFilters
147
+ filters: mockFilters,
148
+ setFilterOptions: mockFilterOptions
143
149
  };
144
150
 
145
151
  mockFilterState = new Map([['group', 'item']]);
@@ -148,7 +154,8 @@ const givenSelectedFilters = () => {
148
154
  const givenFiltersAndAmountToShow = () => {
149
155
  inputProps = {
150
156
  filters: mockFilters,
151
- filterCountToOpen: mockFiltersOpenCount
157
+ filterCountToOpen: mockFiltersOpenCount,
158
+ setFilterOptions: mockFilterOptions
152
159
  };
153
160
  };
154
161
 
@@ -161,7 +168,11 @@ describe('#FilterSidebar', () => {
161
168
  });
162
169
 
163
170
  it('renders without filters', () => {
164
- createTestInstance(<Component />);
171
+ createTestInstance(
172
+ <MemoryRouter>
173
+ <Component />
174
+ </MemoryRouter>
175
+ );
165
176
 
166
177
  expect(mockFilterBlock).not.toHaveBeenCalled();
167
178
  expect(mockCurrentFilters).toHaveBeenCalled();
@@ -170,7 +181,11 @@ describe('#FilterSidebar', () => {
170
181
  it('renders with filters and no selected filters', () => {
171
182
  givenFilters();
172
183
 
173
- const { root } = createTestInstance(<Component />);
184
+ const { root } = createTestInstance(
185
+ <MemoryRouter>
186
+ <Component />
187
+ </MemoryRouter>
188
+ );
174
189
 
175
190
  expect(() => root.findByType(LinkButton)).toThrow();
176
191
  expect(mockFilterBlock).toHaveBeenCalledTimes(mockFilters.length);
@@ -179,7 +194,11 @@ describe('#FilterSidebar', () => {
179
194
  it('renders with filters and selected filter', () => {
180
195
  givenSelectedFilters();
181
196
 
182
- const { root } = createTestInstance(<Component />);
197
+ const { root } = createTestInstance(
198
+ <MemoryRouter>
199
+ <Component />
200
+ </MemoryRouter>
201
+ );
183
202
 
184
203
  expect(() => root.findByType(LinkButton)).not.toThrow();
185
204
  expect(mockFilterBlock).toHaveBeenCalledTimes(mockFilters.length);
@@ -188,7 +207,11 @@ describe('#FilterSidebar', () => {
188
207
  it('handles when a user applies a filter and ref is not provided', () => {
189
208
  givenSelectedFilters();
190
209
 
191
- const { root } = createTestInstance(<Component />);
210
+ const { root } = createTestInstance(
211
+ <MemoryRouter>
212
+ <Component />
213
+ </MemoryRouter>
214
+ );
192
215
 
193
216
  act(() => {
194
217
  root.findAllByType(FilterBlock)[0].props.onApply();
@@ -206,17 +229,22 @@ describe('#FilterSidebar', () => {
206
229
  value: mockScrollTo
207
230
  });
208
231
 
209
- const { root } = createTestInstance(<Component />, {
210
- createNodeMock: () => {
211
- return {
212
- getBoundingClientRect: mockGetBoundingClientRect.mockReturnValue(
213
- {
214
- top: 250
215
- }
216
- )
217
- };
232
+ const { root } = createTestInstance(
233
+ <MemoryRouter>
234
+ <Component />
235
+ </MemoryRouter>,
236
+ {
237
+ createNodeMock: () => {
238
+ return {
239
+ getBoundingClientRect: mockGetBoundingClientRect.mockReturnValue(
240
+ {
241
+ top: 250
242
+ }
243
+ )
244
+ };
245
+ }
218
246
  }
219
- });
247
+ );
220
248
 
221
249
  act(() => {
222
250
  root.findAllByType(FilterBlock)[0].props.onApply();
@@ -229,7 +257,11 @@ describe('#FilterSidebar', () => {
229
257
 
230
258
  it('accepts configurable amount of open filters', () => {
231
259
  givenFiltersAndAmountToShow();
232
- createTestInstance(<Component />);
260
+ createTestInstance(
261
+ <MemoryRouter>
262
+ <Component />
263
+ </MemoryRouter>
264
+ );
233
265
 
234
266
  expect(mockFilterBlock).toHaveBeenCalledTimes(mockFilters.length);
235
267
 
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useCallback, useRef } from 'react';
1
+ import React, { useMemo, useCallback, useRef, useEffect } from 'react';
2
2
  import { FormattedMessage } from 'react-intl';
3
3
  import { array, arrayOf, shape, string, number } from 'prop-types';
4
4
  import { useFilterSidebar } from '@magento/peregrine/lib/talons/FilterSidebar';
@@ -8,6 +8,7 @@ import LinkButton from '../LinkButton';
8
8
  import CurrentFilters from '../FilterModal/CurrentFilters';
9
9
  import FilterBlock from '../FilterModal/filterBlock';
10
10
  import defaultClasses from './filterSidebar.module.css';
11
+ import { useLocation } from 'react-router-dom';
11
12
 
12
13
  const SCROLL_OFFSET = 150;
13
14
 
@@ -17,7 +18,7 @@ const SCROLL_OFFSET = 150;
17
18
  * @param {Object} props.filters - filters to display
18
19
  */
19
20
  const FilterSidebar = props => {
20
- const { filters, filterCountToOpen } = props;
21
+ const { filters, filterCountToOpen, setFilterOptions } = props;
21
22
  const talonProps = useFilterSidebar({ filters });
22
23
  const {
23
24
  filterApi,
@@ -31,6 +32,32 @@ const FilterSidebar = props => {
31
32
 
32
33
  const filterRef = useRef();
33
34
  const classes = useStyle(defaultClasses, props.classes);
35
+ const location = useLocation();
36
+
37
+ //adding the price filter values to the filterstate
38
+ const priceFilters = Array.from(filterItems, ([group]) => {
39
+ if (group == 'price') {
40
+ // preserve all existing params
41
+ const params = new URLSearchParams(location.search);
42
+ const uniqueKeys = new Set(params.keys());
43
+ // iterate over existing param keys
44
+ for (const key of uniqueKeys) {
45
+ // if a key matches a known filter, add its items to the next state
46
+ if (key == 'price[filter]') {
47
+ const value = params.get('price[filter]');
48
+ const item = {
49
+ title: value.split(',')[0],
50
+ value: value.split(',')[1]
51
+ };
52
+ const filterVar = new Set();
53
+ filterVar.add(item);
54
+
55
+ //to display the price filter value after selecting the filter
56
+ filterState.set('price', new Set(filterVar));
57
+ }
58
+ }
59
+ }
60
+ });
34
61
 
35
62
  const handleApplyFilter = useCallback(
36
63
  (...args) => {
@@ -50,6 +77,12 @@ const FilterSidebar = props => {
50
77
  [handleApply, filterRef]
51
78
  );
52
79
 
80
+ useEffect(() => {
81
+ if (filterState) {
82
+ setFilterOptions(filterState);
83
+ }
84
+ }, [filterState, setFilterOptions]);
85
+
53
86
  const filtersList = useMemo(
54
87
  () =>
55
88
  Array.from(filterItems, ([group, items], iteration) => {
@@ -115,6 +148,7 @@ const FilterSidebar = props => {
115
148
  />
116
149
  </h2>
117
150
  </div>
151
+ {priceFilters}
118
152
  <CurrentFilters
119
153
  filterApi={filterApi}
120
154
  filterNames={filterNames}
@@ -20,7 +20,7 @@ exports[`renders if \`items\` is an array of objects 1`] = `
20
20
  className="image placeholder_layoutOnly"
21
21
  height={375}
22
22
  loading="eager"
23
- src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0JyBoZWlnaHQ9JzUnPjxyZWN0IHdpZHRoPSc0JyBoZWlnaHQ9JzUnIHN0eWxlPSdmaWxsOiBub25lJyAvPjwvc3ZnPg=="
23
+ src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0IiBoZWlnaHQ9IjUiIHZpZXdCb3g9Ii0yNSAtMjUgMzEyIDMxMiI+CiAgICA8ZyBpZD0iTGF5ZXJfMi0yIj4KICAgICAgICA8cGF0aCBjbGFzcz0ic3QwIiBzdHlsZT0iZmlsbDogI2YwZjBmMDsgZmlsbC1ydWxlOiBldmVub2RkOyIgZD0iTTM2LDE4OS40di0xMDkuMWMwLTAuNywwLjQtMS42LDEuMS0ybDk0LjctNTcuMWMwLjctMC41LDEuNy0wLjUsMi41LDBsOTEuNSw1N2MwLjcsMC40LDEuMSwxLjEsMS4xLDJ2MTA3LjljMCwwLjctMC40LDEuNS0xLjEsMmwtMTkuMywxMi42Yy0xLjUsMS0zLjYsMC0zLjYtMnYtMTA1LjljMC0wLjctMC40LTEuNi0xLjEtMmwtNjcuNS00MS4zYy0wLjctMC41LTEuNi0wLjUtMi4zLDBsLTY5LjYsNDEuM2MtMC43LDAuNC0xLjEsMS4xLTEuMSwydjEwNS45YzAsMS45LTIsMy0zLjYsMmwtMjEuNS0xMy41aDB2LjJaTTg2LDExMC45djEwNi4zYzAsMC45LDAuNCwxLjYsMS4xLDJsNDQuNSwyNi43YzAuNywwLjUsMS43LDAuNCwyLjUsMGw0Mi41LTI2LjdjMC43LTAuNCwxLjEtMS4xLDEuMS0ydi0xMDUuOGMwLTAuNy0wLjQtMS41LTEuMS0ybC0yOC43LTE3LjljLTEuNS0xLTMuNiwwLjEtMy42LDJ2MTIxLjZjMCwwLjctMC40LDEuNS0xLjEsMmwtOS4zLDUuOWMtMC43LDAuNS0xLjYsMC41LTIuMywwbC0xMS4xLTUuOWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjF2LTEyMS43YzAtMS43LTItMy0zLjUtMmwtMjguOCwxNi4yYy0wLjcsMC40LTEuMSwxLjEtMS4xLDJ2MS41aC4xWiIvPgogICAgPC9nPgo8L3N2Zz4K"
24
24
  style={
25
25
  Object {
26
26
  "--height": "375px",
@@ -115,7 +115,7 @@ exports[`renders if \`items\` is an array of objects 1`] = `
115
115
  className="image placeholder_layoutOnly"
116
116
  height={375}
117
117
  loading="eager"
118
- src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0JyBoZWlnaHQ9JzUnPjxyZWN0IHdpZHRoPSc0JyBoZWlnaHQ9JzUnIHN0eWxlPSdmaWxsOiBub25lJyAvPjwvc3ZnPg=="
118
+ src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0IiBoZWlnaHQ9IjUiIHZpZXdCb3g9Ii0yNSAtMjUgMzEyIDMxMiI+CiAgICA8ZyBpZD0iTGF5ZXJfMi0yIj4KICAgICAgICA8cGF0aCBjbGFzcz0ic3QwIiBzdHlsZT0iZmlsbDogI2YwZjBmMDsgZmlsbC1ydWxlOiBldmVub2RkOyIgZD0iTTM2LDE4OS40di0xMDkuMWMwLTAuNywwLjQtMS42LDEuMS0ybDk0LjctNTcuMWMwLjctMC41LDEuNy0wLjUsMi41LDBsOTEuNSw1N2MwLjcsMC40LDEuMSwxLjEsMS4xLDJ2MTA3LjljMCwwLjctMC40LDEuNS0xLjEsMmwtMTkuMywxMi42Yy0xLjUsMS0zLjYsMC0zLjYtMnYtMTA1LjljMC0wLjctMC40LTEuNi0xLjEtMmwtNjcuNS00MS4zYy0wLjctMC41LTEuNi0wLjUtMi4zLDBsLTY5LjYsNDEuM2MtMC43LDAuNC0xLjEsMS4xLTEuMSwydjEwNS45YzAsMS45LTIsMy0zLjYsMmwtMjEuNS0xMy41aDB2LjJaTTg2LDExMC45djEwNi4zYzAsMC45LDAuNCwxLjYsMS4xLDJsNDQuNSwyNi43YzAuNywwLjUsMS43LDAuNCwyLjUsMGw0Mi41LTI2LjdjMC43LTAuNCwxLjEtMS4xLDEuMS0ydi0xMDUuOGMwLTAuNy0wLjQtMS41LTEuMS0ybC0yOC43LTE3LjljLTEuNS0xLTMuNiwwLjEtMy42LDJ2MTIxLjZjMCwwLjctMC40LDEuNS0xLjEsMmwtOS4zLDUuOWMtMC43LDAuNS0xLjYsMC41LTIuMywwbC0xMS4xLTUuOWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjF2LTEyMS43YzAtMS43LTItMy0zLjUtMmwtMjguOCwxNi4yYy0wLjcsMC40LTEuMSwxLjEtMS4xLDJ2MS41aC4xWiIvPgogICAgPC9nPgo8L3N2Zz4K"
119
119
  style={
120
120
  Object {
121
121
  "--height": "375px",