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 index af6c214ad..ed87b20c7 100644 --- 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 @@ -3,12 +3,17 @@ import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { PatientStatusBannerTag } from './patient-status-tag.component'; import { usePatientHivStatus } from './patientHivStatus'; +import { usePatientOutcome } from './useInfantFinalOutcome'; import { usePatientFamilyNames } from './usePatientFamilyNames'; jest.mock('./patientHivStatus', () => ({ usePatientHivStatus: jest.fn(), })); +jest.mock('./useInfantFinalOutcome', () => ({ + usePatientOutcome: jest.fn(), +})); + jest.mock('./usePatientFamilyNames', () => ({ usePatientFamilyNames: jest.fn(), })); @@ -27,6 +32,10 @@ describe('PatientStatusBannerTag', () => { isError: false, }); + (usePatientOutcome as jest.Mock).mockReturnValue({ + patientOutcome: null, + }); + (usePatientFamilyNames as jest.Mock).mockReturnValue({ childrenNames: [], motherName: null, @@ -37,7 +46,6 @@ describe('PatientStatusBannerTag', () => { }); const { container } = render(); - expect(container.firstChild).toBeNull(); }); @@ -48,6 +56,10 @@ describe('PatientStatusBannerTag', () => { isError: false, }); + (usePatientOutcome as jest.Mock).mockReturnValue({ + patientOutcome: 'Still in Care', + }); + (usePatientFamilyNames as jest.Mock).mockReturnValue({ childrenNames: [], motherName: null, @@ -59,6 +71,7 @@ describe('PatientStatusBannerTag', () => { render(); expect(screen.getByText('HIV Positive')).toBeInTheDocument(); + expect(screen.getByText('Still in Care')).toBeInTheDocument(); }); it('should display the correct tag for HIV negative status', () => { @@ -68,6 +81,10 @@ describe('PatientStatusBannerTag', () => { isError: false, }); + (usePatientOutcome as jest.Mock).mockReturnValue({ + patientOutcome: 'HIV negative infant discharged from PMTCT', + }); + (usePatientFamilyNames as jest.Mock).mockReturnValue({ childrenNames: [], motherName: null, @@ -79,6 +96,7 @@ describe('PatientStatusBannerTag', () => { render(); expect(screen.getByText('HIV Negative')).toBeInTheDocument(); + expect(screen.getByText('HIV negative infant discharged from PMTCT')).toBeInTheDocument(); }); it('should display mother’s name on the Infant banner', () => { @@ -88,6 +106,10 @@ describe('PatientStatusBannerTag', () => { isError: false, }); + (usePatientOutcome as jest.Mock).mockReturnValue({ + patientOutcome: 'Still in Care', + }); + (usePatientFamilyNames as jest.Mock).mockReturnValue({ childrenNames: [], motherName: 'Jane Doe', @@ -108,6 +130,10 @@ describe('PatientStatusBannerTag', () => { isError: false, }); + (usePatientOutcome as jest.Mock).mockReturnValue({ + patientOutcome: null, + }); + (usePatientFamilyNames as jest.Mock).mockReturnValue({ childrenNames: [], motherName: null, 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 049c04451..b47f84d2f 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 @@ -2,13 +2,27 @@ import React from 'react'; import { Tag } from '@carbon/react'; import { useTranslation } from 'react-i18next'; import { usePatientHivStatus } from './patientHivStatus'; +import { usePatientOutcome } from './useInfantFinalOutcome'; import { usePatientFamilyNames } from './usePatientFamilyNames'; export function PatientStatusBannerTag({ patientUuid }) { const { t } = useTranslation(); + const { hivStatus } = usePatientHivStatus(patientUuid); - const { childrenNames, motherName, patientAge, patientGender, isLoading, isError } = - usePatientFamilyNames(patientUuid); + + const { patientOutcome } = usePatientOutcome(patientUuid); + + const greenOutcomes = ['Still in Care', 'HIV negative infant discharged from PMTCT']; + const redOutcomes = ['Confirmed HIV positive', 'Lost to follow up', 'Dead', 'Transferred out']; + + let outcomeTagColor = ''; + if (greenOutcomes.includes(patientOutcome)) { + outcomeTagColor = 'green'; + } else if (redOutcomes.includes(patientOutcome)) { + outcomeTagColor = 'red'; + } + + const { childrenNames, motherName, patientGender, isLoading, isError } = usePatientFamilyNames(patientUuid); if (isLoading) { return null; @@ -20,19 +34,16 @@ export function PatientStatusBannerTag({ patientUuid }) { return ( <> - {/* HIV Status Display */} {hivStatus === 'positive' && {t('hivPositive', 'HIV Positive')}} {hivStatus === 'negative' && {t('hivNegative', 'HIV Negative')}} - {/* Mother Name Display (if patient is under 10) */} - {patientAge !== null && patientAge <= 14 && motherName && Mother: {motherName}} + {patientOutcome && outcomeTagColor && {patientOutcome}} - {/* Children Names Display (if patient is female and over 10) */} - {patientAge !== null && patientAge > 14 && patientGender === 'F' && childrenNames.length > 0 && ( + {motherName && Mother: {motherName}} + + {patientGender === 'F' && childrenNames.length > 0 && ( Children: {childrenNames.join(' || ')} )} ); } - -export default PatientStatusBannerTag; diff --git a/packages/esm-commons-lib/src/components/banner-tags/useInfantFinalOutcome.ts b/packages/esm-commons-lib/src/components/banner-tags/useInfantFinalOutcome.ts new file mode 100644 index 000000000..f459572d2 --- /dev/null +++ b/packages/esm-commons-lib/src/components/banner-tags/useInfantFinalOutcome.ts @@ -0,0 +1,36 @@ +import { useState, useEffect } from 'react'; +import { openmrsFetch, useConfig } from '@openmrs/esm-framework'; + +export const usePatientOutcome = (patientUuid: string) => { + const [patientOutcome, setPatientOutcome] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + const config = useConfig(); + + useEffect(() => { + const fetchPatientOutcome = async () => { + try { + const response = await fetch( + `/openmrs/ws/rest/v1/obs?patient=${patientUuid}&concept=${config.obsConcepts.outcomeStatus}&v=full`, + ); + const data = await response.json(); + + if (data.results.length > 0) { + const outcome = data.results[0].value; + setPatientOutcome(outcome.display ?? null); + } else { + setPatientOutcome(null); + } + } catch (error) { + console.error('Failed to fetch patient outcome:', error); + setIsError(true); + } finally { + setIsLoading(false); + } + }; + + fetchPatientOutcome(); + }, [patientUuid, config.obsConcepts.outcomeStatus]); + + return { patientOutcome, isLoading, isError }; +}; diff --git a/packages/esm-commons-lib/src/components/banner-tags/usePatientFamilyNames.ts b/packages/esm-commons-lib/src/components/banner-tags/usePatientFamilyNames.ts index dcd04e330..2a1e79835 100644 --- a/packages/esm-commons-lib/src/components/banner-tags/usePatientFamilyNames.ts +++ b/packages/esm-commons-lib/src/components/banner-tags/usePatientFamilyNames.ts @@ -11,7 +11,6 @@ export const usePatientFamilyNames = (patientUuid: string) => { const fetchFamilyData = useCallback(async () => { try { - // Fetch patient demographics (age and gender) const response = await fetch(`/openmrs/ws/rest/v1/patient/${patientUuid}?v=full`); const patient = await response.json(); setPatientAge(patient.person.age); @@ -36,11 +35,12 @@ export const usePatientFamilyNames = (patientUuid: string) => { const motherRelationship = relationships.find( (relationship) => - relationship.relationshipType?.displayAIsToB === 'Mother' || - relationship.relationshipType?.displayBIsToA === 'Child', + (relationship.relationshipType?.displayAIsToB === 'Mother' || + relationship.relationshipType?.displayBIsToA === 'Child') && + relationship.personA?.uuid !== patientUuid, ); - setMotherName(motherRelationship?.personA?.display || 'Mother not found'); + setMotherName(motherRelationship?.personA?.display || null); setIsLoading(false); } catch (error) {