From af5af78266c1c3660dad095fba3afc12e99bf70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 16 Dec 2019 17:48:02 +0100 Subject: [PATCH] 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 --- .../js/base/components/price-slider/index.js | 4 +- .../assets/js/base/utils/price.js | 6 +-- .../assets/js/base/utils/test/price.js | 29 ++++++++++++++ .../assets/js/blocks/price-filter/block.js | 15 +++++--- .../test/use-price-constraints.js | 38 +++++++++++++++++++ .../price-filter/use-price-constraints.js | 23 +++++++++++ .../tests/js/jest.config.json | 1 + 7 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/base/utils/test/price.js create mode 100644 plugins/woocommerce-blocks/assets/js/blocks/price-filter/test/use-price-constraints.js create mode 100644 plugins/woocommerce-blocks/assets/js/blocks/price-filter/use-price-constraints.js diff --git a/plugins/woocommerce-blocks/assets/js/base/components/price-slider/index.js b/plugins/woocommerce-blocks/assets/js/base/components/price-slider/index.js index ff51876c6ca..ee75eaffdb4 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/price-slider/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/price-slider/index.js @@ -262,7 +262,7 @@ const PriceSlider = ( { onMouseMove={ findClosestRange } onFocus={ findClosestRange } > - { ! isLoading && hasValidConstraints && ( + { hasValidConstraints && (
) } diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/price.js b/plugins/woocommerce-blocks/assets/js/base/utils/price.js index 1798a22e01d..cf7fc8ec17f 100644 --- a/plugins/woocommerce-blocks/assets/js/base/utils/price.js +++ b/plugins/woocommerce-blocks/assets/js/base/utils/price.js @@ -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, diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/test/price.js b/plugins/woocommerce-blocks/assets/js/base/utils/test/price.js new file mode 100644 index 00000000000..f1ae8752677 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/utils/test/price.js @@ -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 ); + } + ); +} ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.js b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.js index f6f74200f19..09bbe6b5996 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/block.js @@ -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( () => { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/test/use-price-constraints.js b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/test/use-price-constraints.js new file mode 100644 index 00000000000..499ba04893e --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/test/use-price-constraints.js @@ -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
; + }; + + it( 'price constraint should be updated when new price is set', () => { + const renderer = TestRenderer.create( ); + const container = renderer.root.findByType( 'div' ); + + expect( container.props.priceConstraint ).toBe( 10 ); + + renderer.update( ); + + 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( ); + const container = renderer.root.findByType( 'div' ); + + expect( container.props.priceConstraint ).toBe( 10 ); + + renderer.update( ); + + expect( container.props.priceConstraint ).toBe( 10 ); + } ); +} ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/price-filter/use-price-constraints.js b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/use-price-constraints.js new file mode 100644 index 00000000000..bff8a4103bd --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/price-filter/use-price-constraints.js @@ -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 ), + }; +}; diff --git a/plugins/woocommerce-blocks/tests/js/jest.config.json b/plugins/woocommerce-blocks/tests/js/jest.config.json index 5f21d40bd0c..31c268ecfa8 100644 --- a/plugins/woocommerce-blocks/tests/js/jest.config.json +++ b/plugins/woocommerce-blocks/tests/js/jest.config.json @@ -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": [