Add Promo Cards to Collection Pages

📘

Components:

🚧

Information

Findify does not host any of the Promo Cards.
The example below shows how you can extract the Promo Cards from the default Collections (via Findify Fallback) and insert into Findify's Grid.

📘

Tip: Change LazyResults as well as StaticResults

Best practise is to change both files in case someone decides to change the settings to use LazyResults instead of StaticResults (or the other way around).

If you want to insert promo cards to Findify collections you need to update StaticResults/view.tsx or LazyResults/view.tsx depending on whether you use lazy loading or not. (However, best practise is to change both files in case someone in the future decides to change the settings to use LazyResults instead of StaticResults (or the other way around).)

PROMO_CARD_SELECTOR_FROM_FINDIFY_FALLBACK - don't forget to set the selector from which you will take the promo card.

insertAfter function is used to help you insert a promo card after some element

/**
 * @module components/search/StaticResults
 */

import React from 'react';
import ItemsList from 'components/ItemsList';
import Grid from 'components/common/Grid';
import PoweredBy from 'components/PoweredBy';
import Pagination from 'components/Pagination';
import { ThemedSFCProps, MJSConfiguration } from 'types';
import { lifecycle } from 'recompose';

/** Props that StaticResults accepts */
export interface IStaticResultsProps extends ThemedSFCProps {
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Number of columns that one item occupies in 12-col grid */
  columns: number;
};

// This is a util function to help you insert after some element
const insertAfter = (newNode, referenceNode) => referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);

// This function is checking if the cards are inserted already after any types of updates
const checkIfAlreadyExists = () => {
  const bannerAlreadyExists = document.querySelector('.findify-components-common--grid .promo-banner');
  if(bannerAlreadyExists){
    bannerAlreadyExists.parentElement.remove();
  }
  return false;
}

const appendBannerToCollectonsGrid = (widgetType) => {
  if(widgetType === 'smart-collection'){
    checkIfAlreadyExists();
  
    const banner = document.querySelector('PROMO_CARD_SELECTOR_FROM_FINDIFY_FALLBACK').cloneNode(true);
    const searchResultsGrid = document.querySelector('.findify-components-common--grid');
    const searchResults = document.querySelectorAll('.findify-components-common--grid__column');

    if(banner && searchResults.length > 0){
      const wrappedBanner = document.createElement('div');
      wrappedBanner.classList = searchResults[0].classList;
      wrappedBanner.classList.add('findify-custom-promo-banner');
      wrappedBanner.append(banner);
      
      // This will insert a promo card after 5th product
      if(searchResults.length > 6){
        const height = searchResults[4].querySelector('.findify-components--cards--product__image-wrap').offsetHeight;
        wrappedBanner.querySelector('.frame-collection').style.height = `${height}px`;
        searchResultsGrid.insertBefore(wrappedBanner.cloneNode(true), searchResults[4].nextSibling);
      }else{
        // And this will insert promo card at the end, if the products are less than needed amount
        const height = searchResults[searchResults.length - 1].querySelector('.findify-components--cards--product__image-wrap').offsetHeight;
        wrappedBanner.querySelector('.frame-collection').style.height = `${height}px`;
        searchResultsGrid.append(wrappedBanner.cloneNode(true));
      }
    }
  }
}

// Enhancer with Lifecycles
const enhancer = lifecycle({
  componentDidMount(){
    const widgetType = this.props.config.get('type');
    appendBannerToCollectonsGrid(widgetType);
  },
  componentDidUpdate(){
    const widgetType = this.props.config.get('type');
    appendBannerToCollectonsGrid(widgetType);
  }
});

const StaticResultsView = ({ columns, theme, config, colorMapping }: IStaticResultsProps) =>
<div className={theme.root}>
  <ItemsList wrapper={Grid} columns={columns} config={config} />
  <Pagination />
  <PoweredBy />
</div>

export default enhancer(StaticResultsView); // Don't forget to add enhancer here
/**
 * @module components/search/LazyResults
 */

import React from 'react';
import MapArray from 'components/common/MapArray';
import Grid from 'components/common/Grid';
import ProductCard from 'components/Cards/Product'
import Button from 'components/Button';
import Text from 'components/Text';
import { ThemedSFCProps, IProduct, MJSConfiguration } from 'types';
import { List } from 'immutable';
import { ArrayLike } from 'components/common/MapArray';
import { lifecycle } from 'recompose';

/** Props that LazyResultsView accepts */
export interface ILazyResultsProps extends ThemedSFCProps {
  /** List of Products */
  items: List<IProduct>;
  /** MJS Configuration */
  config: MJSConfiguration;
  /** Number of columns that one item occupies in a 12-col grid */
  columns: string;
  /** Method to load next page */
  onLoadNext: () => any;
  /** Method to load previous page */
  onLoadPrev: () => any;
  /** Flag whether to display next button */
  displayNextButton: boolean;
  /** Flag whether to display previous button */
  displayPrevButton: boolean;
  /** Rest of the props get passed down to ProductCard */
  [x: string]: any
}

// This is a util function to help you insert after some element
const insertAfter = (newNode, referenceNode) => referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);

// This function is checking if the cards are inserted already after any types of update
const checkIfAlreadyExists = () => {
  const bannerAlreadyExists = document.querySelector('.findify-components-common--grid .promo-banner');
  if(bannerAlreadyExists){
    bannerAlreadyExists.parentElement.remove();
    checkIfAlreadyExists();
  }
  return false;
}

const appendBannerToCollectonsGrid = (widgetType) => {
  if(widgetType === 'smart-collection'){
    checkIfAlreadyExists();
  
    const banner = document.querySelector('PROMO_CARD_SELECTOR_FROM_FINDIFY_FALLBACK').cloneNode(true);
    const searchResultsGrid = document.querySelector('.findify-components-common--grid');
    const searchResults = document.querySelectorAll('.findify-components-common--grid__column');

    if(banner && searchResults.length > 0){
      const wrappedBanner = document.createElement('div');
      wrappedBanner.classList = searchResults[0].classList;
      wrappedBanner.classList.add('findify-custom-promo-banner');
      wrappedBanner.append(banner);
      
      // This will insert a promo card after 5th product
      if(searchResults.length > 6){
        const height = searchResults[4].querySelector('.findify-components--cards--product__image-wrap').offsetHeight;
        wrappedBanner.querySelector('.frame-collection').style.height = `${height}px`;
        searchResultsGrid.insertBefore(wrappedBanner.cloneNode(true), searchResults[4].nextSibling);
      }else{
        // And this will insert promo card at the end, if the products are less than needed amount
        const height = searchResults[searchResults.length - 1].querySelector('.findify-components--cards--product__image-wrap').offsetHeight;
        wrappedBanner.querySelector('.frame-collection').style.height = `${height}px`;
        searchResultsGrid.append(wrappedBanner.cloneNode(true));
      }
    }
  }
}

// Enhancer with Lifecycles
const enhancer = lifecycle({
  componentDidMount(){
    const widgetType = this.props.config.get('type');
    appendBannerToCollectonsGrid(widgetType);
  },
  componentDidUpdate(){
    const widgetType = this.props.config.get('type');
    appendBannerToCollectonsGrid(widgetType);
  }
});

const LazyResultsView = ({
  items,
  config,
  theme,
  card = ProductCard,
  columns,
  onLoadNext,
  onLoadPrev,
  displayNextButton,
  displayPrevButton,
  ...rest
}: ILazyResultsProps) =>
<div className={theme.root}>
  <Button display-if={displayPrevButton} className={theme.prevButton} onClick={onLoadPrev}>
    <Text primary lowercase>
      { config.getIn(['i18n', 'loadPrev'], 'Load previous') }
    </Text>
  </Button>
  <Grid columns={columns}>
    {
      MapArray({
        ...rest,
        config,
        array: (items as ArrayLike),
        factory: card
      })
    }
  </Grid>
  <Button display-if={displayNextButton} className={theme.nextButton} onClick={onLoadNext}>
    <Text primary lowercase>
      { config.getIn(['i18n', 'loadNext'], 'Load more') }
    </Text>
  </Button>
</div>

export default enhancer(LazyResultsView); // add the enhancer here