Hide Filters in Selected Collections

In certain circumstances, merchants might decide they want to hide specific filtering options for specific collections.

This could be, for example, if you have a collection of 200 products but only 10 have a value for 'size'. In this case, you might want to hide the 'size' filter for this collection, but not for others.

Or, it could be that you have a large amount of filters. This is not a problem for niche collections, but if you have a particularly large collection then you might have 50 filters which is too much for a shopper to navigate through easily. In this case you might want to slim down the filtering options, but only for the larger collection.

Whatever the reason, Findify is able to accommodate this potential merchant requirement.

📘

Components

  • components/Facet/view.tsx
  • components/search/DesktopFacets/view.tsx
  • layouts/Search/view.tsx
  • components/search/MobileFacets/Titles.tsx
  • components/search/MobileFacets/view.tsx

To get the current collection handle, use this code: - const enhancer = withProps(() => ({ collectionHandle: document.URL.split("collections/") }));

To create a list of the collections in which you want to hide some filters, use this code: const CollectionArray = ['baseball','gloves'];

Add to components/Facet/view display-if={ !(isCollection && CollectionArray.find(i => collectionHandle[1].indexOf(i) > -1) && title === 'Color') }

/**
 * @module components/Facet
 */

import React from 'react';
import Button from 'components/Button';
import Text from 'components/Text';
import Icon from 'components/Icon';
import Component from 'components/Facet/Component';
import { ThemedSFCProps, IFacet, MJSConfiguration } from 'types';
import { List, Map } from 'immutable';

/** Props that Facet view accepts */
export interface IFacetProps extends ThemedSFCProps {
  /** Facet component to render */
  FacetComponent: React.Component<any>;
  /** Flag to show open / closed state of facet */
  isOpen?: boolean;
  /** Flag to show if facet is opened on mobile */
  isMobile?: boolean;
  /** Title of facet */
  title: string;
  /** Facet object */
  item: IFacet;
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Filters selected in facet */
  filtersSelected: number;
  isCollection: boolean;
  meta: Map<string, MJSValue>;
  /** Function to toggle open / closed state of facet */
  toggleFacet: () => any
}

const enhancer = withProps(() => ({
      collectionHandle: document.URL.split("collections/")
}));  /** get collection name */


const CollectionArray = ['baseball','gloves']; /** List of collections */

const FacetView = ({
  FacetComponent,
  isOpen,
  theme,
  title,
  item,
  config,
  filtersSelected,
  isCollection,
  toggleFacet,
  meta
}: IFacetProps) => (
  <div display-if={ !(isCollection && CollectionArray.find(i => collectionHandle[1].indexOf(i) > -1) && title === 'Color') } className={theme.root}>    /** Paste here display-if to hide filter from collection */
    <Button className={theme.title} onClick={toggleFacet}>
      <Text primary uppercase className={theme.text}>{ title } {filtersSelected > 0 ? `(${filtersSelected})` : ''}</Text>
      <Icon name={isOpen ? 'Minus' : 'Plus'} className={theme.icon} />
    </Button>
    <Component
      display-if={isOpen}
      facet={item}
      config={config}
      theme={{ root: theme.body }}
      isMobile={true} />
  </div>
)

export default FacetView;

Then you should push forward isCollection in DesktopFacets/view.tsx and Search/view.tsx

/**
 * @module components/search/DesktopFacets
 */

import React from 'react';
import Branch from 'components/common/Branch';
import MapArray from 'components/common/MapArray';
import Facet from 'components/Facet';
import Sticky from 'components/common/Sticky';
import Text from 'components/Text';
import Button from 'components/Button';
import Icon from 'components/Icon';
import { classNames } from 'classnames';
import * as titles from 'components/search/DesktopFacets/Title';
import { MJSConfiguration, ThemedSFCProps, IFacet, MJSValue } from 'types';
import { List, Map } from 'immutable';

const DefaultContent = ({ theme, children, config }) =>
  <div className={theme.root}>{children}</div>

/** Props that DesktopFacets view accepts */
export interface IDesktopFacetsProps extends ThemedSFCProps {
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Facets list */
  facets: List<IFacet>;
  /** Method called to reset facets */
  onReset: () => any;
  /** MJS API Response Metadata */
  meta: Map<string, MJSValue>;
  /** Method to hide facets */
  hideFacets: () => any;
  /** Shows visibility status of facets */
  visible: boolean;
}

const DesktopFacetsView: React.SFC<IDesktopFacetsProps> =  ({
  config,
  facets, theme, onReset, meta, hideFacets, visible, isCollection }: IDesktopFacetsProps) =>
<Branch
  display-if={!config.get('hidableFacets') || visible}
  theme={theme}
  condition={config.getIn(['view', 'stickyFilters'])}
  left={Sticky}
  right={DefaultContent}>
  <Branch
    display-if={!config.get('showFacetsTitle')}
    meta={meta}
    config={config}
    theme={theme}
    onReset={onReset}
    onHide={hideFacets}
    condition={config.get('hidableFacets')}
    left={titles.hidable}
    right={titles.default}
  />
  <MapArray
    theme={{ root: theme.facet }}
    array={facets}
    factory={Facet}
    config={config}
    isCollection={isCollection}/** Paste here isCollection props */
    meta={meta}
    keyAccessor={i => i.get('name')} />

</Branch>

export default DesktopFacetsView;
/**
 * @module layouts/Search
 */
import cx from 'classnames'
import React from 'react';
import Grid from 'components/common/Grid';
import StaticResults from 'components/search/StaticResults';
import LazyResults from 'components/search/LazyResults';
import DesktopFacets from 'components/search/DesktopFacets';
import MobileActions from 'components/search/MobileActions';
import DesktopActions from 'components/search/DesktopActions';
import Branch from 'components/common/Branch';
import Banner from 'components/Banner';
import { List } from 'immutable'
import { MJSConfiguration, ThemedSFCProps, IProduct } from 'types';

/** Props that search layout accepts */
export interface ISearchProps extends ThemedSFCProps {
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Flag that switches Search to mobile layout */
  isMobile?: boolean;
  /** Flag to turn on Smart Collection display mode */
  isCollection?: boolean;
  /** Flag to render mobile facets */
  mobileFacetsOpened?: boolean;
  /** Flag to show filters on the right side of desktop search */
  filtersOnRight?: boolean;
  /** Items list */
  items: List<IProduct>;
}

const SearchLayout = ({ config, meta, isMobile, isCollection, mobileFacetsOpened, filtersOnRight, theme, items }) =>
  <div className={theme.root}>
    <DesktopFacets isCollection={isCollection} display-if={!isMobile && !filtersOnRight} />
    <div className={theme.content}>
      <Branch
        isCollection={isCollection}
        condition={isMobile}
        left={MobileActions}
        right={DesktopActions} />
      <Banner />
      <Branch left={LazyResults} right={StaticResults} condition={config.getIn(['view', 'infinite'])} />
    </div>
    <DesktopFacets isCollection={isCollection} meta={meta} display-if={!isMobile && filtersOnRight} />
  </div>


export default SearchLayout;

For the mobile version you should add this code: display-if={ !(isCollection && CollectionArray.find(i => collectionHandle[1].indexOf(i) > -1) && config.getIn(['facets', 'labels', item.get('name')], item.get('name')) === 'Color') } to components/search/MobileFacets/Titles.tsx to Button

To get the current collection handle use this code: const enhancer = withProps(() => ({ collectionHandle: document.URL.split("collections/") }));

To create the list of collections in which you want to hide some filters use this code: const CollectionArray = ['baseball','gloves'];

/**
 * @module components/search/MobileFacets
 */

import React from 'react';
import { withHandlers, withPropsOnChange, compose, withProps } from 'recompose';
import MapArray from 'components/common/MapArray';
import Button from 'components/Button';
import Text from 'components/Text';
import { ThemedSFCProps, IFacet, MJSConfiguration } from 'types';
import { List } from 'immutable';

const withClickHandler = withHandlers({
  onClick: ({ selectFacet, item }) => () => selectFacet(item.get('name'))
});

/** Props that MobileFacets FacetLabel accepts */
export interface IMobileFacetsLabelProps extends ThemedSFCProps {
  /** Facet */
  item: IFacet;
  /** Count of filters enabled */
  filterCount?: number;
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Click handler to open facet customization menu */
  onClick: (evt?: React.MouseEvent<any>) => any
}


/** TODO: Not sure this is really needed, but find a way to show selected filters count,
 *  when filters are overflowing, which is not hacky
 */


const enhancer = withProps(() => ({
      collectionHandle: document.URL.split("collections/")
}));  /** get collection name */


const CollectionArray = ['baseball','gloves']; /** List of collections */


const FacetLabel = compose(
  withClickHandler,
  enhancer,
  withPropsOnChange(['item'], ({ item }) => ({
    isTextFacet: item && ['category', 'text'].includes(item.get('type')),
    selectedValues: item && item.get('values').filter(item => item.get('selected')) || List(),
  }))
)(({ item, isTextFacet, isCollection, meta, theme, onClick, selectedValues, config, collectionHandle }: any) =>
  <Button 
  display-if={ !(isCollection &&  CollectionArray.find(i => collectionHandle[1].indexOf(i) > -1) &&  config.getIn(['facets', 'labels', item.get('name')], item.get('name')) === 'Color') } 
  raw className={theme.facetTitle} onClick={onClick}>

    <div className={theme.flexFix}>
      <Text primary uppercase inlineBlock>
      { config.getIn(['facets', 'labels', item.get('name')], item.get('name')) }
      </Text>
      <Text
        display-if={isTextFacet}
        secondary
        inlineBlock
        className={theme.selectedValues}>
        {selectedValues.map(item => item.get('value')).join(', ')}
      </Text>
      <Text
        display-if={selectedValues.size > 0 && !isTextFacet}
        className={theme.filterCount}
        secondary
        uppercase
        inlineBlock>
        ({ selectedValues.size })
      </Text>
    </div>
  </Button>
)

/** Props that MobileFacets TitlesView accepts */
export interface IMobileFacetsTitlesProps extends ThemedSFCProps {
  /** immutable.List of facets */
  facets: List<IFacet>;
  /** Method to select facet by its name */
  selectFacet: (name: string) => any;
  /** MJS Configuration */
  config: MJSConfiguration;
}

const MobileFacetsTitlesView = ({ theme, facets, selectFacet, config, meta, isCollection }: IMobileFacetsTitlesProps) =>
  <MapArray
    config={config}
    theme={theme}
    selectFacet={selectFacet}
    factory={FacetLabel}
    isCollection={isCollection}
    meta={meta}
    array={facets} />

export default enhancer(MobileFacetsTitlesView);

And push forward isCollection to components/search/MobileFacets/view.tsx

/**
 * @module components/search/MobileFacets
 */

import React from 'react';
import { withHandlers, withPropsOnChange, compose } from 'recompose';
import Branch from 'components/common/Branch';
import MapArray from 'components/common/MapArray';
import FacetTitles from 'components/search/MobileFacets/Titles';
import Component from 'components/Facet/Component';
import Button from 'components/Button';
import Facet from 'components/Facet';
import cx from 'classnames';
import Icon from 'components/Icon';
import Text from 'components/Text';
import { ThemedSFCProps, IFacet, MJSConfiguration, MJSValue } from 'types';
import { List } from 'immutable';

/** Props that FacetContent accepts */
export interface IFacetContentProps extends ThemedSFCProps {
  /** Currently active facet */
  active: IFacet;
  /** MJS Configuration */
  config: MJSConfiguration;
}

const FacetContent = ({ active, config, theme,isCollection, meta }: IFacetContentProps) => (
  <div className={cx(theme.container, theme[active.get('type') as string])}>
    <Component
      isExpanded
      type={active.get('type')}
      facet={active}
      config={config}
      meta={meta}/** Paste here meta props */
      isCollection={isCollection}/** Paste here isCollection props */
      theme={{
        range: theme.range,
        expand: theme.expand,
        expandedList: theme.expandedList,
      }}
      isMobile={true}
    />
  </div>
);

/** Props that MobileFacets view accepts */
export interface IMobileFacetsProps extends ThemedSFCProps {
  /** immutable.List() of Facets */
  facets: List<IFacet>;
  /** Currently active facet */
  activeFacet?: IFacet;
  /** Method used to select a facet */
  selectFacet: (name?: string) => any
  /** Method used to reset facet */
  onReset: () => any
  /** MJS Configuration */
  config: MJSConfiguration;
  /** MJS API Request Metadata */
  meta: Map<string, MJSValue>;
  /** Method used for hiding modal / drawer */
  hideModal: (name: string) => any
  /** Total filters selected */
  total: number;
  /** Filters selected for active facet */
  filtersSelected: number;
}

export default ({
  theme,
  facets,
  activeFacet,
  selectFacet,
  onReset,
  config,
  meta,
  hideModal,
  total,
  filtersSelected,
  isCollection,
  title,
}: IMobileFacetsProps) =>
<div className={cx(theme.modal, 'mobile')}>
  <div className={theme.header}>

    <div className={theme.title}>
      <Text primary uppercase display-if={!activeFacet}>
        { config.getIn(['facets', 'i18n', 'filters'], 'Filters') }
      </Text>
      <Text secondary uppercase display-if={!activeFacet && total} className={theme.filterCount}>
        ({ total })
      </Text>
      <Text primary uppercase display-if={!!activeFacet}>
        { config.getIn(['facets', 'labels', activeFacet!.get('name')]) }
      </Text>
      <Text secondary uppercase display-if={!!activeFacet && filtersSelected} className={theme.filterCount}>
        ({ filtersSelected })
      </Text>
    </div>

    <Button onClick={activeFacet ? selectFacet : hideModal} className={theme.backButton} >
      <Icon name='ArrowBack' />
    </Button>

    <Button
      display-if={meta.get('filters') && meta!.get('filters')!.size}
      onClick={onReset}>
      <Text secondary uppercase>
        { config.getIn(['facets', 'i18n', 'clearAll'], 'Clear All')}
      </Text>
    </Button>

  </div>
  <div className={theme.body}>
    
    <Branch
      config={config}
      theme={theme}
      meta={meta}
      selectFacet={selectFacet}
      isCollection={isCollection}/** Paste here isCollection props */
      active={activeFacet}
      facets={facets}
      condition={!!activeFacet}
      right={FacetTitles}
      left={FacetContent} />
  </div>
  <Button className={theme.footer} onClick={activeFacet ? selectFacet : hideModal}>
    { config.getIn(['facets', 'i18n', activeFacet ? 'done' : 'showResults'], 'See results')}
  </Button>
</div>