diff --git a/packages/esm-commons-lib/src/api.resource.ts b/packages/esm-commons-lib/src/api.resource.ts
index 0cacbd838..ff6b0c045 100644
--- a/packages/esm-commons-lib/src/api.resource.ts
+++ b/packages/esm-commons-lib/src/api.resource.ts
@@ -1,4 +1,4 @@
-import { openmrsFetch } from '@openmrs/esm-framework';
+import { fhirBaseUrl, openmrsFetch } from '@openmrs/esm-framework';
import dayjs from 'dayjs';
import {
finalHIVCodeConcept,
@@ -358,12 +358,11 @@ export async function getCohortList(
`/ws/rest/v1/encounter?encounterType=${encounterType}&patient=${member.patient.uuid}&v=${encounterRepresentation}`,
).then(({ data }) => {
if (data.results.length) {
- const sortedEncounters = data.results
- .sort(
- (firstEncounter, secondEncounter) =>
- new Date(secondEncounter.encounterDatetime).getTime() -
- new Date(firstEncounter.encounterDatetime).getTime(),
- );
+ const sortedEncounters = data.results.sort(
+ (firstEncounter, secondEncounter) =>
+ new Date(secondEncounter.encounterDatetime).getTime() -
+ new Date(firstEncounter.encounterDatetime).getTime(),
+ );
return sortedEncounters[0];
}
return null;
diff --git a/packages/esm-commons-lib/src/components/banner-tags/.patient-status-tag.test.tsx b/packages/esm-commons-lib/src/components/banner-tags/.patient-status-tag.test.tsx
deleted file mode 100644
index d1f7dc74a..000000000
--- a/packages/esm-commons-lib/src/components/banner-tags/.patient-status-tag.test.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import { render, act, screen } from '@testing-library/react';
-import '@testing-library/jest-dom';
-import { PatientStatusBannerTag } from './patient-status-tag.component';
-import { isPatientHivPositive } from './patientHivStatus';
-
-const mockIsPatientHivPositive = isPatientHivPositive as jest.Mock;
-jest.mock('./patientHivStatus');
-
-describe('PatientStatusBannerTag', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- const hivPositiveSampleUuid = '703AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-
- describe('PatientStatusBannerTag', () => {
- it('renders red tag when patient is HIV positive', async () => {
- mockIsPatientHivPositive.mockResolvedValue(true);
- await act(async () => {
- render();
- });
-
- expect(screen.getByText(/HIV Positive/i)).toBeInTheDocument();
- });
- });
-
- it('does not render red tag when patient is not HIV positive', async () => {
- await act(async () => {
- (isPatientHivPositive as jest.Mock).mockResolvedValue(false);
- render();
- });
-
- expect(screen.queryByText('HIV Positive')).not.toBeInTheDocument();
- });
-});
diff --git a/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.component.tsx b/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.component.tsx
index 8c6a6368b..c19f8bbc7 100644
--- a/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.component.tsx
+++ b/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.component.tsx
@@ -1,18 +1,24 @@
-import React, { useEffect, useState } from 'react';
+import React from 'react';
import { Tag } from '@carbon/react';
import { useTranslation } from 'react-i18next';
-import { isPatientHivPositive } from './patientHivStatus';
+import { finalHIVCodeConcept, finalPositiveHIVValueConcept } from '../../constants';
+import { usePatientsFinalHIVStatus } from './usePatientHivStatus';
export function PatientStatusBannerTag({ patientUuid }) {
const { t } = useTranslation();
- const [hivPositive, setHivPositive] = useState(false);
+ const { isLoading, hivStatus, error } = usePatientsFinalHIVStatus(
+ patientUuid,
+ finalHIVCodeConcept,
+ finalPositiveHIVValueConcept,
+ );
- useEffect(() => {
- isPatientHivPositive(patientUuid).then((result) => setHivPositive(result));
- }, [hivPositive, patientUuid]);
+ if (isLoading) {
+ return
{t('loading', 'Loading...')}
;
+ }
- //TODO: Improve refresh time
- // forceRerender();
+ if (error) {
+ return {t('error', 'Error...')}
;
+ }
- return <>{hivPositive && {t('hivPositive', 'HIV Positive')}}>;
+ return <>{hivStatus && {t('hivPositive', 'HIV Positive')}}>;
}
diff --git a/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.test.tsx b/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.test.tsx
new file mode 100644
index 000000000..03eba9aef
--- /dev/null
+++ b/packages/esm-commons-lib/src/components/banner-tags/patient-status-tag.test.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { PatientStatusBannerTag } from './patient-status-tag.component';
+import { usePatientsFinalHIVStatus } from './usePatientHivStatus';
+
+const mockedUsePatientsFinalHIVStatus = jest.mocked(usePatientsFinalHIVStatus);
+
+jest.mock('./usePatientHivStatus', () => {
+ const originalModule = jest.requireActual('./usePatientHivStatus');
+
+ return {
+ ...originalModule,
+ usePatientsFinalHIVStatus: jest.fn().mockImplementation(() => ({
+ hivStatus: true,
+ isLoading: false,
+ })),
+ };
+});
+
+describe('PatientStatusBannerTag', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ const samplePatientUuid = '703AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
+
+ it('renders red tag when patient is HIV positive', async () => {
+ render();
+ expect(screen.getByText(/HIV Positive/i)).toBeInTheDocument();
+ });
+
+ it('does not render red tag when patient is not HIV positive', async () => {
+ mockedUsePatientsFinalHIVStatus.mockReturnValue({ hivStatus: false, isLoading: false, error: null });
+ render();
+ expect(screen.queryByText('HIV Positive')).not.toBeInTheDocument();
+ });
+});
diff --git a/packages/esm-commons-lib/src/components/banner-tags/patientHivStatus.ts b/packages/esm-commons-lib/src/components/banner-tags/patientHivStatus.ts
deleted file mode 100644
index c3df0b78e..000000000
--- a/packages/esm-commons-lib/src/components/banner-tags/patientHivStatus.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { openmrsFetch } from '@openmrs/esm-framework';
-import { fetchPatientsFinalHIVStatus, fetchPatientComputedConcept_HIV_Status } from '../../api.resource';
-
-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}`;
-
- return openmrsFetch(`/ws/rest/v1/encounter?${query}&v=${htsEncounterRepresentation}`);
-};
-
-const isPatientHivPositive = async (patientUuid: string) => {
- const hivTestResultConceptUUID = 'de18a5c1-c187-4698-9d75-258605ea07e8'; // Concept: Result of HIV test
-
- let isHivPositive = false;
- let htsTestResult;
-
- await fetchPatientHtsEncounters(patientUuid).then((encounters) => {
- encounters.data.results.forEach((encounter) => {
- htsTestResult = encounter.obs.find((observation) => observation.concept.name.uuid === hivTestResultConceptUUID);
-
- if (htsTestResult && htsTestResult.value.name.uuid === 'ade5ba3f-3c7f-42b1-96d1-cfeb9b446980') {
- isHivPositive = true;
- }
- });
- });
-
- const hivFinalStatus = await fetchPatientsFinalHIVStatus(patientUuid);
-
- const computedConcept = await fetchPatientComputedConcept_HIV_Status(patientUuid);
-
- if (hivFinalStatus.toLowerCase().includes('positive') || computedConcept.toLowerCase().includes('positive')) {
- isHivPositive = true;
- } else {
- isHivPositive = false;
- }
-
- return isHivPositive;
-};
-
-export { isPatientHivPositive };
diff --git a/packages/esm-commons-lib/src/components/banner-tags/patientStatus.test.ts b/packages/esm-commons-lib/src/components/banner-tags/patientStatus.test.ts
deleted file mode 100644
index 686e2f835..000000000
--- a/packages/esm-commons-lib/src/components/banner-tags/patientStatus.test.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * @jest-environment jsdom
- */
-
-import { isPatientHivPositive } from './patientHivStatus';
-
-describe('Patient HIV Status', () => {
- it('Should return positive', () => {
- let isHivPositive;
- isPatientHivPositive('b280078a-c0ce-443b-9997-3c66c63ec2f8').then((result) => {
- isHivPositive = result;
-
- expect(isHivPositive).toBe(true);
- });
- });
-});
diff --git a/packages/esm-commons-lib/src/components/banner-tags/usePatientHivStatus.ts b/packages/esm-commons-lib/src/components/banner-tags/usePatientHivStatus.ts
new file mode 100644
index 000000000..5cae13a30
--- /dev/null
+++ b/packages/esm-commons-lib/src/components/banner-tags/usePatientHivStatus.ts
@@ -0,0 +1,16 @@
+import { fhirBaseUrl, openmrsFetch } from '@openmrs/esm-framework';
+import useSWR from 'swr';
+
+export function usePatientsFinalHIVStatus(
+ patientUuid: string,
+ finalHIVCodeConcept: string,
+ finalPositiveHIVValueConcept: string,
+) {
+ const url = `${fhirBaseUrl}/Observation?code=${finalHIVCodeConcept}&value-concept=${finalPositiveHIVValueConcept}&patient=${patientUuid}&_sort=-date&_count=1`;
+ const { data, error, isLoading, mutate } = useSWR<{ data: any }, Error>(url, openmrsFetch);
+
+ const hivStatusResult = data?.data?.entry[0].resource.valueCodeableConcept.coding[0].display;
+ const hivStatus = hivStatusResult.toLowerCase().includes('positive') ? true : false;
+
+ return { hivStatus: hivStatus, isLoading: isLoading, error: error };
+}
diff --git a/packages/esm-commons-lib/src/components/cohort-patient-list/helpers.tsx b/packages/esm-commons-lib/src/components/cohort-patient-list/helpers.tsx
index 76394e274..4f0e6dbbd 100644
--- a/packages/esm-commons-lib/src/components/cohort-patient-list/helpers.tsx
+++ b/packages/esm-commons-lib/src/components/cohort-patient-list/helpers.tsx
@@ -5,9 +5,9 @@ import dayjs from 'dayjs';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import relativeTime from 'dayjs/plugin/relativeTime';
import { AddPatientToListOverflowMenuItem } from '../modals/add-patient-to-list-modal.component';
-import { fetchPatientLastEncounter } from '../../api.resource';
import { launchForm } from '../../utils/ohri-forms-commons';
import { navigate, WorkspaceContainer } from '@openmrs/esm-framework';
+import { useLastEncounter } from '../../hooks/useLastEncounter';
interface PatientMetaConfig {
location: { name: string };
@@ -38,23 +38,25 @@ export const LaunchableFormMenuItem = ({
}) => {
const [actionText, setActionText] = useState(launchableForm.actionText);
const [encounterUuid, setEncounterUuid] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
const continueEncounterActionText = launchableForm.actionText || 'Continue encounter ';
+ const { lastEncounter, isLoading } = useLastEncounter(patientUuid, encounterType);
useEffect(() => {
if (launchableForm.editLatestEncounter && encounterType && !encounterUuid) {
- setIsLoading(true);
- fetchPatientLastEncounter(patientUuid, encounterType).then((latestEncounter) => {
- if (latestEncounter) {
- setActionText(continueEncounterActionText);
- setEncounterUuid(latestEncounter.uuid);
- }
- setIsLoading(false);
- });
- } else {
- setIsLoading(false);
+ if (!isLoading && lastEncounter) {
+ setActionText(continueEncounterActionText);
+ setEncounterUuid(lastEncounter.uuid);
+ }
}
- }, [continueEncounterActionText, encounterType, encounterUuid, launchableForm.editLatestEncounter, patientUuid]);
+ }, [
+ continueEncounterActionText,
+ encounterType,
+ encounterUuid,
+ launchableForm.editLatestEncounter,
+ patientUuid,
+ lastEncounter,
+ isLoading,
+ ]);
return (
<>
@@ -79,21 +81,15 @@ export const LaunchableFormMenuItem = ({
export const ViewSummaryMenuItem = ({ patientUuid, ViewSummary, encounterType }) => {
const [actionText, setActionText] = useState(ViewSummary.actionText);
const [encounterUuid, setEncounterUuid] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
const viewSummaryActionText = ViewSummary.actionText || 'View Summary ';
+ const { lastEncounter, isLoading } = useLastEncounter(patientUuid, encounterType);
useEffect(() => {
if (ViewSummary.editLatestEncounter && encounterType && !encounterUuid) {
- setIsLoading(true);
- fetchPatientLastEncounter(patientUuid, encounterType).then((latestEncounter) => {
- if (latestEncounter) {
- setActionText(viewSummaryActionText);
- setEncounterUuid(latestEncounter.uuid);
- }
- setIsLoading(false);
- });
- } else {
- setIsLoading(false);
+ if (!isLoading && lastEncounter) {
+ setActionText(viewSummaryActionText);
+ setEncounterUuid(lastEncounter.uuid);
+ }
}
}, [ViewSummary.editLatestEncounter, encounterType, encounterUuid, patientUuid, viewSummaryActionText]);
@@ -114,24 +110,19 @@ export const ViewSummaryMenuItem = ({ patientUuid, ViewSummary, encounterType })
>
);
};
+
export const ViewTptSummaryMenuItem = ({ patientUuid, ViewTptSummary, encounterType }) => {
const [actionText, setActionText] = useState(ViewTptSummary.actionText);
const [encounterUuid, setEncounterUuid] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
const viewTptSummaryActionText = ViewTptSummary.actionText || 'View Summary ';
+ const { lastEncounter, isLoading } = useLastEncounter(patientUuid, encounterType);
useEffect(() => {
if (ViewTptSummary.editLatestEncounter && encounterType && !encounterUuid) {
- setIsLoading(true);
- fetchPatientLastEncounter(patientUuid, encounterType).then((latestEncounter) => {
- if (latestEncounter) {
- setActionText(viewTptSummaryActionText);
- setEncounterUuid(latestEncounter.uuid);
- }
- setIsLoading(false);
- });
- } else {
- setIsLoading(false);
+ if (!isLoading && lastEncounter) {
+ setActionText(viewTptSummaryActionText);
+ setEncounterUuid(lastEncounter.uuid);
+ }
}
}, [ViewTptSummary.editLatestEncounter, encounterType, patientUuid, encounterUuid, viewTptSummaryActionText]);
@@ -152,6 +143,7 @@ export const ViewTptSummaryMenuItem = ({ patientUuid, ViewTptSummary, encounterT
>
);
};
+
export function consolidatatePatientMeta(rawPatientMeta, form, config: PatientMetaConfig) {
const {
isDynamicCohort,
diff --git a/packages/esm-commons-lib/src/index.ts b/packages/esm-commons-lib/src/index.ts
index f4982ca46..b788a8bba 100644
--- a/packages/esm-commons-lib/src/index.ts
+++ b/packages/esm-commons-lib/src/index.ts
@@ -5,7 +5,7 @@ export * from './constants';
export * from './api.resource';
export * from './types';
export * from './components/banner-tags/patient-status-tag.component';
-export * from './components/banner-tags/patientHivStatus';
+export * from './components/banner-tags/usePatientHivStatus';
export * from './components/data-table/o-table.component';
export * from './components/empty-state/empty-data-illustration.component';
export * from './components/empty-state/empty-state-comingsoon.component';