Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Vitals Date Range to the URL to remain consistant across page loads #33783

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
15 changes: 15 additions & 0 deletions src/applications/mhv-medical-records/actions/vitals.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export const getVitals = (
}
};

/**
* Updates the list of vitals with the selected vital type, **will** make an API call to populate the data
*
* @param {string} vitalType a valid vital type
* @param {array} vitalList the list of vitals to check if it's empty
*/
export const getVitalDetails = (vitalType, vitalList) => async dispatch => {
try {
if (!isArrayAndHasItems(vitalList)) {
Expand All @@ -44,6 +50,15 @@ export const getVitalDetails = (vitalType, vitalList) => async dispatch => {
}
};

/**
* Updates the list of vitals with the selected vital type, **will not** make an API call to populate the data
*
* @param {string} vitalType a valid vital type
*/
export const setVitalsList = vitalType => async dispatch => {
dispatch({ type: Actions.Vitals.GET, vitalType });
};

export const clearVitalDetails = () => async dispatch => {
dispatch({ type: Actions.Vitals.CLEAR_DETAIL });
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
import { Breadcrumbs, Paths } from '../util/constants';
import { setBreadcrumbs } from '../actions/breadcrumbs';
import { clearPageNumber, setPageNumber } from '../actions/pageTracker';
import { handleDataDogAction } from '../util/helpers';
import { handleDataDogAction, removeTrialingSlash } from '../util/helpers';

const MrBreadcrumbs = () => {
const dispatch = useDispatch();
const location = useLocation();
const history = useHistory();

const crumbsList = useSelector(state => state.mr.breadcrumbs.crumbsList);
const pageNumber = useSelector(state => state.mr.pageTracker.pageNumber);
const phase0p5Flag = useSelector(
Expand All @@ -27,10 +28,12 @@ const MrBreadcrumbs = () => {
);

const textContent = document.querySelector('h1')?.textContent;
const searchIndex = new URLSearchParams(window.location.search);
const searchIndex = new URLSearchParams(location.search);
const page = searchIndex.get('page');
const { labId } = useParams();

const urlVitalsDate = searchIndex.get('timeFrame');

useEffect(
() => {
if (page) dispatch(setPageNumber(+page));
Expand All @@ -56,20 +59,34 @@ const MrBreadcrumbs = () => {
if (pageNumber) {
backToPageNumCrumb = {
...Breadcrumbs[feature],
href: `${Breadcrumbs[feature].href.slice(
0,
-1,
href: `${removeTrialingSlash(
Breadcrumbs[feature].href,
)}?page=${pageNumber}`,
};
dispatch(setBreadcrumbs([backToPageNumCrumb, detailCrumb]));
} else if (urlVitalsDate) {
const backToVitalsDateCrumb = {
...Breadcrumbs[feature],
href: `${removeTrialingSlash(
Breadcrumbs[feature].href,
)}?timeFrame=${urlVitalsDate}`,
};
dispatch(setBreadcrumbs([backToVitalsDateCrumb, detailCrumb]));
} else {
dispatch(setBreadcrumbs([Breadcrumbs[feature], detailCrumb]));
}
} else {
dispatch(setBreadcrumbs([Breadcrumbs[feature]]));
}
},
[dispatch, locationBasePath, locationChildPath, textContent, pageNumber],
[
dispatch,
locationBasePath,
locationChildPath,
textContent,
pageNumber,
urlVitalsDate,
],
);

const handleRouteChange = ({ detail }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {

const VitalListItem = props => {
const { record, options = {} } = props;
const { isAccelerating } = options;
const { isAccelerating, timeFrame } = options;
const displayName = vitalTypeDisplayNames[record.type];

const ddLabelName = useMemo(
Expand Down Expand Up @@ -61,6 +61,10 @@ const VitalListItem = props => {
[updatedRecordType, isAccelerating],
);

const url = `/vitals/${kebabCase(updatedRecordType)}-history${
isAccelerating ? `?timeFrame=${timeFrame}` : ''
}`;

return (
<va-card
class="record-list-item vads-u-border--0 vads-u-padding-left--0 vads-u-padding-top--1 mobile-lg:vads-u-padding-top--2"
Expand Down Expand Up @@ -116,7 +120,7 @@ const VitalListItem = props => {
</div>

<Link
to={`/vitals/${kebabCase(updatedRecordType)}-history`}
to={url}
className="vads-u-line-height--4"
data-testid={dataTestIds.reviewLink}
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { useParams, useLocation } from 'react-router-dom';
import { chunk } from 'lodash';
import { VaPagination } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
import { focusElement } from '@department-of-veterans-affairs/platform-utilities/ui';
Expand All @@ -19,6 +19,7 @@
getVitalDetails,
getVitals,
reloadRecords,
setVitalsList,
} from '../actions/vitals';
import PrintHeader from '../components/shared/PrintHeader';
import PrintDownload from '../components/shared/PrintDownload';
Expand All @@ -39,6 +40,7 @@
ALERT_TYPE_ERROR,
accessAlertTypes,
refreshExtractTypes,
loadStates as LOAD_STATES,
} from '../util/constants';
import AccessTroubleAlertBox from '../components/shared/AccessTroubleAlertBox';
import useAlerts from '../hooks/use-alerts';
Expand All @@ -47,6 +49,7 @@
generateVitalsContent,
generateVitalsIntro,
} from '../util/pdfHelpers/vitals';

import DownloadSuccessAlert from '../components/shared/DownloadSuccessAlert';
import NewRecordsIndicator from '../components/shared/NewRecordsIndicator';
import useListRefresh from '../hooks/useListRefresh';
Expand All @@ -56,6 +59,9 @@
const MAX_PAGE_LIST_LENGTH = 10;
const VitalDetails = props => {
const { runningUnitTest } = props;

const location = useLocation();

const records = useSelector(state => state.mr.vitals.vitalDetails);
const vitalsList = useSelector(state => state.mr.vitals.vitalsList);
const user = useSelector(state => state.user.profile);
Expand Down Expand Up @@ -85,18 +91,19 @@
state => state.mr.vitals.listCurrentAsOf,
);

const { isAcceleratingVitals } = useAcceleratedData();
const { isAcceleratingVitals, isLoading } = useAcceleratedData();

if (records?.length === 0 && isAcceleratingVitals) {
window.location.replace('/my-health/medical-records/vitals');
}
const urlVitalsDate = new URLSearchParams(location.search).get('timeFrame');
const dispatchAction = isCurrent => {
return getVitals(isCurrent, isAcceleratingVitals, urlVitalsDate);
};

useListRefresh({
listState,
listCurrentAsOf: vitalsCurrentAsOf,
refreshStatus: refresh.status,
extractType: refreshExtractTypes.VPR,
dispatchAction: getVitals,
dispatchAction,
dispatch,
});

Expand Down Expand Up @@ -184,19 +191,31 @@
setCurrentVitals(paginatedVitals.current[currentPage - 1]);
}
},
[records],

Check warning on line 194 in src/applications/mhv-medical-records/containers/VitalDetails.jsx

View workflow job for this annotation

GitHub Actions / Linting (Files Changed)

src/applications/mhv-medical-records/containers/VitalDetails.jsx:194:5:React Hook useEffect has a missing dependency: 'currentPage'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setCurrentVitals' needs the current value of 'currentPage'.
);

const displayNums = fromToNums(currentPage, records?.length);

useEffect(
() => {
if (updatedRecordType) {
if (updatedRecordType && !isLoading) {
const formattedVitalType = macroCase(updatedRecordType);
dispatch(getVitalDetails(formattedVitalType, vitalsList));

if (isAcceleratingVitals && vitalsList?.length) {
dispatch(setVitalsList(formattedVitalType));
} else {
dispatch(getVitalDetails(formattedVitalType, vitalsList));
}
}
},
[vitalType, vitalsList, dispatch, updatedRecordType],
[
vitalType,
vitalsList,
dispatch,
updatedRecordType,
isAcceleratingVitals,
isLoading,
],
);

const lastUpdatedText = getLastUpdatedText(
Expand Down Expand Up @@ -439,6 +458,35 @@
</>
);
}
if (!records?.length) {
if (isLoading || listState === LOAD_STATES.FETCHING) {
return (
<div className="vads-u-margin-y--8">
<va-loading-indicator
message="Loading..."
setFocus
data-testid="loading-indicator"
/>
</div>
);
}
return (
<div className="vads-u-margin-y--8">
<p>
We don’t have any {vitalTypeDisplayNames[vitalType]} records for you
right now. Go back to the vitals page to select a different vital.
</p>
<p>
<a
href={`/my-health/medical-records/vitals?timeFrame=${urlVitalsDate}`}
className="vads-u-margin-top--2"
>
Go back to the vitals page
</a>
</p>
</div>
);
}

return (
<div className="vads-u-margin-y--8">
Expand Down
35 changes: 32 additions & 3 deletions src/applications/mhv-medical-records/containers/Vitals.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
updatePageTitle,
usePrintTitle,
} from '@department-of-veterans-affairs/mhv/exports';
import { useHistory, useLocation } from 'react-router-dom';
import RecordList from '../components/RecordList/RecordList';
import { getVitals, reloadRecords } from '../actions/vitals';
import {
Expand All @@ -31,17 +32,24 @@ import CernerFacilityAlert from '../components/shared/CernerFacilityAlert';

const Vitals = () => {
const dispatch = useDispatch();
const history = useHistory();
const location = useLocation();

const updatedRecordList = useSelector(state => state.mr.vitals.updatedList);
const listState = useSelector(state => state.mr.vitals.listState);
const vitals = useSelector(state => state.mr.vitals.vitalsList);
const user = useSelector(state => state.user.profile);
const refresh = useSelector(state => state.mr.refresh);
const [cards, setCards] = useState(null);
const urlVitalsDate = new URLSearchParams(location.search).get('timeFrame');
const [acceleratedVitalsDate, setAcceleratedVitalsDate] = useState(
format(new Date(), 'yyyy-MM'),
urlVitalsDate || format(new Date(), 'yyyy-MM'),
);
const [displayDate, setDisplayDate] = useState(acceleratedVitalsDate);

const activeAlert = useAlerts(dispatch);
const accessAlert = activeAlert && activeAlert.type === ALERT_TYPE_ERROR;

const vitalsCurrentAsOf = useSelector(
state => state.mr.vitals.listCurrentAsOf,
);
Expand Down Expand Up @@ -91,6 +99,22 @@ const Vitals = () => {
[dispatch],
);

useEffect(
() => {
// Only update if there is no time frame. This is only for on initial page load.
const timeFrame = new URLSearchParams(location.search).get('timeFrame');
if (!timeFrame) {
const searchParams = new URLSearchParams(location.search);
searchParams.set('timeFrame', acceleratedVitalsDate);
history.push({
pathname: location.pathname,
search: searchParams.toString(),
});
}
},
[acceleratedVitalsDate, history, location.pathname, location.search],
);

usePrintTitle(
pageTitles.VITALS_PAGE_TITLE,
user.userFullName,
Expand Down Expand Up @@ -127,8 +151,6 @@ const Vitals = () => {
[vitals, VITAL_TYPES],
);

const accessAlert = activeAlert && activeAlert.type === ALERT_TYPE_ERROR;

const content = () => {
if (accessAlert) {
return (
Expand Down Expand Up @@ -164,6 +186,7 @@ const Vitals = () => {
</>
);
}

if (cards?.length) {
return (
<>
Expand Down Expand Up @@ -233,6 +256,12 @@ const Vitals = () => {

const triggerApiUpdate = e => {
e.preventDefault();
const searchParams = new URLSearchParams(location.search);
searchParams.set('timeFrame', acceleratedVitalsDate);
history.push({
pathname: location.pathname,
search: searchParams.toString(),
});
setDisplayDate(acceleratedVitalsDate);
dispatch({
type: Actions.Vitals.UPDATE_LIST_STATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
clearVitalDetails,
getVitalDetails,
getVitals,
setVitalsList,
reloadRecords,
} from '../../actions/vitals';

describe('Get vitals action', () => {
Expand Down Expand Up @@ -74,6 +76,16 @@ describe('Get vital details action', () => {
});
});

describe('set vitals list action', () => {
it('should dispatch a get action', () => {
const dispatch = sinon.spy();
return setVitalsList('vitalType')(dispatch).then(() => {
expect(dispatch.firstCall.args[0].type).to.equal(Actions.Vitals.GET);
expect(dispatch.firstCall.args[0].vitalType).to.equal('vitalType');
});
});
});

describe('Clear vital details action', () => {
it('should dispatch a clear details action', () => {
const dispatch = sinon.spy();
Expand All @@ -84,3 +96,14 @@ describe('Clear vital details action', () => {
});
});
});

describe('reload records action', () => {
it('should dispatch a get action', () => {
const dispatch = sinon.spy();
return reloadRecords()(dispatch).then(() => {
expect(dispatch.firstCall.args[0].type).to.equal(
Actions.Vitals.COPY_UPDATED_LIST,
);
});
});
});
Loading
Loading