sagas/turbo.js

import {
  takeEvery, put, call, select, takeLeading,
} from 'redux-saga/effects';
/**
 * @namespace sagas/turbo
 */
import Constants, { GAME_TYPE, BUFFER_TIME } from '../constants';
import { requestGet } from '../utils/request';

import {
  SHOW_ERROR_MODAL,
  KICK_OFF,
  KICK_OFF_SUCCESS,
  SET_ROUND_LOADER,
  GET_TURBO_ROUND_SUCCESS,
  GET_TURBO_ROUND,
  GET_PLACED_BETS,
  FORCE_BALANCE_UPDATE,
  SET_LAST_BET_ROUND_TURBO,
  GET_BALANCE,
  CLEAR_SELECTIONS,
  GO_TO_BETS,
  SET_TURBO_ROUND_ID,
  DISABLE_PLACEBET,
  SCHEDULE_BET_COUNT,
  SET_FILTERED_SELECTED_ODDS,
} from '../reducers';
import { getInitialTurboBetsLoaded, getTurboRoundId } from '../store/bets';
import {
  getLastBetRoundTurbo,
  getLastTurboRoundBetPlacedId,
  getPlacedSelectionsTurbo,
  getSelectedOdds,
} from '../store/placebet';
import { delay, filterSelectedOdds } from '../utils/common';
import { getCurrentPage } from '../store/common';

/**
 * Represent getting round data for turbo game
 *
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 * @property {Array|null} action.payload.placedSelections
 * @memberof sagas/turbo
 * @async
 */
function* getTurboRound(action) {
  let response;
  try {
    const initialBetsLoaded = yield select(getInitialTurboBetsLoaded);

    yield put({
      type: SET_ROUND_LOADER,
      payload: {
        roundLoading: true,
      },
    });
    response = yield call(requestGet, Constants.API_URLS.KICK_OFF, true);
    if (response.status === -1) {
      throw new Error(response.error.message);
    } else {
      const haveLiveMatches = !!response.data.liveId;
      const roundEnd = response.data.endDate && new Date(response.data.endDate);
      const leftTime = roundEnd && parseInt((roundEnd.getTime() - new Date().getTime()) / 1000);
      const isNoBetTime = roundEnd
        && leftTime <= 2 && leftTime > 0; // change 3 to 2, give time for last moment user kick off
      if (!initialBetsLoaded) {
        yield put({
          type: GET_PLACED_BETS,
          payload: {
            haveLiveMatches,
            isNoBetTime,
            roundId: response.data.roundId,
            liveId: response.data.liveId,
            turbo: true,
          },
        });
        if (response.data.liveId) {
          yield put({
            type: KICK_OFF,
            payload: {
              liveId: response.data.liveId,
            },
          });
        }
      }

      const selectedOdds = yield select(getSelectedOdds);
      const roundId = response.data?.roundId;
      const filteredSelectedOdds = filterSelectedOdds(selectedOdds, roundId);

      yield put({
        type: SET_FILTERED_SELECTED_ODDS,
        payload: {
          selectedOdds: filteredSelectedOdds,
        },
      });
      yield put({
        type: GET_TURBO_ROUND_SUCCESS,
        payload: {
          round: response.data,
          roundEnd,
          winCap: response.data.winCap,
          bonusOddsThreshold: response.data.bonusOddsThreshold,
          bonusPercentages: response.data.bonusPercentages.split('-'),
        },
      });

      yield put({
        type: DISABLE_PLACEBET,
        payload: { placebetDisabled: false },
      });

      if (action.payload?.selectedOdds?.length === 0 || action.payload?.haveGameTypeChanged) {
        yield put({
          type: CLEAR_SELECTIONS,
        });
      }

      const lastBetRound = yield select(getLastBetRoundTurbo);
      if (lastBetRound && parseInt(lastBetRound) !== parseInt(response.data.roundId)) {
        yield put({
          type: FORCE_BALANCE_UPDATE,
          payload: 0,
        });

        const lastTurboRoundId = yield select(getTurboRoundId);

        yield put({
          type: KICK_OFF,
          payload: { liveId: lastTurboRoundId },
        });
      }

      yield put({
        type: SET_TURBO_ROUND_ID,
        payload: {
          roundId: response.data.roundId,
        },
      });
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}

/**
 * Represent getting live data for turbo game
 *
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 * @property {Array|null} action.payload.liveId
 *
 * @memberof sagas/turbo
 * @async
 */
function* kickOff(action) {
  // this is when user click on kick off
  // in the last moments and we call it
  // also because round is ending
  if (action.payload && action.payload.placedSelections === null) {
    return;
  }

  const lastTurboRoundBetPlacedId = yield select(getLastTurboRoundBetPlacedId);

  let response;
  try {
    yield put({
      type: SET_LAST_BET_ROUND_TURBO,
      payload: null,
    });
    const roundId = action.payload && action.payload.liveId
      ? action.payload.liveId
      : yield select(getTurboRoundId);

    if (roundId !== lastTurboRoundBetPlacedId) {
      return;
    }

    response = yield call(requestGet,
      `${Constants.API_URLS.KICK_OFF}/${roundId}/close`, true);

    if (response.status === -1) {
      throw new Error(response.error.message);
    } else {
      let placedSelections = yield select(getPlacedSelectionsTurbo);
      const initialBetsLoaded = yield select(getInitialTurboBetsLoaded);

      placedSelections = placedSelections[roundId];
      const now = new Date(response.data.liveEndDate).getTime()
        - new Date(response.data.liveStartDate).getTime()
        < BUFFER_TIME
        ? Date.now() - BUFFER_TIME
        : Date.now();

      if (new Date(response.data.liveEndDate).getTime() > now) {
        const currentPage = yield select(getCurrentPage);
        // prevents page change when on account page
        const nextPage = currentPage === Constants.PAGES.MY_ACCOUNT_MENU
          ? currentPage : Constants.PAGES.MY_LIVE;
        yield put({
          type: KICK_OFF_SUCCESS,
          payload: {
            haveLiveMatches: true,
            roundResults: response.data,
            liveStart: new Date(response.data.liveStartDate),
            currentPage: nextPage,
            initialBetsLoaded,
          },
        });

        let roundEndTime = response.data.liveEndDate;
        roundEndTime = new Date(Date.parse(roundEndTime) + 3 * 1000);

        yield put({
          type: SCHEDULE_BET_COUNT,
          payload: {
            roundId,
            gameType: GAME_TYPE.TURBO,
            time: roundEndTime,
          },
        });
      } else {
        yield put({
          type: GO_TO_BETS,
        });
      }

      yield put({
        type: CLEAR_SELECTIONS,
      });

      yield put({
        type: GET_TURBO_ROUND,
        payload: {
          placedSelections,
        },
      });

      yield delay((Math.floor(Math.random() * 5) + 5) * 1000);
      yield put({
        type: GET_BALANCE,
        payload: {},
      });
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}
/**
 * @memberof sagas/turbo
 * @async
 * @returns {void}
 */
export default function* turboSaga() {
  yield takeEvery(GET_TURBO_ROUND, getTurboRound);
  yield takeLeading(KICK_OFF, kickOff);
}