department-of-veterans-affairs/vets-website

View on GitHub
src/applications/mhv-medications/api/rxApi.js

Summary

Maintainability
A
2 hrs
Test Coverage
import {
  apiRequest,
  environment,
} from '@department-of-veterans-affairs/platform-utilities/exports';
import { filterOptions, INCLUDE_IMAGE_ENDPOINT } from '../util/constants';
import mockData from '../tests/e2e/fixtures/listOfPrescriptions.json';

const apiBasePath = `${environment.API_URL}/my_health/v1`;
const headers = {
  'Content-Type': 'application/json',
};

/**
 * Helper function to create a delay
 */
const delay = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

/**
 * Testable implementation.
 * @see {@link apiRequestWithRetry} for more information
 * @param {*} retryInterval how long to wait between requests
 * @param {*} apiRequestFunc the API function to call; can be mocked for tests
 * @returns
 */
export const testableApiRequestWithRetry = (
  retryInterval,
  apiRequestFunc,
) => async (path, options, endTime) => {
  if (Date.now() >= endTime) {
    throw new Error('Timed out while waiting for response');
  }

  const response = await apiRequestFunc(path, options);

  // Check if the status code is 202 and if the retry time limit has not been reached
  if (response?.status === 202 && Date.now() < endTime) {
    await delay(retryInterval);
    return testableApiRequestWithRetry(retryInterval, apiRequestFunc)(
      path,
      options,
      endTime,
    );
  }

  return response;
};

/**
 * Recursive function that will continue polling the provided API endpoint if it sends a 404 response.
 * At this time, we will only get a 404 if the patient record has not yet been created.
 * @param {String} path the API endpoint
 * @param {Object} options headers, method, etc.
 * @param {number} endTime the cutoff time to stop polling the path and simply return the error
 * @returns
 */
const apiRequestWithRetry = async (path, options, endTime) => {
  return testableApiRequestWithRetry(2000, apiRequest)(path, options, endTime);
};

export const getAllergies = async () => {
  return apiRequestWithRetry(
    `${apiBasePath}/medical_records/allergies`,
    { headers },
    Date.now() + 90000, // Retry for 90 seconds
  );
};

export const getDocumentation = (id, ndcNumber) => {
  return apiRequest(
    `${apiBasePath}/prescriptions/${id}/documentation?ndc=${ndcNumber}`,
    {
      method: 'GET',
      headers,
    },
  );
};

// **Remove once filter feature is developed and live.**
export const getPaginatedSortedList = (pageNumber = 1, sortEndpoint = '') => {
  return apiRequest(
    `${apiBasePath}/prescriptions?page=${pageNumber}&per_page=20${sortEndpoint}`,
    { headers },
  );
};

export const getFilteredList = async filterOption => {
  async function delayedReturn(value, ms) {
    await delay(ms);
    return value;
  }
  const modifyMockData = rxName => {
    const mockData1 = { ...mockData };
    mockData1.data[0].attributes.prescriptionName = rxName;
    return mockData1;
  };
  switch (filterOption) {
    case filterOptions.ALL_MEDICATIONS.label: {
      // delayed to mimic api fetch lag
      return delayedReturn(modifyMockData('all medications'), 1000);
    }
    case filterOptions.ACTIVE.label: {
      return delayedReturn(modifyMockData('active'), 1000);
    }
    case filterOptions.RECENTLY_REQUESTED.label: {
      return delayedReturn(modifyMockData('recently requested'), 1000);
    }
    case filterOptions.RENEWAL.label: {
      return delayedReturn(modifyMockData('renewal'), 1000);
    }
    case filterOptions.NON_ACTIVE.label: {
      return delayedReturn(modifyMockData('non active'), 1000);
    }
    default:
      return mockData;
  }
};

export const getRefillablePrescriptionList = () => {
  return apiRequest(
    `${apiBasePath}/prescriptions/list_refillable_prescriptions`,
    { headers },
  );
};

export const getPrescriptionImage = cmopNdcNumber => {
  return apiRequest(
    `${apiBasePath}/prescriptions/get_prescription_image/${cmopNdcNumber}`,
    { headers },
  );
};

export const getPrescriptionSortedList = (
  sortEndpoint,
  includeImage = false,
) => {
  return apiRequest(
    `${apiBasePath}/prescriptions?${sortEndpoint}${
      includeImage ? INCLUDE_IMAGE_ENDPOINT : ''
    }`,
    { headers },
  );
};

export const getPrescription = id => {
  return apiRequest(`${apiBasePath}/prescriptions/${id}`, { headers });
};

export const fillRx = id => {
  return apiRequest(`${apiBasePath}/prescriptions/${id}/refill`, {
    method: 'PATCH',
    headers,
  });
};

export const fillRxs = ids => {
  const idParams = ids.map(id => `ids[]=${id}`).join('&');
  const url = `${apiBasePath}/prescriptions/refill_prescriptions?${idParams}`;
  const requestOptions = {
    method: 'PATCH',
    headers,
  };
  return apiRequest(url, requestOptions);
};