redbadger/website-honestly

View on GitHub
site/pages/join-us/benefits-slice/category/index.js

Summary

Maintainability
A
0 mins
Test Coverage
F
40%
// @flow
import React, { Component } from 'react';
import Benefit from '../benefit';
import type { BenefitProps } from '../benefit';
import styles from './style.css';
import ShowMoreIcon from '../../../../components/show-more-button';

export type CategoryProps = {
  name: string,
  icon: string,
  benefits: Array<BenefitProps>,
};

type CategoryState = {
  open: boolean,
  mobileView: boolean,
  mobileBreakPoint: number,
  currentWindowSize: number,
};

class Category extends Component<CategoryProps, CategoryState> {
  constructor(props: CategoryProps) {
    super(props);
    this.state = {
      open: false,
      mobileView: false,
      mobileBreakPoint: 690,
      currentWindowSize: 690,
    };
  }

  componentDidMount = () => {
    // At desktop the user can show/hide individual benefits whereas at mobile
    // they show/hide whole categories. This can't be done with CSS alone
    // hence the direct sampling of window.innerWidth here.

    // Checking for window and innerWidth to prevent errors when rendering server-side
    if (typeof window !== 'undefined' && window.innerWidth) {
      this.setLayoutOnLoad();
      this.setLayoutOnResize();
    }
  };

  setLayoutOnLoad = () => {
    this.setState(({ mobileBreakPoint }) => {
      const mobileViewOnLoad = this.screenIsMobileSize(mobileBreakPoint);

      return {
        mobileView: mobileViewOnLoad,
        open: !mobileViewOnLoad,
        currentWindowSize: window.innerWidth,
      };
    });
  };

  setLayoutOnResize = () => {
    window.addEventListener('resize', () => {
      const mobileViewOnResize = this.screenIsMobileSize.bind(this, this.state.mobileBreakPoint);
      const determineCategoryOpen = this.determineCategoryOpen.bind(this);
      const previousWindowSize = this.state.currentWindowSize;
      const currentWindowSize = window.innerWidth;
      this.setState({
        mobileView: mobileViewOnResize(),
        open: determineCategoryOpen(previousWindowSize, currentWindowSize),
        currentWindowSize,
      });
    });
  };

  props: CategoryProps;

  handleClick = () => {
    // categories can only be opened/closed at mobile.
    if (this.state.mobileView) {
      this.setState(({ open }) => ({ open: !open }));
    }
  };

  screenIsMobileSize = (mobileBreakPoint: number) => {
    return window.innerWidth < mobileBreakPoint;
  };

  toggleCategoriesVisibility = (open: boolean, mobileView: boolean) => {
    if (open || !mobileView) {
      return styles.category__visible;
    }
    return styles.category__hidden;
  };

  determineCategoryOpen = (previousWindowSize: number, currentWindowSize: number) => {
    const { mobileBreakPoint } = this.state;
    // if it transfers from desktop to mobile it should be false
    // if the window width is under the mobile breakpoint. The categories
    // should remain as-is.
    // if it's above the breakpoint it should always be true.
    if (previousWindowSize > mobileBreakPoint && currentWindowSize <= mobileBreakPoint) {
      return false;
    }
    if (currentWindowSize <= mobileBreakPoint) {
      return this.state.open;
    }
    return true;
  };

  /* eslint-disable react/no-danger */
  /* eslint-disable jsx-a11y/no-static-element-interactions */
  render() {
    const { name, icon, benefits } = { ...this.props };
    const { open, mobileView } = { ...this.state };
    return (
      <div className={styles.category}>
        <button
          type="button"
          aria-expanded={open}
          aria-label={`expand ${name} section`}
          className={styles.category__content}
          onClick={this.handleClick}
        >
          <h3 className={styles.category__title}>{name}</h3>
          {mobileView && (
            <div className={styles.categoryButton__container}>
              <ShowMoreIcon open={open} />
            </div>
          )}
          <img src={icon} alt={`${name} icon`} className={styles.category__icon} />
        </button>
        <ul
          className={[
            styles.category__questionList,
            this.toggleCategoriesVisibility(open, mobileView),
          ].join(' ')}
        >
          {benefits.map(({ question, answer }) => (
            <li key={question}>
              <Benefit question={question} answer={answer} mobileView={mobileView} />
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

export default Category;