bensaufley/code-words-web

View on GitHub
src/ducks/games.js

Summary

Maintainability
A
0 mins
Test Coverage
import axios from 'axios';
import { push } from 'react-router-redux';
import moment from 'moment';

import { handleApiError } from '../helpers/requests';

// For redux
export const GAME_CREATED = 'GAME_CREATED',
      GAMES_INDEXED = 'GAMES_INDEXED',
      GAME_UPDATED = 'GAME_UPDATED',
      GAME_REMOVED = 'GAME_REMOVED';

export const gameActions = [
  GAME_CREATED,
  GAMES_INDEXED,
  GAME_UPDATED,
  GAME_REMOVED
];

// For react-dnd
export const PLAYER_CARD = 'PLAYER_CARD';

const processGame = (game) => ({ ...game, updatedAt: moment(game.updatedAt) });

export default function gamesReducer(state = null, action) {
  switch (action.type) {
    case GAMES_INDEXED:
      return action.payload.games.reduce((games, g) => ({ ...games, [g.id]: processGame(g) }), {});
    case GAME_CREATED:
    case GAME_UPDATED:
      return {
        ...state,
        [action.payload.id]: processGame(action.payload)
      };
    case GAME_REMOVED: {
      const { [action.payload.gameId]: _, ...newState } = state;
      return newState;
    }
    default:
      return state;
  }
}

export const createGame = (token) => (dispatch) => {
  const config = { headers: { Authorization: `Bearer ${token}` } };

  return axios.post(`http://${process.env.REACT_APP_API_URL}/api/v1/games/`, null, config)
    .then(({ data }) => {
      dispatch({ type: GAME_CREATED, payload: data });
      dispatch(push(`/games/${data.id}/`));
    })
    .catch(handleApiError(dispatch));
};

export const startGame = (gameId) => (dispatch, getState) => {
  const config = { headers: { Authorization: `Bearer ${getState().session.apiToken}` } };

  return axios.post(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/start`, null, config)
    .then(({ data: game }) => { dispatch({ type: GAME_UPDATED, payload: game }); })
    .catch(handleApiError(dispatch));
};

export const rematchGame = (gameId) => (dispatch, getState) => {
  const config = { headers: { Authorization: `Bearer ${getState().session.apiToken}` } };

  return axios.post(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/rematch`, null, config)
    .then(({ data: game }) => {
      dispatch({ type: GAME_CREATED, payload: game });
      dispatch(push(`/games/${game.id}/`));
    })
    .catch(handleApiError(dispatch));
};

export const deleteGame = (token, gameId) => (dispatch) => {
  const config = { headers: { Authorization: `Bearer ${token}` } };

  return axios.delete(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}`, config)
    .then(() => { dispatch({ type: GAME_REMOVED, payload: { gameId } }); })
    .catch(handleApiError(dispatch));
};

export const addPlayer = (gameId, username) => (dispatch, getState) => {
  const { session: { apiToken } } = getState(),
        config = { headers: { Authorization: `Bearer ${apiToken}` } };

  return axios.post(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/players/`, { username }, config)
    .then(({ data: game }) => { dispatch({ type: GAME_UPDATED, payload: game }); })
    .catch(handleApiError(dispatch));
};

export const assignPlayer = (gameId, playerId, team, role) => (dispatch, getState) => {
  const { session: { apiToken }, games: { [gameId]: { players } } } = getState(),
        config = { headers: { Authorization: `Bearer ${apiToken}` } };

  return new Promise((resolve, reject) => {
    const conflictingPlayer = players.find((p) => p.team === team && p.role === role);
    if (conflictingPlayer) {
      axios.put(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/player/${conflictingPlayer.id}`, { team: null, role: null }, config)
        .then(resolve)
        .catch(reject);
    } else {
      resolve();
    }
  })
    .then(() => axios.put(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/player/${playerId}`, { team, role }, config))
    .then(({ data }) => { dispatch({ type: GAME_UPDATED, payload: data }); })
    .catch(handleApiError(dispatch));
};

export const removePlayer = (gameId, playerId) => (dispatch, getState) => {
  const { session: { apiToken } } = getState(),
        config = { headers: { Authorization: `Bearer ${apiToken}` } };

  return axios.delete(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/player/${playerId}`, config)
    .then((response) => {
      if (response.data) dispatch({ type: GAME_UPDATED, payload: response.data });
      else dispatch(push('/'));
    })
    .catch(handleApiError(dispatch));
};

export const takeTurn = (gameId, turnType) => (data) => (dispatch, getState) => {
  const { session: { apiToken } } = getState(),
        config = { headers: { Authorization: `Bearer ${apiToken}` } };

  return axios.put(`http://${process.env.REACT_APP_API_URL}/api/v1/game/${gameId}/${turnType}`, data, config)
    .then(({ data: game }) => dispatch({ type: GAME_UPDATED, payload: game }))
    .catch(handleApiError(dispatch));
};