Added visually disabling filters instead of hiding them by algolia
This commit is contained in:
		
				
					committed by
					
						
						fabioberger
					
				
			
			
				
	
			
			
			
						parent
						
							785ca4f5d1
						
					
				
				
					commit
					85f243e2e0
				
			@@ -6,6 +6,7 @@ import { colors } from 'ts/style/colors';
 | 
			
		||||
export interface IFilterProps extends IFilterCheckboxProps {
 | 
			
		||||
    label: string;
 | 
			
		||||
    customLabel?: string;
 | 
			
		||||
    isDisabled?: boolean;
 | 
			
		||||
    value: string;
 | 
			
		||||
    refine: (value: string) => void;
 | 
			
		||||
}
 | 
			
		||||
@@ -14,22 +15,26 @@ interface IFilterCheckboxProps {
 | 
			
		||||
    isRefined: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const Filter: React.FC<IFilterProps> = ({ isRefined, label, value, customLabel, refine }) => {
 | 
			
		||||
export const Filter: React.FC<IFilterProps> = ({ isDisabled, isRefined, label, value, customLabel, refine }) => {
 | 
			
		||||
    const handleClick = () => refine(value);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <FilterWrapper onClick={handleClick}>
 | 
			
		||||
        <FilterWrapper isDisabled={isDisabled} onClick={handleClick}>
 | 
			
		||||
            <FilterCheckbox isRefined={isRefined} />
 | 
			
		||||
            <FilterLabel>{customLabel ? customLabel : label}</FilterLabel>
 | 
			
		||||
        </FilterWrapper>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const FilterWrapper = styled.label`
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
const FilterWrapper = styled.label<{ isDisabled: boolean }>`
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    margin-bottom: 0.83rem;
 | 
			
		||||
 | 
			
		||||
    cursor: ${({ isDisabled }) => (isDisabled ? 'not-allowed' : 'pointer')};
 | 
			
		||||
    pointer-events: ${({ isDisabled }) => isDisabled && 'none'};
 | 
			
		||||
    opacity: ${({ isDisabled }) => (isDisabled ? 0.3 : 1)};
 | 
			
		||||
    transition: opacity 250ms ease-in-out;
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
const FilterCheckbox = styled.div<{ isRefined: boolean }>`
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ interface IFiltersGroupProps {
 | 
			
		||||
    attribute: string;
 | 
			
		||||
    heading: string;
 | 
			
		||||
    customLabel?: string;
 | 
			
		||||
    operator?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const transformItems = (items: IFiltersGroupProps[]) => _.orderBy(items, 'label', 'asc');
 | 
			
		||||
@@ -20,7 +21,7 @@ const transformItems = (items: IFiltersGroupProps[]) => _.orderBy(items, 'label'
 | 
			
		||||
export const Filters: React.FC<IFiltersProps> = ({ filters }) => (
 | 
			
		||||
    <SidebarWrapper>
 | 
			
		||||
        {filters.map((filter: IFiltersGroupProps, index: number) => (
 | 
			
		||||
            <FiltersGroup key={`filter-${index}`} transformItems={transformItems} {...filter} />
 | 
			
		||||
            <FiltersGroup key={`filter-${index}`} operator="and" transformItems={transformItems} {...filter} />
 | 
			
		||||
        ))}
 | 
			
		||||
        <FiltersClear />
 | 
			
		||||
    </SidebarWrapper>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,13 +9,49 @@ import { styled } from 'ts/style/theme';
 | 
			
		||||
interface IFilterListProps {
 | 
			
		||||
    heading: string;
 | 
			
		||||
    customLabel?: string;
 | 
			
		||||
    isDisabled?: boolean;
 | 
			
		||||
    items: IFilterProps[];
 | 
			
		||||
    operator: string;
 | 
			
		||||
    refine: (value: string) => void;
 | 
			
		||||
    transformItems: (items: IFilterProps[]) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FiltersList: React.FC<IFilterListProps> = ({ items, customLabel, heading, refine }) => {
 | 
			
		||||
    if (!items.length) {
 | 
			
		||||
    const [filters, setFilters] = React.useState<IFilterProps[]>([]);
 | 
			
		||||
 | 
			
		||||
    //    Note (Piotr): Whenever you choose a filter (refinement), algolia removes all filters that could not match the query.
 | 
			
		||||
    //    What we are doing instead is first grabbing the list of all possible filters on mount (or clearing all filters) and
 | 
			
		||||
    //    then visually disabling filters. That way the user is still able to see all filters, even those that do not apply to
 | 
			
		||||
    //    the current state of filtering.
 | 
			
		||||
 | 
			
		||||
    React.useEffect(
 | 
			
		||||
        () => {
 | 
			
		||||
            // This happens on mount when filters are empty or on clearing all filters, when the items number exceeds that of filters
 | 
			
		||||
            if (!filters.length || items.length >= filters.length) {
 | 
			
		||||
                setFilters(items);
 | 
			
		||||
            } else {
 | 
			
		||||
                const updatedFilters = [...filters];
 | 
			
		||||
 | 
			
		||||
                for (const filter of updatedFilters) {
 | 
			
		||||
                    // Look for item corresponding to the filter we already have
 | 
			
		||||
                    const currentItem = items.find(item => item.label === filter.label);
 | 
			
		||||
                    // No match found means that algolia does not return the filter and we disable it on the initial list
 | 
			
		||||
                    if (!currentItem) {
 | 
			
		||||
                        filter.isDisabled = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    // If there is a matching item and it is refined (active), we update our list of filters so that the filter is checked
 | 
			
		||||
                    if (currentItem && currentItem.isRefined) {
 | 
			
		||||
                        filter.isRefined = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setFilters(updatedFilters);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [items],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!filters.length) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -24,8 +60,8 @@ const FiltersList: React.FC<IFilterListProps> = ({ items, customLabel, heading,
 | 
			
		||||
            <Heading asElement="h3" size={18} fontWeight="400" marginBottom="1rem">
 | 
			
		||||
                {heading}
 | 
			
		||||
            </Heading>
 | 
			
		||||
            {items.map((item: IFilterProps, index: number) => (
 | 
			
		||||
                <Filter key={`filter-${index}`} customLabel={customLabel} refine={refine} {...item} />
 | 
			
		||||
            {filters.map((filter: IFilterProps, index: number) => (
 | 
			
		||||
                <Filter key={`filter-${index}`} customLabel={customLabel} refine={refine} {...filter} />
 | 
			
		||||
            ))}
 | 
			
		||||
        </FiltersGroupWrapper>
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user