From 6b456a2950c9dd5e73ce74024a6f50325ffc9f39 Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Fri, 10 May 2024 17:05:06 -0400 Subject: [PATCH 1/2] Handle the returns from patient-view hooks being sent to multiple REMS Administrators. --- src/components/RequestBox/RequestBox.jsx | 10 ++--- .../RequestDashboard/SettingsSection.jsx | 12 +++--- src/containers/ContextProvider/reducer.js | 4 +- src/containers/RequestBuilder.jsx | 15 +++++-- src/util/buildRequest.js | 8 ++-- src/util/data.js | 43 +++++++++++-------- src/util/util.js | 4 +- 7 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/components/RequestBox/RequestBox.jsx b/src/components/RequestBox/RequestBox.jsx index 2b590353..c0f1f70e 100644 --- a/src/components/RequestBox/RequestBox.jsx +++ b/src/components/RequestBox/RequestBox.jsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import buildNewRxRequest from '../../util/buildScript.2017071.js'; import MuiAlert from '@mui/material/Alert'; import Snackbar from '@mui/material/Snackbar'; -import { shortNameMap } from '../../util/data.js'; +import { shortNameMap, ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW } from '../../util/data.js'; import { getAge, createMedicationDispenseFromMedicationRequest } from '../../util/fhir.js'; import { retrieveLaunchContext, prepPrefetch } from '../../util/util.js'; import './request.css'; @@ -36,18 +36,18 @@ const RequestBox = props => { const emptyField = empty; const submitPatientView = () => { - submitInfo(prepPrefetch(prefetchedResources), null, patient, 'patient-view'); + submitInfo(prepPrefetch(prefetchedResources), null, patient, PATIENT_VIEW); }; const _submitOrderSelect = () => { if (!_.isEmpty(request)) { - submitInfo(prepPrefetch(prefetchedResources), request, patient, 'order-select'); + submitInfo(prepPrefetch(prefetchedResources), request, patient, ORDER_SELECT); } }; const submitOrderSign = request => { if (!_.isEmpty(request)) { - submitInfo(prepPrefetch(prefetchedResources), request, patient, 'order-sign'); + submitInfo(prepPrefetch(prefetchedResources), request, patient, ORDER_SIGN); } }; @@ -264,7 +264,7 @@ const RequestBox = props => { const disableSendToCRD = isOrderNotSelected() || loading; const disableSendRx = isOrderNotSelected() || loading; const disableLaunchSmartOnFhir = isPatientNotSelected(); - const orderSignRemsAdmin = getRemsAdminUrl(request, 'order-sign'); + const orderSignRemsAdmin = getRemsAdminUrl(request, ORDER_SIGN); return ( <> diff --git a/src/components/RequestDashboard/SettingsSection.jsx b/src/components/RequestDashboard/SettingsSection.jsx index 46058a47..37b4d8ec 100644 --- a/src/components/RequestDashboard/SettingsSection.jsx +++ b/src/components/RequestDashboard/SettingsSection.jsx @@ -25,11 +25,11 @@ import AddIcon from '@mui/icons-material/Add'; import env from 'env-var'; import FHIR from 'fhirclient'; -import { headerDefinitions, medicationRequestToRemsAdmins } from '../../util/data'; +import { headerDefinitions, medicationRequestToRemsAdmins, ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START } from '../../util/data'; import { actionTypes, initialState } from '../../containers/ContextProvider/reducer'; import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider'; -const CDS_HOOKS = ['order-sign', 'order-select', 'patient-view', 'encounter-start']; +const CDS_HOOKS = [ORDER_SELECT, ORDER_SIGN, PATIENT_VIEW, ENCOUNTER_START]; const SettingsSection = props => { const [state, dispatch] = React.useContext(SettingsContext); @@ -266,11 +266,11 @@ const SettingsSection = props => { onChange={event => updateSetting(key, event.target.value)} sx={{ width: '100%' }} > - - patient-view + + {PATIENT_VIEW} - - encounter-start + + {ENCOUNTER_START} diff --git a/src/containers/ContextProvider/reducer.js b/src/containers/ContextProvider/reducer.js index d73f500c..1324d929 100644 --- a/src/containers/ContextProvider/reducer.js +++ b/src/containers/ContextProvider/reducer.js @@ -1,4 +1,4 @@ -import { headerDefinitions, medicationRequestToRemsAdmins } from '../../util/data'; +import { headerDefinitions, medicationRequestToRemsAdmins, ORDER_SIGN } from '../../util/data'; import { v4 as uuidv4 } from 'uuid'; export const actionTypes = Object.freeze({ @@ -43,7 +43,7 @@ const getNewStateWithNewCdsHookSetting = (state, settingId) => { newState.medicationRequestToRemsAdmins[uuidv4()] = { rxnorm: 'Fill out Medication RxNorm Code', display: 'Fill out Medication Display Name', - hook: 'order-sign', + hook: ORDER_SIGN, remsAdmin: 'REMS Admin URL for CDS Hook' }; diff --git a/src/containers/RequestBuilder.jsx b/src/containers/RequestBuilder.jsx index 375bbc17..4ad6066b 100644 --- a/src/containers/RequestBuilder.jsx +++ b/src/containers/RequestBuilder.jsx @@ -6,7 +6,7 @@ import DisplayBox from '../components/DisplayBox/DisplayBox.jsx'; import '../index.css'; import RequestBox from '../components/RequestBox/RequestBox.jsx'; import buildRequest from '../util/buildRequest.js'; -import { types } from '../util/data.js'; +import { types, PATIENT_VIEW } from '../util/data.js'; import { createJwt } from '../util/auth.js'; import { getMedicationSpecificRemsAdminUrl, prepPrefetch } from '../util/util.js'; @@ -31,6 +31,7 @@ const RequestBuilder = props => { expanded: true, patientList: [], response: {}, + rUrl: null, code: null, codeSystem: null, display: null, @@ -133,7 +134,6 @@ const RequestBuilder = props => { uniqueUrls?.forEach(url => { sendHook(prepPrefetch(state.prefetchedResources), null, globalState.patient, hook, url); - //TODO: still need to handle multiple sends and multiple cards coming back }); }, [state.medicationRequests]); @@ -198,6 +198,8 @@ const RequestBuilder = props => { body: JSON.stringify(json_request) }) .then(response => { + let responseUrl = response?.url; + setState(prevState => ({ ...prevState, rUrl: responseUrl })); response.json().then(fhirResponse => { console.log(fhirResponse); if (fhirResponse?.status) { @@ -206,7 +208,14 @@ const RequestBuilder = props => { ); console.log(fhirResponse.message); } else { - setState(prevState => ({ ...prevState, response: fhirResponse })); + if (response?.url?.includes(PATIENT_VIEW)) { + // copy the cards from the old response into the new + setState(prevState => ({ + ...prevState, response: { cards: [...(prevState.response.cards || []), ...fhirResponse.cards] } + })); + } else { + setState(prevState => ({ ...prevState, response: fhirResponse })); + } } setState(prevState => ({ ...prevState, loading: false })); }); diff --git a/src/util/buildRequest.js b/src/util/buildRequest.js index e2f8bc20..7cabe932 100644 --- a/src/util/buildRequest.js +++ b/src/util/buildRequest.js @@ -1,3 +1,5 @@ +import { ORDER_SIGN, ORDER_SELECT } from "./data"; + export default function buildRequest( request, user, @@ -43,7 +45,7 @@ export default function buildRequest( r4json.extension = extension; } - if (hook === 'order-select') { + if (hook === ORDER_SELECT) { r4json.context.draftOrders = { resourceType: 'Bundle', entry: [ @@ -53,7 +55,7 @@ export default function buildRequest( ] }; r4json.context.selections = [request.resourceType + '/' + request.id]; - } else if (hook === 'order-sign') { + } else if (hook === ORDER_SIGN) { r4json.context.draftOrders = { resourceType: 'Bundle', entry: [ @@ -62,7 +64,7 @@ export default function buildRequest( } ] }; - //} else if (hook === "patient-view") { + //} else if ((hook === PATIENT_VIEW) || (hook === ENCOUNTER_START)) { } if (includePrefetch) { diff --git a/src/util/data.js b/src/util/data.js index 708cd46c..29eaadb1 100644 --- a/src/util/data.js +++ b/src/util/data.js @@ -83,45 +83,50 @@ const headerDefinitions = { } }; +const ORDER_SIGN = 'order-sign'; +const ORDER_SELECT = 'order-select'; +const PATIENT_VIEW = 'patient-view'; +const ENCOUNTER_START = 'encounter-start'; + const medicationRequestToRemsAdmins = Object.freeze([ { rxnorm: 2183126, display: 'Turalio 200 MG Oral Capsule', hookEndpoints: [ - { hook: 'order-sign', remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, - { hook: 'order-select', remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, - { hook: 'patient-view', remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, - { hook: 'encounter-start', remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } + { hook: ORDER_SIGN, remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, + { hook: ORDER_SELECT, remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, + { hook: PATIENT_VIEW, remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, + { hook: ENCOUNTER_START, remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } ] }, { rxnorm: 6064, display: 'Isotretinoin 20 MG Oral Capsule', hookEndpoints: [ - { hook: 'order-sign', remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, - { hook: 'order-select', remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, - { hook: 'patient-view', remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, - { hook: 'encounter-start', remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } + { hook: ORDER_SIGN, remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, + { hook: ORDER_SELECT, remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, + { hook: PATIENT_VIEW, remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, + { hook: ENCOUNTER_START, remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } ] }, { rxnorm: 1237051, display: 'TIRF 200 UG Oral Transmucosal Lozenge', hookEndpoints: [ - { hook: 'order-sign', remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, - { hook: 'order-select', remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, - { hook: 'patient-view', remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, - { hook: 'encounter-start', remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } + { hook: ORDER_SIGN, remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, + { hook: ORDER_SELECT, remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, + { hook: PATIENT_VIEW, remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, + { hook: ENCOUNTER_START, remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } ] }, { rxnorm: 1666386, display: 'Addyi 100 MG Oral Tablet', hookEndpoints: [ - { hook: 'order-sign', remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, - { hook: 'order-select', remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, - { hook: 'patient-view', remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, - { hook: 'encounter-start', remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } + { hook: ORDER_SIGN, remsAdmin: 'http://localhost:8090/cds-services/rems-order-sign' }, + { hook: ORDER_SELECT, remsAdmin: 'http://localhost:8090/cds-services/rems-order-select' }, + { hook: PATIENT_VIEW, remsAdmin: 'http://localhost:8090/cds-services/rems-patient-view' }, + { hook: ENCOUNTER_START, remsAdmin: 'http://localhost:8090/cds-services/rems-encounter-start' } ] } ]); @@ -258,5 +263,9 @@ export { shortNameMap, stateOptions, types, - medicationRequestToRemsAdmins + medicationRequestToRemsAdmins, + ORDER_SIGN, + ORDER_SELECT, + PATIENT_VIEW, + ENCOUNTER_START }; diff --git a/src/util/util.js b/src/util/util.js index 663c0393..16af6258 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -1,5 +1,5 @@ import axios from 'axios'; - +import { ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START } from './data'; /** * Retrieves a SMART launch context from an endpoint to append as a "launch" query parameter to a SMART app launch URL (see SMART docs for more about launch context). * This applies mainly if a SMART app link on a card is to be launched. The link needs a "launch" query param with some opaque value from the SMART server entity. @@ -104,7 +104,7 @@ const getMedicationSpecificRemsAdminUrl = (request, globalState, hook) => { return undefined; } - if (!(hook === 'patient-view' || hook === 'order-sign' || hook === 'order-select' || hook === 'encounter-start')) { + if (!(hook === PATIENT_VIEW || hook === ORDER_SIGN || hook === ORDER_SELECT || hook === ENCOUNTER_START)) { console.log(`ERROR: unknown hook type: ${hook}`); return undefined; } From 9ce08bc945f7638af631cb43566db34ae5b006fa Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Fri, 10 May 2024 17:28:57 -0400 Subject: [PATCH 2/2] fixes --- src/components/RequestDashboard/SettingsSection.jsx | 2 +- src/containers/RequestBuilder.jsx | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/RequestDashboard/SettingsSection.jsx b/src/components/RequestDashboard/SettingsSection.jsx index 37b4d8ec..261bbfed 100644 --- a/src/components/RequestDashboard/SettingsSection.jsx +++ b/src/components/RequestDashboard/SettingsSection.jsx @@ -29,7 +29,7 @@ import { headerDefinitions, medicationRequestToRemsAdmins, ORDER_SIGN, ORDER_SEL import { actionTypes, initialState } from '../../containers/ContextProvider/reducer'; import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider'; -const CDS_HOOKS = [ORDER_SELECT, ORDER_SIGN, PATIENT_VIEW, ENCOUNTER_START]; +const CDS_HOOKS = [ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START]; const SettingsSection = props => { const [state, dispatch] = React.useContext(SettingsContext); diff --git a/src/containers/RequestBuilder.jsx b/src/containers/RequestBuilder.jsx index 4ad6066b..19daf203 100644 --- a/src/containers/RequestBuilder.jsx +++ b/src/containers/RequestBuilder.jsx @@ -31,7 +31,6 @@ const RequestBuilder = props => { expanded: true, patientList: [], response: {}, - rUrl: null, code: null, codeSystem: null, display: null, @@ -198,8 +197,6 @@ const RequestBuilder = props => { body: JSON.stringify(json_request) }) .then(response => { - let responseUrl = response?.url; - setState(prevState => ({ ...prevState, rUrl: responseUrl })); response.json().then(fhirResponse => { console.log(fhirResponse); if (fhirResponse?.status) {