ahoym/redesert

View on GitHub
src/reducer-factories/fetch-cycle/fetch-reducer.ts

Summary

Maintainability
A
0 mins
Test Coverage
import cloneDeep from 'lodash.clonedeep';
import set from 'lodash.set';
import unset from 'lodash.unset';

import { ReduxSliceState, ReducerConfig } from '../type-definitions';
import {
  API_LIFECYCLE_SUFFIXES,
  API_ACTION_PREFIXES,
  Action,
  isValidActionType,
} from '../../actions';

const { START, FAILURE, SUCCESS } = API_LIFECYCLE_SUFFIXES;

function fetchReducerFactory({ entitiesPath }: ReducerConfig): Function {
  return (state: ReduxSliceState, action: Action): ReduxSliceState => {
    const { errors, meta, payload, type } = action;

    if (!isValidActionType(API_ACTION_PREFIXES.FETCH, type)) return state;

    const newState = cloneDeep(state);
    const referenceId: string | null =
      meta && meta.referenceId ? meta.referenceId.toString() : null;
    let attributePath: string[]; // Determine where to set pending state

    if (!referenceId) {
      attributePath = []; // Assume batch fetch
    } else {
      attributePath = [entitiesPath, referenceId];
    }

    if (type.endsWith(START)) {
      return set(newState, [...attributePath, 'isFetching'], true);
    }

    if (type.endsWith(FAILURE)) {
      set(newState, [...attributePath, 'errors'], errors);
      return set(newState, [...attributePath, 'isFetching'], false);
    }

    if (type.endsWith(SUCCESS)) {
      const attributes: any = payload || {};
      let path: string[] = [entitiesPath];

      if (!!referenceId || attributes.id !== undefined) {
        // Use developer specified referenceId, to retain override
        path = [entitiesPath, referenceId || attributes.id.toString()];
        attributePath = path;
      }

      unset(newState, [...attributePath, 'errors']);
      set(newState, [...attributePath, 'isFetching'], false);
      return set(newState, path, attributes);
    }

    return state;
  };
}

export default fetchReducerFactory;