-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OHRI-2280 Latest HIV Test Result displayed on patient banner (#1914)
* OHRI-2280 Latest HIV Test Result displayed on patient banner * Add configs to PMTCT
- Loading branch information
Showing
10 changed files
with
277 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 10 additions & 10 deletions
20
packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { Tag } from '@carbon/react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { isPatientHivPositive } from './patientHivStatus'; | ||
import { usePatientHivStatus } from './patientHivStatus'; | ||
|
||
export function PatientStatusBannerTag({ patientUuid }) { | ||
const { t } = useTranslation(); | ||
const [hivPositive, setHivPositive] = useState(false); | ||
const { hivStatus } = usePatientHivStatus(patientUuid); | ||
|
||
useEffect(() => { | ||
isPatientHivPositive(patientUuid).then((result) => setHivPositive(result)); | ||
}, [hivPositive, patientUuid]); | ||
|
||
//TODO: Improve refresh time | ||
// forceRerender(); | ||
|
||
return <>{hivPositive && <Tag type="red">{t('hivPositive', 'HIV Positive')}</Tag>}</>; | ||
return ( | ||
<> | ||
{hivStatus === 'positive' && <Tag type="red">{t('hivPositive', 'HIV Positive')}</Tag>} | ||
{hivStatus === 'negative' && <Tag type="green">{t('hivNegative', 'HIV Negative')}</Tag>} | ||
</> | ||
); | ||
} | ||
|
||
export default PatientStatusBannerTag; |
132 changes: 103 additions & 29 deletions
132
packages/esm-commons-lib/src/components/banner-tags/patientHivStatus.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,118 @@ | ||
import { openmrsFetch } from '@openmrs/esm-framework'; | ||
import { openmrsFetch, useConfig } from '@openmrs/esm-framework'; | ||
import { fetchPatientsFinalHIVStatus, fetchPatientComputedConcept_HIV_Status } from '../../api.resource'; | ||
import { useState, useEffect } from 'react'; | ||
|
||
const fetchPatientHtsEncounters = (patientUuid: string) => { | ||
const htsEncounterRepresentation = | ||
'custom:(uuid,encounterDatetime,location:(uuid,name),' + | ||
'encounterProviders:(uuid,provider:(uuid,name)),' + | ||
'obs:(uuid,obsDatetime,concept:(uuid,name:(uuid,name)),value:(uuid,name:(uuid,name))))'; | ||
const htsRetrospectiveTypeUUID = '79c1f50f-f77d-42e2-ad2a-d29304dde2fe'; | ||
const query = `encounterType=${htsRetrospectiveTypeUUID}&patient=${patientUuid}`; | ||
const usePatientHtsEncounters = (patientUuid: string) => { | ||
const [encounters, setEncounters] = useState<any[]>([]); | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
const [isError, setIsError] = useState<boolean>(false); | ||
const config = useConfig(); | ||
|
||
return openmrsFetch(`/ws/rest/v1/encounter?${query}&v=${htsEncounterRepresentation}`); | ||
useEffect(() => { | ||
const fetchEncounters = async () => { | ||
const htsEncounterRepresentation = | ||
'custom:(uuid,encounterDatetime,location:(uuid,name),' + | ||
'encounterProviders:(uuid,provider:(uuid,name)),' + | ||
'obs:(uuid,obsDatetime,concept:(uuid,name:(uuid,name)),value:(uuid,name:(uuid,name))))'; | ||
const antenatalEncounterType = | ||
config.encounterTypes.antenatalEncounterType || '677d1a80-dbbe-4399-be34-aa7f54f11405'; | ||
|
||
if (!antenatalEncounterType) { | ||
setIsError(true); | ||
setIsLoading(false); | ||
return; | ||
} | ||
|
||
const query = `encounterType=${antenatalEncounterType}&patient=${patientUuid}`; | ||
|
||
try { | ||
const response = await openmrsFetch(`/ws/rest/v1/encounter?${query}&v=${htsEncounterRepresentation}`); | ||
setEncounters(response.data.results); | ||
} catch (error) { | ||
setIsError(true); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}; | ||
|
||
if (patientUuid) { | ||
fetchEncounters(); | ||
} | ||
}, [patientUuid, config]); | ||
|
||
return { encounters, isLoading, isError }; | ||
}; | ||
|
||
const isPatientHivPositive = async (patientUuid: string) => { | ||
const hivTestResultConceptUUID = 'de18a5c1-c187-4698-9d75-258605ea07e8'; // Concept: Result of HIV test | ||
const usePatientHivStatus = (patientUuid: string) => { | ||
const [hivStatus, setHivStatus] = useState<string | null>(null); | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
const [isError, setIsError] = useState<boolean>(false); | ||
const config = useConfig(); | ||
const { encounters, isLoading: encountersLoading, isError: encountersError } = usePatientHtsEncounters(patientUuid); | ||
|
||
let isHivPositive = false; | ||
let htsTestResult; | ||
useEffect(() => { | ||
const fetchHivStatus = async () => { | ||
const hivTestResultConceptUUID = | ||
config.obsConcepts.hivTestResultConceptUUID || '159427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; | ||
const positiveUUID = config.obsConcepts.positiveUUID || '138571AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; | ||
const negativeUUID = config.obsConcepts.negativeUUID || '664AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; | ||
|
||
await fetchPatientHtsEncounters(patientUuid).then((encounters) => { | ||
encounters.data.results.forEach((encounter) => { | ||
htsTestResult = encounter.obs.find((observation) => observation.concept.name.uuid === hivTestResultConceptUUID); | ||
let hivStatus = ''; | ||
|
||
if (htsTestResult && htsTestResult.value.name.uuid === 'ade5ba3f-3c7f-42b1-96d1-cfeb9b446980') { | ||
isHivPositive = true; | ||
if (encountersError) { | ||
setIsError(true); | ||
setIsLoading(false); | ||
return; | ||
} | ||
}); | ||
}); | ||
|
||
const hivFinalStatus = await fetchPatientsFinalHIVStatus(patientUuid); | ||
if (!encountersLoading) { | ||
try { | ||
encounters.forEach((encounter) => { | ||
const htsTestResult = encounter.obs.find( | ||
(observation) => observation.concept.uuid === hivTestResultConceptUUID, | ||
); | ||
|
||
if (htsTestResult) { | ||
if (htsTestResult.value.uuid === positiveUUID) { | ||
hivStatus = 'positive'; | ||
} else if (htsTestResult.value.uuid === negativeUUID) { | ||
hivStatus = 'negative'; | ||
} | ||
} | ||
}); | ||
|
||
if (!hivStatus) { | ||
const hivFinalStatus = await fetchPatientsFinalHIVStatus(patientUuid); | ||
const computedConcept = await fetchPatientComputedConcept_HIV_Status(patientUuid); | ||
|
||
const computedConcept = await fetchPatientComputedConcept_HIV_Status(patientUuid); | ||
if ( | ||
hivFinalStatus.toLowerCase().includes('positive') || | ||
computedConcept.toLowerCase().includes('positive') | ||
) { | ||
hivStatus = 'positive'; | ||
} else if ( | ||
hivFinalStatus.toLowerCase().includes('negative') || | ||
computedConcept.toLowerCase().includes('negative') | ||
) { | ||
hivStatus = 'negative'; | ||
} | ||
} | ||
|
||
setHivStatus(hivStatus); | ||
} catch (error) { | ||
setIsError(true); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
} | ||
}; | ||
|
||
if (hivFinalStatus.toLowerCase().includes('positive') || computedConcept.toLowerCase().includes('positive')) { | ||
isHivPositive = true; | ||
} else { | ||
isHivPositive = false; | ||
} | ||
if (patientUuid) { | ||
fetchHivStatus(); | ||
} | ||
}, [patientUuid, encountersLoading, encountersError, encounters, config]); | ||
|
||
return isHivPositive; | ||
return { hivStatus, isLoading, isError }; | ||
}; | ||
|
||
export { isPatientHivPositive }; | ||
export { usePatientHtsEncounters, usePatientHivStatus }; |
52 changes: 42 additions & 10 deletions
52
packages/esm-commons-lib/src/components/banner-tags/patientStatus.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,48 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
import { useConfig } from '@openmrs/esm-framework'; | ||
import { usePatientHivStatus, usePatientHtsEncounters } from './patientHivStatus'; | ||
import { renderHook } from '@testing-library/react'; | ||
|
||
import { isPatientHivPositive } from './patientHivStatus'; | ||
jest.mock('@openmrs/esm-framework', () => ({ | ||
openmrsFetch: jest.fn(), | ||
useConfig: jest.fn(), | ||
})); | ||
|
||
describe('Patient HIV Status', () => { | ||
it('Should return positive', () => { | ||
let isHivPositive; | ||
isPatientHivPositive('b280078a-c0ce-443b-9997-3c66c63ec2f8').then((result) => { | ||
isHivPositive = result; | ||
jest.mock('../../api.resource', () => ({ | ||
fetchPatientsFinalHIVStatus: jest.fn(), | ||
fetchPatientComputedConcept_HIV_Status: jest.fn(), | ||
})); | ||
|
||
expect(isHivPositive).toBe(true); | ||
const mockUseConfig = useConfig as jest.Mock; | ||
|
||
describe('usePatientHtsEncounters', () => { | ||
it('should return loading state initially', () => { | ||
mockUseConfig.mockReturnValue({ | ||
encounterTypes: { antenatalEncounterType: '677d1a80-dbbe-4399-be34-aa7f54f11405' }, | ||
}); | ||
|
||
const { result } = renderHook(() => usePatientHtsEncounters('1a4d8ff9-a95f-4c18-9b24-a59bd40b3fc0')); | ||
|
||
expect(result.current.isLoading).toBe(true); | ||
expect(result.current.isError).toBe(false); | ||
expect(result.current.encounters).toEqual([]); | ||
}); | ||
}); | ||
|
||
describe('usePatientHivStatus', () => { | ||
it('should return loading state initially', () => { | ||
mockUseConfig.mockReturnValue({ | ||
encounterTypes: { antenatalEncounterType: '677d1a80-dbbe-4399-be34-aa7f54f11405' }, | ||
obsConcepts: { | ||
hivTestResultConceptUUID: '159427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
positiveUUID: '138571AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
negativeUUID: '664AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
}, | ||
}); | ||
|
||
const { result } = renderHook(() => usePatientHivStatus('1a4d8ff9-a95f-4c18-9b24-a59bd40b3fc0')); | ||
|
||
expect(result.current.isLoading).toBe(true); | ||
expect(result.current.isError).toBe(false); | ||
expect(result.current.hivStatus).toBe(null); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Type } from '@openmrs/esm-framework'; | ||
|
||
export const configSchema = { | ||
obsConcepts: { | ||
_type: Type.Object, | ||
_description: 'List of observation concept UUIDs.', | ||
_default: { | ||
hivTestResultConceptUUID: '159427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
positiveUUID: '138571AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
negativeUUID: '664AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', | ||
}, | ||
}, | ||
encounterTypes: { | ||
_type: Type.Object, | ||
_description: 'List of encounter type UUIDs', | ||
_default: { | ||
antenatalEncounterType: '677d1a80-dbbe-4399-be34-aa7f54f11405', | ||
}, | ||
}, | ||
}; | ||
|
||
export interface ConfigObject { | ||
encounterTypes: Object; | ||
obsConcepts: object; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.