components/Pagination.js

import React, { Component } from 'react';
import SVGComponent from './SVG/SVGComponent';
import { SVG_ICONS } from '../constants';

/**
 * @module Pagination
 */
/**
 * @typedef {object} props
 * @property {number} page
 * @property {number} totalPage
 * @property {boolean} [isFaded]
 * @property {Function} setPagination
 * @property {Function} paging Calback function when pagging was changed
 */
export default class Pagination extends Component {
  constructor(props) {
    super(props);
    /**
     * @member {object}
     * @property {Array} pages
     */
    this.state = {
      pages: this.setupPagination(props.page, props),
    };
  }

  /**
   * Total pages is changed , setup component
   *
   * @param {object} prevProps
   * @returns {void}
   */
  componentDidUpdate(prevProps) {
    if (this.props.totalPage !== prevProps.totalPage) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({
        pages: this.setupPagination(this.props.page, this.props),
      });
    }
  }

  /**
   * Calculate which pages should be shown
   *
   * @function
   * @param {number} currentPage
   * @param {object} props
   * @returns {Array}
   */
  setupPagination = (currentPage, props) => {
    let pages = [];
    if (props.totalPage > 9) {
      if (currentPage < 6) {
        for (let i = 1; i <= 7; i += 1) {
          pages.push(i);
        }
        pages.push('...');
        pages.push(props.totalPage);
      } else if (currentPage < props.totalPage - 4) {
        pages = [
          1,
          '...',
          currentPage - 2,
          currentPage - 1,
          currentPage,
          currentPage + 1,
          currentPage + 2,
          '...',
          props.totalPage,
        ];
      } else {
        pages = [1, '...'];
        for (let i = props.totalPage - 6; i <= props.totalPage; i += 1) {
          pages.push(i);
        }
      }
    } else {
      for (let i = 1; i <= props.totalPage; i += 1) {
        pages.push(i);
      }
    }
    return pages;
  };

  /**
   * Change pagination page
   *
   * @function
   * @param {number} page
   * @returns {void}
   */
  changePage = (page) => {
    if (this.props.page !== page && page !== '...') {
      this.props.setPagination({ page, callback: this.props.paging });
      this.setState({
        pages: this.setupPagination(page, this.props),
      });
      document.getElementsByClassName('main-wrapper')[0].scrollTo(0, 0);
    }
  };

  /**
   * Go on previous page
   *
   * @returns {void}
   */
  goPrevious = () => {
    if (this.props.page > 1) {
      this.changePage(this.props.page - 1);
    }
  };

  /**
   * Go on next page
   *
   * @returns {void}
   */
  goNext = () => {
    if (this.props.totalPage > this.props.page) {
      this.changePage(this.props.page + 1);
    }
  };

  /**
   * Render page numbers
   *
   * @function
   * @returns {view}
   */
  renderPageNumers = () =>
    this.state.pages.map((page) => (
      <li
        className={this.props.page === page ? 'active' : ''}
        data-page={page}
        onClick={this.changePage.bind(this, page)}
        key={page}
      >
        <span>
          {page}
          <span className="sr-only">(current)</span>
        </span>
      </li>
    ));

  /**
   * Render
   *
   * @returns {view}
   */
  render() {
    return (
      <div className="pagination-container d-flex justify-content-end">
        <nav>
          <ul className="pagination">
            <li data-page="prev" onClick={this.goPrevious}>
              <SVGComponent className="icon-xxs prev-icon" src={`${SVG_ICONS.pagination}#arrow`} />
              <span className="sr-only">(current)</span>
            </li>
            {this.renderPageNumers()}
            <li data-page="next" id="prev" onClick={this.goNext}>
              <SVGComponent className="icon-xxs next-icon" src={`${SVG_ICONS.pagination}#arrow`} />
              <span className="sr-only">(current)</span>
            </li>
          </ul>
        </nav>
      </div>
    );
  }
}