department-of-veterans-affairs/vets-website

View on GitHub
src/platform/forms/save-in-progress/reducers.js

Summary

Maintainability
A
25 mins
Test Coverage
// eslint-disable-next-line no-restricted-imports
import { merge } from 'lodash';

import createSchemaFormReducer from 'platform/forms-system/src/js/state';
import {
  createInitialState,
  recalculateSchemaAndData,
} from 'platform/forms-system/src/js/state/helpers';
import reducers from 'platform/forms-system/src/js/state/reducers';
import {
  SET_SAVE_FORM_STATUS,
  SET_AUTO_SAVE_FORM_STATUS,
  SET_FETCH_FORM_STATUS,
  SET_FETCH_FORM_PENDING,
  SET_IN_PROGRESS_FORM,
  SET_START_OVER,
  SET_PREFILL_UNFILLED,
  SAVE_STATUSES,
  LOAD_STATUSES,
  PREFILL_STATUSES,
  saveErrors,
} from './actions';
import set from '../../utilities/data/set';

export const saveInProgressReducers = {
  [SET_SAVE_FORM_STATUS]: (state, action) => {
    const newState = set('savedStatus', action.status, state);
    newState.isStartingOver = false;
    newState.prefillStatus = PREFILL_STATUSES.notAttempted;

    if (action.status === SAVE_STATUSES.success) {
      newState.lastSavedDate = action.lastSavedDate;
      newState.expirationDate = action.expirationDate;
    }

    // We don't want to show two errors at once, so reset the status
    // of the other save method when there's an error
    if (saveErrors.has(action.status)) {
      newState.autoSavedStatus = SAVE_STATUSES.notAttempted;
    }

    return newState;
  },
  [SET_AUTO_SAVE_FORM_STATUS]: (state, action) => {
    const newState = set('autoSavedStatus', action.status, state);

    if (action.status === SAVE_STATUSES.success) {
      newState.lastSavedDate = action.lastSavedDate;
      newState.expirationDate = action.expirationDate;
      newState.inProgressFormId = action.inProgressFormId;
    }

    if (saveErrors.has(action.status)) {
      newState.savedStatus = SAVE_STATUSES.notAttempted;
    }

    return newState;
  },
  [SET_FETCH_FORM_STATUS]: (state, action) =>
    set('loadedStatus', action.status, state),
  [SET_FETCH_FORM_PENDING]: (state, action) => {
    const newState = set('loadedStatus', LOAD_STATUSES.pending, state);

    if (action.prefill) {
      newState.prefillStatus = PREFILL_STATUSES.pending;
    }

    return newState;
  },
  [SET_IN_PROGRESS_FORM]: (state, action) => {
    let newState;

    // if we’re prefilling, we want to use whatever initial data the form has
    if (state.prefillStatus === PREFILL_STATUSES.pending) {
      const formData = merge({}, state.data, action.data.formData);
      const loadedData = set('formData', formData, action.data);
      newState = set('loadedData', loadedData, state);

      // We get an empty object back when we attempt to prefill and there's
      // no information
      if (
        action.data.formData &&
        Object.keys(action.data.formData).length > 0
      ) {
        newState.prefillStatus = PREFILL_STATUSES.success;
      } else {
        newState.prefillStatus = PREFILL_STATUSES.unfilled;
      }
    } else {
      newState = set('loadedData', action.data, state);
      newState.prefillStatus = PREFILL_STATUSES.notAttempted;
    }

    newState.loadedStatus = LOAD_STATUSES.success;
    newState.data = newState.loadedData.formData;
    newState.pages = action.pages;

    return recalculateSchemaAndData(newState);
  },
  [SET_START_OVER]: state => ({
    ...state,
    isStartingOver: true,
    data: state.initialData,
    loadedStatus: LOAD_STATUSES.pending,
  }),
  [SET_PREFILL_UNFILLED]: state => ({
    ...state,
    prefillStatus: PREFILL_STATUSES.unfilled,
    data: state.initialData,
    loadedStatus: LOAD_STATUSES.notAttempted,
  }),
};

export function createSaveInProgressInitialState(formConfig, initialState) {
  return {
    ...initialState,
    initialData: initialState.data,
    savedStatus: SAVE_STATUSES.notAttempted,
    autoSavedStatus: SAVE_STATUSES.notAttempted,
    loadedStatus: LOAD_STATUSES.notAttempted,
    version: formConfig.version,
    formId: formConfig.formId,
    lastSavedDate: null,
    expirationDate: null,
    disableSave: formConfig.disableSave,
    loadedData: {
      formData: {},
      metadata: {},
    },
    prefillStatus: PREFILL_STATUSES.notAttempted,
    isStartingOver: false,
    migrations: formConfig.migrations,
    prefillTransformer: formConfig.prefillTransformer,
    trackingPrefix: formConfig.trackingPrefix,
    additionalRoutes: formConfig.additionalRoutes,
  };
}

export function createSaveInProgressFormReducer(formConfig) {
  let formReducers = reducers;
  let initialState = createInitialState(formConfig);

  if (!formConfig.disableSave) {
    formReducers = { ...formReducers, ...saveInProgressReducers };
    initialState = createSaveInProgressInitialState(formConfig, initialState);
  }

  return createSchemaFormReducer(formConfig, initialState, formReducers);
}