Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 84bf289

Browse files
mikejolleynerrad
authored andcommitted
Fix price slider constraints (#1125)
* Fix price slider constraints * Update inline comments * use previous tests
1 parent f776ddf commit 84bf289

File tree

5 files changed

+103
-6
lines changed

5 files changed

+103
-6
lines changed

assets/js/base/components/price-slider/index.js

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from '@wordpress/element';
1313
import PropTypes from 'prop-types';
1414
import classnames from 'classnames';
15-
import { useDebounce } from '@woocommerce/base-hooks';
15+
import { useDebounce, usePrevious } from '@woocommerce/base-hooks';
1616

1717
/**
1818
* Internal dependencies
@@ -47,15 +47,25 @@ const PriceSlider = ( {
4747
formatCurrencyForInput( maxPrice, priceFormat, currencySymbol )
4848
);
4949
const debouncedChangeValue = useDebounce( [ minPrice, maxPrice ], 500 );
50+
const prevMinConstraint = usePrevious( minConstraint );
51+
const prevMaxConstraint = usePrevious( maxConstraint );
5052

5153
useEffect( () => {
52-
if ( minPrice === undefined || minConstraint > minPrice ) {
54+
if (
55+
minPrice === undefined ||
56+
minConstraint > minPrice ||
57+
minPrice === prevMinConstraint
58+
) {
5359
setMinPrice( minConstraint );
5460
}
5561
}, [ minConstraint ] );
5662

5763
useEffect( () => {
58-
if ( maxPrice === undefined || maxConstraint < maxPrice ) {
64+
if (
65+
maxPrice === undefined ||
66+
maxConstraint < maxPrice ||
67+
maxPrice === prevMaxConstraint
68+
) {
5969
setMaxPrice( maxConstraint );
6070
}
6171
}, [ maxConstraint ] );
@@ -82,6 +92,18 @@ const PriceSlider = ( {
8292
* Handles styles for the shaded area of the range slider.
8393
*/
8494
const getProgressStyle = useMemo( () => {
95+
if (
96+
! isFinite( minPrice ) ||
97+
! isFinite( maxPrice ) ||
98+
! isFinite( minConstraint ) ||
99+
! isFinite( maxConstraint )
100+
) {
101+
return {
102+
'--low': '0%',
103+
'--high': '100%',
104+
};
105+
}
106+
85107
const low =
86108
Math.round(
87109
100 *
@@ -99,7 +121,7 @@ const PriceSlider = ( {
99121
'--low': low + '%',
100122
'--high': high + '%',
101123
};
102-
}, [ minPrice, minConstraint, maxPrice, maxConstraint ] );
124+
}, [ minPrice, maxPrice, minConstraint, maxConstraint ] );
103125

104126
/**
105127
* Trigger the onChange prop callback with new values.

assets/js/base/hooks/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './use-store-products';
44
export * from './use-collection';
55
export * from './use-collection-header';
66
export * from './use-debounce';
7+
export * from './use-previous';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import TestRenderer, { act } from 'react-test-renderer';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import { usePrevious } from '../use-previous';
10+
11+
describe( 'usePrevious', () => {
12+
const TestComponent = ( { testValue } ) => {
13+
const previousValue = usePrevious( testValue );
14+
return <div testValue={ testValue } previousValue={ previousValue } />;
15+
};
16+
17+
let renderer;
18+
beforeEach( () => ( renderer = null ) );
19+
20+
it( 'should be undefined at first pass', () => {
21+
act( () => {
22+
renderer = TestRenderer.create( <TestComponent testValue={ 1 } /> );
23+
} );
24+
const testValue = renderer.root.findByType( 'div' ).props.testValue;
25+
const testPreviousValue = renderer.root.findByType( 'div' ).props
26+
.previousValue;
27+
28+
expect( testValue ).toBe( 1 );
29+
expect( testPreviousValue ).toBe( undefined );
30+
} );
31+
32+
it( 'test new and previous value', () => {
33+
let testValue;
34+
let testPreviousValue;
35+
act( () => {
36+
renderer = TestRenderer.create( <TestComponent testValue={ 1 } /> );
37+
} );
38+
39+
act( () => {
40+
renderer.update( <TestComponent testValue={ 2 } /> );
41+
} );
42+
testValue = renderer.root.findByType( 'div' ).props.testValue;
43+
testPreviousValue = renderer.root.findByType( 'div' ).props
44+
.previousValue;
45+
expect( testValue ).toBe( 2 );
46+
expect( testPreviousValue ).toBe( 1 );
47+
48+
act( () => {
49+
renderer.update( <TestComponent testValue={ 3 } /> );
50+
} );
51+
testValue = renderer.root.findByType( 'div' ).props.testValue;
52+
testPreviousValue = renderer.root.findByType( 'div' ).props
53+
.previousValue;
54+
expect( testValue ).toBe( 3 );
55+
expect( testPreviousValue ).toBe( 2 );
56+
} );
57+
} );
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useRef, useEffect } from 'react';
2+
3+
/**
4+
* Use Previous from https://usehooks.com/usePrevious/.
5+
* @param {mixed} value
6+
*/
7+
export const usePrevious = ( value ) => {
8+
const ref = useRef();
9+
10+
useEffect( () => {
11+
ref.current = value;
12+
}, [ value ] );
13+
14+
return ref.current;
15+
};

assets/js/blocks/price-filter/block.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ const PriceFilterBlock = ( { attributes } ) => {
4545
const { showInputFields, showFilterButton } = attributes;
4646
const minConstraint = isLoading
4747
? undefined
48-
: parseInt( results.min_price, 10 );
48+
: // Round up to nearest 10 to match the step attribute.
49+
Math.floor( parseInt( results.min_price, 10 ) / 10 ) * 10;
4950
const maxConstraint = isLoading
5051
? undefined
51-
: parseInt( results.max_price, 10 );
52+
: // Round down to nearest 10 to match the step attribute.
53+
Math.ceil( parseInt( results.max_price, 10 ) / 10 ) * 10;
5254

5355
const onChange = useCallback(
5456
( prices ) => {

0 commit comments

Comments
 (0)