From cf1e6d0015320ebd3aa0f78b8f63b592644e989f Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Wed, 3 Apr 2024 15:08:32 -0400 Subject: [PATCH 1/5] Rework etasu endpoint to call new standards based endpoint --- package.json | 1 + src/components/EtasuStatus/EtasuStatus.jsx | 60 +++++++++++-------- .../EtasuStatus/EtasuStatusButton.jsx | 12 +++- .../EtasuStatus/EtasuStatusComponent.jsx | 18 +++--- .../EtasuStatus/EtasuStatusModal.jsx | 24 +++++--- src/containers/RequestBuilder.jsx | 1 + src/util/fhir.js | 15 ++++- src/util/util.js | 29 +++++---- 8 files changed, 99 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index b9a18075..1d1e7e90 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react-dom": "^17.0.0", "react-markdown": "^8.0.7", "react-router-dom": "^6.17.0", + "uuid": "^9.0.1", "vite": "^5.1.6", "vite-tsconfig-paths": "^4.3.2" }, diff --git a/src/components/EtasuStatus/EtasuStatus.jsx b/src/components/EtasuStatus/EtasuStatus.jsx index 2b0f996d..49fa0b83 100644 --- a/src/components/EtasuStatus/EtasuStatus.jsx +++ b/src/components/EtasuStatus/EtasuStatus.jsx @@ -1,43 +1,51 @@ -import { EtasuStatusButton } from './EtasuStatusButton.jsx'; -import { EtasuStatusModal } from './EtasuStatusModal.jsx'; import { useState, useEffect, useContext } from 'react'; -import { Card, Typography } from '@mui/material'; import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider.jsx'; -import axios from 'axios'; import { EtasuStatusComponent } from './EtasuStatusComponent.jsx'; -import { getEtasu } from '../../util/util.js'; +import { standardsBasedGetEtasu } from '../../util/util.js'; +import { createMedicationFromMedicationRequest } from '../../util/fhir.js'; // converts code into etasu for the component to render // simplifies usage for applications that only know the code, not the case they want to display export const EtasuStatus = props => { const [globalState, _] = useContext(SettingsContext); - const { code } = - props; + const { code, request } = props; const [remsAdminResponse, setRemsAdminResponse] = useState({}); - useEffect(() => getEtasuStatus(), [code]); - const getEtasuStatus = () => { - const patientFirstName = globalState.patient?.name?.at(0)?.given?.at(0); - const patientLastName = globalState.patient?.name?.at(0)?.family; - const patientDOB = globalState.patient?.birthDate; - - console.log( - 'get Etastu Status: ' + - patientFirstName + - ' ' + - patientLastName + - ' - ' + - patientDOB + - ' - ' + - code - ); - const etasuUrl = `${globalState.remsAdminServer}/etasu/met/patient/${patientFirstName}/${patientLastName}/${patientDOB}/drugCode/${code}`; - getEtasu(etasuUrl, setRemsAdminResponse); + const [etasuData, setEtasuData] = useState({}); + + useEffect(() => { + const medication = createMedicationFromMedicationRequest(request); + getEtasuStatus(medication); + }, [code]); + + const getEtasuStatus = (medication) => { + const body = makeBody(medication); + setEtasuData(body); + const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; + standardsBasedGetEtasu(standardEtasuUrl, body, setRemsAdminResponse); + }; + + const makeBody = (medication) => { + return { + resourceType: "Parameters", + parameter: [ + { + name: 'patient', + resource: globalState.patient + }, + { + name: 'medication', + resource: medication + } + ] + } + } + return ( <> - {remsAdminResponse.case_number ? : ""} + {remsAdminResponse.contained ? : ""} ); }; diff --git a/src/components/EtasuStatus/EtasuStatusButton.jsx b/src/components/EtasuStatus/EtasuStatusButton.jsx index 06aa1895..fc884782 100644 --- a/src/components/EtasuStatus/EtasuStatusButton.jsx +++ b/src/components/EtasuStatus/EtasuStatusButton.jsx @@ -12,7 +12,7 @@ export const EtasuStatusButton = props => { ETASU: - {remsAdminResponse?.status || 'Not Started'} + {convertStatus(remsAdminResponse?.status)} {renderTimestamp(lastCheckedEtasuTime)} @@ -62,3 +62,13 @@ const convertTimeDifference = start => { } return `Last checked ${prefix} ago`; }; + +const convertStatus = status => { + if (status === 'success') { + return 'Approved'; + } else if (status === 'data-required') { + return 'Pending'; + } else { + return 'Not Started'; + } +} diff --git a/src/components/EtasuStatus/EtasuStatusComponent.jsx b/src/components/EtasuStatus/EtasuStatusComponent.jsx index 2e863b9f..9118c80b 100644 --- a/src/components/EtasuStatus/EtasuStatusComponent.jsx +++ b/src/components/EtasuStatus/EtasuStatusComponent.jsx @@ -1,15 +1,14 @@ import { EtasuStatusButton } from './EtasuStatusButton.jsx'; import { EtasuStatusModal } from './EtasuStatusModal.jsx'; import { useState, useEffect, useContext } from 'react'; -import { Card, Typography } from '@mui/material'; +import { Card } from '@mui/material'; import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider.jsx'; -import axios from 'axios'; -import { getEtasu } from '../../util/util.js'; +import { standardsBasedGetEtasu } from '../../util/util.js'; export const EtasuStatusComponent = props => { const [globalState, _] = useContext(SettingsContext); - const { remsAdminResponseInit } = + const { remsAdminResponseInit, data } = props; const [remsAdminResponse, setRemsAdminResponse] = useState(remsAdminResponseInit); @@ -30,16 +29,13 @@ export const EtasuStatusComponent = props => { const refreshEtasu = () => { if(remsAdminResponse) { - const etasuUrl = `${globalState.remsAdminServer}/etasu/met/patient/${remsAdminResponse.patientFirstName}/${remsAdminResponse.patientLastName}/${remsAdminResponse.patientDOB}/drugCode/${remsAdminResponse.drugCode}`; - getEtasu(etasuUrl, setRemsAdminResponse); + const standarEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; + standardsBasedGetEtasu(standarEtasuUrl, data, setRemsAdminResponse); setLastCheckedEtasuTime(Date.now()); } } return ( - - {remsAdminResponse?.drugName} - { export const getStatusColor = status => { switch (status) { - case 'Approved': + case 'success': return 'green'; - case 'Pending': + case 'data-required': return '#f0ad4e'; default: return '#0c0c0c'; diff --git a/src/components/EtasuStatus/EtasuStatusModal.jsx b/src/components/EtasuStatus/EtasuStatusModal.jsx index 713b5afb..c098be98 100644 --- a/src/components/EtasuStatus/EtasuStatusModal.jsx +++ b/src/components/EtasuStatus/EtasuStatusModal.jsx @@ -31,7 +31,7 @@ export const EtasuStatusModal = props => {
Case Number: {getIdText(remsAdminResponse)}
-
Status: {remsAdminResponse.status || 'N/A'}
+
Status: {convertStatus(remsAdminResponse.status)}
@@ -53,24 +53,24 @@ export const EtasuStatusModal = props => { {remsAdminResponse ? ( - {remsAdminResponse?.metRequirements?.map((metRequirements) => ( + {remsAdminResponse?.contained[0]?.parameter.map((metRequirements) => ( - {metRequirements.completed ? ( + {metRequirements.resource.status === 'success' ? ( ) : ( )} - {metRequirements.completed ? ( - + {metRequirements.resource.status === 'success' ? ( + ) : ( )} @@ -99,3 +99,13 @@ const modalStyle = { boxShadow: 24, p: 4 }; + +const convertStatus = status => { + if (status === 'success') { + return 'Approved'; + } else if (status === 'data-required') { + return 'Pending'; + } else { + return 'Not Started'; + } + } diff --git a/src/containers/RequestBuilder.jsx b/src/containers/RequestBuilder.jsx index 5bb65cf1..e5bb46bc 100644 --- a/src/containers/RequestBuilder.jsx +++ b/src/containers/RequestBuilder.jsx @@ -306,6 +306,7 @@ const RequestBuilder = props => { )} diff --git a/src/util/fhir.js b/src/util/fhir.js index 0cbb845e..8e24627f 100644 --- a/src/util/fhir.js +++ b/src/util/fhir.js @@ -80,10 +80,23 @@ function createMedicationDispenseFromMedicationRequest(medicationRequest) { return medicationDispense; } +function createMedicationFromMedicationRequest(medicationRequest) { + let medication = {}; + medication.resourceType = 'Medication'; + medication.id = medicationRequest?.id + '-med'; + if (medicationRequest.medicationCodeableConcept) { + medication.code = medicationRequest.medicationCodeableConcept; + } else if (medicationRequest.medicationReference) { + medication.medicationReference = medicationRequest.medicationReference; + } + return medication; +} + export { fhir, getAge, getDrugCodeableConceptFromMedicationRequest, getDrugCodeFromMedicationRequest, - createMedicationDispenseFromMedicationRequest + createMedicationDispenseFromMedicationRequest, + createMedicationFromMedicationRequest }; diff --git a/src/util/util.js b/src/util/util.js index 244e805a..9a92a55d 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -66,30 +66,29 @@ function retrieveLaunchContext(link, patientId, clientState) { }); } -function getEtasu(etasuUrl, responseCallback) { +function standardsBasedGetEtasu(etasuUrl, body, responseCallback) { axios({ - method: 'get', - url: etasuUrl - }).then( - response => { + method: 'post', + url: etasuUrl, + data: body + }).then(response => { // Sorting an array mutates the data in place. const remsMetRes = response.data; - if (remsMetRes.metRequirements) { - remsMetRes.metRequirements.sort((first, second) => { + if (remsMetRes?.parameter[0]?.resource?.contained) { + remsMetRes.parameter[0].resource.contained[0].parameter.sort((first, second) => { // Keep the other forms unsorted. - if (second.requirementName.includes('Patient Status Update')) { + if (second.name.includes('Patient Status Update')) { // Sort the Patient Status Update forms in descending order of timestamp. - return second.requirementName.localeCompare(first.requirementName); + return second.name.localeCompare(first.name); } return 0; }); } - responseCallback(response.data); - }, - error => { - console.log(error); + responseCallback(response.data.parameter[0].resource); + }, error => { + console.log('error -- > ', error); } - ); + ) } -export { retrieveLaunchContext, getEtasu }; +export { retrieveLaunchContext, standardsBasedGetEtasu }; From cfbc57b30d60717ac5889eb88158d4bab4090ed3 Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Wed, 3 Apr 2024 20:49:14 -0400 Subject: [PATCH 2/5] Update patient portal etasu call --- .../ListSelections/NotificationsSection.jsx | 66 ++++++++++++++++--- src/components/EtasuStatus/EtasuStatus.jsx | 5 +- .../EtasuStatus/EtasuStatusComponent.jsx | 7 +- .../EtasuStatus/EtasuStatusModal.jsx | 2 +- src/util/util.js | 2 +- 5 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/components/Dashboard/ListSelections/NotificationsSection.jsx b/src/components/Dashboard/ListSelections/NotificationsSection.jsx index 4e17d257..b36bdcc2 100644 --- a/src/components/Dashboard/ListSelections/NotificationsSection.jsx +++ b/src/components/Dashboard/ListSelections/NotificationsSection.jsx @@ -3,31 +3,77 @@ import useStyles from '../styles'; import { SettingsContext } from '../../../containers/ContextProvider/SettingsProvider'; import { EtasuStatusComponent } from '../../EtasuStatus/EtasuStatusComponent'; import axios from 'axios'; +import { createMedicationFromMedicationRequest } from '../../../util/fhir'; +import { standardsBasedGetEtasu } from '../../../util/util'; const NotificationsSection = () => { const [globalState, _] = useContext(SettingsContext); const classes = useStyles(); const [etasu, setEtasu] = useState([]); + const [medications, setMedications] = useState([]); useEffect(() => { - const patientFirstName = globalState.patient?.name?.at(0)?.given?.at(0); - const patientLastName = globalState.patient?.name?.at(0)?.family; - const patientDOB = globalState.patient?.birthDate; + setEtasu([]); + getMedicationRequest(); + }, []); + + useEffect(() => { + getAllEtasu(); + }, [medications]); - const etasuUrl = `${globalState.remsAdminServer}/etasu/met/patient/${patientFirstName}/${patientLastName}/${patientDOB}`; + const getMedicationRequest = () => { + const patientsMedications = []; axios({ method: 'get', - url: etasuUrl - }).then((response) => { - setEtasu(response.data); + url: `${globalState.baseUrl}/MedicationRequest?subject=Patient/${globalState.patient.id}` + }).then((result) => { + result?.data.entry.forEach((m) => { + const medication = createMedicationFromMedicationRequest(m.resource); + patientsMedications.push(medication); + }) + setMedications(patientsMedications); }, (error) =>{ console.error(error); - }) - }, []); + }); + }; + + const compileResponses = (newRequest, body) => { + if (newRequest.contained) { + newRequest.body = body; + setEtasu(prevState => [ ...prevState, newRequest]); + } + } + + const getAllEtasu = () => { + medications.forEach((medication) => { + const body = makeBody(medication); + const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; + standardsBasedGetEtasu(standardEtasuUrl, body, compileResponses); + }); + + } + + const makeBody = (medication) => { + return { + resourceType: "Parameters", + parameter: [ + { + name: 'patient', + resource: globalState.patient + }, + { + name: 'medication', + resource: medication + } + ] + } + } + return (

Notifications

{etasu.map((remsCase) => { - return + const display = remsCase.body.parameter[1]?.resource.code.coding[0].display; + return })}
); diff --git a/src/components/EtasuStatus/EtasuStatus.jsx b/src/components/EtasuStatus/EtasuStatus.jsx index 49fa0b83..3d0b54a3 100644 --- a/src/components/EtasuStatus/EtasuStatus.jsx +++ b/src/components/EtasuStatus/EtasuStatus.jsx @@ -12,6 +12,7 @@ export const EtasuStatus = props => { const { code, request } = props; const [remsAdminResponse, setRemsAdminResponse] = useState({}); const [etasuData, setEtasuData] = useState({}); + const [display, setDisplay] = useState(''); useEffect(() => { const medication = createMedicationFromMedicationRequest(request); @@ -21,6 +22,8 @@ export const EtasuStatus = props => { const getEtasuStatus = (medication) => { const body = makeBody(medication); setEtasuData(body); + const display = body.parameter[1]?.resource.code.coding[0].display; + setDisplay(display); const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; standardsBasedGetEtasu(standardEtasuUrl, body, setRemsAdminResponse); @@ -45,7 +48,7 @@ export const EtasuStatus = props => { return ( <> - {remsAdminResponse.contained ? : ""} + {remsAdminResponse.contained ? : ""} ); }; diff --git a/src/components/EtasuStatus/EtasuStatusComponent.jsx b/src/components/EtasuStatus/EtasuStatusComponent.jsx index 9118c80b..2dbaccb1 100644 --- a/src/components/EtasuStatus/EtasuStatusComponent.jsx +++ b/src/components/EtasuStatus/EtasuStatusComponent.jsx @@ -1,14 +1,14 @@ import { EtasuStatusButton } from './EtasuStatusButton.jsx'; import { EtasuStatusModal } from './EtasuStatusModal.jsx'; import { useState, useEffect, useContext } from 'react'; -import { Card } from '@mui/material'; +import { Card, Typography } from '@mui/material'; import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider.jsx'; import { standardsBasedGetEtasu } from '../../util/util.js'; export const EtasuStatusComponent = props => { const [globalState, _] = useContext(SettingsContext); - const { remsAdminResponseInit, data } = + const { remsAdminResponseInit, data, display } = props; const [remsAdminResponse, setRemsAdminResponse] = useState(remsAdminResponseInit); @@ -36,6 +36,9 @@ export const EtasuStatusComponent = props => { } return ( + + {display} + {

ETASU

- {remsAdminResponse ? ( + {remsAdminResponse && remsAdminResponse.contained ? ( {remsAdminResponse?.contained[0]?.parameter.map((metRequirements) => ( { console.log('error -- > ', error); } From b947ccbb875c70fcef2ab7c368bc43004bd1a801 Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Thu, 4 Apr 2024 13:06:54 -0400 Subject: [PATCH 3/5] remove case number --- src/components/EtasuStatus/EtasuStatusModal.jsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/EtasuStatus/EtasuStatusModal.jsx b/src/components/EtasuStatus/EtasuStatusModal.jsx index 0b160b52..cef86c62 100644 --- a/src/components/EtasuStatus/EtasuStatusModal.jsx +++ b/src/components/EtasuStatus/EtasuStatusModal.jsx @@ -6,8 +6,6 @@ import './EtasuStatusModal.css'; import CheckCircle from '@mui/icons-material/CheckCircle'; import Close from '@mui/icons-material/Close'; -const getIdText = remsAdminResponse => remsAdminResponse?.case_number || 'N/A'; - export const EtasuStatusModal = props => { const { callback, onClose, remsAdminResponse, update } = props; const [spin, setSpin] = useState(false); @@ -28,9 +26,6 @@ export const EtasuStatusModal = props => {
-
- Case Number: {getIdText(remsAdminResponse)} -
Status: {convertStatus(remsAdminResponse.status)}
From 47e2e9e8d1cb109a943ac981bfe6ed27e47f1e86 Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Thu, 4 Apr 2024 13:29:11 -0400 Subject: [PATCH 4/5] Remove section copied from abvoe --- src/util/fhir.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util/fhir.js b/src/util/fhir.js index 8e24627f..3fdcb31d 100644 --- a/src/util/fhir.js +++ b/src/util/fhir.js @@ -86,8 +86,6 @@ function createMedicationFromMedicationRequest(medicationRequest) { medication.id = medicationRequest?.id + '-med'; if (medicationRequest.medicationCodeableConcept) { medication.code = medicationRequest.medicationCodeableConcept; - } else if (medicationRequest.medicationReference) { - medication.medicationReference = medicationRequest.medicationReference; } return medication; } From f3912be5d33047fc0cb8d70fcf2e251a896a62ea Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Thu, 4 Apr 2024 14:52:23 -0400 Subject: [PATCH 5/5] Clean up code --- src/components/EtasuStatus/EtasuStatus.jsx | 1 + src/components/EtasuStatus/EtasuStatusButton.jsx | 2 +- src/components/EtasuStatus/EtasuStatusComponent.jsx | 4 ++-- src/components/EtasuStatus/EtasuStatusModal.jsx | 11 +---------- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/components/EtasuStatus/EtasuStatus.jsx b/src/components/EtasuStatus/EtasuStatus.jsx index 3d0b54a3..97417aba 100644 --- a/src/components/EtasuStatus/EtasuStatus.jsx +++ b/src/components/EtasuStatus/EtasuStatus.jsx @@ -31,6 +31,7 @@ export const EtasuStatus = props => { const makeBody = (medication) => { + console.log('patient -- > ', globalState.patient); return { resourceType: "Parameters", parameter: [ diff --git a/src/components/EtasuStatus/EtasuStatusButton.jsx b/src/components/EtasuStatus/EtasuStatusButton.jsx index fc884782..ed87d7c8 100644 --- a/src/components/EtasuStatus/EtasuStatusButton.jsx +++ b/src/components/EtasuStatus/EtasuStatusButton.jsx @@ -63,7 +63,7 @@ const convertTimeDifference = start => { return `Last checked ${prefix} ago`; }; -const convertStatus = status => { +export const convertStatus = status => { if (status === 'success') { return 'Approved'; } else if (status === 'data-required') { diff --git a/src/components/EtasuStatus/EtasuStatusComponent.jsx b/src/components/EtasuStatus/EtasuStatusComponent.jsx index 2dbaccb1..17e541df 100644 --- a/src/components/EtasuStatus/EtasuStatusComponent.jsx +++ b/src/components/EtasuStatus/EtasuStatusComponent.jsx @@ -29,8 +29,8 @@ export const EtasuStatusComponent = props => { const refreshEtasu = () => { if(remsAdminResponse) { - const standarEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; - standardsBasedGetEtasu(standarEtasuUrl, data, setRemsAdminResponse); + const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`; + standardsBasedGetEtasu(standardEtasuUrl, data, setRemsAdminResponse); setLastCheckedEtasuTime(Date.now()); } } diff --git a/src/components/EtasuStatus/EtasuStatusModal.jsx b/src/components/EtasuStatus/EtasuStatusModal.jsx index cef86c62..d025fda5 100644 --- a/src/components/EtasuStatus/EtasuStatusModal.jsx +++ b/src/components/EtasuStatus/EtasuStatusModal.jsx @@ -5,6 +5,7 @@ import { getStatusColor } from './EtasuStatusComponent'; import './EtasuStatusModal.css'; import CheckCircle from '@mui/icons-material/CheckCircle'; import Close from '@mui/icons-material/Close'; +import { convertStatus } from './EtasuStatusButton'; export const EtasuStatusModal = props => { const { callback, onClose, remsAdminResponse, update } = props; @@ -94,13 +95,3 @@ const modalStyle = { boxShadow: 24, p: 4 }; - -const convertStatus = status => { - if (status === 'success') { - return 'Approved'; - } else if (status === 'data-required') { - return 'Pending'; - } else { - return 'Not Started'; - } - }