sagas/init.js

/* eslint-disable no-param-reassign */
import {
  takeEvery, put, call, select,
} from 'redux-saga/effects';
/**
 * @namespace sagas/init
 */
import Constants, { CNT_PATH, GAME_TYPE } from '../constants';
import { requestGet } from '../utils/request';
import {
  parseMarkets,
  getPlacedBetsResults,
  parseSelectedMarket,
} from '../utils/parser';
import {
  GET_INIT_SUCCESS,
  CHECK_SESSION,
  GET_ROUND_SELECTIONS,
  GET_ROUND_SELECTIONS_SUCCESS,
  GET_TURBO_ROUND_SELECTIONS,
  GET_INIT,
  SHOW_ERROR_MODAL,
  SET_LOADER,
  SELECT_LEAGUE,
  GET_ROUND,
  GET_TURBO_ROUND,
  SELECT_LEAGUE_SUCCESS,
  GO_TO_LOGIN,
  GET_OPEN_BETS,
  TOGGLE_ODDS,
  SCHEDULE_BET_COUNT,
  ADD_TICKET_TO_THE_COUNT,
  SET_LAST_TURBO_ROUND_PLAYED,
  ADD_PLACED_BET_BULK,
} from '../reducers';

import {
  getMarkets,
  getGameType,
} from '../store/bets';
import { getUser } from '../store/common';
import { getSelectedOdds } from '../store/placebet';

/**
 * @memberof sagas/init
 * @typedef Market
 * @type {object}
 * @property {string} info - Information about market
 * @property {string} name - Market name
 * @property {Array<Subselection>} [submarkets] - Present if market have subselection
 * @property {Array<Selection>} [selections] - Present if market dont have subselection
 */
/**
 * @memberof sagas/init
 * @typedef Subselection
 * @type {object}
 * @property {string} name - Name of subselection
 * @property {Array<Selection>} selections - Present if market dont have subselection
 */
/**
 * @memberof sagas/init
 * @typedef Selection
 * @type {object}
 * @property {string} name - Name of selection
 * @property {string} fullName - Name showen in betslip and tickets details selection
 * @property {string} winningScores - Parsed scores. Contain only scores when selection is winning.
 * @property {boolean} alwaysWin - Indicate if selection is once win is it surely winning.
 * @property {boolean} alwaysLose - Indicate if selection is once lost is it surely losing.
 */
/**
 * @memberof sagas/init
 * @typedef BetslipSettings
 * @type {object}
 * @property {Array<number>} accountOptions - Contain showen stake buttons
 * @property {number} maxLineBetslip - Maximim number of selections
 * @property {number} maxStake - Maximum stake for placebet
 * @property {number} maxSystemCombinations - Maximum number of system combinations
 * @property {number} minStake - Minimum stake for placebet
 * @property {number} minStakePerSelection - Minimum stake for placebet
 *  for combination and split bet type
 */
/**
 * @memberof sagas/init
 * @typedef League
 * @type {object}
 * @property {number} enabled - Is league in use (0-not in use, 1-in use)
 * @property {string} flag - Name of flag for league icon
 * @property {number} id - League id
 * @property {string|null} logo - Not in use
 * @property {string} name - League name
 */
/**
 * @memberof sagas/init
 * @typedef "init/response.data"
 * @type {object}
 * @property {number} noBettingTime - Duration of No Betting time in seconds
 * @property {number} noBettingTimeCountdown - Duration of No Betting time showing modal in seconds
 * @property {number} liveMatchDuration - Duration of live match in seconds
 * @property {Array<Market>} markets - Define all markets/selections with name and informations
 * @property {BetslipSettings} betslipSettings - Configuration of betslip
 * @property {object} bonusLeveling - Indicates whether the Courage component is present.
 * @property {string} cnt - Config of bonus informations.
 * @property {object} destinations - paths of images and links.
 * @property {Array<League>} leagues - Leagues definition.
 * @property {object} configs - Contain currency symbol.
 * @property {number} numbets - Number of showing bets in Bet History.
 */

/**
 * Initialize data in app
 *
 * @memberof sagas/init
 * @async
 * @yields {put} SET_LOADER
 * @yields {call} /game/init
 * @yields {put} GET_INIT_SUCCESS
 * @yields {put} CHECK_SESSION
 * @yields {put} SHOW_ERROR_MODAL
 */
function* init() {
  let response;
  try {
    yield put({
      type: SET_LOADER,
      payload: {
        isLoading: true,
      },
    });
    response = yield call(requestGet, Constants.API_URLS.INIT);

    if (response.status === -1) {
      throw new Error(response.error.message);
    } else {
      const newState = response.data;
      newState.markets = parseMarkets(newState.markets, newState.correctScoreIndex);
      newState.leagues = newState.leagues.map((l) => { l.liveEnabled = l.enabled; return l; });
      newState.selectedLeagueIndex = newState.leagues.findIndex((l) => l.enabled === 1);
      newState.selectedLeague = newState.leagues[newState.selectedLeagueIndex];
      newState.cnt = CNT_PATH || newState.cnt;

      // hardcoded market order markets
      const marketIdOrder = [
        Constants.MARKET_IDS.MARKET_1X2,
        Constants.MARKET_IDS.MARKET_OVER_UNDER,
        Constants.MARKET_IDS.MARKET_HOME_OVER_UNDER,
        Constants.MARKET_IDS.MARKET_AWAY_OVER_UNDER,
        Constants.MARKET_IDS.MARKET_CORRECT_SCORE,
        Constants.MARKET_IDS.MARKET_GOAL_NO_GOAL,
        Constants.MARKET_IDS.MARKET_DOUBLE_CHANCE,
        Constants.MARKET_IDS.MARKET_1X2_OVER_UNDER,
        Constants.MARKET_IDS.MARKET_MULTIGOAL,
        Constants.MARKET_IDS.MARKET_MULTIGOAL_HOME,
        Constants.MARKET_IDS.MARKET_MULTIGOAL_AWAY,
        Constants.MARKET_IDS.MARKET_DC_OVER_UNDER,
      ];

      const marketMap = {};
      for (let i = 0; i < newState.markets.length; i += 1) {
        const market = newState.markets[i];
        marketMap[market.id] = market;

        // sort submarkets for 1X2 + Over/Under
        if (market.id === Constants.MARKET_IDS.MARKET_1X2_OVER_UNDER) {
          const mId = market.id;
          marketMap[mId].submarkets = marketMap[mId].submarkets.sort((a, b) => a.id - b.id);
        }
      }

      const reorderedMarkets = [];
      for (let i = 0; i < marketIdOrder.length; i += 1) {
        const marketId = marketIdOrder[i];
        if (marketMap[marketId]) {
          reorderedMarkets.push(marketMap[marketId]);
        }
      }

      newState.markets = reorderedMarkets;

      newState.selectedMarket = parseSelectedMarket(newState.markets[0]);
      yield put({
        type: GET_INIT_SUCCESS,
        payload: newState,
      });
      yield put({
        type: CHECK_SESSION,
      });
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 * @memberof sagas/init
 * @typedef "roundSelections/response.data"
 * @type {object}
 * @property {Array} selections - Defned by league:match:selection:odd
 * (example:["2:3:101:1.37", "2:4:101:1.65"])
 * @property {number} numbets - Number of placed bets
 */

/**
 * Used for setting placed selections for passed roundId
 *
 * @memberof sagas/init
 * @async
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 * @property {number} action.payload.roundId - Can be current round for placeing
 *  bets and current Live round
 *
 * @yields {call} /bet/roundselections/{roundId}
 * @yields {select} getMarkets
 * @yields {put} GET_ROUND_SELECTIONS_SUCCESS
 * @yields {put} SHOW_ERROR_MODAL
 */
function* roundSelections(action) {
  let response;

  try {
    if (action.payload.roundId) {
      response = yield call(requestGet, `${Constants.API_URLS.ROUND_SELECTIONS}/${action.payload.roundId}`, true);

      if (response.status !== -1) {
        const markets = yield select(getMarkets);
        const palcedBets = getPlacedBetsResults(response.data.selections, markets);

        yield put({
          type: GET_ROUND_SELECTIONS_SUCCESS,
          payload: {
            placedSelections: palcedBets,
            roundId: action.payload.roundId,
          },
        });
      }
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 * Used for setting placed selections for passed roundId
 *
 * @memberof sagas/init
 * @async
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 * @property {number} action.payload.roundId - Can be current round for placeing
 *  bets and current Live round
 *
 * @yields {call} /bet/roundselections/{roundId}
 * @yields {select} getMarkets
 * @yields {put} GET_ROUND_SELECTIONS_SUCCESS
 * @yields {put} SHOW_ERROR_MODAL
 */
function* turboRoundSelections(action) {
  let response;

  try {
    if (action.payload.roundId) {
      response = yield call(requestGet, `${Constants.API_URLS.TURBO_ROUND_SELECTIONS}/${action.payload.roundId}`, true);

      if (response.status !== -1) {
        const markets = yield select(getMarkets);
        const palcedBets = getPlacedBetsResults(response.data.selections, markets);

        if (response.data.selections.length > 0) {
          yield put({
            type: SET_LAST_TURBO_ROUND_PLAYED,
            payload: { roundId: action.payload.roundId },
          });
        }

        yield put({
          type: GET_ROUND_SELECTIONS_SUCCESS,
          payload: {
            placedSelectionsTurbo: palcedBets,
            roundId: action.payload.roundId,
          },
        });
      }
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}
/**
 * Used for changing league and changing game type
 *
 * @memberof sagas/init
 * @async
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 */
function* selectLeague(action) {
  try {
    const gameType = yield select(getGameType);
    const user = yield select(getUser);
    const selectedOdds = yield select(getSelectedOdds);

    yield put({
      type: SELECT_LEAGUE_SUCCESS,
      payload: {
        ...action.payload,
        clearLiveMatch: gameType && action.payload.type !== gameType,
      },
    });
    if (selectedOdds?.length > 0) {
      yield put({
        type: TOGGLE_ODDS,
        payload: { selectedOdds },
      });
    }
    if (gameType && action.payload.type !== gameType) {
      if (user) {
        if (action.payload.type === GAME_TYPE.CLASSIC) {
          yield put({
            type: GET_ROUND,
            payload: { selectedOdds, haveGameTypeChanged: action.payload.type !== gameType },
          });
        } else {
          yield put({
            type: GET_TURBO_ROUND,
            payload: { selectedOdds, haveGameTypeChanged: action.payload.type !== gameType },
          });
        }
      } else if (action.payload.type !== GAME_TYPE.CLASSIC) {
        yield put({
          type: GO_TO_LOGIN,
          payload: {
            loadRound: true,
          },
        });
      }
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 *
 */
function* roundBets() {
  let response;
  try {
    response = yield call(requestGet, `${Constants.API_URLS.ROUND_BETS}`, true);

    if (response.status !== -1) {
      const roundKeys = Object.keys(response.data);
      for (let i = 0; i < roundKeys.length; i += 1) {
        const roundKey = roundKeys[i];
        const { roundId, coupons } = response.data[roundKey];
        if (roundId > 0 && coupons.length > 0) {
          yield put({
            type: ADD_PLACED_BET_BULK,
            payload: {
              roundId,
              coupons,
            },
          });
        }
      }
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 *
 */
function* openBets() {
  let response;
  try {
    response = yield call(requestGet, `${Constants.API_URLS.OPEN_BETS}`, true);

    if (response.status !== -1) {
      const clasicBets = response.data.bettingRoundClassic;
      const clasicBetsLive = response.data.liveRoundClassic;
      const tubroBets = response.data.bettingRoundTurbo;
      const tubroBetsLive = response.data.liveRoundTurbo;

      if (clasicBets > 0 || clasicBetsLive > 0) {
        const clasicRoundResponse = yield call(requestGet, Constants.API_URLS.ROUND, true);
        if (clasicBets > 0) {
          yield put({
            type: ADD_TICKET_TO_THE_COUNT,
            payload: {
              roundId: clasicRoundResponse.data.round.roundId,
              gameType: GAME_TYPE.CLASSIC,
              count: clasicBets,
            },
          });
          yield put({
            type: SCHEDULE_BET_COUNT,
            payload: {
              roundId: clasicRoundResponse.data.round.roundId,
              gameType: GAME_TYPE.CLASSIC,
              time: new Date(Date.parse(clasicRoundResponse.data.round.endDate)
               + 3000 + 1000 * clasicRoundResponse.data.roundResults.liveRoundDuration),
            },
          });
        }
        if (clasicBetsLive > 0) {
          yield put({
            type: ADD_TICKET_TO_THE_COUNT,
            payload: {
              roundId: clasicRoundResponse.data.roundResults.roundId,
              gameType: GAME_TYPE.CLASSIC,
              count: clasicBetsLive,
            },
          });
          yield put({
            type: SCHEDULE_BET_COUNT,
            payload: {
              roundId: clasicRoundResponse.data.roundResults.roundId,
              gameType: GAME_TYPE.CLASSIC,
              time: new Date(Date.parse(clasicRoundResponse.data.roundResults.liveEndDate) + 3000),
            },
          });
        }
      }

      if (tubroBets > 0 || tubroBetsLive > 0) {
        const turboRoundResponse = yield call(requestGet, Constants.API_URLS.KICK_OFF, true);
        const endDate = turboRoundResponse.data.endDate;
        if (endDate) {
          yield put({
            type: ADD_TICKET_TO_THE_COUNT,
            payload: {
              roundId: turboRoundResponse.data.roundId,
              gameType: GAME_TYPE.TURBO,
              count: tubroBets + tubroBetsLive,
            },
          });
          yield put({
            type: SCHEDULE_BET_COUNT,
            payload: {
              roundId: turboRoundResponse.data.roundId,
              gameType: GAME_TYPE.TURBO,
              time: new Date(Date.parse(endDate) + 3000),
            },
          });
        }
      }
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 * @memberof sagas/init
 * @async
 * @returns {void}
 */
export default function* initSaga() {
  yield takeEvery(GET_INIT, init);
  yield takeEvery(GET_ROUND_SELECTIONS, roundSelections);
  yield takeEvery(GET_TURBO_ROUND_SELECTIONS, turboRoundSelections);
  yield takeEvery(SELECT_LEAGUE, selectLeague);
  yield takeEvery(GET_OPEN_BETS, openBets);
  yield takeEvery(GET_OPEN_BETS, roundBets);
}