Source: app/reducers/entitiesReducer/index.js

import entityTypeReducer from './entityTypeReducer';
import { ADD_ENTITIES } from '../../actions/entities/entityActions';
import { strictIdCheck } from '../../data/entityTypes';

/**
 * The root reducer for all entities. It contains a entityTypeReducer for each
 * entity type. These reducers are called automatically when an action of the
 * relevant type is dispatched.
 *
 * state structure:
 * {
 *   [entity type]: entityTypeReducer(),
 *   ...
 * }
 */
const entitiesReducer = (state = {}, action) => {
  // if an action is targeted towards a specific entity type, update that key
  if (action.meta && action.meta.entityType) {
    return {
      ...state,
      [action.meta.entityType]: entityTypeReducer(
        state[action.meta.entityType],
        action,
        strictIdCheck.includes(action.meta.entityType),
      ),
    };
  }

  // handle actions that are not targeted towards a specific entity type
  switch (action.type) {
    case ADD_ENTITIES: {
      const newState = { ...state };
      Object.keys(action.payload).forEach(entityType => {
        if (strictIdCheck.includes(entityType)) {
          Object.keys(action.payload[entityType]).forEach(id => {
            if (action.payload[entityType][id].id !== id) {
              throw new Error(
                `Strict id check failed: key of ${entityType} entity must match entity id`,
              );
            }
          });
        }

        newState[entityType] = {
          ...(state[entityType] || {}),
          ...action.payload[entityType],
        };
      });
      return newState;
    }
    default:
      return state;
  }
};

/**
 * This is a simple helper function to get a specific entity from the entities reducer.
 * Because memoization is not really needed here, we use this simple util instead of creating
 * a reselect selector
 *
 * @param state {object} The current state.entities state
 * @param type {string} The type of entity to get
 * @param id {string} The entity id to get
 */
export const getEntity = (state, type, id) => state[type] && state[type][id];

export default entitiesReducer;