Skip to content

Commit 88a4aba

Browse files
authored
Merge pull request #134 from mcode/dev
Dev
2 parents f341795 + 1921527 commit 88a4aba

File tree

12 files changed

+176
-93
lines changed

12 files changed

+176
-93
lines changed

.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ VITE_PIMS_SERVER = http://localhost:5051/doctorOrders/api/addRx
1919
VITE_PUBLIC_KEYS = http://localhost:3000/request-generator/.well-known/jwks.json
2020
VITE_REALM = ClientFhirServer
2121
VITE_RESPONSE_EXPIRATION_DAYS = 30
22-
VITE_SERVER = http://localhost:8090
2322
VITE_SMART_LAUNCH_URL = http://localhost:4040/
2423
VITE_URL = http://localhost:3000
2524
VITE_USER = alice
2625
VITE_HOOK_TO_SEND = patient-view
2726
VITE_URL_FILTER = http://localhost:3000/*
27+
VITE_USE_INTERMEDIARY = false
28+
VITE_INTERMEDIARY = http://localhost:3003

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ Following are a list of modifiable paths:
129129
| VITE_PUBLIC_KEYS | `http://localhost:3000/request-generator/.well-known/jwks.json` | The endpoint which contains the public keys for authentication with the REMS admin. Should be changed if the keys are moved elsewhere. |
130130
| VITE_REALM | `ClientFhirServer` | The Keycloak realm to use. Only relevant is using Keycloak as an authentication server. This only affects direct logins like through the Patient Portal, not SMART launches like opening the app normally. |
131131
| VITE_RESPONSE_EXPIRATION_DAYS | `30` | The number of days old a Questionnaire Response can be before it is ignored and filtered out. This ensures the patient search excludes outdated or obsolete prior sessions from creating clutter. |
132-
| VITE_SERVER | `http://localhost:8090` | The default base URL of the CDS service. Typically this will be the base url of the REMS Admin. |
133132
| VITE_SMART_LAUNCH_URL | `http://localhost:4040/` | The base url of the SMART app. This is used for opening the app directly, rather than doing an EHR SMART launch. |
134133
| VITE_URL | `http://localhost:3000` | The base url of this app. Should be modified if the port or domain change. |
135-
| VITE_USER | `alice` | The default user to login as when opening the app. |
134+
| VITE_USER | `alice` | The default user to login as when opening the app. |
135+
| VITE_USE_INTERMEDIARY | false | When true, the app will send all CDS Hooks and REMS ETASU check calls to the intermediary defined in VITE_INTERMEDIARY. |
136+
| VITE_INTERMEDIARY | `http://localhost:3030` | The base url of the intermediary. |

src/components/Dashboard/ListSelections/NotificationsSection.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { SettingsContext } from '../../../containers/ContextProvider/SettingsPro
44
import { EtasuStatusComponent } from '../../EtasuStatus/EtasuStatusComponent';
55
import axios from 'axios';
66
import { createMedicationFromMedicationRequest } from '../../../util/fhir';
7-
import { standardsBasedGetEtasu } from '../../../util/util';
7+
import { standardsBasedGetEtasu, getMedicationSpecificEtasuUrl } from '../../../util/util';
88

99
const NotificationsSection = () => {
1010
const [globalState, _] = useContext(SettingsContext);
@@ -49,7 +49,7 @@ const NotificationsSection = () => {
4949
const getAllEtasu = () => {
5050
medications.forEach(medication => {
5151
const body = makeBody(medication);
52-
const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`;
52+
const standardEtasuUrl = getMedicationSpecificEtasuUrl(medication?.code, globalState);
5353
standardsBasedGetEtasu(standardEtasuUrl, body, compileResponses);
5454
});
5555
};
@@ -81,6 +81,7 @@ const NotificationsSection = () => {
8181
display={display}
8282
remsAdminResponseInit={remsCase}
8383
data={remsCase.body}
84+
medication={remsCase.body.parameter[1]?.resource}
8485
/>
8586
);
8687
})}

src/components/DisplayBox/DisplayBox.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ const DisplayBox = props => {
287287
card.links.map((link, ind) => {
288288
if (link.type === 'smart') {
289289
linksSection.push(
290-
<ListItem sx={{ marginLeft: '-12px' }}>
290+
<ListItem key={ind} sx={{ marginLeft: '-12px' }}>
291291
<Button
292292
key={ind}
293293
variant="outlined"
@@ -318,7 +318,7 @@ const DisplayBox = props => {
318318
card.links.map((link, ind) => {
319319
if (link.type === 'absolute') {
320320
documentationSection.push(
321-
<ListItem>
321+
<ListItem key={ind}>
322322
<Box key={ind}>
323323
<Button
324324
variant="text"

src/components/EtasuStatus/EtasuStatus.jsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useState, useEffect, useContext } from 'react';
22
import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider.jsx';
33
import { EtasuStatusComponent } from './EtasuStatusComponent.jsx';
4-
import { standardsBasedGetEtasu } from '../../util/util.js';
5-
import { createMedicationFromMedicationRequest, getDrugCodeableConceptFromMedicationRequest } from '../../util/fhir.js';
4+
import { standardsBasedGetEtasu, getMedicationSpecificEtasuUrl } from '../../util/util.js';
5+
import { createMedicationFromMedicationRequest } from '../../util/fhir.js';
66

77
// converts code into etasu for the component to render
88
// simplifies usage for applications that only know the code, not the case they want to display
@@ -12,6 +12,7 @@ export const EtasuStatus = props => {
1212
const { code, request } = props;
1313
const [remsAdminResponse, setRemsAdminResponse] = useState({});
1414
const [etasuData, setEtasuData] = useState({});
15+
const [medication, setMedication] = useState({});
1516
const [display, setDisplay] = useState('');
1617

1718
useEffect(() => {
@@ -22,9 +23,10 @@ export const EtasuStatus = props => {
2223
const getEtasuStatus = medication => {
2324
const body = makeBody(medication);
2425
setEtasuData(body);
26+
setMedication(medication);
2527
const display = body.parameter[1]?.resource.code?.coding[0].display;
2628
setDisplay(display);
27-
const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`;
29+
const standardEtasuUrl = getMedicationSpecificEtasuUrl(medication?.code, globalState);
2830
standardsBasedGetEtasu(standardEtasuUrl, body, setRemsAdminResponse);
2931
};
3032

@@ -47,11 +49,12 @@ export const EtasuStatus = props => {
4749

4850
return (
4951
<>
50-
{remsAdminResponse.contained ? (
52+
{remsAdminResponse?.contained ? (
5153
<EtasuStatusComponent
5254
remsAdminResponseInit={remsAdminResponse}
5355
data={etasuData}
5456
display={display}
57+
medication={medication}
5558
/>
5659
) : (
5760
''

src/components/EtasuStatus/EtasuStatusComponent.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { EtasuStatusModal } from './EtasuStatusModal.jsx';
33
import { useState, useEffect, useContext } from 'react';
44
import { Card, Typography } from '@mui/material';
55
import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider.jsx';
6-
import { standardsBasedGetEtasu } from '../../util/util.js';
6+
import { standardsBasedGetEtasu, getMedicationSpecificEtasuUrl } from '../../util/util.js';
77

88
export const EtasuStatusComponent = props => {
99
const [globalState, _] = useContext(SettingsContext);
1010

11-
const { remsAdminResponseInit, data, display } = props;
11+
const { remsAdminResponseInit, data, display, medication } = props;
1212

1313
const [remsAdminResponse, setRemsAdminResponse] = useState(remsAdminResponseInit);
1414
const [lastCheckedEtasuTime, setLastCheckedEtasuTime] = useState(0);
@@ -28,7 +28,7 @@ export const EtasuStatusComponent = props => {
2828

2929
const refreshEtasu = () => {
3030
if (remsAdminResponse) {
31-
const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`;
31+
const standardEtasuUrl = getMedicationSpecificEtasuUrl(medication?.code, globalState);
3232
standardsBasedGetEtasu(standardEtasuUrl, data, setRemsAdminResponse);
3333
setLastCheckedEtasuTime(Date.now());
3434
}

src/components/RequestBox/RequestBox.jsx

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@ import buildNewRxRequest from '../../util/buildScript.2017071.js';
66
import MuiAlert from '@mui/material/Alert';
77
import Snackbar from '@mui/material/Snackbar';
88
import { shortNameMap, ORDER_SIGN, PATIENT_VIEW } from '../../util/data.js';
9-
import { getAge, createMedicationDispenseFromMedicationRequest, createMedicationFromMedicationRequest } from '../../util/fhir.js';
10-
import { retrieveLaunchContext, prepPrefetch } from '../../util/util.js';
9+
import {
10+
getAge,
11+
createMedicationDispenseFromMedicationRequest,
12+
createMedicationFromMedicationRequest,
13+
getDrugCodeableConceptFromMedicationRequest
14+
} from '../../util/fhir.js';
15+
import {
16+
retrieveLaunchContext,
17+
prepPrefetch,
18+
getMedicationSpecificEtasuUrl
19+
} from '../../util/util.js';
1120
import './request.css';
1221
import axios from 'axios';
1322

@@ -17,7 +26,7 @@ const RequestBox = props => {
1726
response: {},
1827
submittedRx: false
1928
});
20-
const [globalState,] = useContext(SettingsContext);
29+
const [globalState] = useContext(SettingsContext);
2130

2231
const {
2332
prefetchedResources,
@@ -56,7 +65,6 @@ const RequestBox = props => {
5665
}
5766
}, [prefetchCompleted]);
5867

59-
6068
const renderPatientInfo = () => {
6169
if (Object.keys(patient).length === 0) {
6270
return <div className="demographics"></div>;
@@ -214,26 +222,30 @@ const RequestBox = props => {
214222
*/
215223
const sendRx = async () => {
216224
console.log('Sending NewRx to: ' + pimsUrl);
217-
console.log('Getting auth number ')
225+
console.log('Getting auth number ');
218226
const medication = createMedicationFromMedicationRequest(request);
219227
const body = makeBody(medication);
220-
const standardEtasuUrl = `${globalState.remsAdminServer}/4_0_0/GuidanceResponse/$rems-etasu`;
228+
const standardEtasuUrl = getMedicationSpecificEtasuUrl(
229+
getDrugCodeableConceptFromMedicationRequest(request),
230+
globalState
231+
);
221232
let authNumber = '';
222233
await axios({
223234
method: 'post',
224235
url: standardEtasuUrl,
225236
data: body
226-
}).then(
227-
response => {
228-
if (response.data.parameter[0].resource && response.data.parameter[0].resource.contained) {
229-
response.data.parameter[0].resource?.contained[0]?.parameter.map(metRequirements => {
237+
}).then(response => {
238+
if (
239+
response.data.parameter?.[0].resource &&
240+
response.data.parameter?.[0].resource.contained
241+
) {
242+
response.data.parameter?.[0].resource?.contained[0]?.parameter.map(metRequirements => {
230243
if (metRequirements.name === 'auth_number') {
231244
authNumber = metRequirements.valueString;
232245
}
233246
});
234-
}
235247
}
236-
);
248+
});
237249

238250
// build the NewRx Message
239251
var newRx = buildNewRxRequest(

src/components/RequestDashboard/SettingsSection.jsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ import AddIcon from '@mui/icons-material/Add';
2525
import env from 'env-var';
2626
import FHIR from 'fhirclient';
2727

28-
import { headerDefinitions, medicationRequestToRemsAdmins, ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START } from '../../util/data';
28+
import { headerDefinitions, medicationRequestToRemsAdmins, ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START, REMS_ETASU } from '../../util/data';
2929
import { actionTypes, initialState } from '../../containers/ContextProvider/reducer';
3030
import { SettingsContext } from '../../containers/ContextProvider/SettingsProvider';
3131

32-
const CDS_HOOKS = [ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START];
32+
const ENDPOINT = [ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START, REMS_ETASU];
3333

3434
const SettingsSection = props => {
3535
const [state, dispatch] = React.useContext(SettingsContext);
@@ -299,13 +299,14 @@ const SettingsSection = props => {
299299
maxHeight: 440
300300
}}
301301
>
302+
{!state['useIntermediary'] && (
302303
<Table stickyHeader aria-label="sticky table">
303304
<TableHead>
304305
<TableRow sx={{ th: { fontWeight: 'bold' } }}>
305306
<TableCell width={500}>Medication Display</TableCell>
306307
<TableCell width={200}>Medication RxNorm Code</TableCell>
307-
<TableCell width={200}>CDS Hook</TableCell>
308-
<TableCell width={500}>REMS Admin Endpoint</TableCell>
308+
<TableCell width={200}>Hook / Endpoint</TableCell>
309+
<TableCell width={500}>REMS Admin URL</TableCell>
309310
{/* This empty TableCell corresponds to the add and delete
310311
buttons. It is used to fill up the sticky header which
311312
will appear over the gray/white table rows. */}
@@ -348,19 +349,19 @@ const SettingsSection = props => {
348349
<Select
349350
labelId="dropdown-label"
350351
id="dropdown"
351-
value={row.hook}
352+
value={row.endpointType}
352353
onChange={event =>
353354
dispatch({
354355
type: actionTypes.updateCdsHookSetting,
355356
settingId: key,
356-
value: { hook: event.target.value }
357+
value: { endpointType: event.target.value }
357358
})
358359
}
359360
sx={{ width: '100%' }}
360361
>
361-
{CDS_HOOKS.map(hook => (
362-
<MenuItem key={hook} value={hook}>
363-
{hook}
362+
{ENDPOINT.map(endpointType => (
363+
<MenuItem key={endpointType} value={endpointType}>
364+
{endpointType}
364365
</MenuItem>
365366
))}
366367
</Select>
@@ -408,6 +409,7 @@ const SettingsSection = props => {
408409
})}
409410
</TableBody>
410411
</Table>
412+
)}
411413
</TableContainer>
412414
</Grid>
413415

src/containers/ContextProvider/reducer.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const getNewStateWithNewCdsHookSetting = (state, settingId) => {
4343
newState.medicationRequestToRemsAdmins[uuidv4()] = {
4444
rxnorm: 'Fill out Medication RxNorm Code',
4545
display: 'Fill out Medication Display Name',
46-
hook: ORDER_SIGN,
46+
endpointType: ORDER_SIGN,
4747
remsAdmin: 'REMS Admin URL for CDS Hook'
4848
};
4949

@@ -108,10 +108,10 @@ export const initialState = (() => {
108108
});
109109

110110
medicationRequestToRemsAdmins.forEach(row => {
111-
const { rxnorm, display, hookEndpoints } = row;
112-
hookEndpoints.forEach(({ hook, remsAdmin }) => {
113-
const key = `${rxnorm}_${hook}`;
114-
state.medicationRequestToRemsAdmins[key] = { rxnorm, display, hook, remsAdmin };
111+
const { rxnorm, display, endpoints } = row;
112+
endpoints.forEach(({ endpointType, remsAdmin }) => {
113+
const key = `${rxnorm}_${endpointType}`;
114+
state.medicationRequestToRemsAdmins[key] = { rxnorm, display, endpointType, remsAdmin };
115115
});
116116
});
117117
return state;

src/containers/RequestBuilder.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import RequestBox from '../components/RequestBox/RequestBox.jsx';
88
import buildRequest from '../util/buildRequest.js';
99
import { types, PATIENT_VIEW } from '../util/data.js';
1010
import { createJwt } from '../util/auth.js';
11-
import { getMedicationSpecificRemsAdminUrl, prepPrefetch } from '../util/util.js';
11+
import { getMedicationSpecificCdsHooksUrl, prepPrefetch } from '../util/util.js';
1212

1313
import Accordion from '@mui/material/Accordion';
1414
import AccordionSummary from '@mui/material/AccordionSummary';
@@ -121,7 +121,7 @@ const RequestBuilder = props => {
121121
let remsAdminUrls = [];
122122
// get all the remsAdminUrl for each MedicationRequest
123123
state.medicationRequests?.data?.forEach(request => {
124-
const remsAdminUrl = getMedicationSpecificRemsAdminUrl(request, globalState, hook);
124+
const remsAdminUrl = getMedicationSpecificCdsHooksUrl(request, globalState, hook);
125125
if (remsAdminUrl) {
126126
remsAdminUrls.push(remsAdminUrl);
127127
}
@@ -138,7 +138,7 @@ const RequestBuilder = props => {
138138
console.log('Initiating form submission ', types.info);
139139
let remsAdminUrl = null;
140140
if (request) {
141-
remsAdminUrl = getMedicationSpecificRemsAdminUrl(request, globalState, hook);
141+
remsAdminUrl = getMedicationSpecificCdsHooksUrl(request, globalState, hook);
142142
sendHook(prefetch, request, patient, hook, remsAdminUrl);
143143
} else {
144144
// get all MedicationRequests for the patient, then continue

0 commit comments

Comments
 (0)