import _ from 'lodash'; import i18next from 'i18next'; import PropTypes from 'prop-types'; import React, { useState, forwardRef, Ref, useEffect } from 'react'; import IconFilter from '../images/icon-selector-filter.svg'; import IconFilterBlue from '../images/icon-selector-filter-blue.svg'; import InputNumber from '../InputNumber'; import RadioButton from '../RadioButton'; import iconCheckMarkBlue from '../images/icon-check-mark-blue.svg'; import { Container, FilterIcon, TitleContainer, Title, FilterContainer, Content, RowContainer, RowLabel, Icon, ActionContainer, ItemSelectionList, ItemSelectionListRow, } from './styledComponents'; import { getSelectorFilters } from './constants'; import { Props } from './interfaces'; const renderItemSelector = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any list: any[], filterPropertyKey: string, handleSelectItemList: Function ) => { const orderedList = _.orderBy( list, [ (item) => { if (item.id === 'GENERAL_ALL') { return -1; } return (item[filterPropertyKey] || '').toLowerCase(); }, ], ['asc'] ); return ( {orderedList.map((item) => ( handleSelectItemList(item, filterPropertyKey)} selected={item.selected} > {item.name} {item.selected && ( )} ))} ); }; const renderContent = ( type: string, handleCriterionSelection: Function, selectedCriterionId: string, value: number | string, limitValues: { minValue: number | string; maxValue: number | string; }, handleInputChange ) => { const selectorFilters = getSelectorFilters(); if (!Object.prototype.hasOwnProperty.call(selectorFilters, type)) { return null; } return ( <> {selectorFilters[type].content.map((criterion) => ( handleCriterionSelection(criterion.id, criterion.type) } > {criterion.name} {selectedCriterionId === criterion.id && ( )} ))} > ); }; const SelectorFilter = forwardRef( (props: Props, ref: Ref): JSX.Element => { const { type, itemList, filterId, selectedFilter, filterPropertyKey, handleFilterSelection, onFilterChange, isFilterActive, languageCode, customPosition, } = props; // eslint-disable-next-line @typescript-eslint/no-explicit-any const [listToDisplay, setListToDisplay] = useState([]); const [selectedCriterionId, setSelectedCriterionId] = useState(''); const [value, setValue] = useState(0); const [limitValues, setLimitValues] = useState<{ minValue: number | string; maxValue: number | string; }>({ minValue: 0, maxValue: 0, }); useEffect(() => { if (itemList && itemList.length && !listToDisplay.length) { setListToDisplay([ { id: 'GENERAL_ALL', name: i18next.t('GENERAL_ALL'), selected: false, }, ...itemList, ]); } }, [itemList, listToDisplay]); useEffect(() => { if (!isFilterActive) { if (listToDisplay.length) { const updatedListToDisplay = listToDisplay.map((item) => ({ ...item, selected: false, })); setListToDisplay(updatedListToDisplay); } if (selectedCriterionId) { setValue(0); setLimitValues({ minValue: 0, maxValue: 0, }); setSelectedCriterionId(''); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isFilterActive]); useEffect(() => { if (type === 'string' && listToDisplay && listToDisplay.length) { const selectedItems = listToDisplay.filter((item) => item.selected); onFilterChange( `string-selector-filter-${filterPropertyKey}`, getSelectorFilters().string.content[0].doFilter, selectedItems ); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [type, listToDisplay]); useEffect(() => { i18next.changeLanguage(languageCode); }, [languageCode]); const isFilterSelected = selectedFilter === filterId; const handleCriterionSelection = ( criterionId: string, criterionType: string ) => { setSelectedCriterionId( criterionId !== selectedCriterionId ? criterionId : '' ); if (criterionType === 'single') { setValue(0); } else { setLimitValues({ minValue: 0, maxValue: 0 }); } }; const handleSelectItemList = (selectedItem) => { if (selectedItem.id === 'GENERAL_ALL') { const areAllItemsSelected = listToDisplay.every((item) => { if (item.id === 'GENERAL_ALL') { return true; } return item.selected; }); const updatedListToDisplay = listToDisplay.map((item) => ({ ...item, selected: !areAllItemsSelected, })); setListToDisplay(updatedListToDisplay); return; } const updatedListToDisplay = listToDisplay.map((item) => { if (item.name === selectedItem.name) { return { ...item, selected: !item.selected, }; } return item; }); const areAllUpdatedItemsSelected = updatedListToDisplay.every((item) => { if (item.id === 'GENERAL_ALL') { return true; } return item.selected; }); setListToDisplay( updatedListToDisplay.map((item) => { if (item.id === 'GENERAL_ALL') { return { ...item, selected: areAllUpdatedItemsSelected, }; } return item; }) ); }; const handleFilter = () => { // get values according to type of the chosen filter criterion const filterValues = selectedCriterionId === 'between' ? limitValues : value; const selectorFilters = getSelectorFilters(); // get filter criterion definition const filterCriterion = selectorFilters[type].content.find( (criterion) => criterion.id === selectedCriterionId ); // update filter if (filterCriterion) { onFilterChange(filterId, filterCriterion.doFilter, filterValues); } else { onFilterChange(filterId, null, null); } handleFilterSelection(filterId); }; const handleInputChange = (e, id: string) => { const formattedValue = !Number.isNaN(parseInt(e.target.value, 10)) ? parseInt(e.target.value, 10) : null; if (formattedValue === null) { return; } if (id === 'min') { setLimitValues({ ...limitValues, ...{ minValue: formattedValue } }); } else if (id === 'max') { setLimitValues({ ...limitValues, ...{ maxValue: formattedValue } }); } else { setValue(formattedValue); } }; return ( { e.stopPropagation(); handleFilterSelection(filterId); }} onMouseEnter={(e) => !isFilterActive && e.target.setAttribute('src', IconFilterBlue) } onMouseLeave={(e) => !isFilterActive && e.target.setAttribute('src', IconFilter) } /> {isFilterSelected && ( e.stopPropagation()} customPosition={customPosition} > {type === 'string' && renderItemSelector( listToDisplay, filterPropertyKey, handleSelectItemList )} {type !== 'string' && ( <> {i18next.t('COMPONENT_VALUE_SELECTOR_FILTER_SELECTION')} {renderContent( type, handleCriterionSelection, selectedCriterionId, value, limitValues, handleInputChange )} {i18next.t('GENERAL_VALIDATE')} > )} )} ); } ); SelectorFilter.propTypes = { filterId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) .isRequired, type: PropTypes.string.isRequired, handleFilterSelection: PropTypes.func.isRequired, onFilterChange: PropTypes.func.isRequired, selectedFilter: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.object, ]), languageCode: PropTypes.string, // eslint-disable-next-line react/forbid-prop-types itemList: PropTypes.arrayOf(PropTypes.any), filterPropertyKey: PropTypes.string.isRequired, isFilterActive: PropTypes.bool, customPosition: PropTypes.string, }; SelectorFilter.defaultProps = { itemList: [], languageCode: 'fr', selectedFilter: null, isFilterActive: false, customPosition: '-135', }; export default SelectorFilter;
{criterion.name}