Added visually disabling filters instead of hiding them by algolia

This commit is contained in:
Piotr Janosz
2019-08-05 17:03:01 +02:00
committed by fabioberger
parent 785ca4f5d1
commit 85f243e2e0
3 changed files with 50 additions and 8 deletions

View File

@@ -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 }>`

View File

@@ -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>

View File

@@ -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>
);