diff --git a/assets/js/base/components/formatted-monetary-amount/index.tsx b/assets/js/base/components/formatted-monetary-amount/index.tsx index 4eb92f962b5..4b7bef06de9 100644 --- a/assets/js/base/components/formatted-monetary-amount/index.tsx +++ b/assets/js/base/components/formatted-monetary-amount/index.tsx @@ -18,6 +18,8 @@ interface FormattedMonetaryAmountProps extends Omit< NumberFormatProps, 'onValueChange' > { 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.tsx b/assets/js/base/components/price-slider/index.tsx index e18aa9f4102..aa1ef665945 100644 --- a/assets/js/base/components/price-slider/index.tsx +++ b/assets/js/base/components/price-slider/index.tsx @@ -19,6 +19,7 @@ import { Currency, isObject } from '@woocommerce/types'; import './style.scss'; import { constrainRangeSliderValues } from './constrain-range-slider-values'; import FilterSubmitButton from '../filter-submit-button'; +import { isValidMaxValue, isValidMinValue } from './utils'; export interface PriceSliderProps { /** @@ -240,9 +241,27 @@ const PriceSlider = ( { ) { return; } + const isMin = event.target.classList.contains( 'wc-block-price-filter__amount--min' ); + + // When the user inserts in the max price input a value less or equal than the current minimum price, + // we set to 0 the minimum price. + 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, @@ -351,6 +370,12 @@ const PriceSlider = ( { 'Filter products by minimum price', 'woo-gutenberg-products-block' ) } + allowNegative={ false } + isAllowed={ isValidMinValue( { + minConstraint, + minorUnit: currency.minorUnit, + currentMaxValue: maxPriceInput, + } ) } onValueChange={ ( value ) => { if ( value === minPriceInput ) { return; @@ -369,6 +394,10 @@ const PriceSlider = ( { 'Filter products by maximum price', 'woo-gutenberg-products-block' ) } + isAllowed={ isValidMaxValue( { + 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..1fbab6fe2f9 --- /dev/null +++ b/assets/js/base/components/price-slider/utils.ts @@ -0,0 +1,41 @@ +/** + * External dependencies + */ +import { NumberFormatValues } from 'react-number-format'; + +/** + Check if that the value is minor than the max price and greater than 0. + */ +export const isValidMaxValue = ( { + maxConstraint, + minorUnit, +}: { + maxConstraint: number; + minorUnit: number; +} ) => ( { floatValue }: NumberFormatValues ): boolean => { + const maxPrice = maxConstraint / 10 ** minorUnit; + + return floatValue !== undefined && floatValue <= maxPrice && floatValue > 0; +}; + +/** + Check if that the value is minor than the max price and greater than 0. + */ +export const isValidMinValue = ( { + 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 + ); +};