containers/Live/index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import Constants, { SVG_ICONS, GAME_TYPE } from '../../constants';
import { parseCompetitors } from '../../utils/parser';
import SVGComponent from '../../components/SVG/SVGComponent';
import { changePage, setSelectedLeague, resetLiveData } from '../../reducers';
import {
  getLeagues, getSelectedLeagueIndex, getSelectedLeague, getGameType, getRoundId, getLiveId,
} from '../../store/bets';
import { getCurrentPage, getUser, getCnt } from '../../store/common';
import {
  getScores, getBlink, getLiveCountdown,
} from '../../store/live';
import { getPlacedSelections, getPlacedSelectionsTurbo } from '../../store/placebet';

const mapToProps = (state) => ({
  currentPage: getCurrentPage(state),
  leagues: getLeagues(state),
  selectedLeagueIndex: getSelectedLeagueIndex(state),
  selectedLeague: getSelectedLeague(state),
  user: getUser(state),
  placedSelections: getPlacedSelections(state),
  placedSelectionsTurbo: getPlacedSelectionsTurbo(state),
  scores: getScores(state),
  blink: getBlink(state),
  cnt: getCnt(state),
  gameType: getGameType(state),
  liveCountdown: getLiveCountdown(state),
  roundId: getRoundId(state),
  liveId: getLiveId(state),
});

const actionsToProps = (dispatch) => ({
  changePage: (payload) => dispatch(changePage(payload)),
  setSelectedLeague: (payload) => dispatch(setSelectedLeague(payload)),
  resetLiveData: (payload) => dispatch(resetLiveData(payload)),
});

/**
 * @class
 * @property {object} props
 * @property {string} props.currentPage Indicate current page
 * @property {object} props.selectedLeague Selected league information
 * @property {number} props.selectedLeagueIndex Indicate selected league index in leagues array
 * @property {object} props.user User information
 * @property {Array} props.leagues All leagues information
 * @property {Array} props.placedSelections Array of selections showed on My Live page
 * @property {Array} props.placedSelectionsTurbo Array of selections Turbo
 * showed on My Live page
 * @property {string} props.cnt CNT path
 *
 * @property {Function} props.setSelectedLeague Change selected league
 * @property {Function} props.changePage Change page
 */
class Live extends Component {
  constructor(props) {
    super(props);
    /**
     * @member {object}
     * @property {object} collapsedMatches Key (league-match) indicate is it collapsed or expanded
     */
    this.state = {
      collapsedMatches: {},
    };

    this.lastReveal = {};

    this.COLOR_ID_CLASSES = {};
    this.COLOR_ID_CLASSES[Constants.COLOR_IDS.ALWAYS_LOSE] = 'txt-r';
    this.COLOR_ID_CLASSES[Constants.COLOR_IDS.LOSE] = '';
    this.COLOR_ID_CLASSES[Constants.COLOR_IDS.WIN] = '';
    this.COLOR_ID_CLASSES[Constants.COLOR_IDS.ALWAYS_WIN] = 'txt-g';
  }

  /**
   * Clear all intervals and timeouts
   *
   * @returns {void}
   */
  componentWillUnmount() {
    this.props.resetLiveData();
  }

  /**
   * Toggle collapse/expand placed selections
   *
   * @function
   * @param {number} index
   * @param {number} leagueId
   * @returns {void}
   */
  expandSelections = (index, leagueId) => {
    if (!this.state.collapsedMatches[`${leagueId}-${index}`]) {
      this.state.collapsedMatches[`${leagueId}-${index}`] = true;
    } else {
      this.state.collapsedMatches[`${leagueId}-${index}`] = false;
    }
    this.setState({ collapsedMatches: this.state.collapsedMatches });
  }

  /**
   * Render live matches table view depend on current Live page
   *
   * @function
   * @param {Array} liveMatches
   * @returns {view}
   */
  renderLive = (liveMatches) => {
    switch (this.props.currentPage) {
      case Constants.PAGES.ALL_LIVE:
        return this.props.leagues.map((league) => (league.liveEnabled ? (
          league.liveMatches.map((match, ind) => this.renderLiveMatch(match, ind, [], true, league))
        ) : (null)));
      case Constants.PAGES.MY_LIVE: {
        const placedSelectionsLive = this.props.gameType === GAME_TYPE.TURBO
          ? this.props.placedSelectionsTurbo[this.props.liveId]
          : this.props.placedSelections[this.props.liveId];
        return placedSelectionsLive
          && this.props.leagues.map((league) => (league.liveEnabled ? (
            league.liveMatches.map((match, ind) => (placedSelectionsLive[league.id]
              && placedSelectionsLive[league.id][ind]
              ? this.renderLiveMatch(
                match,
                ind,
                placedSelectionsLive[league.id][ind],
                true,
                league,
              )
              : null))
          ) : (null)));
      }
      default:
        return liveMatches.map((el, ind) => (
          this.renderLiveMatch(el, ind, null, false, this.props.selectedLeague)));
    }
  }

  /**
   * Render one row view
   *
   * @function
   * @param {string} match
   * @param {number} index
   * @param {Array} placedSelectionsLive
   * @param {boolean} showLeague
   * @param {object} league
   * @returns {view}
   */
  renderLiveMatch = (match, index, placedSelectionsLive, showLeague, league) => {
    const teams = parseCompetitors(match);
    const HIndex = index * 2;
    const AIndex = (index * 2) + 1;
    const blink = this.props.blink[league.id] || [];
    const score = this.props.scores[league.id] || [];
    const totalGoals = parseInt(score[AIndex]) + parseInt(score[HIndex]);
    const collapse = this.state.collapsedMatches[`${league.id}-${index}`];
    // we are using pulse0, pulse1, reveal0 and reveal1 to fix bad animation of near goals
    let reveal = blink[HIndex] === true || blink[AIndex] === true ? ` reveal${totalGoals % 2} ` : ' ';

    if (reveal === ' ') {
      reveal = this.lastReveal[`${league}-${match}`] || ' ';
    } else {
      this.lastReveal[`${league}-${match}`] = reveal;
    }

    const pulseClass = ` pulse${totalGoals % 2} `;
    return (
      <div
        className={`live__matches-row ${showLeague && !collapse ? '' : 'collapsed'}`}
        data-toggle="collapse"
        href="#match1"
        role="button"
        onClick={this.expandSelections.bind(this, index, league.id)}
        key={match}
      >
        <div className="live__matches-toggle">
          {showLeague && (
            <div className="live__matches-league">
              <SVGComponent
                className="live__matches-team-flag"
                src={`${SVG_ICONS.flags}#${league.flag}`}
              />
            </div>
          )}
          <div className={`live__matches-goal ${reveal}`}>
            <div className="txt">Goal!</div>
          </div>
          <div className="live__matches-team home">
            <SVGComponent
              key={league.id}
              className="live__matches-team-flag mr-3"
              src={`${SVG_ICONS.shirts}${league.name.toLowerCase().replace(/\s/g, '')}.svg#${league.flag}-${teams[0].toLowerCase()}-home`}
            />
            <span className="live__matches-team-name text-right">
              {teams[0]}
            </span>
          </div>
          <div className="live__matches-result">
            <span className={`${blink[HIndex] === true ? pulseClass : ''}`}>{score[HIndex]}</span>
            <span>-</span>
            <span className={`${blink[AIndex] === true ? pulseClass : ''}`}>{score[AIndex]}</span>
          </div>
          <div className="live__matches-team away">
            <span className="live__matches-team-name">{teams[1]}</span>
            <SVGComponent
              key={league.id}
              className="live__matches-team-flag ml-3"
              src={`${SVG_ICONS.shirts}${league.name.toLowerCase().replace(/\s/g, '')}.svg#${league.flag}-${teams[1].toLowerCase()}-away`}
            />
          </div>
          {Constants.PAGES.MY_LIVE === this.props.currentPage && (
            <div className="live__matches-arrow">
              <SVGComponent
                className="icon-m"
                src={`${SVG_ICONS.utility}#icon__arrow`}
              />
            </div>
          )}
        </div>
        {this.renderColapse(placedSelectionsLive, showLeague && !collapse)}
      </div>
    );
  }

  /**
   * Render placed selections view
   *
   * @function
   * @param {Array} placedSelectionsLive
   * @param {boolean} expand
   * @returns {view}
   */
  renderColapse = (placedSelectionsLive, expand) => (
    <div className={`live__matches-content collapse ${expand && 'show'}`} id="match1">
      <div className="live__matches-table">
        {placedSelectionsLive && placedSelectionsLive.map((selection) => (
          <div
            className={`live__matches-table-row ${this.COLOR_ID_CLASSES[this.renderUpdatedColorId(selection.colorId)]}`}
            key={selection.selection.fullName}
          >
            <div className="live__matches-odd-name">
              {selection.selection.fullName}
            </div>
            <div className="live__matches-odd-value">
              <span>{parseFloat(selection.odd).toFixed(2)}</span>
              {this.renderSelctionStatus(selection.colorId)}
            </div>
          </div>
        ))}
      </div>
    </div>
  )

  /**
   * Render updated color id on full time
   *
   * @function
   * @param {number} colorId
   * @returns {view}
   */
  renderUpdatedColorId = (colorId) => {
    let updatedColorId = colorId;
    if ((this.props.liveCountdown <= 0 || this.props.liveCountdown === 'FULL TIME')
      && (colorId === Constants.COLOR_IDS.LOSE || colorId === Constants.COLOR_IDS.WIN)) {
      updatedColorId += 1;
    }
    return updatedColorId;
  }

  /**
   * Render selectionStatus
   *
   * @function
   * @param {number} colorId
   * @returns {view}
   */
  renderSelctionStatus = (colorId) => {
    const updatedColorId = this.renderUpdatedColorId(colorId);
    switch (updatedColorId) {
      case Constants.COLOR_IDS.WIN:
        return (<span className="live__matches-status t-win">W</span>);
      case Constants.COLOR_IDS.LOSE:
        return (<span className="live__matches-status t-lost">L</span>);
      case Constants.COLOR_IDS.ALWAYS_WIN:
        return (<span className="live__matches-status won">W</span>);
      case Constants.COLOR_IDS.ALWAYS_LOSE:
        return (<span className="live__matches-status lost">L</span>);
      default:
        return null;
    }
  }

  /**
   * Render
   *
   * @see module:LiveLeagueNavigation
   * @returns {view}
   */
  render() {
    const liveMatches = this.props.selectedLeague && this.props.selectedLeague.liveMatches;
    return (
      <div className="scroll-area">
        <div className="live">
          <div className="live__matches">
            {liveMatches ? this.renderLive(liveMatches) : null}
          </div>
        </div>
      </div>
    );
  }
}

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