Skip to content
Merged

Dev #137

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ VITE_GH_PAGES=false
VITE_LAUNCH_URL = http://localhost:4040/launch
VITE_PASSWORD = alice
VITE_PATIENT_FHIR_QUERY = Patient?_sort=identifier&_count=12
VITE_PIMS_SERVER = http://localhost:5051/doctorOrders/api/addRx
VITE_PIMS_SERVER = http://localhost:5051/ncpdp/script
VITE_PUBLIC_KEYS = http://localhost:3000/request-generator/.well-known/jwks.json
VITE_REALM = ClientFhirServer
VITE_RESPONSE_EXPIRATION_DAYS = 30
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Following are a list of modifiable paths:
| VITE_LAUNCH_URL | `http://localhost:4040/launch` | The launch URL of the SMART app the request generator should use for standalone launches. Note that this URL is only used outside of the context of the CDS Hooks workflow. Normally, the SMART app launch URL will come from a link inside a card that is returned by the REMS Admin. |
| VITE_PASSWORD | `alice` | The default password for logging in as the default user, defined by VITE_USER. This should be changed if using a different default user. |
| VITE_PATIENT_FHIR_QUERY | `Patient?_sort=identifier&_count=12` | The FHIR query the app makes when searching for patients in the EHR. This should be modified if a different behavior is desired by the apps patient selection popup. This can also be modified directly in the app's settings. |
| VITE_PIMS_SERVER | `http://localhost:5051/doctorOrders/api/addRx` | The Pharmacy System endpoint for submitting medications. This should be changed depending on which pharmacy system you want to connect with. |
| VITE_PIMS_SERVER | `http://localhost:5051/ncpdp/script` | The Pharmacy System endpoint for submitting medications. This should be changed depending on which pharmacy system you want to connect with. |
| 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. |
| 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. |
| 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. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createMedicationFromMedicationRequest } from '../../../util/fhir';
import { standardsBasedGetEtasu, getMedicationSpecificEtasuUrl } from '../../../util/util';

const NotificationsSection = () => {
const [globalState, _] = useContext(SettingsContext);
const [globalState] = useContext(SettingsContext);
const classes = useStyles();
const [etasu, setEtasu] = useState([]);
const [medications, setMedications] = useState([]);
Expand Down
2 changes: 1 addition & 1 deletion src/components/EtasuStatus/EtasuStatus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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 [globalState] = useContext(SettingsContext);

const { code, request } = props;
const [remsAdminResponse, setRemsAdminResponse] = useState({});
Expand Down
2 changes: 1 addition & 1 deletion src/components/EtasuStatus/EtasuStatusComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { SettingsContext } from '../../containers/ContextProvider/SettingsProvid
import { standardsBasedGetEtasu, getMedicationSpecificEtasuUrl } from '../../util/util.js';

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

const { remsAdminResponseInit, data, display, medication } = props;

Expand Down
10 changes: 2 additions & 8 deletions src/components/RequestBox/PatientSearchBar/PatientSearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defaultValues } from '../../../util/data';

import PatientBox from '../../SMARTBox/PatientBox';
import './PatientSearchBarStyle.css';
import { getPatientFirstAndLastName } from '../../../util/util';

const PatientSearchBar = props => {
const [options] = useState(defaultValues);
Expand All @@ -14,18 +15,11 @@ const PatientSearchBar = props => {
useEffect(() => {
const newList = props.searchablePatients.map(patient => ({
id: patient.id,
name: getName(patient)
name: getPatientFirstAndLastName(patient)
}));
setListOfPatients([newList]);
}, [props.searchablePatients]);

function getName(patient) {
if (patient.name) {
return patient.name[0].given[0] + ' ' + patient.name[0].family;
}
return '';
}

function getFilteredLength(searchString, listOfPatients) {
const filteredListOfPatients = listOfPatients[0].filter(element => {
if (searchString === '') {
Expand Down
5 changes: 3 additions & 2 deletions src/components/RequestBox/RequestBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
import {
retrieveLaunchContext,
prepPrefetch,
getMedicationSpecificEtasuUrl
getMedicationSpecificEtasuUrl,
getPatientFirstAndLastName
} from '../../util/util.js';
import './request.css';
import axios from 'axios';
Expand Down Expand Up @@ -71,7 +72,7 @@ const RequestBox = props => {
}
let name;
if (patient.name) {
name = <span> {`${patient.name[0].given[0]} ${patient.name[0].family}`} </span>;
name = <span>{getPatientFirstAndLastName(patient)}</span>;
} else {
name = emptyField;
}
Expand Down
265 changes: 136 additions & 129 deletions src/components/RequestDashboard/SettingsSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ import AddIcon from '@mui/icons-material/Add';
import env from 'env-var';
import FHIR from 'fhirclient';

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

const ENDPOINT = [ORDER_SIGN, ORDER_SELECT, PATIENT_VIEW, ENCOUNTER_START, REMS_ETASU];
Expand Down Expand Up @@ -255,30 +262,30 @@ const SettingsSection = props => {
case 'dropdown':
return (
<React.Fragment key={key}>
<Grid key={key} item xs={6}>
<FormControl fullWidth>
<InputLabel id="dropdown-label">Hook to send when selecting a patient</InputLabel>
<Select
labelId="dropdown-label"
id="dropdown"
value={state[key]}
label="Hook to send when selecting a patient"
onChange={event => updateSetting(key, event.target.value)}
sx={{ width: '100%' }}
>
<MenuItem key={PATIENT_VIEW} value={PATIENT_VIEW}>
{PATIENT_VIEW}
</MenuItem>
<MenuItem key={ENCOUNTER_START} value={ENCOUNTER_START}>
{ENCOUNTER_START}
</MenuItem>
</Select>
</FormControl>

</Grid>
<Grid key={key} item xs={6}>
<FormControl fullWidth>
<InputLabel id="dropdown-label">
Hook to send when selecting a patient
</InputLabel>
<Select
labelId="dropdown-label"
id="dropdown"
value={state[key]}
label="Hook to send when selecting a patient"
onChange={event => updateSetting(key, event.target.value)}
sx={{ width: '100%' }}
>
<MenuItem key={PATIENT_VIEW} value={PATIENT_VIEW}>
{PATIENT_VIEW}
</MenuItem>
<MenuItem key={ENCOUNTER_START} value={ENCOUNTER_START}>
{ENCOUNTER_START}
</MenuItem>
</Select>
</FormControl>
</Grid>
</React.Fragment>

)
);
default:
return (
<div key={key}>
Expand All @@ -300,115 +307,115 @@ const SettingsSection = props => {
}}
>
{!state['useIntermediary'] && (
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow sx={{ th: { fontWeight: 'bold' } }}>
<TableCell width={500}>Medication Display</TableCell>
<TableCell width={200}>Medication RxNorm Code</TableCell>
<TableCell width={200}>Hook / Endpoint</TableCell>
<TableCell width={500}>REMS Admin URL</TableCell>
{/* This empty TableCell corresponds to the add and delete
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow sx={{ th: { fontWeight: 'bold' } }}>
<TableCell width={500}>Medication Display</TableCell>
<TableCell width={200}>Medication RxNorm Code</TableCell>
<TableCell width={200}>Hook / Endpoint</TableCell>
<TableCell width={500}>REMS Admin URL</TableCell>
{/* This empty TableCell corresponds to the add and delete
buttons. It is used to fill up the sticky header which
will appear over the gray/white table rows. */}
<TableCell width={150} />
</TableRow>
</TableHead>
<TableBody>
{Object.entries(state.medicationRequestToRemsAdmins).map(([key, row]) => {
return (
<TableRow key={key}>
<TableCell>
<TextField
variant="outlined"
value={row.display}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { display: event.target.value }
})
}
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell>
<TextField
variant="outlined"
value={row.rxnorm}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { rxnorm: event.target.value }
})
}
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell>
<Select
labelId="dropdown-label"
id="dropdown"
value={row.endpointType}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { endpointType: event.target.value }
})
}
sx={{ width: '100%' }}
>
{ENDPOINT.map(endpointType => (
<MenuItem key={endpointType} value={endpointType}>
{endpointType}
</MenuItem>
))}
</Select>
</TableCell>
<TableCell>
<TextField
variant="outlined"
value={row.remsAdmin}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { remsAdmin: event.target.value }
})
}
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell align="right">
<Tooltip title="Add a new row below">
<IconButton
color="primary"
onClick={() =>
dispatch({ type: actionTypes.addCdsHookSetting, settingId: key })
<TableCell width={150} />
</TableRow>
</TableHead>
<TableBody>
{Object.entries(state.medicationRequestToRemsAdmins).map(([key, row]) => {
return (
<TableRow key={key}>
<TableCell>
<TextField
variant="outlined"
value={row.display}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { display: event.target.value }
})
}
size="large"
>
<AddIcon fontSize="large" />
</IconButton>
</Tooltip>
<Tooltip title="Delete this row">
<IconButton
color="primary"
onClick={() =>
dispatch({ type: actionTypes.deleteCdsHookSetting, settingId: key })
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell>
<TextField
variant="outlined"
value={row.rxnorm}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { rxnorm: event.target.value }
})
}
size="large"
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell>
<Select
labelId="dropdown-label"
id="dropdown"
value={row.endpointType}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { endpointType: event.target.value }
})
}
sx={{ width: '100%' }}
>
<DeleteIcon fontSize="large" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
{ENDPOINT.map(endpointType => (
<MenuItem key={endpointType} value={endpointType}>
{endpointType}
</MenuItem>
))}
</Select>
</TableCell>
<TableCell>
<TextField
variant="outlined"
value={row.remsAdmin}
onChange={event =>
dispatch({
type: actionTypes.updateCdsHookSetting,
settingId: key,
value: { remsAdmin: event.target.value }
})
}
sx={{ width: '100%' }}
/>
</TableCell>
<TableCell align="right">
<Tooltip title="Add a new row below">
<IconButton
color="primary"
onClick={() =>
dispatch({ type: actionTypes.addCdsHookSetting, settingId: key })
}
size="large"
>
<AddIcon fontSize="large" />
</IconButton>
</Tooltip>
<Tooltip title="Delete this row">
<IconButton
color="primary"
onClick={() =>
dispatch({ type: actionTypes.deleteCdsHookSetting, settingId: key })
}
size="large"
>
<DeleteIcon fontSize="large" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
)}
</TableContainer>
</Grid>
Expand Down
Loading