Home Reference Source

src/components/snippets/Spinner/Spinner.jsx

import React, { Component, Fragment } from 'react';
import { Spinner } from 'reactstrap';
import cx from 'classnames';
import { eq, values } from 'lodash';
import PropTypes from 'prop-types';

const TYPE = {
  INLINE: 'inline',
  COVER: 'cover',
};

let Comp = Spinner;

const timer = ms => new Promise(res => setTimeout(res, ms));

class BaseSpinner extends Component {
  constructor(props) {
    super(props);

    this.state = {
      endTimeout: false,
    };

    this.delayTimer = this.delayTimer.bind(this);
    this.renderCoverSpiner = this.renderCoverSpiner.bind(this);
    this.renderLineSpinner = this.renderLineSpinner.bind(this);
  }

  static setSpinner(component) {
    Comp = component;
  }

  async componentDidUpdate(prevProps) {
    if (!prevProps.loading && this.props.loading) {
      await this.delayTimer();
    }
  }

  async componentDidMount() {
    if (this.props.loading) {
      await this.delayTimer();
    }
  }

  async delayTimer() {
    const { endTimeout } = this.state;
    const { delay } = this.props;

    if (delay) {
      this.setState({ endTimeout: false });
      await timer(delay);
      this.setState({ endTimeout: true });
    }
  }

  renderCoverSpiner() {
    const { children, className, text, loading, type, ...rest } = this.props;
    const { endTimeout } = this.state;
    return (
      <div
        className={cx('n2o-spinner-wrapper', {
          [className]: className,
        })}
      >
        {endTimeout && loading && (
          <Fragment>
            <div className="n2o-spinner-container ">
              <Comp color="primary" {...rest} />
              <div className="loading_text">{text}</div>
            </div>
            <div className="spinner-background" />
          </Fragment>
        )}
        {children}
      </div>
    );
  }

  renderLineSpinner() {
    const { type, ...rest } = this.props;
    return <Comp {...rest} />;
  }

  render() {
    const { type } = this.props;
    return eq(type, TYPE.COVER)
      ? this.renderCoverSpiner()
      : this.renderLineSpinner();
  }
}

BaseSpinner.propTypes = {
  loading: PropTypes.bool,
  type: PropTypes.oneOf(values(TYPE)),
  delay: PropTypes.number,
  text: PropTypes.string,
};

BaseSpinner.defaultProps = {
  loading: true,
  type: 'inline',
  delay: 400,
  text: '',
};

export default BaseSpinner;