Skip to content

Commit

Permalink
Price slider implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
del22123 committed Jan 17, 2025
1 parent e55b120 commit 0f73ad4
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/peregrine/lib/talons/FilterModal/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const getStateFromSearch = (initialValue, filterKeys, filterItems) => {

if (existingFilter) {
items.add(existingFilter);
} else {
} else if (group !== 'price') {
console.warn(
`Existing filter ${value} not found in possible filters`
);
Expand Down
11 changes: 9 additions & 2 deletions packages/peregrine/lib/talons/FilterModal/useFilterBlock.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import { useCallback, useState, useEffect, useMemo } from 'react';
import { useLocation } from 'react-router-dom';

export const useFilterBlock = props => {
const { filterState, items, initialOpen } = props;
const { filterState, items, initialOpen, group } = props;
const location = useLocation();

const hasSelected = useMemo(() => {
const params = new URLSearchParams(location.search);
//expansion of price filter dropdown
if (group == 'price') {
return params.get('price[filter]') ? true : false;
}
return items.some(item => {
return filterState && filterState.has(item);
});
}, [filterState, items]);
}, [filterState, items, group, location.search]);

const [isExpanded, setExpanded] = useState(hasSelected || initialOpen);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,10 @@ export const useFilterSidebar = props => {
}, [handleClose]);

const handleReset = useCallback(() => {
filterApi.clear();
setIsApplying(true);
}, [filterApi, setIsApplying]);
//filterApi.clear();
//setIsApplying(true);
history.replace({ search: 'page=1' });
}, [history]);

const handleKeyDownActions = useCallback(
event => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
import { useIntl } from 'react-intl';
import { shape, string, func } from 'prop-types';
import { X as Remove } from 'react-feather';
import { useHistory, useLocation } from 'react-router-dom';

import { useStyle } from '../../../classify';
import Icon from '../../Icon';
Expand All @@ -12,13 +13,22 @@ const CurrentFilter = props => {
const { group, item, removeItem, onRemove } = props;
const classes = useStyle(defaultClasses, props.classes);
const { formatMessage } = useIntl();
const location = useLocation();
const history = useHistory();

const handleClick = useCallback(() => {
removeItem({ group, item });
if (typeof onRemove === 'function') {
onRemove(group, item);
}
}, [group, item, removeItem, onRemove]);

if (group == 'price') {
// preserve all existing params
const params = new URLSearchParams(location.search);
params.delete('price[filter]');
history.replace({ search: params.toString() });
}
}, [group, item, removeItem, onRemove, history, location.search]);

const ariaLabel = formatMessage(
{
Expand Down
131 changes: 100 additions & 31 deletions packages/venia-ui/lib/components/FilterModal/FilterList/filterList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, useMemo } from 'react';
import React, { Fragment, useMemo, useState, useRef } from 'react';
import { array, func, number, shape, string } from 'prop-types';
import { useIntl } from 'react-intl';
import setValidator from '@magento/peregrine/lib/validators/set';
Expand All @@ -8,6 +8,8 @@ import { useStyle } from '../../../classify';
import FilterItem from './filterItem';
import defaultClasses from './filterList.module.css';
import FilterItemRadioGroup from './filterItemRadioGroup';
import RangeSlider from '../../RangeSlider/rangeSlider';
import { useHistory, useLocation } from 'react-router-dom';

const labels = new WeakMap();

Expand All @@ -22,13 +24,65 @@ const FilterList = props => {
items,
onApply
} = props;
const { pathname, search } = useLocation();
const history = useHistory();
const classes = useStyle(defaultClasses, props.classes);
const talonProps = useFilterList({ filterState, items, itemCountToShow });
const { isListExpanded, handleListToggle } = talonProps;
const { formatMessage } = useIntl();

// memoize item creation
// search value is not referenced, so this array is stable
if (name === 'Price') {
debugger;
var minRange = Number(items[0].value.split('_')[0]);
var maxRange = Number(items[items.length - 1].value.split('_')[1]);
}

const [value, setValue] = useState([
minRange ? minRange : null,
maxRange ? maxRange : null
]);

const [isSliding, setIsSliding] = useState(false); // Track whether the user is sliding
const sliderTimeoutRef = useRef(null);

const handleSliderStart = () => {
setIsSliding(true); // User started sliding
if (sliderTimeoutRef.current) {
clearTimeout(sliderTimeoutRef.current);
}
};

const handleSliderEnd = newValue => {
setIsSliding(false); // User stopped sliding
// Call the actual onChange only after a brief delay (debounce)
sliderTimeoutRef.current = setTimeout(() => {
handleChange(newValue);
}, 300); // Delay of 300ms after the user stops interacting with the slider
};

const handleChange = newValue => {
// Remove the previous price filter from the URL
const test = String(search).split('&');
const filters = test.filter(element => {
return !element.includes('price');
});
const newSearch = filters.join('&');
const nextParams = new URLSearchParams(newSearch);

// Append the new price filter range in the URL
const DELIMITER = ',';
const title = String(newValue.min) + '-' + String(newValue.max);
const value = String(newValue.min) + '_' + String(newValue.max);
nextParams.append(`${group}[filter]`, `${title}${DELIMITER}${value}`);

// Write price filter state to history
history.push({ pathname, search: String(nextParams) });

// Set new value to the slider when the slider stops
setValue(newValue);
};

// Memoize item creation
const itemElements = useMemo(() => {
if (filterFrontendInput === 'boolean') {
const key = `item-${group}`;
Expand All @@ -51,36 +105,44 @@ const FilterList = props => {
);
}

return items.map((item, index) => {
const { title, value } = item;
const key = `item-${group}-${value}`;

if (!isListExpanded && index >= itemCountToShow) {
return null;
}

// create an element for each item
const element = (
<li
key={key}
className={classes.item}
data-cy="FilterList-item"
>
<FilterItem
filterApi={filterApi}
filterState={filterState}
group={group}
item={item}
onApply={onApply}
if (name === 'Price') {
return (
<div className={classes.root}>
<RangeSlider
min={minRange}
max={maxRange}
onChange={handleChange}
/>
</li>
</div>
);
} else {
return items.map((item, index) => {
const { title, value } = item;
const key = `item-${group}-${value}`;

// associate each element with its normalized title
// titles are not unique, so use the element as the key
labels.set(element, title.toUpperCase());
return element;
});
if (!isListExpanded && index >= itemCountToShow) {
return null;
}

const element = (
<li
key={key}
className={classes.item}
data-cy="FilterList-item"
>
<FilterItem
filterApi={filterApi}
filterState={filterState}
group={group}
item={item}
onApply={onApply}
/>
</li>
);
labels.set(element, title.toUpperCase());
return element;
});
}
}, [
classes,
filterApi,
Expand All @@ -91,7 +153,14 @@ const FilterList = props => {
items,
isListExpanded,
itemCountToShow,
onApply
onApply,
history,
minRange,
maxRange,
pathname,
search,
value,
isSliding
]);

const showMoreLessItem = useMemo(() => {
Expand Down
3 changes: 2 additions & 1 deletion packages/venia-ui/lib/components/FilterModal/filterBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const FilterBlock = props => {
const talonProps = useFilterBlock({
filterState,
items,
initialOpen
initialOpen,
group
});
const { handleClick, isExpanded } = talonProps;
const iconSrc = isExpanded ? ArrowUp : ArrowDown;
Expand Down
28 changes: 28 additions & 0 deletions packages/venia-ui/lib/components/FilterSidebar/filterSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import LinkButton from '../LinkButton';
import CurrentFilters from '../FilterModal/CurrentFilters';
import FilterBlock from '../FilterModal/filterBlock';
import defaultClasses from './filterSidebar.module.css';
import { useLocation } from 'react-router-dom';

const SCROLL_OFFSET = 150;

Expand All @@ -31,6 +32,32 @@ const FilterSidebar = props => {

const filterRef = useRef();
const classes = useStyle(defaultClasses, props.classes);
const location = useLocation();

//adding the price filter values to the filterstate
const priceFilters = Array.from(filterItems, ([group]) => {
if (group == 'price') {
// preserve all existing params
const params = new URLSearchParams(location.search);
const uniqueKeys = new Set(params.keys());
// iterate over existing param keys
for (const key of uniqueKeys) {
// if a key matches a known filter, add its items to the next state
if (key == 'price[filter]') {
const value = params.get('price[filter]');
const item = {
title: value.split(',')[0],
value: value.split(',')[1]
};
const filterVar = new Set();
filterVar.add(item);

//to display the price filter value after selecting the filter
filterState.set('price', new Set(filterVar));
}
}
}
});

const handleApplyFilter = useCallback(
(...args) => {
Expand Down Expand Up @@ -115,6 +142,7 @@ const FilterSidebar = props => {
/>
</h2>
</div>
{priceFilters}
<CurrentFilters
filterApi={filterApi}
filterNames={filterNames}
Expand Down
Loading

0 comments on commit 0f73ad4

Please sign in to comment.