diff --git a/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx b/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx index 32270b5..1746429 100644 --- a/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx +++ b/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx @@ -16,17 +16,20 @@ import RefreshIcon from '@mui/icons-material/Refresh'; import Box from '@mui/material/Box'; import ListIcon from '@mui/icons-material/List'; import LocalPharmacyIcon from '@mui/icons-material/LocalPharmacy'; -import { BundleEntry, Patient, MedicationRequest, Resource } from 'fhir/r4'; +import { + BundleEntry, + Patient, + MedicationRequest, + Resource, + MedicationDispense +} from 'fhir/r4'; import Client from 'fhirclient/lib/Client'; import { ReactElement, useEffect, useState } from 'react'; import example from '../../../cds-hooks/prefetch/exampleHookService.json'; // TODO: Replace with request to CDS service import { hydrate } from '../../../cds-hooks/prefetch/PrefetchHydrator'; import { Hook, Card as HooksCard, OrderSelectHook } from '../../../cds-hooks/resources/HookTypes'; import OrderSelect from '../../../cds-hooks/resources/OrderSelect'; -import { - getDrugCodeFromMedicationRequest, - getDrugCodeableConceptFromMedicationRequest -} from '../../Questionnaire/questionnaireUtil'; +import { getDrugCodeFromMedicationRequest } from '../../Questionnaire/questionnaireUtil'; import './MedReqDropDown.css'; import * as env from 'env-var'; import { MedicationBundle, submitToREMS } from '../PatientView'; @@ -42,7 +45,6 @@ import PharmacyStatus from './pharmacyStatus/PharmacyStatus'; import axios from 'axios'; import MetRequirements from './etasuStatus/MetRequirements'; import RemsMetEtasuResponse from './etasuStatus/RemsMetEtasuResponse'; -import DoctorOrder from './pharmacyStatus/DoctorOrder'; interface MedReqDropDownProps { client: Client; @@ -81,7 +83,9 @@ function MedReqDropDown({ const [checkedEtasuTime, setCheckedEtasuTime] = useState(0); // Pharmacy const [showPharmacy, setShowPharmacy] = useState(false); - const [pimsResponse, setPimsResponse] = useState(null); + const [testEhrResponse, setTestEhrResponse] = useState | null>( + null + ); const [checkedPharmacyTime, setCheckedPharmacyTime] = useState(0); useEffect(() => { @@ -185,47 +189,18 @@ function MedReqDropDown({ return `Last checked ${prefix} ago`; }; const refreshPharmacyBundle = () => { - // setSpin(true); - const patientFirstName = patient?.name?.at(0)?.given?.at(0); - const patientLastName = patient?.name?.at(0)?.family; - const patientDOB = patient?.birthDate; - const rxDate = selectedMedicationCard?.authoredOn; setCheckedPharmacyTime(Date.now()); - let drugCodeableConcept = undefined; - if (selectedMedicationCard) { - drugCodeableConcept = getDrugCodeableConceptFromMedicationRequest(selectedMedicationCard); - } - const drugNames = drugCodeableConcept?.coding?.at(0)?.display; - console.log( - 'refreshPharmacyBundle: ' + - patientFirstName + - ' ' + - patientLastName + - ' - ' + - patientDOB + - ' - ' + - rxDate + - ' - ' + - drugNames - ); - const ndcDrugCoding = drugCodeableConcept?.coding?.find( - ({ system }) => system === 'http://hl7.org/fhir/sid/ndc' - ); - let queryString: string = - 'rxDate=' + rxDate + '&drugNames=' + encodeURIComponent(drugNames || ''); - if (ndcDrugCoding != undefined) { - queryString = queryString + '&drugNdcCode=' + ndcDrugCoding?.code; - } - const pharmacyUrl = `${env - .get('REACT_APP_PHARMACY_SERVER_BASE') - .asString()}/doctorOrders/api/getRx/${patientFirstName}/${patientLastName}/${patientDOB}?${queryString}`; - console.log(pharmacyUrl); + const rxId = selectedMedicationCard?.id; + + const url = `${env + .get('REACT_APP_DEFAULT_ISS') + .asString()}/MedicationDispense?prescription=${rxId}`; axios({ method: 'get', - url: pharmacyUrl + url: url }).then( response => { - setPimsResponse(response.data); + setTestEhrResponse(response?.data?.entry ? response?.data?.entry[0] : null); }, error => { console.log(error); @@ -320,14 +295,20 @@ function MedReqDropDown({ } else if (remsAdminResponse?.status === 'Pending') { color = '#f0ad4e'; // orange } - const pStatus = pimsResponse?.dispenseStatus; - let pColor = '#0c0c0c'; // white - if (pStatus === 'Approved') { + + const pStatus = testEhrResponse?.resource?.status; + const getMedicationStatus = (status: string | undefined) => { + if (status === 'completed') { + return 'Picked Up'; + } else if (status === 'unknown') { + return 'Not Started'; + } else { + return 'N/A'; + } + }; + let pColor = '#0c0c0c'; // black + if (pStatus === 'completed') { pColor = '#5cb85c'; // green - } else if (pStatus === 'Pending') { - pColor = '#f0ad4e'; // orange - } else if (pStatus === 'Picked Up') { - pColor = '#0275d8'; // blue } const etasuSx = { @@ -438,8 +419,8 @@ function MedReqDropDown({ >
-

Pharmacy:

-

{pimsResponse?.dispenseStatus || 'Not Started'}

+

Medication:

+

{getMedicationStatus(pStatus)}

{renderTimestamp(checkedPharmacyTime)} @@ -474,7 +455,7 @@ function MedReqDropDown({ diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx b/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx index f015b8f..b79a8c4 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx @@ -1,19 +1,14 @@ import { Tooltip, IconButton, Grid } from '@mui/material'; import AutorenewIcon from '@mui/icons-material/Autorenew'; -import { MedicationRequest, Patient } from 'fhir/r4'; - -import axios from 'axios'; +import { BundleEntry, MedicationDispense } from 'fhir/r4'; import { useState, useEffect } from 'react'; import './PharmacyStatus.css'; -import DoctorOrder from './DoctorOrder'; -import { getDrugCodeableConceptFromMedicationRequest } from '../../../Questionnaire/questionnaireUtil'; -import * as env from 'env-var'; interface PharmacyStatusProps { callback: () => void; - pimsResponse: DoctorOrder | null; + testEhrResponse: BundleEntry | null; update: boolean; } @@ -26,24 +21,30 @@ const PharmacyStatus = (props: PharmacyStatusProps) => { } }, [props.update]); - const status = props.pimsResponse?.dispenseStatus; - let color = '#f7f7f7'; // white - if (status === 'Approved') { + const getMedicationStatus = (status: string | undefined) => { + if (status === 'completed') { + return 'Picked Up'; + } else if (status === 'unknown') { + return 'Not Started'; + } else { + return 'N/A'; + } + }; + + const status = props.testEhrResponse?.resource?.status; + let color = '#0c0c0c'; // black + if (status === 'completed') { color = '#5cb85c'; // green - } else if (status === 'Pending') { - color = '#f0ad4e'; // orange - } else if (status === 'Picked Up') { - color = '#0275d8'; // blue } return (
-

Pharmacy Status

+

Medication Status

-
ID: {props.pimsResponse?._id || 'N/A'}
-
Status: {props.pimsResponse?.dispenseStatus || 'N/A'}
+
ID: {props.testEhrResponse?.resource?.id || 'N/A'}
+
Status: {getMedicationStatus(status)}
diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx index ec9159f..8684e61 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx @@ -1,103 +1,44 @@ import { fireEvent, render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { Patient, MedicationRequest } from 'fhir/r4'; -import nock from 'nock'; +import { MedicationDispense, BundleEntry } from 'fhir/r4'; import PharmacyStatus from '../PharmacyStatus'; -import DoctorOrder from '../DoctorOrder'; -import MetRequirements from '../../etasuStatus/MetRequirements'; -const pharmacy_server_base = 'http://localhost:5051'; - -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' - }, +const testMedicationDispense: BundleEntry = { + resource: { + resourceType: 'MedicationDispense', + id: 'pat017-mr-turalio-dispense', + meta: { + versionId: '4', + lastUpdated: '2024-02-08T16:02:57.850+00:00', + source: '#pat017-mr-turali' + }, + status: 'completed', + medicationCodeableConcept: { + coding: [ + { + system: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '2183126', + display: 'Turalio 200 MG Oral Capsule' + }, + { + system: 'http://hl7.org/fhir/sid/ndc', + code: '65597-402-20' + } + ] + }, + subject: { + reference: 'Patient/pat017', + display: 'Jon Snow' + }, + authorizingPrescription: [ { - system: 'http://hl7.org/fhir/sid/ndc', - code: '0245-0571-01' + reference: 'MedicationRequest/pat017-mr-turalio' } ] - }, - status: 'active', - intent: 'order', - subject: { - reference: 'Patient/pat017', - display: 'Jon Snow' - }, - authoredOn: '2020-07-11' + } }; -const generateDoctorOrder = () => { - const patientEnrollmentForm: MetRequirements = { - completed: true, - metRequirementId: 'asldkf23a', - requirementDescription: 'Submit Patient Enrollment form to the REMS Administrator', - requirementName: 'Patient Enrollment Form', - stakeholderId: 'dlksk2222' - }; - const prescriberEnrollmentForm: MetRequirements = { - completed: false, - metRequirementId: 'asldkf23b', - requirementDescription: 'Submit Prescriber Enrollment form to the REMS Administrator', - requirementName: 'Prescriber Enrollment Form', - stakeholderId: 'dlksk2222' - }; - const pharmacistEnrollmentForm: MetRequirements = { - completed: true, - metRequirementId: 'asldkf23c', - requirementDescription: 'Submit Pharmacist Enrollment form to the REMS Administrator', - requirementName: 'Pharmacist Enrollment Form', - stakeholderId: 'dlksk2222' - }; - const doctorOrder: DoctorOrder = { - _id: '1234', - caseNumber: '2k3js', - patientName: 'Jon Snow', - patientFirstName: 'Jon', - patientLastName: 'Snow', - patientDOB: '1996-06-01', - patientCity: 'Winterfell', - patientStateProvince: 'Westeros', - patientPostalCode: '00008', - patientCountry: 'USA', - doctorName: 'Dr. Jane Doe', - doctorContact: '555-123-4567', - doctorID: 'sdk2kd991', - doctorEmail: 'jane.doe@doctor.com', - drugNames: 'Medication', - simpleDrugName: 'Medication', - rxDate: '2023-03-04', - drugPrice: 35, - drugNdcCode: '0245-0571-01', - quanitities: '20', - total: 1, - pickupDate: '2023-04-04', - dispenseStatus: 'Pending', - metRequirements: [patientEnrollmentForm, prescriberEnrollmentForm, pharmacistEnrollmentForm] - }; - return doctorOrder; -}; describe('Test the PharmacyStatus Component', () => { function expectContains(value: string) { const element = screen.getByText(value); @@ -108,10 +49,10 @@ describe('Test the PharmacyStatus Component', () => { const update = false; // render the module - render( {}} pimsResponse={null} />); + render( {}} testEhrResponse={null} />); // test the status fields and headings are present - expectContains('Pharmacy Status'); + expectContains('Medication Status'); expectContains('ID: N/A'); expectContains('Status: N/A'); @@ -120,11 +61,13 @@ describe('Test the PharmacyStatus Component', () => { expect(refreshButton).toBeInTheDocument(); }); test('Renders order', async () => { - const doctorOrder = generateDoctorOrder(); - render( {}} pimsResponse={doctorOrder} />); - - expect(await screen.findByText(`ID: ${doctorOrder._id}`)).toBeInTheDocument(); - expect(await screen.findByText(`Status: ${doctorOrder.dispenseStatus}`)).toBeInTheDocument(); + render( + {}} testEhrResponse={testMedicationDispense} /> + ); + expect( + await screen.findByText(`ID: ${testMedicationDispense.resource?.id}`) + ).toBeInTheDocument(); + expect(await screen.findByText('Status: Picked Up')).toBeInTheDocument(); }); test('Loads data on start', () => { @@ -134,8 +77,8 @@ describe('Test the PharmacyStatus Component', () => { pimsResponse = true; }; // render the module - render(); - // verify that the values are updated from the call to get the Pharmacy Status + render(); + // verify that the values are updated from the call to get the Medication Status expect(pimsResponse).toBeTruthy(); }); @@ -146,26 +89,26 @@ describe('Test the PharmacyStatus Component', () => { called = true; }; // render the module - render(); + render(); // click the refresh button const refreshButton = screen.getByTestId('refresh'); fireEvent.click(refreshButton); - // verify that the values are updated from the call to get the Pharmacy Status + // verify that the values are updated from the call to get the Medication Status expect(called).toBe(true); }); test('Failed to load status', async () => { const update = true; // render the module - render( {}} pimsResponse={null} />); + render( {}} testEhrResponse={null} />); // click the refresh button const refreshButton = screen.getByTestId('refresh'); fireEvent.click(refreshButton); - // verify that the values are updated from the call to get the Pharmacy Status + // verify that the values are updated from the call to get the Medication Status expect(await screen.findByText('ID: N/A')).toBeInTheDocument(); expect(await screen.findByText('Status: N/A')).toBeInTheDocument(); }); diff --git a/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx b/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx index 6fd3720..dbd362c 100644 --- a/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx +++ b/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx @@ -1,12 +1,19 @@ import React, { useEffect, useState } from 'react'; import ResourceEntry from './ResourceEntry'; import './RemsInterface.css'; -import { getDrugCodeableConceptFromMedicationRequest } from '../../questionnaireUtil'; -import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; +import axios from 'axios'; import Paper from '@mui/material/Paper'; import Button from '@mui/material/Button'; import AutorenewIcon from '@mui/icons-material/Autorenew'; -import { Bundle, MedicationRequest, MessageHeader, Parameters, Patient } from 'fhir/r4'; +import { + Bundle, + MedicationDispense, + BundleEntry, + MessageHeader, + Parameters, + Patient +} from 'fhir/r4'; +import * as env from 'env-var'; interface RemsInterfaceProps { remsAdminResponse: RemsAdminResponse; @@ -30,7 +37,8 @@ interface JsonData { export default function RemsInterface(props: RemsInterfaceProps) { const [remsAdminResponse, setRemsAdminResponse] = useState(null); - const [response, setResponse] = useState(null); + const [response, setResponse] = useState | null>(null); + const [spin, setSpin] = useState(false); const [spinPis, setSpinPis] = useState(false); const [viewResponse, setViewResponse] = useState(false); @@ -40,16 +48,6 @@ export default function RemsInterface(props: RemsInterfaceProps) { sendRemsMessage(); }, []); - const getAxiosOptions = () => { - const options: AxiosRequestConfig = { - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - }; - return options; - }; - const unfurlJson = (jsonData: JsonData) => { return jsonData.metRequirements .sort((first: MetRequirements, second: MetRequirements) => { @@ -91,7 +89,7 @@ export default function RemsInterface(props: RemsInterfaceProps) { return null; }; - const sendGetRx = () => { + const refreshPharmacyBundle = () => { if (props.specialtyRxBundle.entry && props.specialtyRxBundle.entry[0].resource) { // extract params and questionnaire response identifier const messageHeader: MessageHeader = props.specialtyRxBundle.entry[0] @@ -105,7 +103,6 @@ export default function RemsInterface(props: RemsInterfaceProps) { const params = potentialParams as Parameters; // stakeholder and medication references let prescriptionReference = ''; - let patientReference = ''; if (params.parameter) { for (const param of params.parameter) { if ( @@ -114,38 +111,25 @@ export default function RemsInterface(props: RemsInterfaceProps) { param.valueReference.reference ) { prescriptionReference = param.valueReference.reference; - } else if ( - param.name === 'source-patient' && - param.valueReference && - param.valueReference.reference - ) { - patientReference = param.valueReference.reference; } } } - - // obtain drug information from database const potentialPrescription = getResource(props.specialtyRxBundle, prescriptionReference); - const potentialPatient = getResource(props.specialtyRxBundle, patientReference); - if (potentialPrescription && potentialPatient) { - const prescription = potentialPrescription as MedicationRequest; - const medicationCodeableConcept = - getDrugCodeableConceptFromMedicationRequest(prescription); - const simpleDrugName = medicationCodeableConcept?.coding?.[0].display?.split(' ')[0]; - const rxDate = prescription.authoredOn; - const patient = potentialPatient as Patient; - const patientFirstName = patient.name?.[0].given?.[0]; - const patientLastName = patient.name?.[0].family; - const patientDOB = patient.birthDate; - axios - .get( - `http://localhost:5051/doctorOrders/api/getRx/${patientFirstName}/${patientLastName}/${patientDOB}?simpleDrugName=${simpleDrugName}&rxDate=${rxDate}`, - getAxiosOptions() - ) - .then(response => { - setResponse(response); - }); - } + const rxId = potentialPrescription?.id; + const url = `${env + .get('REACT_APP_DEFAULT_ISS') + .asString()}/MedicationDispense?prescription=${rxId}`; + axios({ + method: 'get', + url: url + }).then( + response => { + setResponse(response?.data?.entry ? response?.data?.entry[0] : null); + }, + error => { + console.log(error); + } + ); } } } @@ -155,7 +139,7 @@ export default function RemsInterface(props: RemsInterfaceProps) { setRemsAdminResponse(remsAdminResponse); // Will not send post request to PIS if only for patient enrollment if (remsAdminResponse?.data?.case_number) { - sendGetRx(); + refreshPharmacyBundle(); } }; @@ -182,7 +166,7 @@ export default function RemsInterface(props: RemsInterfaceProps) { const refreshPisBundle = () => { setSpinPis(true); - sendGetRx(); + refreshPharmacyBundle(); }; const refreshBundle = () => { @@ -202,20 +186,26 @@ export default function RemsInterface(props: RemsInterfaceProps) { color = '#f0ad4e'; } - let colorPis = '#f7f7f7'; - const statusPis = response?.data?.dispenseStatus; + let colorPis = '#0c0c0c'; + const statusPis = response?.resource?.status; - if (statusPis === 'Approved') { + if (statusPis === 'completed') { colorPis = '#5cb85c'; - } else if (statusPis === 'Pending') { - colorPis = '#f0ad4e'; - } else if (statusPis === 'Picked Up') { - colorPis = '#0275d8'; } // Checking if REMS Request (pt enrollment) || Met Requirments (prescriber Form) const hasRemsCase = remsAdminResponse?.data?.case_number ? true : false; + const getMedicationStatus = (status: string | undefined) => { + if (status === 'completed') { + return 'Picked Up'; + } else if (status === 'unknown') { + return 'Not Started'; + } else { + return 'N/A'; + } + }; + return (
@@ -269,22 +259,17 @@ export default function RemsInterface(props: RemsInterfaceProps) {
-

Pharmacy Status

+

Medication Status

-
ID : {response?.data?._id || 'N/A'}
-
Status: {response?.data?.dispenseStatus}
+
ID : {response?.resource?.id || 'N/A'}
+
Status: {getMedicationStatus(statusPis)}
- {/* */} - {response?.data?._id ? ( - setSpinPis(false)} - /> - ) : ( - '' - )} + setSpinPis(false)} + />