containers/TopBar/index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import Constants, { GAME_TYPE } from '../../constants';
import BetsCountDown from '../../components/TopBar/BetsCountDown';
import LeagueSelection from '../../components/TopBar/LeagueSelection';
import BonusHeader from '../../components/TopBar/BonusHeader';
import MyAccount from '../../components/Account/MyAccount';
import {
  changePage, openModal, disablePlacebet, setSelectedLeague, toggleAccount,
  liveFinished, getTicketsRequest, setupLiveRequest, getScoresRequest, setupTurboLiveRequest,
  getRoundRequest,
  getTurboRoundRequest,
} from '../../reducers';
import {
  getCurrentPage, getUser, getBonus, getBonusLeveling, getConfigs, getFreeBets,
  getCnt, getIsAccountOpen,
} from '../../store/common';
import {
  getNoBettingTimeCountdown, getLeagues, getSelectedLeague, getShowNoBetTime,
  getRoundEnd, getLiveStart, getLiveMatchDuration, getNoBettingTime,
  getHaveLiveMatches, getGameType, getSelectedLeagueIndex, getRoundId, getLiveId,
} from '../../store/bets';
import { getPlacebetDisabled, getPlacedSelections, getPlacedSelectionsTurbo } from '../../store/placebet';
import {
  isSetup,
  getLiveCountdown,
  getLiveDecrement,
} from '../../store/live';
import LiveCountDown from '../../components/TopBar/LiveCountDown';
import { isLivePage } from '../../utils/common';
import { getNumberOfBets, getNumberOfBetsTurbo, getHasPendingTickets } from '../../store/tickets';
import LiveLeagueNavigation from '../../components/LiveLeagueNavigation';

const mapToProps = (state) => ({
  bonus: getBonus(state),
  bonusLeveling: getBonusLeveling(state),
  currentPage: getCurrentPage(state),
  cnt: getCnt(state),
  config: getConfigs(state),
  freeBets: getFreeBets(state),
  gameType: getGameType(state),
  hasPendingTickets: getHasPendingTickets(state),
  haveLiveMatches: getHaveLiveMatches(state),
  isAccountOpen: getIsAccountOpen(state),
  isSetup: isSetup(state),
  leagues: getLeagues(state),
  liveCountdown: getLiveCountdown(state),
  liveDecrement: getLiveDecrement(state),
  liveMatchDuration: getLiveMatchDuration(state),
  liveStart: getLiveStart(state),
  noBettingTimeCountdown: getNoBettingTimeCountdown(state),
  noBettingTime: getNoBettingTime(state),
  numberOfBets: getNumberOfBets(state),
  numberOfBetsTurbo: getNumberOfBetsTurbo(state),
  placebetDisabled: getPlacebetDisabled(state),
  placedSelections: getPlacedSelections(state),
  placedSelectionsTurbo: getPlacedSelectionsTurbo(state),
  roundEnd: getRoundEnd(state),
  selectedLeague: getSelectedLeague(state),
  showNoBetTime: getShowNoBetTime(state),
  selectedLeagueIndex: getSelectedLeagueIndex(state),
  user: getUser(state),
  roundId: getRoundId(state),
  liveId: getLiveId(state),
});

const actionsToProps = (dispatch) => ({
  changePage: (payload) => dispatch(changePage(payload)),
  openModal: (payload) => dispatch(openModal(payload)),
  disablePlacebet: (payload) => dispatch(disablePlacebet(payload)),
  setSelectedLeague: (payload) => dispatch(setSelectedLeague(payload)),
  toggleAccount: (payload) => dispatch(toggleAccount(payload)),
  liveFinished: (payload) => dispatch(liveFinished(payload)),
  getTickets: (payload) => dispatch(getTicketsRequest(payload)),
  setupLive: (payload) => dispatch(setupLiveRequest(payload)),
  setupTurboLive: (payload) => dispatch(setupTurboLiveRequest(payload)),
  getScores: (payload) => dispatch(getScoresRequest(payload)),
  getRound: (payload) => dispatch(getRoundRequest(payload)),
  getTurboRound: (payload) => dispatch(getTurboRoundRequest(payload)),
});
/**
 * @class
 * @property {object} props
 * @property {string} props.currentPage Indicate current page
 * @property {object} props.user User information
 * @property {object} props.bonus Bonus information
 * @property {boolean} props.isAccountOpen Indicate is account modal open
 * @property {Array} props.bonusLeveling Bonus leveling information
 * @property {Array} props.freeBets Free bets information
 * @property {number} props.noBettingTimeCountdown Indicate number
 * of seconds for no bet time countdown
 * @property {Array} props.leagues All leagues information
 * @property {object} props.selectedLeague Selected league information
 * @property {boolean} props.showNoBetTime Indicate is no bet time modal showen
 * @property {Time} props.roundEnd Time of round ending
 * @property {Time} props.liveStart Time of new live start
 * @property {number} props.liveMatchDuration Indicate seconds number of live game duration
 * @property {boolean} props.placebetDisabled Indicate when to disable placebet
 * @property {number} props.noBettingTime Indicate seconds before round end when no betting start
 * @property {number} props.config Contain currency string
 * @property {string} props.cnt CNT path
 * @property {string} props.gameType Game type Classic/Turbo
 *
 * @property {Function} props.getTickets API call for new tickets
 * @property {Function} props.liveFinished Remove live game
 * @property {Function} props.toggleAccount Toggle account modal in the header
 * @property {Function} props.disablePlacebet Disable placebet button in betslip
 * @property {Function} props.openModal Open modal
 * @property {Function} props.changePage Change page
 */
class TopBar extends Component {
  constructor(props) {
    super(props);
    /**
     * @member {object}
     * @property {boolean} isLeagueSelectionOpen
     * @property {boolean} isBonusHeaderOpen
     */
    this.state = {
      isLeagueSelectionOpen: false,
      isBonusHeaderOpen: false,
    };
    /**
     * @member {boolean}
     * @description Reference on BetsCountDown component
     */
    this.BetsCountDown = null;
    /**
     * @member  {boolean}
     * @description Reference on BonusHeader component
     */
    this.BonusHeader = null;
    /**
     * @member {boolean}
     * @description Reference on LiveCountDown component
     */
    this.LiveCountDown = null;
    /**
     * @member {boolean}
     */
    this.intervalId = null;

    // ComponentWillMount
    if (props.showNoBetTime) {
      this.openNoBettingModal();
    } else {
      this.startInterval();
    }
  }

  /**
   * Start coundown if data from first round call is fatched. Also close
   * modals when page change and when account modal is open
   *
   * @param {object} prevProps
   * @returns {void}
   */
  componentDidUpdate(prevProps) {
    if (this.props.showNoBetTime && this.intervalId == null) {
      this.openNoBettingModal();
    } else if ((this.props.roundEnd && this.intervalId == null)
      || this.wereLeaguesUpdated(prevProps.leagues, this.props.leagues)) {
      this.startInterval();
    }
    if ((this.props.currentPage !== prevProps.currentPage)
      || (this.props.isAccountOpen && !prevProps.isAccountOpen)) {
      this.toggleLeagueSelectionModal(true);
      this.toggleBonusHeader(true);
    }
  }

  /**
   * Call clear interval
   *
   * @returns {void}
   */
  componentWillUnmount() {
    clearInterval(this.intervalId);
  }

  /**
   * Check if leagues were enabled/disabled in the meanwhile
   *
   * @function
   * @param {Array} leagues1
   * @param {Array} leagues2
   * @returns {boolean}
   */
  wereLeaguesUpdated = (leagues1, leagues2) => leagues1.filter((l) => l.enabled).map((l) => l.id).join('') !== leagues2.filter((l) => l.enabled).map((l) => l.id).join('');

  /**
   * Toggle bonus and close other
   *
   * @function
   * @param {boolean} close
   * @returns {void}
   */
  toggleBonusHeader = (close) => {
    const collapseContent = document.getElementById('c-bonus');
    if (collapseContent) {
      collapseContent.scrollTop = 0;
    }
    this.setState({
      isBonusHeaderOpen: close === true
        ? false
        : !this.props.isAccountOpen && !this.state.isBonusHeaderOpen,
    });
    if (close !== true) {
      this.toggleLeagueSelectionModal(true);
    }
  }

  /**
   * Close other modals to awoid to have 2 in the same time opened
   *
   * @function
   * @param {boolean} close
   * @returns {void}
   */
  toggleLeagueSelectionModal = (close) => {
    this.setState({
      isLeagueSelectionOpen: close === true
        ? false
        : !this.props.isAccountOpen && !this.state.isLeagueSelectionOpen,
    });
    if (close !== true) {
      this.toggleBonusHeader(true);
    }
  }

  /**
   * Start all counters: bonus counter, next round start counter, live counter
   *
   * @function
   * @returns {void}
   */
  startInterval = () => {
    // @TODO sometimes counter decrement for 2 seconds
    const competitions = this.props.leagues.filter((l) => l.enabled);
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
    this.intervalId = setInterval((leagues) => {
      if (this.BetsCountDown) {
        if (this.props.user
          && this.props.liveStart
          && this.props.haveLiveMatches
          && this.props.gameType === GAME_TYPE.TURBO
        ) {
          const timeDiff = parseInt((new Date().getTime() - this.props.liveStart.getTime()) / 1000);
          if (timeDiff > this.props.liveMatchDuration) {
            this.props.liveFinished({
              gameType: this.props.gameType,
              extraDuration: isLivePage(this.props.currentPage),
            });
          }
        }
        if (this.props.roundEnd) {
          this.BetsCountDown.setTime(this.props.roundEnd, this.props.liveStart);
        } else {
          this.BetsCountDown.clear();
        }
      }
      if (this.BonusHeader && this.props.bonus && this.props.bonus.active) {
        this.BonusHeader.calculateBonusTime(this.props.bonus.expirationDate);
      }
      if (this.LiveCountDown && !this.LiveCountDown.isUnmounted
        && isLivePage(this.props.currentPage) && this.props.haveLiveMatches) {
        this.LiveCountDown.startLiveCountdown(leagues);
      }
    }, 1000, competitions);
  }

  /**
   * Open No Betting Modal
   *
   * @function
   * @returns {void}
   */
  openNoBettingModal = () => {
    this.props.openModal({
      modal: Constants.MODALS.NO_BETTING_TIME,
      props: {
        round: '',
        noBettingTimeCountdown: this.props.noBettingTimeCountdown,
        leftTime: null,
        fatchingRoundInProgress: true,
        isTurbo: this.props.gameType === GAME_TYPE.TURBO,
      },
    });
    this.intervalId = 1;
  }

  /**
   * Render
   *
   * @see module:TopBar/LeagueSelection
   * @see module:TopBar/BonusHeader
   * @see module:Account/MyAccount
   * @see module:TopBar/LiveCountDown
   * @returns {view}
   */
  render() {
    const props = this.props;
    const bonusRank = props.bonus && props.bonus.bonusName.toLowerCase();
    const hasPlacedSelections = this.props.gameType === GAME_TYPE.TURBO
      ? this.props.placedSelectionsTurbo[this.props.liveId]
      : this.props.placedSelections[this.props.liveId];

    return (
      <>
        <div className={`l-bar bonus--${bonusRank} ${props.currentPage === Constants.PAGES.LOGIN && 'hidden'}`}>
          <BetsCountDown
            ref={(reff) => { this.BetsCountDown = reff; }}
            numberOfBets={this.props.numberOfBets + this.props.numberOfBetsTurbo}
            noBettingTimeCountdown={props.noBettingTimeCountdown}
            setCurrentPage={props.changePage}
            toggleLeagueSelectionModal={this.toggleLeagueSelectionModal}
            openModal={props.openModal}
            selectedLeague={props.selectedLeague}
            isLeagueSelectionOpen={this.state.isLeagueSelectionOpen}
            liveFinished={this.props.liveFinished}
            liveMatchDuration={this.props.liveMatchDuration}
            noBettingTime={this.props.noBettingTime}
            placebetDisabled={this.props.placebetDisabled}
            haveLiveMatches={this.props.haveLiveMatches}
            disablePlacebet={this.props.disablePlacebet}
            currentPage={this.props.currentPage}
            getTickets={this.props.getTickets}
            gameType={this.props.gameType}
            hasPendingTickets={this.props.hasPendingTickets}
            getRound={this.props.getRound}
            getTurboRound={this.props.getTurboRound}
          />
          <LeagueSelection
            isLeagueSelectionOpen={this.state.isLeagueSelectionOpen && !this.props.isAccountOpen}
            leagues={props.leagues}
            turbo
            cnt={this.props.cnt}
            currentPage={this.props.currentPage}
            setSelectedLeague={props.setSelectedLeague}
            toggleLeagueSelectionModal={this.toggleLeagueSelectionModal}
            user={props.user}
            gameType={this.props.gameType}
            selectedLeagueIndex={this.props.selectedLeagueIndex}
            liveFinished={this.props.liveFinished}
            setCurrentPage={props.changePage}
            haveLiveMatches={this.props.haveLiveMatches}
          />

          {props.bonus && (
            <BonusHeader
              ref={(reff) => { this.BonusHeader = reff; }}

              bonus={props.bonus}
              freeBets={props.freeBets}
              bonusLeveling={props.bonusLeveling}
              isBonusHeaderOpen={this.state.isBonusHeaderOpen && !this.props.isAccountOpen}
              toggleBonusHeader={this.toggleBonusHeader}
              config={this.props.config}
            />
          )}

          {props.user && (
            <MyAccount
              userAmount={props.user.balance.amount}
              className="account-scrolled"
              toggleAccount={props.toggleAccount}
              isAccountOpen={props.isAccountOpen}
              currencySymbol={props.config?.currencySymbol}
            />
          )}
        </div>

        {isLivePage(this.props.currentPage)
          && (
            <>
              <LiveLeagueNavigation
                showMyLive={!!this.props.user && hasPlacedSelections}
                currentPage={this.props.currentPage}
                changePage={this.props.changePage}
                leagues={this.props.leagues}
                setSelectedLeague={this.props.setSelectedLeague}
                selectedLeagueIndex={this.props.selectedLeagueIndex}
                cnt={this.props.cnt}
                selectedLeague={this.props.selectedLeague}
                gameType={this.props.gameType}
              />
              <LiveCountDown
                ref={(reff) => { this.LiveCountDown = reff; }}
                liveCountdown={this.props.liveCountdown}
                selectedLeague={this.props.selectedLeague}
                liveDecrement={this.props.liveDecrement}
                liveMatchDuration={this.props.liveMatchDuration}
                liveStart={this.props.liveStart}
                isSetup={this.props.isSetup}
                currentPage={this.props.currentPage}
                setupLive={this.props.setupLive}
                setupTurboLive={this.props.setupTurboLive}
                getScores={this.props.getScores}
                gameType={this.props.gameType}
                getTickets={this.props.getTickets}
                liveFinished={this.props.liveFinished}
                openModal={props.openModal}
                roundId={this.props.roundId}
              />
            </>
          )}
      </>
    );
  }
}

export default connect(
  mapToProps,
  actionsToProps,
)(TopBar);