index.js

import React, { useRef } from 'react';
import { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import useDimensions from '../../../hooks/common/useDimension';
import { sendEventViewItem } from '../../../utility/analytics/events';
import PlainText from '../../composite/plain-text';

import './index.scss';

const ps_all = 24; // padding: 12px
const ps_xs = 12; // padding: 6px
const PREV = 'prev';
const NEXT = 'next';
const SLIDER_MAX_COUNT = 6;

// Analytics
function send(params, location) {
  sendEventViewItem(params, location);
}

function getCardCount(width) {
  let count;
  // prettier-ignore
  switch (true) {
    case (width < 576): count = 2.1; break;
    case (width < 768): count = 3.5; break;
    case (width < 992): count = 4.5; break;
    case (width < 1200): count = 5; break;
    case (width < 1600): count = 6; break;
    case (width < 2000): count = 7; break;
    case (width > 2000): count = Math.floor(width / 350); break;
  }
  return count;
}

function getCardSize(width) {
  const padding = width > 576 ? ps_all : ps_xs;
  const count = getCardCount(width);
  return width / count - padding;
}

function getSetCount(width, data) {
  const { list } = data;
  // NOTE: flooring the value to show only full sets
  const sets = Math.floor(list.length / (getCardCount(width) * 2));
  // NOTE: limiting the number of sets maximum
  return sets < SLIDER_MAX_COUNT ? sets : SLIDER_MAX_COUNT;
}

function getTemplateTwoRow(params) {
  const { data, offscreen, location, category, width } = params;
  let template = [];
  const { list } = data;
  const cardWidth = getCardSize(width);

  function getCard(list, i) {
    const isActive = i < getCardCount(width) * 2;
    // NOTE: auto loading type loads image immediately
    // NOTE: lazy loading type loads image if it comes in view
    const loadingType = isActive && !offscreen ? 'auto' : 'lazy';
    const imgStyle = { width: `${cardWidth}px`, height: `${cardWidth * 0.56}px` };
    const { videoId, url, title } = list[i];
    return (
      <div className="slider-card" style={{ width: `${cardWidth}px` }} key={videoId}>
        <Link
          to={`/watch/${videoId}`}
          onClick={() => send({ to: `/watch/${videoId}`, videoId, title, category }, location)}
        >
          <img className="slider-image" src={url} style={imgStyle} loading={loadingType} />
          <div className="title">
            <PlainText text={title} />
          </div>
        </Link>
      </div>
    );
  }

  for (let i = 0; i < list.length; i++) {
    let column = [];
    let keyName = '';
    column.push(getCard(list, i));
    keyName += list[i].videoId;
    if (i + 1 < list.length) {
      i = i + 1;
      column.push(getCard(list, i));
      keyName += list[i].videoId;
    }
    template.push(
      <section className="slider-card-column" key={keyName}>
        {column}
      </section>
    );
  }

  return template;
}

export default function SliderCards({ data, offscreen, category }) {
  const sliderCardsRef = useRef();
  const { title } = data;
  const [dimensions] = useDimensions(sliderCardsRef);
  const { width } = dimensions;
  const location = useLocation();
  const [index, setIndex] = useState(0);
  const [translateBy, setTranslateBy] = useState(0);
  const templateRowParams = { data, offscreen, location, category, width };
  const sliderBodyContent = getTemplateTwoRow(templateRowParams);
  const noOfSets = getSetCount(width, data);

  // EVENT HANDLERS
  // TODO: add resize handler
  function chevronClicked(type) {
    let _index;
    const { clientWidth: cw } = document.body;

    if (!type) throw Error('chevron type not passed to click handler');
    if (type === PREV) {
      _index = index === 0 ? noOfSets - 1 : index - 1;
    }
    if (type === NEXT) {
      _index = index === noOfSets - 1 ? 0 : index + 1;
    }
    const translateBy = _index === 0 ? 0 : _index * cw;
    setIndex(_index);
    setTranslateBy(translateBy);
  }

  function onClickPrev() {
    chevronClicked(PREV);
  }

  function onClickNext() {
    chevronClicked(NEXT);
  }

  return (
    <div className="slider-cards" data-ride="slider" ref={sliderCardsRef}>
      <div className="slider-header">
        <h2 className="slider-header-title">{title}</h2>
        <ol className="slider-indicators">
          {Array.from(new Array(noOfSets).keys()).map((_, _index) => {
            return <li className={`${index === _index ? ' active' : ''}`} key={_index.toString()}></li>;
          })}
        </ol>
      </div>
      <div className="slider-body">
        <div className="slider-items" style={{ transform: `translateX(-${translateBy}px)` }}>
          {sliderBodyContent}
        </div>
        <a className="slider-control slider-control-prev" onClick={onClickPrev}>
          <svg className="icon prev-chevron" fill="none">
            <use href="#next-chevron"></use>
          </svg>
        </a>
        <a className="slider-control slider-control-next" onClick={onClickNext}>
          <svg className="icon next-chevron" fill="none">
            <use href="#next-chevron"></use>
          </svg>
        </a>
      </div>
    </div>
  );
}