department-of-veterans-affairs/vets-website

View on GitHub
src/applications/mhv-medical-records/reducers/vaccines.js

Summary

Maintainability
D
2 days
Test Coverage
import { Actions } from '../util/actionTypes';
import { EMPTY_FIELD, loadStates } from '../util/constants';
import {
  isArrayAndHasItems,
  extractContainedResource,
  formatDate,
} from '../util/helpers';

const initialState = {
  /**
   * The last time that the list was fetched and known to be up-to-date
   * @type {Date}
   */
  listCurrentAsOf: undefined,
  /**
   * PRE_FETCH, FETCHING, FETCHED
   */
  listState: loadStates.PRE_FETCH,

  /**
   * The list of vaccines returned from the api
   * @type {Array}
   */
  vaccinesList: undefined,
  /**
   * New list of records retrieved. This list is NOT displayed. It must manually be copied into the display list.
   * @type {Array}
   */
  updatedList: undefined,
  /**
   * The vaccine currently being displayed to the user
   */
  vaccineDetails: undefined,
};

/**
 * Extracts the location name from a vaccine object.
 *
 * @param {object} vaccine - The vaccine object containing location information.
 * @returns {string} - The location name or an empty field if not found.
 */
export const extractLocation = vaccine => {
  // Check if the vaccine object contains valid location and contained resource data
  if (
    vaccine.location &&
    vaccine.location.reference &&
    vaccine.contained &&
    isArrayAndHasItems(vaccine.contained)
  ) {
    // Extract the reference ID from the location field
    const refId = vaccine.location.reference;
    const location = extractContainedResource(vaccine, refId);
    return location?.name || EMPTY_FIELD;
  }
  return EMPTY_FIELD;
};

/**
 * Extracts the observation code text from a vaccine object.
 *
 * @param {object} vaccine - The vaccine object containing observation information.
 * @returns {string} - The observation code text or an empty field if not found.
 */
export const extractReaction = vaccine => {
  if (isArrayAndHasItems(vaccine.contained)) {
    const observation = vaccine.contained.find(
      item => item.resourceType === 'Observation',
    );
    // Check if the observation object and its code.text property exist
    if (observation && observation.code && observation.code.text) {
      // Extract and log the observation code text
      const reactions = observation.code.text;

      return reactions || EMPTY_FIELD;
    }
  }
  return EMPTY_FIELD;
};

/**
 * Extracts the note text from a vaccine object.
 *
 * @param {object} vaccine - The vaccine object containing note information.
 * @returns {string} - The note text or an empty field if not found.
 */
export const extractNote = vaccine => {
  // Check if the vaccine object contains valid note data
  return (
    (isArrayAndHasItems(vaccine.note) &&
      vaccine.note.map(note => note.text).join().length &&
      vaccine.note.map(note => note.text)) ||
    []
  );
};

/**
 * Convert the FHIR vaccine resource from the backend into the appropriate model.
 * @param {Object} vaccine a FHIR vaccine resource
 * @returns a vaccine object that this application can use, or null if the param is null/undefined
 */

export const convertVaccine = vaccine => {
  if (typeof vaccine === 'undefined' || vaccine === null) {
    return null;
  }
  return {
    id: vaccine.id,
    name: vaccine.vaccineCode?.text,
    date: vaccine.occurrenceDateTime
      ? formatDate(vaccine.occurrenceDateTime)
      : EMPTY_FIELD,
    location: extractLocation(vaccine),
    manufacturer: vaccine.manufacturer || EMPTY_FIELD,
    reactions: extractReaction(vaccine),
    notes: extractNote(vaccine),
  };
};

export const vaccineReducer = (state = initialState, action) => {
  switch (action.type) {
    case Actions.Vaccines.GET: {
      const vaccine = action.response;
      return {
        ...state,
        vaccineDetails: convertVaccine(vaccine),
      };
    }
    case Actions.Vaccines.GET_FROM_LIST: {
      return {
        ...state,
        vaccineDetails: action.response,
      };
    }
    case Actions.Vaccines.GET_LIST: {
      const oldList = state.vaccinesList;
      const newList =
        action.response.entry
          ?.map(record => {
            const vaccine = record.resource;
            return convertVaccine(vaccine);
          })
          .sort((a, b) => new Date(b.date) - new Date(a.date)) || [];

      return {
        ...state,
        listCurrentAsOf: action.isCurrent ? new Date() : null,
        listState: loadStates.FETCHED,
        vaccinesList: typeof oldList === 'undefined' ? newList : oldList,
        updatedList: typeof oldList !== 'undefined' ? newList : undefined,
      };
    }
    case Actions.Vaccines.COPY_UPDATED_LIST: {
      const originalList = state.vaccinesList;
      const { updatedList } = state;
      if (
        Array.isArray(originalList) &&
        Array.isArray(updatedList) &&
        originalList.length !== updatedList.length
      ) {
        return {
          ...state,
          vaccinesList: state.updatedList,
          updatedList: undefined,
        };
      }
      return {
        ...state,
      };
    }
    case Actions.Vaccines.CLEAR_DETAIL: {
      return {
        ...state,
        vaccineDetails: undefined,
      };
    }
    case Actions.Vaccines.UPDATE_LIST_STATE: {
      return {
        ...state,
        listState: action.payload,
      };
    }
    default:
      return state;
  }
};