Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #68

Merged
merged 19 commits into from
Jan 12, 2024
Merged

Dev #68

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
26 changes: 10 additions & 16 deletions .env
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
# Development URLS

REACT_APP_REMS_ADMIN_SERVER_BASE = http://localhost:8090
REACT_APP_REMS_HOOKS_PATH = /cds-services/rems-
REACT_APP_PHARMACY_SERVER_BASE = http://localhost:5051
REACT_APP_ETASU_STATUS_ENABLED = true
REACT_APP_PHARMACY_STATUS_ENABLED = true
REACT_APP_SEND_RX_ENABLED = true
REACT_APP_SEND_FHIR_AUTH_ENABLED = false
BROWSER=none
GENERATE_SOURCEMAP=false
PORT=4040
REACT_APP_CLIENT_SCOPES = launch openid profile user/Patient.read patient/Patient.read user/Practitioner.read
REACT_APP_DEFAULT_CLIENT_ID = app-login
REACT_APP_DEFAULT_ISS = http://localhost:8080/test-ehr/r4
REACT_APP_CLIENT_SCOPES = launch openid profile user/Patient.read patient/Patient.read user/Practitioner.read
REACT_APP_DEVELOPER_MODE = true
GENERATE_SOURCEMAP=false
BROWSER=none

# To Override start command:
# REACT_APP_REMS_HOOKS_PATH=http://example.com PORT=6000 npm start
# Note that .env values can only be accessed by react app starting with 'REACT_APP_'
REACT_APP_ETASU_STATUS_ENABLED = true
REACT_APP_PHARMACY_SERVER_BASE = http://localhost:5051
REACT_APP_PHARMACY_STATUS_ENABLED = true
REACT_APP_REMS_ADMIN_SERVER_BASE = http://localhost:8090
REACT_APP_REMS_HOOKS_PATH = /cds-services/rems-
REACT_APP_SEND_FHIR_AUTH_ENABLED = false
REACT_APP_SEND_RX_ENABLED = true
16 changes: 0 additions & 16 deletions .github/auto_assign.yml

This file was deleted.

49 changes: 27 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Getting Started with REMS SMART on FHIR

The REMS SMART on FHIR application can be launched from an EHR that does not support CDS Hooks. The application will interact with the REMS Administrator using CDS Hooks on behalf of the EHR, allowing the provider to complete the normal REMS workflow.
The REMS SMART on FHIR application can be launched from an EHR that does not support CDS Hooks. The application will interact with the REMS Administrator using CDS Hooks on behalf of the EHR, allowing the provider to complete the normal REMS workflow.

This application must be launched by an EHR or SMART sandbox imitating an EHR.

## Initialization

After cloning the repository, the submodules must be initialized. To do this you can run:

### `git submodule update --init`
Expand All @@ -22,30 +23,35 @@ The page will reload if you make edits.\
You will also see any lint errors in the console.

### How To Override Defaults
The .env file contains the default URI paths, these can be overwritten from the start command as follows:
`REACT_APP_REMS_HOOKS_PATH=http://example.com PORT=6000 npm start`

Following are a list of modifiable paths:

| URI Name | Default |
| ----------- | ----------- |
| REACT_APP_REMS_ADMIN_SERVER_BASE | `http://localhost:8090` |
| REACT_APP_REMS_HOOKS_PATH | `/cds-services/rems-order-sign` |
| REACT_APP_PHARMACY_SERVER_BASE | `http://localhost:5051` |
| REACT_APP_ETASU_STATUS_ENABLED | `true` |
| REACT_APP_PHARMACY_STATUS_ENABLED | `true` |
| REACT_APP_DEVELOPER_MODE | `true` |
| REACT_APP_SEND_RX_ENABLED | `true` |
| REACT_APP_SEND_FHIR_AUTH_ENABLED | `false` |
| PORT | `4040`|

*Note that .env values can only be accessed by react app starting with `REACT_APP_`*

The .env file contains the default URI paths, which can be overwritten from the start command as follows:
a) `REACT_APP_LAUNCH_URL=http://example.com PORT=6000 npm start` or b) by specifying the environment variables and desired values in a `.env.local`.

Following are a list of modifiable paths:

| URI Name | Default |
| --------------------------------- | ------------------------------------------------------------------------------------- |
| BROWSER | `none` |
| GENERATE_SOURCEMAP | `false` |
| PORT | `4040` |
| REACT_APP_CLIENT_SCOPES | `launch openid profile user/Patient.read patient/Patient.read user/Practitioner.read` |
| REACT_APP_DEFAULT_CLIENT_ID | `app-login` |
| REACT_APP_DEFAULT_ISS | `http://localhost:8080/test-ehr/r4` |
| REACT_APP_DEVELOPER_MODE | `true` |
| REACT_APP_ETASU_STATUS_ENABLED | `true` |
| REACT_APP_PHARMACY_SERVER_BASE | `http://localhost:5051` |
| REACT_APP_PHARMACY_STATUS_ENABLED | `true` |
| REACT_APP_REMS_ADMIN_SERVER_BASE | `http://localhost:8090` |
| REACT_APP_REMS_HOOKS_PATH | `/cds-services/rems-` |
| REACT_APP_SEND_FHIR_AUTH_ENABLED | `false` |
| REACT_APP_SEND_RX_ENABLED | `true` |

_Note that .env values can only be accessed by the React app starting with `REACT_APP_`\_

### `npm test`

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
See the section about [running tests](https://create-react-app.dev/docs/running-tests/) for more information.

### `npm run build`

Expand All @@ -55,5 +61,4 @@ It correctly bundles React in production mode and optimizes the build for the be
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

See the section about [deployment](https://create-react-app.dev/docs/deployment/) for more information.
2 changes: 0 additions & 2 deletions README.old.md

This file was deleted.

6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

79 changes: 58 additions & 21 deletions src/views/Patient/PatientView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface PatientViewProps {
client: Client;
tabCallback: (n: ReactElement, m: string, o: string) => void;
}
type InfoRow = { header: string; data: string }[];

export interface MedicationBundle {
data: MedicationRequest[];
Expand Down Expand Up @@ -182,19 +183,58 @@ function PatientView(props: PatientViewProps) {
client.patient.read().then((patient: any) => setPatient(patient));
}, [client.patient, client]);

const rows: { header: string; data: string }[] = [
{ header: 'ID', data: patient?.['id'] || '' },
function getAge(dateString: string) {
const today = new Date();
const birthDate = new Date(dateString);
let age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
}
const renderRows = (rows: InfoRow) => {
return rows.map(({ header, data }, i) => {
let backgroundColor = '#fdfdfd';
if (i % 2 === 0) {
// is even
backgroundColor = '#dcdcdc';
}
return (
<TableRow key={header} sx={{ backgroundColor: backgroundColor }}>
<TableCell component="th" scope="row" variant="head">
<span style={{ fontWeight: 'bold' }}>{header}</span>
</TableCell>
<TableCell sx={{ whiteSpace: 'pre' }} variant="body">
{data}
</TableCell>
</TableRow>
);
});
};
let birthday = patient?.birthDate;
let age;
if (birthday) {
age = getAge(birthday);
birthday = `${birthday} (${age} years old)`;
}
const patientName = `${patient?.name?.[0]?.given?.[0]} ${patient?.name?.[0]?.family}`;
const patientFullName = `${patient?.name?.[0]?.given?.join(' ')} ${patient?.name?.[0]?.family}`;
const rows: InfoRow = [
{
header: 'Full Name',
data: `${patient?.name?.[0]?.given?.[0]} ${patient?.name?.[0]?.family}`
data: patientFullName
},
{
header: 'Gender',
data: patient?.['gender']
? patient.gender.charAt(0).toUpperCase() + patient.gender.slice(1)
: ''
},
{ header: 'Gender', data: patient?.['gender'] || '' },
{ header: 'Date of Birth', data: patient?.['birthDate'] || '' },
{ header: 'Date of Birth', data: birthday || '' },
{
header: 'Address',
data: `${(patient?.address?.[0].line, patient?.address?.[0]['city'])}\n${
patient?.address?.[0]?.state
}, ${patient?.address?.[0]?.postalCode}`
data: `${patient?.address?.[0].line?.[0]}\n${patient?.address?.[0].city}\n${patient?.address?.[0]?.state}, ${patient?.address?.[0]?.postalCode}`
}
];

Expand All @@ -206,12 +246,12 @@ function PatientView(props: PatientViewProps) {
<Card sx={{ bgcolor: 'white' }}>
<CardContent>
<Grid container>
<Grid item xs={10} sm={11} md={12} lg={10} alignSelf="center">
<Grid item xs={10} sm={11} md={10} lg={10} alignSelf="center">
<Typography component="h1" variant="h5">
Patient information loaded from patient context
Patient:
</Typography>
</Grid>
<Grid item xs={2} sm={1} md={12} lg={2}>
<Grid item xs={2} sm={1} md={2} lg={2}>
<IconButton
color="primary"
onClick={() => submitToREMS(cdsHook, setHooksCards)}
Expand All @@ -220,19 +260,16 @@ function PatientView(props: PatientViewProps) {
<RefreshIcon fontSize="large" />
</IconButton>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={12}>
<h5 style={{ paddingLeft: '16px', paddingBottom: '16px' }}>
<span style={{ fontWeight: 'bold' }}>{patientName}</span>{' '}
{`(ID: ${patient.id})`}
</h5>
</Grid>
</Grid>
<TableContainer>
<Table>
<TableBody>
{rows.map(({ header, data }) => (
<TableRow key={header}>
<TableCell component="th" scope="row" variant="head">
{header}
</TableCell>
<TableCell variant="body">{data}</TableCell>
</TableRow>
))}
</TableBody>
<TableBody>{renderRows(rows)}</TableBody>
</Table>
</TableContainer>
</CardContent>
Expand Down
3 changes: 2 additions & 1 deletion src/views/Questionnaire/QuestionnaireForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ export function QuestionnaireForm(props: QuestionnaireProps) {
loadAndMergeForms(savedResponse);
const formErrors = LForms.Util.checkValidity();
setFormValidationErrors(formErrors == null ? [] : formErrors);
document.addEventListener('change', event => {

document.addEventListener('click', event => {
if (
props.filterChecked &&
event.target instanceof Element &&
Expand Down
19 changes: 14 additions & 5 deletions src/views/Questionnaire/SmartApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,11 @@

// update the ignore required checkbox
const updateRequired = (defaultFilter: boolean) => {
let checked: boolean, requiredCheckbox: HTMLInputElement;

Check warning on line 349 in src/views/Questionnaire/SmartApp.tsx

View workflow job for this annotation

GitHub Actions / Check tsc, lint, and prettier

'requiredCheckbox' is defined but never used

Check warning on line 349 in src/views/Questionnaire/SmartApp.tsx

View workflow job for this annotation

GitHub Actions / Check tsc, lint, and prettier

'requiredCheckbox' is defined but never used
if (!defaultFilter) {
requiredCheckbox = document.getElementById('required-fields-checkbox') as HTMLInputElement;
const requiredCheckbox = document.getElementById(
questionnaire ? `required-fields-checkbox-${questionnaire.id}` : 'required-fields-checkbox'
) as HTMLInputElement;
checked = requiredCheckbox ? requiredCheckbox.checked : false;
} else {
checked = true;
Expand Down Expand Up @@ -523,10 +525,17 @@
// iterate over valueSet definitions
elm.library.valueSets.def.forEach(valueSetDef => {
// find FHIR value set artifact
const valueSetDefId = valueSetDef.id.replace(/https:\/\//, 'http://'); // vsac only returns urls with http in the resource
const valueSet = artifacts.valueSets.find(
valueSet => valueSet.id == valueSetDefId || valueSet.url == valueSetDefId
);
const valueSetDefId = valueSetDef.id;
const valueSet = artifacts.valueSets.find(valueSet => {
if (valueSet.id && valueSetDefId.includes(valueSet.id)) {
return true;
} else {
if (valueSet.url && valueSetDefId.includes(valueSet.url)) {
return true;
}
}
return false;
});
if (valueSet != null) {
// make sure it has an expansion
if (valueSet.expansion != null) {
Expand Down
Loading