InsidersByte/honeymoon-gift-list

View on GitHub
public/redux/basket.js

Summary

Maintainability
A
2 hrs
Test Coverage
/* @flow */

import type { BasketType, ActionType, ItemType } from '../types';

const ADD_TO_BASKET = 'our-wedding-heroes/basket/ADD_TO_BASKET';
const REMOVE_FROM_BASKET = 'our-wedding-heroes/basket/REMOVE_FROM_BASKET';
const DELETE_FROM_BASKET = 'our-wedding-heroes/basket/DELETE_FROM_BASKET';
const EMPTY_BASKET = 'our-wedding-heroes/basket/EMPTY_BASKET';

const reducer = (state: BasketType = new Map(), action: ActionType): BasketType => {
  switch (action.type) {
    case ADD_TO_BASKET: {
      const { payload: item } = action;
      const { id } = item;

      const existingItem = state.get(id) || { quantity: 0 };
      const updatedItem = { ...existingItem, ...item };
      updatedItem.quantity += 1;

      if (updatedItem.quantity > updatedItem.remaining) {
        updatedItem.quantity = updatedItem.remaining;
      }

      state.set(id, updatedItem);
      return new Map(state);
    }

    case REMOVE_FROM_BASKET: {
      const { payload: item } = action;
      const { id } = item;

      const existingItem = state.get(id);

      if (!existingItem) {
        throw new Error(`Cannot find item with id: '${id}'`);
      }

      if (existingItem.quantity <= 1) {
        return state;
      }

      const updatedItem = { ...existingItem, quantity: (existingItem.quantity -= 1) };

      state.set(id, updatedItem);
      return new Map(state);
    }

    case DELETE_FROM_BASKET: {
      state.delete(action.payload.id);
      return new Map(state);
    }

    case EMPTY_BASKET:
      return new Map();

    default:
      return state;
  }
};

export default reducer;

export const addToBasket = (item: ItemType): ActionType => ({
  type: ADD_TO_BASKET,
  payload: item,
});

export const removeFromBasket = (item: ItemType): ActionType => ({
  type: REMOVE_FROM_BASKET,
  payload: item,
});

export const deleteFromBasket = (item: ItemType): ActionType => ({
  type: DELETE_FROM_BASKET,
  payload: item,
});

export const emptyBasket = (): ActionType => ({
  type: EMPTY_BASKET,
});

export const getBasketCount = (state: BasketType): number => {
  let count = 0;

  for (const item of state.values()) {
    const { quantity } = item;
    count += quantity;
  }

  return count;
};

export const getBasketTotal = (state: BasketType): number => {
  let total = 0;

  for (const item of state.values()) {
    const { quantity, price } = item;
    total += price * quantity;
  }

  return total;
};