sagas/placebet.js

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

import {
  UPDATE_BALANCE,
  PLACEBET,
  SET_PLACEBET_LOADER,
  PLACEBET_SUCCESS,
  SHOW_ERROR_MODAL,
  PLACEBET_ERROR_LOGIN,
  GET_LOYALTY,
  SET_FREE_BETS,
  SET_END_DATE,
  SET_PLACED_BETS_RECORD,
  SET_LAST_BET_ROUND,
  SET_LAST_BET_ROUND_TURBO,
  ADD_NEXT_ROUND_BET,
  ADD_TICKET_TO_THE_COUNT,
  SCHEDULE_BET_COUNT,
  SET_LAST_TURBO_ROUND_PLAYED,
  ADD_PLACED_BET,
} from '../reducers';

import { parsePlacedSelections, parseNum } from '../utils/parser';
import { getUser } from '../store/common';
import { getNumberOfBets, getPlacedBetsRecord } from '../store/tickets';
import {
  getMarkets,
  getGameType,
  getSelectedLeague,
  getHaveLiveMatches,
  getRoundEnd,
  getLiveMatchDuration,
} from '../store/bets';
import { getPlacedSelections, getPlacedSelectionsTurbo } from '../store/placebet';
import {
  sortFreeBets,
  addToPlacedBetsRecord,
  updateBetCounter,
  parseCouponData,
} from '../utils/common';

/**
 * @memberof sagas/placebet
 * @typedef "placebet/response.data"
 * @type {object}
 * @property {number} amount
 * @property {number} bonusAmount
 * @property {string} currency
 */

/**
 * Placeing bet
 *
 * @memberof sagas/placebet
 * @async
 * @param {object} action
 * @property {object} action
 * @property {object} action.payload
 * @property {string} action.payload.betData Parsed bet data
 * (betType|league:match:selection$..|totalAmount or combinationType:stake&...&T:totalAmount)"
 * @property {number} action.payload.round  Round ID
 * @property {number} action.payload.maxPotWin Maximum potential win
 * @property {number|null} action.payload.freeBetId If free bets is placed, id of placed free bet
 *
 * @yields {select} getUser
 * @yields {put} PLACEBET_ERROR_LOGIN
 * @yields {put} SET_PLACEBET_LOADER
 * @yields {select} getRoundId
 * @yields {call} /bet/placebet
 * @yields {put} SET_FREE_BETS
 * @yields {put} UPDATE_BALANCE
 * @yields {put} GET_LOYALTY
 * @yields {select} getPlacedSelections
 * @yields {select} getNumberOfBets
 * @yields {select} getMarkets
 * @yields {put} PLACEBET_SUCCESS
 * @yields {put} SET_NUM_OF_BETS
 * @yields {put} SHOW_ERROR_MODAL
 */
function* placebet(action) {
  let response;
  try {
    const user = yield select(getUser);
    if (!user) {
      yield put({
        type: PLACEBET_ERROR_LOGIN,
      });
      yield put({
        type: SET_PLACEBET_LOADER,
        payload: {
          placebetAfterLogin: action.payload,
          isLoadingPlaceBet: false,
          placeBetErrorMgs: null,
        },
      });
      return;
    }

    let betSelections = action.payload.odds;
    let processedStake = action.payload.stake;

    // filter out selections no stake was put on, ONLY SINGLE BET
    if (action.payload.type === Constants.BET_TYPE_VALUES.SINGLE) {
      let stakes = action.payload.stake.split('&');
      stakes.pop(); // remove last (total) stake
      const playedSelectionsIndexes = stakes.map((s) => parseInt(s.split(':')[0]));
      const selectionIndexesObject = {};
      playedSelectionsIndexes.map((x) => { selectionIndexesObject[x] = true; });

      const betSelectionsArray = betSelections.split('$');
      betSelections = betSelectionsArray.filter((s, i) => selectionIndexesObject[i + 1]).join('$');

      // update stakes
      stakes = action.payload.stake.split('&');
      const lastStake = stakes[stakes.length - 1];
      stakes.pop();
      // update stake indexes because we removed some selections
      stakes = stakes.map((s, i) => { const elems = s.split(':'); elems[0] = i + 1; return elems.join(':'); }).join('&');
      processedStake = `${stakes}&${lastStake}`;
    }

    const data = `${action.payload.type}|${betSelections}|${processedStake}`;
    yield put({
      type: SET_PLACEBET_LOADER,
      payload: {
        isLoadingPlaceBet: true,
        placebetAfterLogin: null,
        placeBetErrorMgs: null,
      },
    });

    const roundId = action.payload.roundId;
    const gameType = yield select(getGameType);
    const selectedLeague = yield select(getSelectedLeague);
    const turbo = gameType === GAME_TYPE.TURBO;

    response = yield call(
      requestPost, Constants.API_URLS.PLACEBET,
      {
        betData: data,
        round: roundId,
        maxPotWin: action.payload.maxPotWin,
        freeBetId: action.payload.freeBetId,
        turbo,
        newSplitBetPotentialWinCalculation:
          action.payload.type === Constants.BET_TYPE_VALUES.SPLIT_COLUMN,
        newSingleBetPotentialWinCalculation:
          action.payload.type === Constants.BET_TYPE_VALUES.SINGLE,
      }, true,
    );
    if (response.status === -1) {
      yield put({
        type: SET_PLACEBET_LOADER,
        payload: {
          placebetAfterLogin: null,
          placeBetErrorMgs: response.error.message,
          isLoadingPlaceBet: false,
        },
      });
    } else {
      yield put({
        type: ADD_PLACED_BET,
        payload: {
          roundId,
          couponData: parseCouponData(action.payload.type, betSelections, processedStake),
        },
      });

      if (turbo) {
        yield put({
          type: SET_LAST_TURBO_ROUND_PLAYED,
          payload: { roundId },
        });

        yield put({
          type: SET_END_DATE,
          payload: {
            roundEnd: new Date(response.data.round.endDate),
            showKickOff: true,
          },
        });
      } else {
        const isLive = yield select(getHaveLiveMatches);
        if (isLive) {
          yield put({
            type: ADD_NEXT_ROUND_BET,
            payload: {},
          });
        }
      }
      if (response.data.freeBets) {
        yield put({
          type: SET_FREE_BETS,
          payload: {
            freeBets: sortFreeBets(response.data.freeBets),
          },
        });
      } else {
        user.balance.amount = parseNum(response.data.amount);
        user.balance.bonusAmount = parseNum(response.data.bonusAmount);
        yield put({
          type: UPDATE_BALANCE,
          payload: {
            user,
          },
        });
        yield put({
          type: GET_LOYALTY,
          payload: {
            isAfterPlacebet: true,
          },
        });
      }

      if (turbo) {
        yield put({
          type: SET_LAST_BET_ROUND_TURBO,
          payload: roundId,
        });
      } else {
        yield put({
          type: SET_LAST_BET_ROUND,
          payload: roundId,
        });
      }

      let placedSelections = yield select(getPlacedSelections);
      placedSelections = placedSelections[roundId] || null;
      let placedSelectionsTurbo = yield select(getPlacedSelectionsTurbo);
      placedSelectionsTurbo = placedSelectionsTurbo[roundId] || null;
      let numberOfBets = yield select(getNumberOfBets);
      let placedBetsRecord = yield select(getPlacedBetsRecord);
      const markets = yield select(getMarkets);

      placedBetsRecord = addToPlacedBetsRecord(placedBetsRecord, {
        gameType,
        pastWeek: selectedLeague.liveWeek || 0,
        currentWeek: selectedLeague.week || 0,
      });
      numberOfBets = updateBetCounter(placedBetsRecord);

      let filteredSelections = action.payload.placedSelection;
      if (action.payload.type === 1) {
        const stakes = action.payload.stake.split('&');
        stakes.splice(-1, 1);
        const realSelections = [];
        for (let i = 0; i < stakes.length; i += 1) {
          const bettedSelection = parseInt(stakes[i].split(':')[0]) - 1;
          realSelections.push(filteredSelections[bettedSelection]);
        }
        filteredSelections = realSelections;
      }

      if (gameType === GAME_TYPE.TURBO) {
        placedSelectionsTurbo = parsePlacedSelections(
          filteredSelections,
          placedSelectionsTurbo || {},
          markets,
        );
      } else {
        placedSelections = parsePlacedSelections(
          filteredSelections,
          placedSelections || {},
          markets,
        );
      }

      yield put({
        type: ADD_TICKET_TO_THE_COUNT,
        payload: {
          roundId,
          count: 1,
          gameType,
        },
      });

      yield put({
        type: SET_PLACED_BETS_RECORD,
        payload: {
          numberOfBets,
          placedBetsRecord,
        },
      });

      let roundEndTime = gameType === GAME_TYPE.TURBO
        ? response.data.round.endDate : yield select(getRoundEnd);
      const roundLiveDuration = gameType === GAME_TYPE.TURBO
        ? 5 : yield select(getLiveMatchDuration);
      roundEndTime = new Date(Date.parse(roundEndTime) + (roundLiveDuration + 3) * 1000);

      yield put({
        type: SCHEDULE_BET_COUNT,
        payload: {
          roundId,
          gameType,
          time: roundEndTime,
        },
      });

      yield put({
        type: PLACEBET_SUCCESS,
        payload: {
          placedSelections,
          placedSelectionsTurbo,
          round: response.data.round,
          turbo,
          roundId,
        },
      });
    }
  } catch (error) {
    yield put({
      type: SHOW_ERROR_MODAL,
      payload: {
        activeModal: error.modal || Constants.MODALS.GENERAL_ERROR,
        message: error.message,
      },
    });
  }
}
/**
 * @memberof sagas/placebet
 * @async
 * @returns {void}
 */
export default function* placebetSaga() {
  yield takeEvery(PLACEBET, placebet);
}