Price filter: preserve previous constraints while loading (https://github.com/woocommerce/woocommerce-blocks/pull/1386)

* Typo

* Save previous constraint while loading

* Add tests for formatPrice

* Small code refactor

* Refactor usePriceConstraints to DRY and add tests

* Add base-hooks to jest config
This commit is contained in:
Albert Juhé Lluveras 2019-12-16 17:48:02 +01:00 committed by GitHub
parent 77bb23bf32
commit af5af78266
7 changed files with 106 additions and 10 deletions

View File

@ -262,7 +262,7 @@ const PriceSlider = ( {
onMouseMove={ findClosestRange }
onFocus={ findClosestRange }
>
{ ! isLoading && hasValidConstraints && (
{ hasValidConstraints && (
<Fragment>
<div
className="wc-block-price-filter__range-input-progress"
@ -281,6 +281,7 @@ const PriceSlider = ( {
min={ minConstraint }
max={ maxConstraint }
ref={ minRange }
disabled={ isLoading }
/>
<input
type="range"
@ -295,6 +296,7 @@ const PriceSlider = ( {
min={ minConstraint }
max={ maxConstraint }
ref={ maxRange }
disabled={ isLoading }
/>
</Fragment>
) }

View File

@ -9,17 +9,17 @@ import { CURRENCY } from '@woocommerce/settings';
*
* @param {number} value Number to format.
* @param {string} priceFormat Price format string.
* @param {string} currencySymbol Curency symbol.
* @param {string} currencySymbol Currency symbol.
*/
export const formatPrice = (
value,
priceFormat = CURRENCY.price_format,
currencySymbol = CURRENCY.symbol
) => {
if ( value === '' || undefined === value ) {
const formattedNumber = parseInt( value, 10 );
if ( ! isFinite( formattedNumber ) ) {
return '';
}
const formattedNumber = parseInt( value, 10 );
const formattedValue = sprintf(
priceFormat,
currencySymbol,

View File

@ -0,0 +1,29 @@
/**
* Internal dependencies
*/
import { formatPrice } from '../price';
describe( 'formatPrice', () => {
test.each`
value | priceFormat | currencySymbol | expected
${10} | ${'%1$s%2$s'} | ${'€'} | ${'€10'}
${10} | ${'%2$s%1$s'} | ${'€'} | ${'10€'}
${10} | ${'%2$s%1$s'} | ${'$'} | ${'10$'}
${'10'} | ${'%1$s%2$s'} | ${'€'} | ${'€10'}
${0} | ${'%1$s%2$s'} | ${'€'} | ${'€0'}
${''} | ${'%1$s%2$s'} | ${'€'} | ${''}
${null} | ${'%1$s%2$s'} | ${'€'} | ${''}
${undefined} | ${'%1$s%2$s'} | ${'€'} | ${''}
`(
'correctly formats price given "$value", "$priceFormat", and "$currencySymbol"',
( { value, priceFormat, currencySymbol, expected } ) => {
const formattedPrice = formatPrice(
value,
priceFormat,
currencySymbol
);
expect( formattedPrice ).toEqual( expected );
}
);
} );

View File

@ -12,6 +12,11 @@ import { CURRENCY } from '@woocommerce/settings';
import { useDebouncedCallback } from 'use-debounce';
import PropTypes from 'prop-types';
/**
* Internal dependencies
*/
import usePriceConstraints from './use-price-constraints.js';
/**
* Component displaying a price filter.
*/
@ -31,12 +36,10 @@ const PriceFilterBlock = ( { attributes, isEditor = false } ) => {
const [ minPrice, setMinPrice ] = useState();
const [ maxPrice, setMaxPrice ] = useState();
const minConstraint = isNaN( results.min_price )
? null
: Math.floor( parseInt( results.min_price, 10 ) / 10 ) * 10;
const maxConstraint = isNaN( results.max_price )
? null
: Math.ceil( parseInt( results.max_price, 10 ) / 10 ) * 10;
const { minConstraint, maxConstraint } = usePriceConstraints( {
minPrice: results.min_price,
maxPrice: results.max_price,
} );
// Updates the query after a short delay.
const [ debouncedUpdateQuery ] = useDebouncedCallback( () => {

View File

@ -0,0 +1,38 @@
/**
* External dependencies
*/
import TestRenderer from 'react-test-renderer';
/**
* Internal dependencies
*/
import { usePriceConstraint } from '../use-price-constraints';
describe( 'usePriceConstraints', () => {
const TestComponent = ( { price } ) => {
const priceConstraint = usePriceConstraint( price );
return <div priceConstraint={ priceConstraint } />;
};
it( 'price constraint should be updated when new price is set', () => {
const renderer = TestRenderer.create( <TestComponent price={ 10 } /> );
const container = renderer.root.findByType( 'div' );
expect( container.props.priceConstraint ).toBe( 10 );
renderer.update( <TestComponent price={ 20 } /> );
expect( container.props.priceConstraint ).toBe( 20 );
} );
it( 'previous price constraint should be preserved when new price is not a infinite number', () => {
const renderer = TestRenderer.create( <TestComponent price={ 10 } /> );
const container = renderer.root.findByType( 'div' );
expect( container.props.priceConstraint ).toBe( 10 );
renderer.update( <TestComponent price={ Infinity } /> );
expect( container.props.priceConstraint ).toBe( 10 );
} );
} );

View File

@ -0,0 +1,23 @@
/**
* External dependencies
*/
import { usePrevious } from '@woocommerce/base-hooks';
export const usePriceConstraint = ( price ) => {
const currentConstraint = isNaN( price )
? null
: Math.floor( parseInt( price, 10 ) / 10 ) * 10;
const previousConstraint = usePrevious( currentConstraint, ( val ) =>
Number.isFinite( val )
);
return Number.isFinite( currentConstraint )
? currentConstraint
: previousConstraint;
};
export default ( { minPrice, maxPrice } ) => {
return {
minConstraint: usePriceConstraint( minPrice ),
maxConstraint: usePriceConstraint( maxPrice ),
};
};

View File

@ -15,6 +15,7 @@
"@woocommerce/base-components(.*)$": "assets/js/base/components/$1",
"@woocommerce/base-context(.*)$": "assets/js/base/context/$1",
"@woocommerce/base-hocs(.*)$": "assets/js/base/hocs/$1",
"@woocommerce/base-hooks(.*)$": "assets/js/base/hooks/$1",
"@woocommerce/block-data": "assets/js/data"
},
"setupFiles": [