diff --git a/src/applications/mhv-medical-records/actions/blueButtonReport.js b/src/applications/mhv-medical-records/actions/blueButtonReport.js index 2f9822efa9a0..09320b333d4a 100644 --- a/src/applications/mhv-medical-records/actions/blueButtonReport.js +++ b/src/applications/mhv-medical-records/actions/blueButtonReport.js @@ -16,64 +16,86 @@ import { Actions } from '../util/actionTypes'; import * as Constants from '../util/constants'; import { addAlert } from './alerts'; -export const getBlueButtonReportData = () => async dispatch => { +export const getBlueButtonReportData = (options = {}) => async dispatch => { try { - const [ - labs, - notes, - vaccines, - allergies, - conditions, - vitals, - radiology, - medications, - appointments, - demographics, - militaryService, - patient, - ] = await Promise.all([ - getLabsAndTests(), - getNotes(), - getVaccineList(), - getAllergies(), - getConditions(), - getVitalsList(), - getMhvRadiologyTests(), - getMedications(), - getAppointments(), - getDemographicInfo(), - getMilitaryService(), - getPatient(), - ]); - dispatch({ - type: Actions.LabsAndTests.GET_LIST, - labsAndTestsResponse: labs, - radiologyResponse: radiology, - }); - dispatch({ - type: Actions.CareSummariesAndNotes.GET_LIST, - response: notes, - }); - dispatch({ - type: Actions.Vaccines.GET_LIST, - response: vaccines, - }); - dispatch({ - type: Actions.Allergies.GET_LIST, - response: allergies, - }); - dispatch({ - type: Actions.Conditions.GET_LIST, - response: conditions, - }); - dispatch({ type: Actions.Vitals.GET_LIST, response: vitals }); - dispatch({ - type: Actions.BlueButtonReport.GET, - medicationsResponse: medications, - appointmentsResponse: appointments, - demographicsResponse: demographics, - militaryServiceResponse: militaryService, - patientResponse: patient, + const fetchMap = { + labs: getLabsAndTests, + notes: getNotes, + vaccines: getVaccineList, + allergies: getAllergies, + conditions: getConditions, + vitals: getVitalsList, + radiology: getMhvRadiologyTests, + medications: getMedications, + appointments: getAppointments, + demographics: getDemographicInfo, + militaryService: getMilitaryService, + patient: getPatient, + }; + + const promises = Object.entries(fetchMap) + .filter(([key]) => options[key]) // Only include enabled fetches + .map(([key, fetchFn]) => fetchFn().then(response => ({ key, response }))); + + const results = await Promise.all(promises); + + results.forEach(({ key, response }) => { + switch (key) { + case 'labs': + dispatch({ + type: Actions.LabsAndTests.GET_LIST, + labsAndTestsResponse: response, + }); + break; + case 'notes': + dispatch({ + type: Actions.CareSummariesAndNotes.GET_LIST, + response, + }); + break; + case 'vaccines': + dispatch({ + type: Actions.Vaccines.GET_LIST, + response, + }); + break; + case 'allergies': + dispatch({ + type: Actions.Allergies.GET_LIST, + response, + }); + break; + case 'conditions': + dispatch({ + type: Actions.Conditions.GET_LIST, + response, + }); + break; + case 'vitals': + dispatch({ + type: Actions.Vitals.GET_LIST, + response, + }); + break; + case 'radiology': + dispatch({ + type: Actions.LabsAndTests.GET_LIST, + radiologyResponse: response, + }); + break; + case 'medications': + case 'appointments': + case 'demographics': + case 'militaryService': + case 'patient': + dispatch({ + type: Actions.BlueButtonReport.GET, + [`${key}Response`]: response, + }); + break; + default: + break; + } }); } catch (error) { dispatch(addAlert(Constants.ALERT_TYPE_ERROR, error)); diff --git a/src/applications/mhv-medical-records/components/DownloadRecords/DownloadFileType.jsx b/src/applications/mhv-medical-records/components/DownloadRecords/DownloadFileType.jsx index 58a47c85e5fd..9786ed9fa9c3 100644 --- a/src/applications/mhv-medical-records/components/DownloadRecords/DownloadFileType.jsx +++ b/src/applications/mhv-medical-records/components/DownloadRecords/DownloadFileType.jsx @@ -31,8 +31,6 @@ const DownloadFileType = props => { const user = useSelector(state => state.user.profile); const name = formatName(user.userFullName); const dob = formatDateLong(user.dob); - const [blueButtonRequested, setBlueButtonRequested] = useState(false); - const [downloadType, setDownloadType] = useState(''); const labsAndTests = useSelector( state => state.mr.labsAndTests.labsAndTestsList, @@ -61,22 +59,16 @@ const DownloadFileType = props => { const [downloadStarted, setDownloadStarted] = useState(false); - const allAreDefined = arrayOfArrays => { - return arrayOfArrays.every( - data => - (typeof data === 'object' && Object.keys(data)?.length) || - (typeof data === 'string' && data?.length) || - (Array.isArray(data) && !!data?.length), - ); - }; - - useEffect(() => { - if (!dateFilter) { - history.push('/download/date-range'); - } else if (!recordFilter) { - history.push('/download/record-type'); - } - }); + useEffect( + () => { + if (!dateFilter) { + history.push('/download/date-range'); + } else if (!recordFilter) { + history.push('/download/record-type'); + } + }, + [dateFilter, history, recordFilter], + ); const [filterFromDate, filterToDate] = useMemo( () => { @@ -85,109 +77,170 @@ const DownloadFileType = props => { [dateFilter], ); - const filterByDate = recDate => { - return ( - isBefore(new Date(filterFromDate), new Date(recDate)) && - isAfter(new Date(filterToDate), new Date(recDate)) - ); - }; - - const recordData = useMemo(() => { - if ( - !allAreDefined([ - labsAndTests, - notes, + /** + * True if all the records that were specified in the filters have been fetched, otherwise false. + */ + const isDataFetched = useMemo( + () => { + // Map the recordFilter keys to the corresponding data domains + const dataMap = { + labTests: labsAndTests, + careSummaries: notes, vaccines, allergies, conditions, vitals, - ]) - ) { - dispatch(getBlueButtonReportData()); - } else { - return { - labsAndTests: recordFilter?.includes('labTests') - ? labsAndTests.filter(rec => filterByDate(rec.sortDate)) - : null, - notes: recordFilter?.includes('careSummaries') - ? notes.filter(rec => filterByDate(rec.sortByDate)) - : null, - vaccines: recordFilter?.includes('vaccines') - ? vaccines.filter(rec => filterByDate(rec.date)) - : null, + medications, + upcomingAppts: appointments, + pastAppts: appointments, + demographics, + militaryService, + accountSummary, + }; + + // Check if all domains in the recordFilter are truthy + return recordFilter?.every(filter => !!dataMap[filter]); + }, + [ + labsAndTests, + notes, + vaccines, + allergies, + conditions, + vitals, + medications, + appointments, + demographics, + militaryService, + accountSummary, + recordFilter, + ], + ); + + useEffect( + () => { + const options = { + labs: recordFilter?.includes('labTests'), + notes: recordFilter?.includes('careSummaries'), + vaccines: recordFilter?.includes('vaccines'), allergies: recordFilter?.includes('allergies') || - recordFilter?.includes('medications') - ? allergies - : null, - conditions: recordFilter?.includes('conditions') ? conditions : null, - vitals: recordFilter?.includes('vitals') - ? vitals.filter(rec => filterByDate(rec.date)) - : null, - medications: recordFilter?.includes('medications') - ? medications.filter(rec => filterByDate(rec.lastFilledOn)) - : null, + recordFilter?.includes('medications'), + conditions: recordFilter?.includes('conditions'), + vitals: recordFilter?.includes('vitals'), + medications: recordFilter?.includes('medications'), appointments: recordFilter?.includes('upcomingAppts') || - recordFilter?.includes('pastAppts') - ? appointments.filter( - rec => - filterByDate(rec.date) && - ((recordFilter.includes('upcomingAppts') && rec.isUpcoming) || - (recordFilter.includes('pastAppts') && !rec.isUpcoming)), - ) - : null, - demographics: recordFilter?.includes('demographics') - ? demographics - : null, - militaryService: recordFilter?.includes('militaryService') - ? militaryService - : null, - accountSummary, + recordFilter?.includes('pastAppts'), + demographics: recordFilter?.includes('demographics'), + militaryService: recordFilter?.includes('militaryService'), }; - } - return {}; - }); - const recordCount = useMemo(() => { - let count = 0; - count += recordData?.labsAndTests ? recordData?.labsAndTests?.length : 0; - count += recordData?.notes ? recordData?.notes?.length : 0; - count += recordData?.vaccines ? recordData?.vaccines?.length : 0; - count += recordData?.allergies ? recordData?.allergies?.length : 0; - count += recordData?.conditions ? recordData?.conditions?.length : 0; - count += recordData?.vitals ? recordData?.vitals?.length : 0; - count += recordData?.medications ? recordData?.medications?.length : 0; - count += recordData?.appointments ? recordData?.appointments?.length : 0; - count += recordData?.demographics ? 1 : 0; - count += recordData?.militaryService ? 1 : 0; + if (!isDataFetched) { + dispatch(getBlueButtonReportData(options)); + } + }, + [isDataFetched, recordFilter, dispatch], + ); + + const recordData = useMemo( + () => { + const filterByDate = recDate => { + return ( + isBefore(new Date(filterFromDate), new Date(recDate)) && + isAfter(new Date(filterToDate), new Date(recDate)) + ); + }; + + if (isDataFetched) { + return { + labsAndTests: recordFilter?.includes('labTests') + ? labsAndTests.filter(rec => filterByDate(rec.sortDate)) + : null, + notes: recordFilter?.includes('careSummaries') + ? notes.filter(rec => filterByDate(rec.sortByDate)) + : null, + vaccines: recordFilter?.includes('vaccines') + ? vaccines.filter(rec => filterByDate(rec.date)) + : null, + allergies: + recordFilter?.includes('allergies') || + recordFilter?.includes('medications') + ? allergies + : null, + conditions: recordFilter?.includes('conditions') ? conditions : null, + vitals: recordFilter?.includes('vitals') + ? vitals.filter(rec => filterByDate(rec.date)) + : null, + medications: recordFilter?.includes('medications') + ? medications.filter(rec => filterByDate(rec.lastFilledOn)) + : null, + appointments: + recordFilter?.includes('upcomingAppts') || + recordFilter?.includes('pastAppts') + ? appointments.filter( + rec => + filterByDate(rec.date) && + ((recordFilter.includes('upcomingAppts') && + rec.isUpcoming) || + (recordFilter.includes('pastAppts') && !rec.isUpcoming)), + ) + : null, + demographics: recordFilter?.includes('demographics') + ? demographics + : null, + militaryService: recordFilter?.includes('militaryService') + ? militaryService + : null, + accountSummary, + }; + } + return null; + }, + [ + isDataFetched, + filterFromDate, + filterToDate, + recordFilter, + labsAndTests, + notes, + vaccines, + allergies, + conditions, + vitals, + medications, + appointments, + demographics, + militaryService, + accountSummary, + ], + ); + + const recordCount = useMemo( + () => { + let count = 0; + count += recordData?.labsAndTests ? recordData?.labsAndTests?.length : 0; + count += recordData?.notes ? recordData?.notes?.length : 0; + count += recordData?.vaccines ? recordData?.vaccines?.length : 0; + count += recordData?.allergies ? recordData?.allergies?.length : 0; + count += recordData?.conditions ? recordData?.conditions?.length : 0; + count += recordData?.vitals ? recordData?.vitals?.length : 0; + count += recordData?.medications ? recordData?.medications?.length : 0; + count += recordData?.appointments ? recordData?.appointments?.length : 0; + count += recordData?.demographics ? 1 : 0; + count += recordData?.militaryService ? 1 : 0; - return count; - }); + return count; + }, + [recordData], + ); const generatePdf = useCallback( async () => { setDownloadStarted(true); - setDownloadType('pdf'); - setBlueButtonRequested(true); dispatch(clearAlerts()); - const allDefd = allAreDefined([ - labsAndTests, - notes, - vaccines, - allergies, - conditions, - vitals, - medications, - appointments, - demographics, - militaryService, - accountSummary, - ]); - if (!allDefd) { - dispatch(getBlueButtonReportData()); - } else { - setBlueButtonRequested(false); + + if (isDataFetched) { const title = 'Blue Button report'; const subject = 'VA Medical Record'; const scaffold = generatePdfScaffold(user, title, subject); @@ -201,97 +254,21 @@ const DownloadFileType = props => { makePdf(pdfName, pdfData, title, runningUnitTest, 'blueButtonReport'); } }, - [ - accountSummary, - allergies, - appointments, - conditions, - demographics, - dispatch, - dob, - labsAndTests, - medications, - militaryService, - name, - notes, - user, - vaccines, - vitals, - ], + [dispatch, dob, isDataFetched, name, recordData, runningUnitTest, user], ); - /** - * Generate text function - */ const generateTxt = useCallback( async () => { setDownloadStarted(true); - setDownloadType('txt'); - setBlueButtonRequested(true); dispatch(clearAlerts()); - if ( - !allAreDefined([ - labsAndTests, - notes, - vaccines, - allergies, - conditions, - vitals, - ]) - ) { - dispatch(getBlueButtonReportData()); - } else { - setBlueButtonRequested(false); + if (isDataFetched) { const pdfName = `VA-Blue-Button-report-${getNameDateAndTime(user)}`; const content = getTxtContent(recordData, user); generateTextFile(content, pdfName, user); } }, - [ - allergies, - conditions, - dispatch, - labsAndTests, - notes, - user, - vaccines, - vitals, - ], - ); - - useEffect( - () => { - if ( - allAreDefined([ - labsAndTests, - notes, - vaccines, - allergies, - conditions, - vitals, - ]) && - blueButtonRequested - ) { - if (downloadType === 'pdf') { - generatePdf(); - } else { - generateTxt(); - } - } - }, - [ - labsAndTests, - notes, - vaccines, - allergies, - conditions, - vitals, - generatePdf, - generateTxt, - downloadType, - blueButtonRequested, - ], + [dispatch, isDataFetched, recordData, user], ); return ( @@ -332,6 +309,7 @@ const DownloadFileType = props => {