From 63e075ed82f14d54174d684b7b0814f3368bce5b Mon Sep 17 00:00:00 2001
From: Brian Seek
Date: Tue, 19 Nov 2024 09:30:25 -0800
Subject: [PATCH] Cc/95263/provider mock (#32994)
* added provider generator util.
* added new mock for provider using generator.
* add test
* rename func and add tests.
* provider mock redux stuff
* return error rather than null
* added error provider for testing
* remove try/catch in service since error handing is occurring in other try/catch
* revert test data
---
.../ChooseDateAndTime.jsx | 78 ++++++++++++++-----
.../referral-appointments/redux/actions.js | 29 +++++++
.../referral-appointments/redux/reducers.js | 21 +++++
.../referral-appointments/redux/selectors.js | 7 ++
.../temp-data/referral.js | 1 +
.../tests/utils/provider.unit.spec.js | 26 +++++++
.../referral-appointments/utils/provider.js | 43 ++++++++++
src/applications/vaos/services/mocks/index.js | 8 ++
.../vaos/services/referral/index.js | 10 +++
9 files changed, 205 insertions(+), 18 deletions(-)
create mode 100644 src/applications/vaos/referral-appointments/tests/utils/provider.unit.spec.js
create mode 100644 src/applications/vaos/referral-appointments/utils/provider.js
diff --git a/src/applications/vaos/referral-appointments/ChooseDateAndTime.jsx b/src/applications/vaos/referral-appointments/ChooseDateAndTime.jsx
index 76413e6c7b58..6c1052adab4a 100644
--- a/src/applications/vaos/referral-appointments/ChooseDateAndTime.jsx
+++ b/src/applications/vaos/referral-appointments/ChooseDateAndTime.jsx
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
+import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import { startOfMonth, format, addMinutes, isWithinInterval } from 'date-fns';
import { zonedTimeToUtc } from 'date-fns-tz';
@@ -11,10 +11,14 @@ import { referral } from './temp-data/referral';
import { getSelectedDate } from '../new-appointment/redux/selectors';
import { selectUpcomingAppointments } from '../appointment-list/redux/selectors';
import { routeToNextReferralPage, routeToPreviousReferralPage } from './flow';
-import { setFormCurrentPage } from './redux/actions';
-import { selectCurrentPage } from './redux/selectors';
+import { setFormCurrentPage, fetchProviderDetails } from './redux/actions';
+import { selectCurrentPage, getProviderInfo } from './redux/selectors';
+import { FETCH_STATUS } from '../utils/constants';
+import { scrollAndFocus } from '../utils/scrollAndFocus';
export const ChooseDateAndTime = () => {
+ const dispatch = useDispatch();
+
const history = useHistory();
const selectedDate = useSelector(state => getSelectedDate(state));
const upcomingAppointments = useSelector(state =>
@@ -22,7 +26,6 @@ export const ChooseDateAndTime = () => {
);
const location = useLocation();
const currentPage = useSelector(selectCurrentPage);
- const dispatch = useDispatch();
const startMonth = format(startOfMonth(referral.preferredDate), 'yyyy-MM');
const [error, setError] = useState('');
const pageTitle = 'Schedule an appointment with your provider';
@@ -55,6 +58,23 @@ export const ChooseDateAndTime = () => {
[dispatch],
);
+ const { provider, providerFetchStatus } = useSelector(
+ state => getProviderInfo(state),
+ shallowEqual,
+ );
+
+ useEffect(
+ () => {
+ if (providerFetchStatus === FETCH_STATUS.notStarted) {
+ dispatch(fetchProviderDetails(referral.provider));
+ } else if (providerFetchStatus === FETCH_STATUS.succeeded) {
+ scrollAndFocus('h1');
+ } else if (providerFetchStatus === FETCH_STATUS.failed) {
+ scrollAndFocus('h2');
+ }
+ },
+ [dispatch, providerFetchStatus],
+ );
useEffect(
() => {
dispatch(setFormCurrentPage('scheduleAppointment'));
@@ -142,6 +162,28 @@ export const ChooseDateAndTime = () => {
},
[hasConflict, selectedDate, upcomingAppointments],
);
+ if (
+ providerFetchStatus === FETCH_STATUS.loading ||
+ providerFetchStatus === FETCH_STATUS.notStarted
+ ) {
+ return (
+
+
+
+ );
+ }
+
+ if (providerFetchStatus === FETCH_STATUS.failed) {
+ return (
+
+ "We’re sorry. We’ve run into a problem"
+
+ We’re having trouble getting your upcoming appointments. Please try
+ again later.
+
+
+ );
+ }
return (
<>
@@ -152,29 +194,29 @@ export const ChooseDateAndTime = () => {
appointment online with this provider:
- {referral.providerName}
+ {provider.providerName}
{referral.typeOfCare}
- {referral.orgName}
+ {provider.orgName}
- {referral.orgAddress.street1}
- {referral.orgAddress.street2 && (
+ {provider.orgAddress.street1}
+ {provider.orgAddress.street2 && (
<>
- {referral.orgAddress.street2}
+ {provider.orgAddress.street2}
>
)}
- {referral.orgAddress.street3 && (
+ {provider.orgAddress.street3 && (
<>
- {referral.orgAddress.street3}
+ {provider.orgAddress.street3}
>
)}
- {referral.orgAddress.city}, {referral.orgAddress.state},{' '}
- {referral.orgAddress.zip}
+ {provider.orgAddress.city}, {provider.orgAddress.state},{' '}
+ {provider.orgAddress.zip}
- Phone: {referral.orgPhone}
+ Phone: {provider.orgPhone}
- {referral.driveTime} ({referral.driveDistance})
+ {provider.driveTime} ({provider.driveDistance})
Choose a date and time
@@ -211,7 +253,7 @@ export const ChooseDateAndTime = () => {
{
+ try {
+ dispatch({
+ type: FETCH_PROVIDER_DETAILS,
+ });
+ const providerDetails = await getProviderById(id);
+
+ dispatch({
+ type: FETCH_PROVIDER_DETAILS_SUCCEEDED,
+ data: providerDetails,
+ });
+ return providerDetails;
+ } catch (error) {
+ dispatch({
+ type: FETCH_PROVIDER_DETAILS_FAILED,
+ });
+ return captureError(error);
+ }
+ };
+}
diff --git a/src/applications/vaos/referral-appointments/redux/reducers.js b/src/applications/vaos/referral-appointments/redux/reducers.js
index d0541f59aac6..dc15f7eb9cc3 100644
--- a/src/applications/vaos/referral-appointments/redux/reducers.js
+++ b/src/applications/vaos/referral-appointments/redux/reducers.js
@@ -4,13 +4,18 @@ import {
SET_SORT_PROVIDER_BY,
SET_SELECTED_PROVIDER,
SET_FORM_CURRENT_PAGE,
+ FETCH_PROVIDER_DETAILS,
+ FETCH_PROVIDER_DETAILS_FAILED,
+ FETCH_PROVIDER_DETAILS_SUCCEEDED,
} from './actions';
+import { FETCH_STATUS } from '../../utils/constants';
const initialState = {
facility: null,
sortProviderBy: '',
selectedProvider: '',
currentPage: null,
+ providerFetchStatus: FETCH_STATUS.notStarted,
};
function ccAppointmentReducer(state = initialState, action) {
@@ -41,6 +46,22 @@ function ccAppointmentReducer(state = initialState, action) {
...state,
currentPage: action.payload,
};
+ case FETCH_PROVIDER_DETAILS:
+ return {
+ ...state,
+ providerFetchStatus: FETCH_STATUS.loading,
+ };
+ case FETCH_PROVIDER_DETAILS_SUCCEEDED:
+ return {
+ ...state,
+ providerFetchStatus: FETCH_STATUS.succeeded,
+ selectedProvider: action.data,
+ };
+ case FETCH_PROVIDER_DETAILS_FAILED:
+ return {
+ ...state,
+ providerFetchStatus: FETCH_STATUS.failed,
+ };
default:
return state;
}
diff --git a/src/applications/vaos/referral-appointments/redux/selectors.js b/src/applications/vaos/referral-appointments/redux/selectors.js
index 4d14355a7fc7..2acca535c69e 100644
--- a/src/applications/vaos/referral-appointments/redux/selectors.js
+++ b/src/applications/vaos/referral-appointments/redux/selectors.js
@@ -2,3 +2,10 @@ export const selectCCAppointment = state => state.ccAppointment;
export const selectProvider = state => state.referral.selectedProvider;
export const selectProviderSortBy = state => state.referral.sortProviderBy;
export const selectCurrentPage = state => state.referral.currentPage;
+
+export function getProviderInfo(state) {
+ return {
+ provider: state.referral.selectedProvider,
+ providerFetchStatus: state.referral.providerFetchStatus,
+ };
+}
diff --git a/src/applications/vaos/referral-appointments/temp-data/referral.js b/src/applications/vaos/referral-appointments/temp-data/referral.js
index dfa0fbf9c4cf..049bf0383efb 100644
--- a/src/applications/vaos/referral-appointments/temp-data/referral.js
+++ b/src/applications/vaos/referral-appointments/temp-data/referral.js
@@ -19,6 +19,7 @@ const getAvailableSlots = (number = 2) => {
const referral = {
id: 123456,
providerName: 'Dr. Face',
+ provider: '111',
typeOfCare: 'Dermatology',
appointmentCount: 2,
orgName: 'New Skin Technologies',
diff --git a/src/applications/vaos/referral-appointments/tests/utils/provider.unit.spec.js b/src/applications/vaos/referral-appointments/tests/utils/provider.unit.spec.js
new file mode 100644
index 000000000000..a3df3f73934c
--- /dev/null
+++ b/src/applications/vaos/referral-appointments/tests/utils/provider.unit.spec.js
@@ -0,0 +1,26 @@
+import { addDays, startOfDay, addHours } from 'date-fns';
+import { expect } from 'chai';
+
+const providerUtil = require('../../utils/provider');
+
+describe('VAOS provider generator', () => {
+ const tomorrow = addDays(startOfDay(new Date()), 1);
+ describe('createProviderDetails', () => {
+ const providerObjectTwoSlots = providerUtil.createProviderDetails(2);
+ const providerObjectNoSlots = providerUtil.createProviderDetails(0);
+ it('Creates a provider with specified number of slots', () => {
+ expect(providerObjectTwoSlots.slots.length).to.equal(2);
+ });
+ it('Creates slots for tomorrow an hour apart starting at 12', () => {
+ expect(providerObjectTwoSlots.slots[0].start).to.equal(
+ addHours(tomorrow, 12).toISOString(),
+ );
+ expect(providerObjectTwoSlots.slots[1].start).to.equal(
+ addHours(tomorrow, 13).toISOString(),
+ );
+ });
+ it('Creates empty slots array with 0', () => {
+ expect(providerObjectNoSlots.slots.length).to.equal(0);
+ });
+ });
+});
diff --git a/src/applications/vaos/referral-appointments/utils/provider.js b/src/applications/vaos/referral-appointments/utils/provider.js
new file mode 100644
index 000000000000..94afcb411f16
--- /dev/null
+++ b/src/applications/vaos/referral-appointments/utils/provider.js
@@ -0,0 +1,43 @@
+/* eslint-disable no-plusplus */
+const dateFns = require('date-fns');
+
+/**
+ * Creates a provider object with a configurable number of slots an hour apart.
+ *
+ * @param {Number} numberOfSlots How many slots to create
+ * @returns {Object} Provider object
+ */
+const createProviderDetails = numberOfSlots => {
+ const slots = [];
+ const tomorrow = dateFns.addDays(dateFns.startOfDay(new Date()), 1);
+ let hourFromNow = 12;
+ for (let i = 0; i < numberOfSlots; i++) {
+ const startTime = dateFns.addHours(tomorrow, hourFromNow);
+ slots.push({
+ end: dateFns.addMinutes(startTime, 30).toISOString(),
+ id: Math.floor(Math.random() * 90000) + 10000,
+ start: startTime.toISOString(),
+ });
+ hourFromNow++;
+ }
+ return {
+ providerName: 'Dr. Face',
+ typeOfCare: 'Dermatology',
+ orgName: 'New Skin Technologies',
+ orgAddress: {
+ street1: '111 Lori Ln.',
+ street2: '',
+ street3: '',
+ city: 'New York',
+ state: 'New York',
+ zip: '10016',
+ },
+ orgPhone: '555-867-5309',
+ driveTime: '7 minute drive',
+ driveDistance: '8 miles',
+ slots,
+ location: 'New skin technologies bldg 2',
+ };
+};
+
+module.exports = { createProviderDetails };
diff --git a/src/applications/vaos/services/mocks/index.js b/src/applications/vaos/services/mocks/index.js
index e7beecf6ff4c..d15904a1ee55 100644
--- a/src/applications/vaos/services/mocks/index.js
+++ b/src/applications/vaos/services/mocks/index.js
@@ -58,6 +58,7 @@ const providerOrgs = require('./epsApi/providerOrganizations.json');
const providerServices = require('./epsApi/providerServices.json');
const providerSlots = require('./epsApi/providerServicesSlots.json');
const referralUtils = require('../../referral-appointments/utils/referrals');
+const providerUtils = require('../../referral-appointments/utils/provider');
// Returns the meta object without any backend service errors
const meta = require('./v2/meta.json');
@@ -667,6 +668,13 @@ const responses = {
data: getSlot.find(slot => slot?.id === req.params.slotId),
});
},
+ 'GET /vaos/v2/epsApi/providerDetails/:providerId': (req, res) => {
+ // Provider 3 throws error
+ if (req.params.providerId === '3') {
+ return res.status(500).json({ error: true });
+ }
+ return res.json({ data: providerUtils.createProviderDetails(5) });
+ },
'GET /v0/user': {
data: {
attributes: {
diff --git a/src/applications/vaos/services/referral/index.js b/src/applications/vaos/services/referral/index.js
index 98861ffb1577..8e5365efa73c 100644
--- a/src/applications/vaos/services/referral/index.js
+++ b/src/applications/vaos/services/referral/index.js
@@ -28,3 +28,13 @@ export async function getPatientReferralById(referralId) {
return null;
}
}
+
+export async function getProviderById(providerId) {
+ const response = await apiRequestWithUrl(
+ `/vaos/v2/epsApi/providerDetails/${providerId}`,
+ {
+ method: 'GET',
+ },
+ );
+ return response.data;
+}