diff --git a/app/search/[collection]/page.tsx b/app/search/[collection]/page.tsx index 3494d6e5b..860dfea79 100644 --- a/app/search/[collection]/page.tsx +++ b/app/search/[collection]/page.tsx @@ -82,11 +82,11 @@ const constructFilterInput = (filters: { } if (filters[`${PRICE_FILTER_ID}.max`]) { price.max = Number(filters[`${PRICE_FILTER_ID}.max`]); + !price.min && (price.min = 0); } - if (price.max && !price.min) { - price.min = 0; + if (price.max || price.min) { + results.push({ price }); } - results.push({ price }); return results; }; diff --git a/components/layout/search/filters/price-range.tsx b/components/layout/search/filters/price-range.tsx index 59a494b64..9fb335c6d 100644 --- a/components/layout/search/filters/price-range.tsx +++ b/components/layout/search/filters/price-range.tsx @@ -1,6 +1,7 @@ 'use client'; import Price from 'components/price'; +import { useDebounce } from 'hooks'; import { Filter } from 'lib/shopify/types'; import { createUrl } from 'lib/utils'; import get from 'lodash.get'; @@ -16,21 +17,6 @@ const currencySymbol = .formatToParts(1) .find((part) => part.type === 'currency')?.value || '$'; -const useDebounce = (value: string, delay = 500) => { - const [debouncedValue, setDebouncedValue] = useState(''); - const timerRef = useRef>(); - - useEffect(() => { - timerRef.current = setTimeout(() => setDebouncedValue(value), delay); - - return () => { - clearTimeout(timerRef.current); - }; - }, [value, delay]); - - return debouncedValue; -}; - const PriceRange = ({ id, values }: { id: string; values: Filter['values'] }) => { const highestPrice = values.reduce( (acc, { value }) => Math.max(acc, get(value, 'price.max', 0)), @@ -41,76 +27,85 @@ const PriceRange = ({ id, values }: { id: string; values: Filter['values'] }) => const pathname = usePathname(); const router = useRouter(); - const priceMin = searchParams.get(`${id}.min`); - const priceMax = searchParams.get(`${id}.max`); + const initialPriceMin = searchParams.get(`${id}.min`); + const initialPriceMax = searchParams.get(`${id}.max`); - const [min, setMin] = useState(priceMin || ''); - const [max, setMax] = useState(priceMax || ''); + const [minPrice, setMinPrice] = useState(initialPriceMin || ''); + const [maxPrice, setMaxPrice] = useState(initialPriceMax || ''); - const debouncedMin = useDebounce(min); - const debouncedMax = useDebounce(max); + const debouncedMinPrice = useDebounce(minPrice); + const debouncedMaxPrice = useDebounce(maxPrice); - const minRef = useRef(min); - const maxRef = useRef(max); + const minPriceRef = useRef(minPrice); + const maxPriceRef = useRef(maxPrice); const updateSearchParams = useCallback( (priceRange: { min: string; max: string }) => { const newSearchParams = new URLSearchParams(searchParams); - newSearchParams.set(`${id}.min`, priceRange.min); - newSearchParams.set(`${id}.max`, priceRange.max); + if (!priceRange.min) { + newSearchParams.delete(`${id}.min`); + } else { + newSearchParams.set(`${id}.min`, priceRange.min); + } + if (!priceRange.max) { + newSearchParams.delete(`${id}.max`); + } else { + newSearchParams.set(`${id}.max`, priceRange.max); + } router.replace(createUrl(pathname, newSearchParams), { scroll: false }); }, [id, pathname, router, searchParams] ); const handleChangeMinPrice = (value: string) => { - setMin(value); - minRef.current = value; + setMinPrice(value); + minPriceRef.current = value; }; const handleChangeMaxPrice = (value: string) => { - setMax(value); - maxRef.current = value; + setMaxPrice(value); + maxPriceRef.current = value; }; + useEffect(() => { - if (debouncedMin) { - let _minPrice = debouncedMin; + if (debouncedMinPrice) { + let _minPrice = debouncedMinPrice; const minNum = Number(_minPrice); if (minNum < 0) { _minPrice = '0'; } - if (maxRef.current && minNum > Number(maxRef.current)) { - _minPrice = maxRef.current; + if (maxPriceRef.current && minNum > Number(maxPriceRef.current)) { + _minPrice = maxPriceRef.current; } if (minNum > highestPrice) { _minPrice = String(highestPrice); } - if (_minPrice !== debouncedMin) { + if (_minPrice !== debouncedMinPrice) { handleChangeMinPrice(_minPrice); } - updateSearchParams({ min: _minPrice, max: maxRef.current }); + updateSearchParams({ min: _minPrice, max: maxPriceRef.current }); } else { - updateSearchParams({ min: '', max: maxRef.current }); + updateSearchParams({ min: '', max: maxPriceRef.current }); } - }, [debouncedMin, highestPrice, updateSearchParams]); + }, [debouncedMinPrice, highestPrice, updateSearchParams]); useEffect(() => { - if (debouncedMax) { - let _maxPrice = debouncedMax; + if (debouncedMaxPrice) { + let _maxPrice = debouncedMaxPrice; const maxNum = Number(_maxPrice); - if (minRef.current && maxNum < Number(minRef.current)) { - _maxPrice = minRef.current; + if (minPriceRef.current && maxNum < Number(minPriceRef.current)) { + _maxPrice = minPriceRef.current; } if (maxNum > highestPrice) { _maxPrice = String(highestPrice); } - if (_maxPrice !== debouncedMax) { + if (_maxPrice !== debouncedMaxPrice) { handleChangeMaxPrice(_maxPrice); } - updateSearchParams({ min: minRef.current, max: _maxPrice }); + updateSearchParams({ min: minPriceRef.current, max: _maxPrice }); } else { - updateSearchParams({ min: minRef.current, max: '' }); + updateSearchParams({ min: minPriceRef.current, max: '' }); } - }, [debouncedMax, highestPrice, updateSearchParams]); + }, [debouncedMaxPrice, highestPrice, updateSearchParams]); return (
@@ -126,7 +121,7 @@ const PriceRange = ({ id, values }: { id: string; values: Filter['values'] }) => min={0} max={highestPrice} placeholder="From" - value={min} + value={minPrice} onChange={(e) => handleChangeMinPrice(e.target.value)} />
@@ -135,10 +130,10 @@ const PriceRange = ({ id, values }: { id: string; values: Filter['values'] }) => handleChangeMaxPrice(e.target.value)} /> diff --git a/hooks/index.tsx b/hooks/index.tsx new file mode 100644 index 000000000..055c3cb9b --- /dev/null +++ b/hooks/index.tsx @@ -0,0 +1,16 @@ +import { useEffect, useRef, useState } from 'react'; + +export const useDebounce = (value: string, delay = 500) => { + const [debouncedValue, setDebouncedValue] = useState(''); + const timerRef = useRef>(); + + useEffect(() => { + timerRef.current = setTimeout(() => setDebouncedValue(value), delay); + + return () => { + clearTimeout(timerRef.current); + }; + }, [value, delay]); + + return debouncedValue; +};