import React, { Component } from 'react';
import { connect } from 'react-redux';
import Constants, { FIXED_HEADER_HEIGHT, HEADER_HEIGHT, GAME_TYPE } from '../../constants';
import SVGProvider from '../../components/SVG/SVGProvider';
import Header from '../../components/Header';
import PushMenu from '../../components/PushMenu';
import MMenu from '../../components/MMenu';
import TopBar from '../TopBar';
import MyAccountWrap from '../../components/Account/MyAccountWrap';
import Router from '../../Router';
import Modals from '../Modals';
import {
initRequest, logoutRequest, getBalanceAndBonusRequest, togglePM, changePage,
toggleBetslip, setSelectedLeague, toggleAccount, goToLogin, goToMyAccountMenu,
setNeedReCountBet, liveFinished, reCount, setBlockMultipleRecount,
setNeedTurboReCountBet,
setNeedTurboKickOffReCountBet,
wakeUpApp, setAppOutOfFocus,
closeModal, setInitialiseBet,
setPlacebetAfterLogin, showHideKickOff, removeTicketsFromCount, setSelectedBetType,
} from '../../reducers';
import {
getIsPMOpen, getCurrentPage, getUser, getBonus, getIsAccountOpen, getIsLoading,
getDestinations, getCnt, getlastReqBalanceDateTime,
getIsBalanceLoading,
getConfigs,
getSelectedBetType,
getFreeBets,
} from '../../store/common';
import {
getNumberOfBets,
getNumberOfBetsTurbo,
getPlacedBetsRecord,
getBlockMultipleRecount,
getTotalBetCount,
getBetCountSchedule,
} from '../../store/tickets';
import {
getHaveLiveMatches, getLeagues, getSelectedLeague, getGameType, getRoundEnd,
getLiveMatchDuration,
getSelectedLeagueIndex,
getRoundLoading,
getRoundId,
getLiveId,
} from '../../store/bets';
import {
getNumberOfSelections,
getNeedReCountBet,
getNeedTurboReCountBet,
getTurboRoundDuration,
getNeedTurboKickOffReCountBet,
getSelectedOdds,
getPlacedSelectionsTurbo,
} from '../../store/placebet';
const mapToProps = (state) => ({
isPMOpen: getIsPMOpen(state),
currentPage: getCurrentPage(state),
numberOfBets: getNumberOfBets(state),
numberOfBetsTurbo: getNumberOfBetsTurbo(state),
haveLiveMatches: getHaveLiveMatches(state),
user: getUser(state),
bonus: getBonus(state),
isAccountOpen: getIsAccountOpen(state),
isLoading: getIsLoading(state),
destinations: getDestinations(state),
leagues: getLeagues(state),
numberOfSelections: getNumberOfSelections(state),
selectedLeague: getSelectedLeague(state),
cnt: getCnt(state),
gameType: getGameType(state),
lastReqBalanceDateTime: getlastReqBalanceDateTime(state),
isBalanceLoading: getIsBalanceLoading(state),
roundEnd: getRoundEnd(state),
liveMatchDuration: getLiveMatchDuration(state),
placedBetsRecord: getPlacedBetsRecord(state),
needReCountBet: getNeedReCountBet(state),
blockMultipleRecount: getBlockMultipleRecount(state),
needTurboReCountBet: getNeedTurboReCountBet(state),
turboRoundDuration: getTurboRoundDuration(state),
needTurboKickOffReCountBet: getNeedTurboKickOffReCountBet(state),
config: getConfigs(state),
selectedLeagueIndex: getSelectedLeagueIndex(state),
selectedOdds: getSelectedOdds(state),
totalBetCount: getTotalBetCount(state),
betCountSchedule: getBetCountSchedule(state),
selectedBetType: getSelectedBetType(state),
placedSelectionsTurbo: getPlacedSelectionsTurbo(state),
freeBets: getFreeBets(state),
roundLoading: getRoundLoading(state),
roundId: getRoundId(state),
liveId: getLiveId(state),
});
const actionsToProps = (dispatch) => ({
init: (payload) => dispatch(initRequest(payload)),
logout: (payload) => dispatch(logoutRequest(payload)),
getBalanceAndBonus: (payload) => dispatch(getBalanceAndBonusRequest(payload)),
goToMyAccountMenu: (payload) => dispatch(goToMyAccountMenu(payload)),
togglePM: (payload) => dispatch(togglePM(payload)),
changePage: (payload) => dispatch(changePage(payload)),
toggleBetslip: (payload) => dispatch(toggleBetslip(payload)),
setSelectedLeague: (payload) => dispatch(setSelectedLeague(payload)),
toggleAccount: (payload) => dispatch(toggleAccount(payload)),
goToLogin: (payload) => dispatch(goToLogin(payload)),
setNeedReCountBet: (payload) => dispatch(setNeedReCountBet(payload)),
liveFinished: (payload) => dispatch(liveFinished(payload)),
reCount: (payload) => dispatch(reCount(payload)),
setBlockMultipleRecount: (payload) => dispatch(setBlockMultipleRecount(payload)),
setNeedTurboReCountBet: (payload) => dispatch(setNeedTurboReCountBet(payload)),
setNeedTurboKickOffReCountBet: (payload) => dispatch(setNeedTurboKickOffReCountBet(payload)),
setAppOutOfFocus: (payload) => dispatch(setAppOutOfFocus(payload)),
wakeUpApp: (payload) => dispatch(wakeUpApp(payload)),
closeModal: (payload) => dispatch(closeModal(payload)),
setInitialiseBet: (payload) => dispatch(setInitialiseBet(payload)),
setPlacebetAfterLogin: (payload) => dispatch(setPlacebetAfterLogin(payload)),
showHideKickOff: (payload) => dispatch(showHideKickOff(payload)),
removeTicketsFromCount: (payload) => dispatch(removeTicketsFromCount(payload)),
setSelectedBetType: (payload) => dispatch(setSelectedBetType(payload)),
});
let turboTimeout;
let normalLeagueTimeout;
let betcountScheduleInterval;
/**
* @class
* @property {object} props
* @property {boolean} props.isPMOpen Indicate is Push Menue on left side is open
* @property {string} props.currentPage Indicate current page
* @property {number} props.numberOfBets Number of placed bets showed in bottom menu
* @property {boolean} props.haveLiveMatches Indicate is LIVE round is in progress
* @property {object} props.user User informations
* @property {object} props.bonus Bonus informations
* @property {boolean} props.isAccountOpen Indicate is account from Header is open
* @property {boolean} props.isLoading Indicate is loader active
* @property {object} props.destinations Destination informations
* @property {object} props.leagues Leagues informations
* @property {number} props.numberOfSelections Number of selected odds
* @property {object} props.selectedLeague Selected league informations
* @property {string} props.cnt CNT path for SVG icons
* @property {string} props.gameType Classic/Turbo
*
* @property {Function} props.init Get inital data from API
* @property {Function} props.logout Logout user
* @property {Function} props.getBalanceAndBonus API call to refresh balance
* @property {Function} props.togglePM Toogle push menu on left side
* @property {Function} props.changePage Action to change page
* @property {Function} props.toggleBetslip Toggle betslip modal
* @property {Function} props.setSelectedLeague Change selected league
* @property {Function} props.toggleAccount Toggle account menu from the header
* @property {Function} props.goToLogin Change page to Login page
* @property {Function} props.goToMyAccountMenu Change page to My account menu section
*/
class App extends Component {
constructor() {
super();
/**
* @member {object}
* @property {boolean} fixedTopBar
*/
this.state = {
fixedTopBar: false,
};
/**
* @member {number}
*/
this.startPos = 0;
/**
* @member {Element}
*/
this.handleScrollDiv = null;
}
/**
* Call init API
*
* @returns {void}
*/
componentDidMount() {
this.props.init();
window.addEventListener('blur', this.setAppOutOfFocus.bind(this));
window.addEventListener('focus', this.wakeUpApp.bind(this));
betcountScheduleInterval = setInterval(this.checkBetCountSchedule.bind(this), 1000);
}
/**
* Add handler for scroll Event Listener
*
* @param {object} prevProps
* @returns {void}
*/
componentDidUpdate(prevProps) {
const scrollArea = document.getElementsByClassName('scroll-area')[0];
if (scrollArea && !scrollArea.classList.contains('listener')) {
this.startPos = this.state.fixedTopBar !== 1
? scrollArea.getBoundingClientRect().top
: scrollArea.getBoundingClientRect().top + FIXED_HEADER_HEIGHT;
this.startPos = parseInt(this.startPos);
if (scrollArea.childNodes[0].offsetHeight + this.startPos + FIXED_HEADER_HEIGHT
> window.innerHeight) {
this.handleScrollDiv = scrollArea.childNodes[0];
scrollArea.classList.add('listener');
scrollArea.addEventListener('scroll', this.handleFixTopBar);
}
}
if (this.props.currentPage !== prevProps.currentPage) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ fixedTopBar: 0 });
}
if (this.props.gameType === GAME_TYPE.TURBO
&& (this.props.needTurboKickOffReCountBet || this.props.needTurboReCountBet)) {
clearTimeout(turboTimeout);
}
const { selectedOdds, freeBets } = this.props;
if (selectedOdds.length !== prevProps.selectedOdds.length
|| (freeBets.length === 0 && prevProps.freeBets.length === 1)) {
const matches = {};
for (let i = 0; i < selectedOdds.length; i += 1) {
const sel = selectedOdds[i];
matches[`${sel.league}-${sel.matchId}`] = true;
}
if (selectedOdds.length === 0) {
this.props.setSelectedBetType({ selectedBetType: Constants.BET_TYPE.NO_BET });
} else if (freeBets.length > 0 && Object.keys(matches).length === selectedOdds.length) {
this.props.setSelectedBetType({ selectedBetType: Constants.BET_TYPE.FREEBET });
} else if (selectedOdds.length === 1 || Object.keys(matches).length === 1) {
this.props.setSelectedBetType({ selectedBetType: Constants.BET_TYPE.SINGLE });
} else if (Object.keys(matches).length !== selectedOdds.length) {
this.props.setSelectedBetType({ selectedBetType: Constants.BET_TYPE.SPLIT_COLUMN });
} else if (this.props.selectedBetType !== Constants.BET_TYPE.COMBINATION) {
this.props.setSelectedBetType({ selectedBetType: Constants.BET_TYPE.MULTIPLE });
}
}
}
/**
* Remove handler for scroll Event Listener
*
* @returns {void}
*/
componentWillUnmount() {
document.removeEventListener('scroll', this.handleFixTopBar);
window.removeEventListener('blur', this.setAppOutOfFocus.bind(this));
window.removeEventListener('focus', this.wakeUpApp.bind(this));
clearTimeout(turboTimeout);
clearTimeout(normalLeagueTimeout);
clearInterval(betcountScheduleInterval);
}
/**
* Set app is not in focus
*
* @param {object} e
*/
setAppOutOfFocus(e) {
e.stopPropagation();
this.props.setAppOutOfFocus();
}
/**
* Handler on scroll Event Listener on TopBar
*
* @function
* @returns {void}
*/
handleFixTopBar = () => {
let { top } = this.handleScrollDiv.getBoundingClientRect();
top = parseInt(top);
if (top === this.startPos || this.props.isAccountOpen || top === 0) {
this.setState({ fixedTopBar: 0 });
} else if (top < this.startPos - HEADER_HEIGHT && this.state.fixedTopBar !== 1) {
this.setState({ fixedTopBar: 1 });
} else if (top >= this.startPos - HEADER_HEIGHT && this.state.fixedTopBar !== 0) {
this.setState({ fixedTopBar: 0 });
}
}
/**
* Check for betcount schedule
*
*/
checkBetCountSchedule() {
const schedule = this.props.betCountSchedule;
const rounds = Object.keys(schedule);
const endedRounds = rounds.filter((r) => new Date(schedule[r].time) < new Date());
if (endedRounds.length > 0) {
this.props.removeTicketsFromCount({
roundId: endedRounds[0],
gameType: schedule[endedRounds[0]].gameType,
});
}
}
/**
* Wake up app when gets focus back
*
* @param {object} e
*/
wakeUpApp(e) {
e.stopPropagation();
this.props.wakeUpApp();
}
/**
* Render
*
* @see module:SVG/SVGProvider
* @see module:PushMenu
* @see module:Header
* @see TopBar
* @see Router
* @see module:MMenu
* @see module:Account/MyAccountWrap
* @see Modals
* @returns {view}
*/
render() {
const props = this.props;
const isLobby = Constants.PAGES.LEAGUE_SELECTION === props.currentPage
|| Constants.PAGES.LOGIN === props.currentPage;
const isBetslipOpen = Constants.PAGES.BETSLIP === props.currentPage;
return (
<SVGProvider
isPMOpen={props.isPMOpen}
isAccountOpen={props.isAccountOpen}
cnt={props.cnt}
isBetslipOpen={isBetslipOpen}
wrapperClass={this.state.fixedTopBar === 1 ? 'scroll-down' : this.state.fixedTopBar === -1 ? 'scroll-up' : ''}
>
<PushMenu
isOpen={props.isPMOpen}
togglePM={props.togglePM}
changePage={props.changePage}
haveLiveMatches={props.haveLiveMatches}
toggleBetslip={props.toggleBetslip}
numberOfSelections={props.selectedOdds.length}
destinations={props.destinations}
leagues={props.leagues}
setSelectedLeague={props.setSelectedLeague}
goToMyAccountMenu={props.goToMyAccountMenu}
user={props.user}
numberOfBets={props.numberOfBets}
gameType={props.gameType}
currencySymbol={props.config?.currencySymbol}
selectedLeagueIndex={props.selectedLeagueIndex}
/>
<Header
currentPage={props.currentPage}
changePage={props.changePage}
user={props.user}
toggleAccount={props.toggleAccount}
isAccountOpen={props.isAccountOpen}
goToLogin={props.goToLogin}
isLoading={props.isLoading}
destinations={props.destinations}
gameType={props.gameType}
currencySymbol={props.config?.currencySymbol}
setInitialiseBet={props.setInitialiseBet}
setPlacebetAfterLogin={props.setPlacebetAfterLogin}
/>
<main
className={`flex-grow-1 ${props.isLoading ? 'loading' : ''} ${isLobby ? 'lobby' : 'markets'}`}
id="market"
>
{!props.isLoading && props.currentPage !== Constants.PAGES.LEAGUE_SELECTION && (
<TopBar />
)}
{/* CHILDREN */}
<Router
currentPage={props.currentPage}
/>
</main>
{
!isLobby && (
<MMenu
isOpen={props.isPMOpen}
currentPage={props.currentPage}
togglePM={props.togglePM}
changePage={props.changePage}
leagues={props.leagues}
setSelectedLeague={props.setSelectedLeague}
numberOfBets={props.numberOfBets + props.numberOfBetsTurbo}
totalBetCount={props.totalBetCount}
haveLiveMatches={props.haveLiveMatches}
toggleBetslip={props.toggleBetslip}
numberOfSelections={props.selectedOdds.length}
selectedOdds={props.selectedOdds}
user={props.user}
closeModal={props.closeModal}
placedSelectionsLiveTurbo={props.placedSelectionsTurbo[this.props.liveId]}
roundLoading={props.roundLoading}
/>
)
}
<MyAccountWrap
user={props.user}
bonus={props.bonus}
totalBetCount={props.totalBetCount}
isAccountOpen={props.isAccountOpen}
changePage={props.changePage}
toggleAccount={props.toggleAccount}
logout={props.logout}
getBalanceAndBonus={props.getBalanceAndBonus}
goToMyAccountMenu={props.goToMyAccountMenu}
gameType={this.props.gameType}
lastReqBalanceDateTime={this.props.lastReqBalanceDateTime}
isBalanceLoading={this.props.isBalanceLoading}
currencySymbol={this.props.config?.currencySymbol}
/>
<div className="push-menu-mask" onClick={this.props.togglePM} />
<Modals />
</SVGProvider>
);
}
}
export default connect(
mapToProps,
actionsToProps,
)(App);