diff --git a/assets/js/base/components/formatted-monetary-amount/index.tsx b/assets/js/base/components/formatted-monetary-amount/index.tsx index 213b665d27c..394fd379180 100644 --- a/assets/js/base/components/formatted-monetary-amount/index.tsx +++ b/assets/js/base/components/formatted-monetary-amount/index.tsx @@ -17,6 +17,8 @@ import './style.scss'; interface FormattedMonetaryAmountProps { className?: string; displayType?: NumberFormatProps[ 'displayType' ]; + allowNegative?: boolean; + isAllowed?: ( formattedValue: NumberFormatValues ) => boolean; value: number | string; // Value of money amount. currency: Currency | Record< string, never >; // Currency configuration object. onValueChange?: ( unit: number ) => void; // Function to call when value changes. diff --git a/assets/js/base/components/price-slider/index.js b/assets/js/base/components/price-slider/index.js index 18edd7677f9..533bded0d3f 100644 --- a/assets/js/base/components/price-slider/index.js +++ b/assets/js/base/components/price-slider/index.js @@ -20,6 +20,7 @@ import { isObject } from '@woocommerce/types'; import './style.scss'; import { constrainRangeSliderValues } from './constrain-range-slider-values'; import FilterSubmitButton from '../filter-submit-button'; +import { withMaxValueLimit, withMinValueLimit } from './utils'; /** * Price slider component. @@ -212,9 +213,27 @@ const PriceSlider = ( { ) { return; } + const isMin = event.target.classList.contains( 'wc-block-price-filter__amount--min' ); + + // When user insert in the minimum price input a value greater than the max price, + // we update the value of the slider to 0 - max. + if ( minPriceInput > maxPriceInput ) { + const values = constrainRangeSliderValues( + [ 0, maxPriceInput ], + null, + null, + stepValue, + isMin + ); + return onChange( [ + parseInt( values[ 0 ], 10 ), + parseInt( values[ 1 ], 10 ), + ] ); + } + const values = constrainRangeSliderValues( [ minPriceInput, maxPriceInput ], null, @@ -322,6 +341,12 @@ const PriceSlider = ( { 'Filter products by minimum price', 'woo-gutenberg-products-block' ) } + allowNegative={ false } + isAllowed={ withMinValueLimit( { + minConstraint, + minorUnit: currency.minorUnit, + currentMaxValue: maxPriceInput, + } ) } onValueChange={ ( value ) => { if ( value === minPriceInput ) { return; @@ -340,6 +365,10 @@ const PriceSlider = ( { 'Filter products by maximum price', 'woo-gutenberg-products-block' ) } + isAllowed={ withMaxValueLimit( { + maxConstraint, + minorUnit: currency.minorUnit, + } ) } onValueChange={ ( value ) => { if ( value === maxPriceInput ) { return; diff --git a/assets/js/base/components/price-slider/utils.ts b/assets/js/base/components/price-slider/utils.ts new file mode 100644 index 00000000000..88c1038ea30 --- /dev/null +++ b/assets/js/base/components/price-slider/utils.ts @@ -0,0 +1,35 @@ +/** + * External dependencies + */ +import { NumberFormatValues } from 'react-number-format'; + +export const withMaxValueLimit = ( { + maxConstraint, + minorUnit, +}: { + maxConstraint: number; + minorUnit: number; +} ) => ( { floatValue }: NumberFormatValues ): boolean => { + const maxPrice = maxConstraint / 10 ** minorUnit; + + return floatValue !== undefined && floatValue <= maxPrice; +}; + +export const withMinValueLimit = ( { + minConstraint, + currentMaxValue, + minorUnit, +}: { + minConstraint: number; + currentMaxValue: number; + minorUnit: number; +} ) => ( { floatValue }: NumberFormatValues ): boolean => { + const minPrice = minConstraint / 10 ** minorUnit; + const currentMaxPrice = currentMaxValue / 10 ** minorUnit; + + return ( + floatValue !== undefined && + floatValue >= minPrice && + floatValue < currentMaxPrice + ); +};