From 8b51b6fe9d686a6e6b6cb214a3412b7de82aabce Mon Sep 17 00:00:00 2001 From: Ariel Virgulto Date: Mon, 12 Feb 2024 10:30:25 -0500 Subject: [PATCH] Revert "Update UI to not check with pharmacy for status of medication" This reverts commit b1a856fbaa326348a41505496ac52e1303b48961. --- .../Patient/MedReqDropDown/MedReqDropDown.tsx | 66 ++++++--- .../pharmacyStatus/PharmacyStatus.tsx | 22 ++- .../__test__/PharmacyStatus.test.tsx | 140 +++++++++++++----- .../RemsInterface/RemsInterface.tsx | 86 +++++++---- 4 files changed, 218 insertions(+), 96 deletions(-) diff --git a/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx b/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx index e2376f1..1983f4e 100644 --- a/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx +++ b/src/views/Patient/MedReqDropDown/MedReqDropDown.tsx @@ -16,7 +16,7 @@ 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, Practitioner, Resource, MedicationDispense } from 'fhir/r4'; +import { BundleEntry, Patient, MedicationRequest, Practitioner, Resource } 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 @@ -43,6 +43,7 @@ import sendRx from './rxSend/rxSend'; import axios from 'axios'; import MetRequirements from './etasuStatus/MetRequirements'; import RemsMetEtasuResponse from './etasuStatus/RemsMetEtasuResponse'; +import DoctorOrder from './pharmacyStatus/DoctorOrder'; interface MedReqDropDownProps { client: Client; @@ -83,7 +84,7 @@ function MedReqDropDown({ const [checkedEtasuTime, setCheckedEtasuTime] = useState(0); // Pharmacy const [showPharmacy, setShowPharmacy] = useState(false); - const [testEhrResponse, setTestEhrResponse] = useState | null>(null); + const [pimsResponse, setPimsResponse] = useState(null); const [checkedPharmacyTime, setCheckedPharmacyTime] = useState(0); const [sendRxEnabled, setSendRxEnabled] = useState(false); @@ -207,18 +208,47 @@ 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()); - const rxId = selectedMedicationCard?.id; - console.log('selected medication card -- > ', rxId); - - // new url to hit url --- > - const url = `${env.get('REACT_APP_DEFAULT_ISS').asString()}/MedicationDispense?prescription=${rxId}`; + 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); axios({ method: 'get', - url: url + url: pharmacyUrl }).then( response => { - setTestEhrResponse(response?.data?.entry ? response?.data?.entry[0] : null); + setPimsResponse(response.data); }, error => { console.log(error); @@ -313,17 +343,15 @@ function MedReqDropDown({ } else if (remsAdminResponse?.status === 'Pending') { color = '#f0ad4e'; // orange } - const pStatus = testEhrResponse?.resource?.status; - console.log('pstatus -- > ', pStatus); + const pStatus = pimsResponse?.dispenseStatus; let pColor = '#0c0c0c'; // white - if (pStatus === 'completed') { + if (pStatus === 'Approved') { pColor = '#5cb85c'; // green + } else if (pStatus === 'Pending') { + pColor = '#f0ad4e'; // orange + } else if (pStatus === 'Picked Up') { + pColor = '#0275d8'; // blue } - // else if (pStatus === 'Pending') { - // pColor = '#f0ad4e'; // orange - // } else if (pStatus === 'Picked Up') { - // pColor = '#0275d8'; // blue - // } const etasuSx = { backgroundColor: color, @@ -434,7 +462,7 @@ function MedReqDropDown({

Pharmacy:

-

{testEhrResponse?.resource?.status || 'Not Started'}

+

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

{renderTimestamp(checkedPharmacyTime)} @@ -476,7 +504,7 @@ function MedReqDropDown({ diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx b/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx index 22fae1f..f015b8f 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/PharmacyStatus.tsx @@ -1,15 +1,19 @@ import { Tooltip, IconButton, Grid } from '@mui/material'; import AutorenewIcon from '@mui/icons-material/Autorenew'; -import { BundleEntry, MedicationDispense } from 'fhir/r4'; +import { MedicationRequest, Patient } from 'fhir/r4'; +import axios from 'axios'; 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; - testEhrResponse: BundleEntry | null; + pimsResponse: DoctorOrder | null; update: boolean; } @@ -22,10 +26,14 @@ const PharmacyStatus = (props: PharmacyStatusProps) => { } }, [props.update]); - const status = props.testEhrResponse?.resource?.status; - let color = '#0c0c0c'; // black - if (status === 'completed') { + const status = props.pimsResponse?.dispenseStatus; + let color = '#f7f7f7'; // white + if (status === 'Approved') { color = '#5cb85c'; // green + } else if (status === 'Pending') { + color = '#f0ad4e'; // orange + } else if (status === 'Picked Up') { + color = '#0275d8'; // blue } return ( @@ -34,8 +42,8 @@ const PharmacyStatus = (props: PharmacyStatusProps) => {
-
ID: {props.testEhrResponse?.resource?.id || 'N/A'}
-
Status: {props.testEhrResponse?.resource?.status || 'N/A'}
+
ID: {props.pimsResponse?._id || 'N/A'}
+
Status: {props.pimsResponse?.dispenseStatus || 'N/A'}
diff --git a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx index edd5756..ec9159f 100644 --- a/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx +++ b/src/views/Patient/MedReqDropDown/pharmacyStatus/__test__/PharmacyStatus.test.tsx @@ -1,43 +1,102 @@ import { fireEvent, render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { MedicationDispense, BundleEntry } from 'fhir/r4'; +import { Patient, MedicationRequest } from 'fhir/r4'; +import nock from 'nock'; import PharmacyStatus from '../PharmacyStatus'; +import DoctorOrder from '../DoctorOrder'; +import MetRequirements from '../../etasuStatus/MetRequirements'; +const pharmacy_server_base = 'http://localhost:5051'; -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': [ - { - 'reference': 'MedicationRequest/pat017-mr-turalio' - } +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 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) { @@ -49,7 +108,7 @@ describe('Test the PharmacyStatus Component', () => { const update = false; // render the module - render( {}} testEhrResponse={null} />); + render( {}} pimsResponse={null} />); // test the status fields and headings are present expectContains('Pharmacy Status'); @@ -61,10 +120,11 @@ describe('Test the PharmacyStatus Component', () => { expect(refreshButton).toBeInTheDocument(); }); test('Renders order', async () => { - render( {}} testEhrResponse={testMedicationDispense} />); + const doctorOrder = generateDoctorOrder(); + render( {}} pimsResponse={doctorOrder} />); - expect(await screen.findByText(`ID: ${testMedicationDispense?.resource?.id}`)).toBeInTheDocument(); - expect(await screen.findByText(`Status: ${testMedicationDispense?.resource?.status}`)).toBeInTheDocument(); + expect(await screen.findByText(`ID: ${doctorOrder._id}`)).toBeInTheDocument(); + expect(await screen.findByText(`Status: ${doctorOrder.dispenseStatus}`)).toBeInTheDocument(); }); test('Loads data on start', () => { @@ -74,7 +134,7 @@ describe('Test the PharmacyStatus Component', () => { pimsResponse = true; }; // render the module - render(); + render(); // verify that the values are updated from the call to get the Pharmacy Status expect(pimsResponse).toBeTruthy(); }); @@ -86,7 +146,7 @@ describe('Test the PharmacyStatus Component', () => { called = true; }; // render the module - render(); + render(); // click the refresh button const refreshButton = screen.getByTestId('refresh'); @@ -99,7 +159,7 @@ describe('Test the PharmacyStatus Component', () => { test('Failed to load status', async () => { const update = true; // render the module - render( {}} testEhrResponse={null} />); + render( {}} pimsResponse={null} />); // click the refresh button const refreshButton = screen.getByTestId('refresh'); diff --git a/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx b/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx index 6db2a9c..6fd3720 100644 --- a/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx +++ b/src/views/Questionnaire/components/RemsInterface/RemsInterface.tsx @@ -1,12 +1,12 @@ import React, { useEffect, useState } from 'react'; import ResourceEntry from './ResourceEntry'; import './RemsInterface.css'; -import axios from 'axios'; +import { getDrugCodeableConceptFromMedicationRequest } from '../../questionnaireUtil'; +import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import Paper from '@mui/material/Paper'; import Button from '@mui/material/Button'; import AutorenewIcon from '@mui/icons-material/Autorenew'; -import { Bundle, MedicationDispense, BundleEntry, MessageHeader, Parameters } from 'fhir/r4'; -import * as env from 'env-var'; +import { Bundle, MedicationRequest, MessageHeader, Parameters, Patient } from 'fhir/r4'; interface RemsInterfaceProps { remsAdminResponse: RemsAdminResponse; @@ -30,7 +30,7 @@ interface JsonData { export default function RemsInterface(props: RemsInterfaceProps) { const [remsAdminResponse, setRemsAdminResponse] = useState(null); - const [response, setResponse] = useState | null>(null); + const [response, setResponse] = useState(null); const [spin, setSpin] = useState(false); const [spinPis, setSpinPis] = useState(false); const [viewResponse, setViewResponse] = useState(false); @@ -40,6 +40,16 @@ 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) => { @@ -81,7 +91,7 @@ export default function RemsInterface(props: RemsInterfaceProps) { return null; }; - const refreshPharmacyBundle = () => { + const sendGetRx = () => { if (props.specialtyRxBundle.entry && props.specialtyRxBundle.entry[0].resource) { // extract params and questionnaire response identifier const messageHeader: MessageHeader = props.specialtyRxBundle.entry[0] @@ -95,6 +105,7 @@ 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 ( @@ -103,28 +114,38 @@ 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 rxId = potentialPrescription?.id; - // // now get new url hit: - - 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); - } - ); + 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); + }); + } } } } @@ -134,7 +155,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) { - refreshPharmacyBundle(); + sendGetRx(); } }; @@ -161,7 +182,7 @@ export default function RemsInterface(props: RemsInterfaceProps) { const refreshPisBundle = () => { setSpinPis(true); - refreshPharmacyBundle(); + sendGetRx(); }; const refreshBundle = () => { @@ -181,11 +202,15 @@ export default function RemsInterface(props: RemsInterfaceProps) { color = '#f0ad4e'; } - let colorPis = '#0c0c0c'; - const statusPis = response?.resource?.status; + let colorPis = '#f7f7f7'; + const statusPis = response?.data?.dispenseStatus; - if (statusPis === 'completed') { + if (statusPis === 'Approved') { 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) @@ -247,10 +272,11 @@ export default function RemsInterface(props: RemsInterfaceProps) {

Pharmacy Status

-
ID : {response?.resource?.id || 'N/A'}
-
Status: {response?.resource?.status ? response?.resource?.status?.charAt(0).toUpperCase() + response?.resource?.status?.slice(1) : 'N/A'}
+
ID : {response?.data?._id || 'N/A'}
+
Status: {response?.data?.dispenseStatus}
- {response?.resource?.id ? ( + {/* */} + {response?.data?._id ? (