diff --git a/public/index.html b/public/index.html index f8c8213..1ef6739 100644 --- a/public/index.html +++ b/public/index.html @@ -49,7 +49,7 @@ This HTML file is a template. If you open it directly in the browser, you will see an empty page. - You can add webfonts, meta tags, or analytics to this file. + You can add web fonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the tag. To begin the development, run `npm start` or `yarn start`. diff --git a/src/cds-hooks b/src/cds-hooks index 9d175cc..94a78e8 160000 --- a/src/cds-hooks +++ b/src/cds-hooks @@ -1 +1 @@ -Subproject commit 9d175cc38fd2f484e65da8564f951a36e170558a +Subproject commit 94a78e8cd27734938ec41858f8d0ca4028da5f21 diff --git a/src/index.tsx b/src/index.tsx index 83547e3..c263ab8 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; diff --git a/src/views/Patient/MedReqDropDown/cdsHooksCards/cdsHooksCard.tsx b/src/views/Patient/MedReqDropDown/cdsHooksCards/cdsHooksCard.tsx index 1e41d3a..12afee1 100644 --- a/src/views/Patient/MedReqDropDown/cdsHooksCards/cdsHooksCard.tsx +++ b/src/views/Patient/MedReqDropDown/cdsHooksCards/cdsHooksCard.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, ReactElement } from 'react'; +import { useState, useEffect, ReactElement } from 'react'; import { Button, Card, CardActions, CardContent, Grid, Typography } from '@mui/material'; import axios from 'axios'; diff --git a/src/views/Patient/MedReqDropDown/etasuStatus/EtasuStatus.tsx b/src/views/Patient/MedReqDropDown/etasuStatus/EtasuStatus.tsx index 33d8f12..9350a3a 100644 --- a/src/views/Patient/MedReqDropDown/etasuStatus/EtasuStatus.tsx +++ b/src/views/Patient/MedReqDropDown/etasuStatus/EtasuStatus.tsx @@ -10,22 +10,11 @@ import AutorenewIcon from '@mui/icons-material/Autorenew'; import CheckCircle from '@mui/icons-material/CheckCircle'; import Close from '@mui/icons-material/Close'; -import { - GuidanceResponse, - MedicationRequest, - Parameters, - ParametersParameter, - Patient -} from 'fhir/r4'; +import { GuidanceResponse, Parameters, ParametersParameter } from 'fhir/r4'; -import axios from 'axios'; import { useState, useEffect } from 'react'; -import RemsMetEtasuResponse from './RemsMetEtasuResponse'; -import MetRequirements from './MetRequirements'; -import * as env from 'env-var'; import './EtasuStatus.css'; -import { getDrugCodeFromMedicationRequest } from '../../../Questionnaire/questionnaireUtil'; import { getStatus } from '../MedReqDropDown'; interface EtasuStatusProps { diff --git a/src/views/Patient/MedReqDropDown/etasuStatus/RemsMetEtasuResponse.ts b/src/views/Patient/MedReqDropDown/etasuStatus/RemsMetEtasuResponse.ts index 495f4ae..9a7a6ac 100644 --- a/src/views/Patient/MedReqDropDown/etasuStatus/RemsMetEtasuResponse.ts +++ b/src/views/Patient/MedReqDropDown/etasuStatus/RemsMetEtasuResponse.ts @@ -4,7 +4,7 @@ export interface RemsMetEtasuResponse { case_number: string; drugCode: string; drugName: string; - patientFirstname: string; + patientFirstName: string; patientLastName: string; patientDOB: string; status: string; diff --git a/src/views/Patient/MedReqDropDown/etasuStatus/__test__/EtasuStatus.test.tsx b/src/views/Patient/MedReqDropDown/etasuStatus/__test__/EtasuStatus.test.tsx index 0be0f87..de6ce6f 100644 --- a/src/views/Patient/MedReqDropDown/etasuStatus/__test__/EtasuStatus.test.tsx +++ b/src/views/Patient/MedReqDropDown/etasuStatus/__test__/EtasuStatus.test.tsx @@ -1,58 +1,9 @@ import { fireEvent, render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { - Patient, - MedicationRequest, - GuidanceResponse, - ParametersParameter, - Parameters -} from 'fhir/r4'; -import nock from 'nock'; +import { ParametersParameter, Parameters } from 'fhir/r4'; import EtasuStatus from '../EtasuStatus'; -import RemsMetEtasuResponse from '../RemsMetEtasuResponse'; -import MetRequirements from '../MetRequirements'; - -const rems_admin_server_base = 'http://localhost:8090'; - -const testPatient: Patient = { - resourceType: 'Patient', - id: 'pat017', - gender: 'male', - birthDate: '1996-06-01', - name: [ - { - use: 'official', - family: 'Snow', - given: ['Jon', 'Stark'] - } - ] -}; -const testMedicationRequest: MedicationRequest = { - resourceType: 'MedicationRequest', - id: 'pat017-mr-IPledge', - medicationCodeableConcept: { - coding: [ - { - system: 'http://www.nlm.nih.gov/research/umls/rxnorm', - code: '6064', - display: 'Isotretinoin 20 MG Oral Capsule' - }, - { - system: 'http://hl7.org/fhir/sid/ndc', - code: '0245-0571-01' - } - ] - }, - status: 'active', - intent: 'order', - subject: { - reference: 'Patient/pat017', - display: 'Jon Snow' - }, - authoredOn: '2020-07-11' -}; const generateEtasuStatus = () => { const patientEnrollmentForm: ParametersParameter = { name: 'Patient Enrollment', @@ -157,9 +108,8 @@ describe('Test the EtasuStatus Component', () => { test('Loads data on start', async () => { const update = true; - - const etasuStatus = generateEtasuStatus(); let called = false; + const callback = () => { called = true; }; @@ -169,6 +119,7 @@ describe('Test the EtasuStatus Component', () => { // just need to call callback expect(called).toBeTruthy(); }); + test('Renders passed data', async () => { // render the module const etasu = generateEtasuStatus(); @@ -188,6 +139,7 @@ describe('Test the EtasuStatus Component', () => { expect(await screen.findAllByTestId('etasu-item')).toHaveLength(3); } }); + test('Update retrieves data', async () => { const update = false; let called = false; diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/DoctorOrder.ts b/src/views/Patient/MedReqDropDown/pharmacyStatus/DoctorOrder.ts index 3c0f9d1..be41500 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/DoctorOrder.ts +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/DoctorOrder.ts @@ -1,6 +1,6 @@ import MetRequirements from '../etasuStatus/MetRequirements'; -export interface DoctorOrder { +export type DoctorOrder = { _id: string; caseNumber: string; patientName: string; @@ -20,11 +20,9 @@ export interface DoctorOrder { rxDate: string; drugPrice: number; drugNdcCode: string; - quanitities: string; + quantities: string; total: number; pickupDate: string; dispenseStatus: string; metRequirements: MetRequirements[]; -} - -export default DoctorOrder; +}; diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx index 8684e61..f182e9c 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx @@ -11,7 +11,7 @@ const testMedicationDispense: BundleEntry = { meta: { versionId: '4', lastUpdated: '2024-02-08T16:02:57.850+00:00', - source: '#pat017-mr-turali' + source: '#pat017-mr-turalio' }, status: 'completed', medicationCodeableConcept: { diff --git a/src/views/Patient/PatientView.tsx b/src/views/Patient/PatientView.tsx index c9d8d0a..6eccd48 100644 --- a/src/views/Patient/PatientView.tsx +++ b/src/views/Patient/PatientView.tsx @@ -16,7 +16,6 @@ import { MedicationRequest, Patient } from 'fhir/r4'; import Client from 'fhirclient/lib/Client'; import { ReactElement, useEffect, useState } from 'react'; import MedReqDropDown from './MedReqDropDown/MedReqDropDown'; -import './PatientView.css'; import { Hook, Card as HooksCard } from '../../cds-hooks/resources/HookTypes'; import axios from 'axios'; import * as env from 'env-var'; diff --git a/src/views/Questionnaire/QuestionnaireForm.tsx b/src/views/Questionnaire/QuestionnaireForm.tsx index 8ac815d..b479440 100644 --- a/src/views/Questionnaire/QuestionnaireForm.tsx +++ b/src/views/Questionnaire/QuestionnaireForm.tsx @@ -58,7 +58,7 @@ declare global { interface QuestionnaireProps { response: QuestionnaireResponse | null; - qform: Questionnaire; + questionnaireForm: Questionnaire; standalone: boolean; cqlPrepopulationResults: PrepopulationResults | null; smartClient: Client; @@ -118,13 +118,13 @@ export function QuestionnaireForm(props: QuestionnaireProps) { const [formValidationErrors, setFormValidationErrors] = useState([]); const partialForms: PartialForms = {}; const LForms = window.LForms; - const questionnaireFormId = `formContainer-${props.qform.id}-${props.tabIndex}`; + const questionnaireFormId = `formContainer-${props.questionnaireForm.id}-${props.tabIndex}`; useEffect(() => { // search for any partially completed QuestionnaireResponses if (props.response) { const response = props.response; - const items = props.qform.item; + const items = props.questionnaireForm.item; const parentItems: QuestionnaireResponseItem[] = []; if (items && response.item) { handleGtable(items, parentItems, response.item); @@ -142,7 +142,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { status: 'in-progress' }; newResponse.item = []; // defined here to avoid compiler thinking it's potentially undefined - const items = props.qform.item || []; + const items = props.questionnaireForm.item || []; const parentItems: QuestionnaireResponseItem[] = []; handleGtable(items, parentItems, newResponse.item); prepopulate(items, newResponse.item, false); @@ -161,7 +161,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { if ( props.filterChecked && event.target instanceof Element && - event.target?.id != `filterCheckbox-${props.qform.id}` && + event.target?.id != `filterCheckbox-${props.questionnaireForm.id}` && event.target.id != 'attestationCheckbox' ) { const checkIfFilter = ( @@ -202,7 +202,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { }); const loadAndMergeForms = (newResponse: QuestionnaireResponse | null) => { let lform = LForms.Util.convertFHIRQuestionnaireToLForms( - props.qform, + props.questionnaireForm, props.fhirVersion.toUpperCase() ); @@ -229,7 +229,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { if (specificForm) { const header = specificForm.getElementsByClassName('lf-form-title')[0]; const el = document.createElement('div'); - el.setAttribute('id', `button-container-${props.qform.id}`); + el.setAttribute('id', `button-container-${props.questionnaireForm.id}`); header.appendChild(el); props.renderButtons(el); @@ -267,7 +267,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { status: 'in-progress' }; newResponse.item = []; - const items = props.qform.item || []; + const items = props.questionnaireForm.item || []; const parentItems: QuestionnaireResponseItem[] = []; handleGtable(items, parentItems, newResponse.item); prepopulate(items, newResponse.item, false); @@ -303,7 +303,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { } return firstResponse; }; - // handlGtable expands the items with contains a table level expression + // handleGtable expands the items with contains a table level expression // the expression should be a list of objects // this function creates the controls based on the size of the expression // then set the value of for each item @@ -602,9 +602,9 @@ export function QuestionnaireForm(props: QuestionnaireProps) { const answerOption = item.answerOption; let selectedCode; - if (answerValueSetReference && props.qform.contained) { + if (answerValueSetReference && props.questionnaireForm.contained) { const vs_id = answerValueSetReference.substr(1); - const fhirResource = props.qform.contained.find(r => r.id == vs_id); + const fhirResource = props.questionnaireForm.contained.find(r => r.id == vs_id); if (fhirResource && fhirResource.resourceType == 'ValueSet') { const vs: ValueSet = fhirResource; if (vs && vs.expansion && vs.expansion.contains) { @@ -765,7 +765,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { }; newResponse.item = []; - const items = props.qform.item; + const items = props.questionnaireForm.item; if (items) { prepopulate(items, newResponse.item, saved_response); @@ -920,7 +920,10 @@ export function QuestionnaireForm(props: QuestionnaireProps) { `#${questionnaireFormId}` ); //const mergedResponse = this.mergeResponseForSameLinkId(currentQuestionnaireResponse); - retrieveQuestions(url, buildNextQuestionRequest(props.qform, currentQuestionnaireResponse)) + retrieveQuestions( + url, + buildNextQuestionRequest(props.questionnaireForm, currentQuestionnaireResponse) + ) .then(result => result.json()) .then(result => { console.log( @@ -965,13 +968,15 @@ export function QuestionnaireForm(props: QuestionnaireProps) { let idMatch = false; if (bundleEntry.resource?.contained) { const questionnaireId = bundleEntry.resource?.contained[0].id; - idMatch = props.qform.id === questionnaireId; + idMatch = props.questionnaireForm.id === questionnaireId; } const questionnaireIdUrl = bundleEntry.resource?.questionnaire; if ( idMatch || - (questionnaireIdUrl && props.qform.id && questionnaireIdUrl.includes(props.qform.id)) + (questionnaireIdUrl && + props.questionnaireForm.id && + questionnaireIdUrl.includes(props.questionnaireForm.id)) ) { count = count + 1; // add the option to the popupOptions @@ -1007,9 +1012,9 @@ export function QuestionnaireForm(props: QuestionnaireProps) { }; const isAdaptiveForm = () => { return ( - props.qform.meta && - props.qform.meta.profile && - props.qform.meta.profile.includes( + props.questionnaireForm.meta && + props.questionnaireForm.meta.profile && + props.questionnaireForm.meta.profile.includes( 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-adapt' ) ); @@ -1018,13 +1023,18 @@ export function QuestionnaireForm(props: QuestionnaireProps) { const isAdaptiveFormWithoutItem = () => { return ( isAdaptiveForm() && - props.qform && - (props.qform.item === undefined || props.qform.item.length <= 0) + props.questionnaireForm && + (props.questionnaireForm.item === undefined || props.questionnaireForm.item.length <= 0) ); }; const isAdaptiveFormWithItem = () => { - return isAdaptiveForm() && props.qform && props.qform.item && props.qform.item.length > 0; + return ( + isAdaptiveForm() && + props.questionnaireForm && + props.questionnaireForm.item && + props.questionnaireForm.item.length > 0 + ); }; const isFilledOut = () => { @@ -1291,14 +1301,14 @@ export function QuestionnaireForm(props: QuestionnaireProps) { }; const storeQuestionnaireResponseToEhr = ( - questionnaireReponse: QuestionnaireResponseSmart, + questionnaireResponse: QuestionnaireResponseSmart, showPopup: boolean | undefined ) => { // send the QuestionnaireResponse to the EHR FHIR server const questionnaireUrl = sessionStorage['serviceUri'] + '/QuestionnaireResponse'; console.log('Storing QuestionnaireResponse to: ' + questionnaireUrl); props.smartClient - .create(questionnaireReponse) + .create(questionnaireResponse) .then( result => { if (showPopup) { @@ -1326,7 +1336,7 @@ export function QuestionnaireForm(props: QuestionnaireProps) { // add the contained questionnaire for adaptive form if (isAdaptiveForm()) { qr.contained = []; - qr.contained.push(props.qform); + qr.contained.push(props.questionnaireForm); } if (status == 'in-progress') { @@ -1614,8 +1624,8 @@ export function QuestionnaireForm(props: QuestionnaireProps) { focus: [{ reference: 'Parameters/param0111' }], source: { // TODO: url should be dynamically created - // also if DTR expects to recieve a response it - // will need an endpoint to recieve it at + // also if DTR expects to receive a response it + // will need an endpoint to receive it at endpoint: 'http://localhost:3005' } }; diff --git a/src/views/Questionnaire/SmartApp.tsx b/src/views/Questionnaire/SmartApp.tsx index 8e781c4..fe89c1d 100644 --- a/src/views/Questionnaire/SmartApp.tsx +++ b/src/views/Questionnaire/SmartApp.tsx @@ -301,9 +301,9 @@ export function SmartApp(props: SmartAppProps) { } else { // check for multi-choice questions // get all empty questions - const emptyq = element.querySelectorAll('.ng-empty'); + const emptyQuestions = element.querySelectorAll('.ng-empty'); let doFilter = true; - emptyq.forEach(e => { + emptyQuestions.forEach(e => { const ul = e.parentElement?.querySelector('ul'); if (ul && !ul.querySelector('li')) { // the multi-choice question doesn't have an answer @@ -346,7 +346,7 @@ export function SmartApp(props: SmartAppProps) { // update the ignore required checkbox const updateRequired = (defaultFilter: boolean) => { - let checked: boolean, requiredCheckbox: HTMLInputElement; + let checked: boolean; if (!defaultFilter) { const requiredCheckbox = document.getElementById( questionnaire ? `required-fields-checkbox-${questionnaire.id}` : 'required-fields-checkbox' @@ -508,7 +508,7 @@ export function SmartApp(props: SmartAppProps) { }); }); }; - // fill the valueSetDB in executionInputs with the required valuesets from their artifact source + // fill the valueSetDB in executionInputs with the required ValueSets from their artifact source const fillValueSetDB = (executionInputs: ExecutionInputs, artifacts: ReturnValue) => { if (!executionInputs.elmDependencies) { return; @@ -540,7 +540,7 @@ export function SmartApp(props: SmartAppProps) { // make sure it has an expansion if (valueSet.expansion != null) { // add all codes to the the value set db. it is a map in a map, where the first layer key - // is the value set id and second layer key is the value set version. for this purpose we are using un-versioned valuesets + // is the value set id and second layer key is the value set version. for this purpose we are using un-versioned ValueSets executionInputs.valueSetDB[valueSetDef.id] = {}; executionInputs.valueSetDB[valueSetDef.id][''] = valueSet.expansion.contains?.map( code => { @@ -701,7 +701,7 @@ export function SmartApp(props: SmartAppProps) { /> ) : ( (''); - // const 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 updateValues = (patient: string, responseId: string) => { const response = props.responses.find(response => { return response.id === responseId; diff --git a/src/views/Questionnaire/components/RemsInterface/RemsInterface.css b/src/views/Questionnaire/components/RemsInterface/RemsInterface.css index 0c81535..ec28ebc 100644 --- a/src/views/Questionnaire/components/RemsInterface/RemsInterface.css +++ b/src/views/Questionnaire/components/RemsInterface/RemsInterface.css @@ -21,7 +21,6 @@ body { } .resource-entry{ - /* clear: both; */ border-left: 4px solid #ffcccb; padding: 5px; border-bottom: 1px solid grey; diff --git a/src/views/Questionnaire/components/RemsInterface/ResourceEntry.tsx b/src/views/Questionnaire/components/RemsInterface/ResourceEntry.tsx index 7338420..714eb99 100644 --- a/src/views/Questionnaire/components/RemsInterface/ResourceEntry.tsx +++ b/src/views/Questionnaire/components/RemsInterface/ResourceEntry.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import './RemsInterface.css'; import { FhirResource } from 'fhir/r4'; diff --git a/src/views/Questionnaire/components/SelectPopup.tsx b/src/views/Questionnaire/components/SelectPopup.tsx index d54dc48..8879007 100644 --- a/src/views/Questionnaire/components/SelectPopup.tsx +++ b/src/views/Questionnaire/components/SelectPopup.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { List, ListItemButton, ListItemText, DialogTitle, Dialog } from '@mui/material'; interface SimpleDialogProps { diff --git a/src/views/Questionnaire/elm/executeElm.ts b/src/views/Questionnaire/elm/executeElm.ts index 4f780d7..ebe4c5b 100644 --- a/src/views/Questionnaire/elm/executeElm.ts +++ b/src/views/Questionnaire/elm/executeElm.ts @@ -83,7 +83,6 @@ function executeElmAgainstPatientSource( executionInputs: ExecutionInputs, patientSource: PatientSource ): Promise { - // executionInputs.elmDependencies = [ fhirhelpersElm ] let repository = undefined; if (executionInputs.elmDependencies) { repository = new cql.Repository(executionInputs.elmDependencies); diff --git a/src/views/Questionnaire/questionnaireUtil.ts b/src/views/Questionnaire/questionnaireUtil.ts index b953083..ae1d870 100644 --- a/src/views/Questionnaire/questionnaireUtil.ts +++ b/src/views/Questionnaire/questionnaireUtil.ts @@ -20,7 +20,7 @@ export interface AppContext { // to get FHIR properties of the form answer{whatever} export function getAppContext(appContextString: string) { const appContext: AppContext = {}; - // Fix + encoded spaces back to precent encoded spaces + // Fix + encoded spaces back to percent encoded spaces const encodedAppString = appContextString.replace(/\+/g, '%20'); const appString = decodeURIComponent(encodedAppString); // Could switch to this later @@ -147,8 +147,8 @@ export function buildFhirUrl(reference: string, fhirPrefix: string, fhirVersion: if (reference.startsWith('http')) { const endIndex = reference.lastIndexOf('/'); const startIndex = reference.lastIndexOf('/', endIndex - 1) + 1; - const resoruce = reference.substr(startIndex, endIndex - startIndex); - return fhirPrefix + fhirVersion + '/' + resoruce + '?url=' + reference; + const resource = reference.substr(startIndex, endIndex - startIndex); + return fhirPrefix + fhirVersion + '/' + resource + '?url=' + reference; } else { return fhirPrefix + fhirVersion + '/' + reference; } diff --git a/src/views/Smart/Launch.tsx b/src/views/Smart/Launch.tsx index 2e357af..9c9738e 100644 --- a/src/views/Smart/Launch.tsx +++ b/src/views/Smart/Launch.tsx @@ -1,4 +1,4 @@ -import React, { memo, useState, useEffect } from 'react'; +import { memo, useState, useEffect } from 'react'; import FHIR from 'fhirclient'; import env from 'env-var'; import Register from './Register';