Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

U4X-687: Returning the previous two viral load results onto the care panel #244

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState } from 'react';
import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import styles from './care-panel-tabs.scss';
import DSDMHistory from '../../dsdm-history/dsdm-history.component';
import ViralLoadList from '../../vl-history/vl-history.component';

interface CarePanelTabsProps {
patientUuid: string;
}

const CarePanelTabs: React.FC<CarePanelTabsProps> = ({ patientUuid }) => {
const { t } = useTranslation();

const [selectedTab, setSelectedTab] = useState(0);
return (
<div className={styles.tabContainer}>
<Tabs
selectedIndex={selectedTab}
onChange={({ selectedIndex }) => setSelectedTab(selectedIndex)}
className={styles.tabs}
>
<TabList contained className={styles.tabList}>
<Tab>{t('dsdmHistory', 'DSDM History')}</Tab>
<Tab>{t('vlHistory', 'Viral Load History')}</Tab>
</TabList>
<TabPanels>
<TabPanel>
<DSDMHistory patientUuid={patientUuid} />
</TabPanel>
<TabPanel>
<ViralLoadList patientUuid={patientUuid} />
</TabPanel>
</TabPanels>
</Tabs>
</div>
);
};
export default CarePanelTabs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@use '@carbon/styles/scss/spacing';
@use '@carbon/styles/scss/type';
@import "~@openmrs/esm-styleguide/src/vars";
.tabContainer {
margin-top: 1rem;
}

.tabList {
padding-left: 2rem
}

.tabWidth {
width: 150px
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ProgramEnrollmentTB from '../program-enrollment/program-enrollment-tb.com
import { programs } from '../constants';
import DSDMHistory from '../dsdm-history/dsdm-history.component';
import { CardHeader } from '@openmrs/esm-patient-common-lib';
import CarePanelTabs from './care-panel-tabs/care-panel-tabs.component';

interface CarePanelProps {
patientUuid: string;
Expand Down Expand Up @@ -87,6 +88,8 @@ const CarePanel: React.FC<CarePanelProps> = ({ patientUuid, formEntrySub, launch
launchPatientWorkspace={launchPatientWorkspace}
PatientChartProps={''}
/>

<CarePanelTabs patientUuid={patientUuid} />
</div>
)}
{switchItem?.name === programs.tb && (
Expand All @@ -101,12 +104,6 @@ const CarePanel: React.FC<CarePanelProps> = ({ patientUuid, formEntrySub, launch
/>
</div>
)}
{switchItem?.name === programs.hiv && dsdmModels && (
<div>
<div className={styles.sectionTitle}>{t('dsdmHistory', 'DSD Model History')}</div>
<DSDMHistory patientUuid={patientUuid} />
</div>
)}
</div>
) : (
<div className={styles.careProgramContainer}>
Expand Down
4 changes: 4 additions & 0 deletions packages/esm-care-panel-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,8 @@ export const configSchema = {
_type: Type.ConceptUuid,
_default: '813e21e7-4ccb-4fe9-aaab-3c0e40b6e356',
},
viralLoadSetUuid: {
_type: Type.ConceptUuid,
_default: '1eb05918-f50c-4cad-a827-3c78f296a10a',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,6 @@ const DSDMHistory: React.FC<dsdmnProps> = ({ patientUuid }) => {
<DataTable rows={tableRows} headers={columns} useZebraStyles overflowMenuOnHover={true}>
{({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
<TableContainer className={styles.tableContainer}>
<TableToolbar
style={{
position: 'static',
}}
></TableToolbar>
<Table {...getTableProps()} className={styles.activePatientsTable}>
<TableHead>
<TableRow>
Expand Down
4 changes: 3 additions & 1 deletion packages/esm-care-panel-app/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getAsyncLifecycle, defineConfigSchema, registerBreadcrumbs, getSyncLifecycle } from '@openmrs/esm-framework';
import { configSchema } from './config-schema';
import { dashboardMeta } from './dashboard.meta';
import { createDashboardLink, registerWorkspace } from '@openmrs/esm-patient-common-lib';
import { createDashboardLink } from '@openmrs/esm-patient-common-lib';

const moduleName = '@ugandaemr/esm-care-panel-app';

Expand All @@ -13,6 +13,8 @@ export const importTranslation = require.context('../translations', false, /.jso

export const patientProgramSummary = getAsyncLifecycle(() => import('./care-panel/care-panel.component'), options);

export const ViralLoadList = getAsyncLifecycle(() => import('./vl-history/vl-history.component'), options);

export const carePanelPatientSummary = getAsyncLifecycle(
() => import('./patient-summary/patient-summary.component'),
options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,6 @@ const ProgramEnrollment: React.FC<ProgramEnrollmentProps> = ({ enrollments = [],
key: 'baselineCd4',
uuidConfig: configSchema.baselineCd4Uuid._default,
},
{
key: 'hivViralLoadDate',
uuidConfig: configSchema.hivViralLoadDateUuid._default,
processValue: (date) => {
return date && dayjs(date).isValid() ? dayjs(date).format('DD-MM-YYYY') : '--';
},
},
{
key: 'hivViralLoadQualitative',
uuidConfig: configSchema.hivViralLoadQualitativeUuid._default,
},
{
key: 'hivViralLoad',
uuidConfig: configSchema.hivViralLoadUuid._default,
},
{
key: 'currentARVDuration',
uuidConfig: configSchema.currentARVDurationUuid._default,
Expand Down Expand Up @@ -97,8 +82,6 @@ const ProgramEnrollment: React.FC<ProgramEnrollmentProps> = ({ enrollments = [],
whoClinicalStage: '--',
dateConfirmedHivPositive: '--',
baselineCd4: '--',
hivViralLoadQualitative: '--',
hivViralLoad: '--',
currentARVDuration: '--',
tptStatus: '--',
});
Expand Down Expand Up @@ -158,22 +141,6 @@ const ProgramEnrollment: React.FC<ProgramEnrollmentProps> = ({ enrollments = [],
</div>
</div>
<br></br>
<div className={styles.sectionTitle}>{t('lastViralLoadResults', 'Last Viral Load Results')}</div>
<div className={styles.container}>
<div className={styles.content}>
<p className={styles.label}>{t('viralLoadDate', 'HIV Viral Load Date')}</p>
<span className={styles.value}>{programData.hivViralLoadDate}</span>
</div>
<div className={styles.content}>
<p className={styles.label}>{t('viralLoadQual', 'Viral Load Qualitative')}</p>
<span className={styles.value}>{programData.hivViralLoadQualitative}</span>
</div>
<div className={styles.content}>
<p className={styles.label}>{t('hivViralLoad', 'HIV Viral Load')}</p>
<span className={styles.value}>{programData.hivViralLoad}</span>
</div>
</div>
<br></br>
<div className={styles.sectionTitle}>{t('tptDetails', 'TPT Details')}</div>
<div className={styles.container}>
<div className={styles.content}>
Expand Down
138 changes: 138 additions & 0 deletions packages/esm-care-panel-app/src/vl-history/vl-history.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React, { useMemo, useState } from 'react';
import { usePatientObservations } from './vl-history.resource';
import { configSchema } from '../config-schema';
import { usePagination } from '@openmrs/esm-framework';
import {
DataTable,
DataTableSkeleton,
Pagination,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableHeader,
TableRow,
TableToolbar,
Tile,
} from '@carbon/react';
import styles from '../dsdm-history/dsdm-history.scss';
import { useTranslation } from 'react-i18next';

interface ViralLoadProps {
patientUuid: string;
}

const ViralLoadList: React.FC<ViralLoadProps> = ({ patientUuid }) => {
const { t } = useTranslation();

const observationConfig = useMemo(
() => [
{
key: 'hivViralLoadDate',
uuidConfig: configSchema.hivViralLoadDateUuid._default,
},
{
key: 'hivViralLoadQualitative',
uuidConfig: configSchema.hivViralLoadQualitativeUuid._default,
},
{
key: 'hivViralLoad',
uuidConfig: configSchema.hivViralLoadUuid._default,
},
],
[],
);

const conceptUuids = observationConfig.map((config) => config.uuidConfig);

const { observations: groupedObservations, isLoading } = usePatientObservations(patientUuid, conceptUuids);

const pageSizes = [10, 20, 30, 40, 50];
const [currentPageSize, setPageSize] = useState(10);

const tableHeaders = [
{ id: 0, header: t('hivViralLoadDate', 'Viral Load Date'), key: 'hivViralLoadDate' },
{ id: 1, header: t('hivViralLoadQualitative', 'Viral Load Qualitative'), key: 'hivViralLoadQualitative' },
{ id: 2, header: t('hivViralLoad', 'HIV Viral Load'), key: 'hivViralLoad' },
];

const tableRows = useMemo(() => {
const rows = [];

if (groupedObservations) {
Object.keys(groupedObservations)?.forEach((dateTime, index) => {
const group = groupedObservations[dateTime];
rows.push({
id: index.toString(),
hivViralLoadDate: group.dateArray?.[0].split('T')[0] || '',
hivViralLoadQualitative: group.displayArray?.[0] || '',
hivViralLoad: group?.valuesArray?.[0] || '',
});
});
}

return rows;
}, [groupedObservations]);

const { goTo, results: paginatedData, currentPage } = usePagination(tableRows, currentPageSize);

if (isLoading) {
return <DataTableSkeleton role="progressbar" />;
}

return (
<DataTable rows={paginatedData} headers={tableHeaders} useZebraStyles overflowMenuOnHover={true}>
{({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
<TableContainer className={styles.tableContainer}>
<Table {...getTableProps()} className={styles.activePatientsTable}>
<TableHead>
<TableRow>
{headers.map((header) => (
<TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow {...getRowProps({ row })} key={row.id}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
{rows.length === 0 ? (
<div className={styles.tileContainer}>
<Tile className={styles.tile}>
<div className={styles.tileContent}>
<p className={styles.content}>{t('noVlHistoryToDisplay', 'Patient has no viral load history')}</p>
</div>
</Tile>
</div>
) : null}
<Pagination
forwardText="Next page"
backwardText="Previous page"
page={currentPage}
pageSize={currentPageSize}
pageSizes={pageSizes}
totalItems={tableRows.length}
className={styles.pagination}
onChange={({ pageSize, page }) => {
if (pageSize !== currentPageSize) {
setPageSize(pageSize);
}
if (page !== currentPage) {
goTo(page);
}
}}
/>
</TableContainer>
)}
</DataTable>
);
};

export default ViralLoadList;
54 changes: 54 additions & 0 deletions packages/esm-care-panel-app/src/vl-history/vl-history.resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { fhirBaseUrl, openmrsFetch } from '@openmrs/esm-framework';
import { useMemo } from 'react';
import useSWR from 'swr';
import { configSchema } from '../config-schema';

export function usePatientObservations(patientUuid, conceptUuids) {
const conceptsQueryParam = conceptUuids.join('%2C');
const apiUrl = `${fhirBaseUrl}/Observation?patient=${patientUuid}&code=${conceptsQueryParam}&_summary=data&_sort=-date&_count=12`;

const { data, error, isValidating, mutate } = useSWR<{ data: any }, Error>(apiUrl, openmrsFetch);

const observationsByDate = useMemo(() => {
if (!data) return {};

const observations = data?.data?.entry?.map((entry) => entry.resource);

// Grouped observations by effectiveDateTime
const groupedObservations = observations?.reduce((acc, observation) => {
const { effectiveDateTime } = observation;
if (!acc[effectiveDateTime]) {
acc[effectiveDateTime] = {
observations: [],
valuesArray: [],
dateArray: [],
displayArray: [],
};
}
acc[effectiveDateTime]?.observations.push(observation);

const coding = observation?.code?.coding[0];
if (coding?.code === `${configSchema.hivViralLoadUuid._default}` && observation?.valueQuantity) {
acc[effectiveDateTime].valuesArray.push(observation.valueQuantity.value);
} else if (coding?.code === `${configSchema.hivViralLoadDateUuid._default}` && observation?.effectiveDateTime) {
acc[effectiveDateTime].dateArray.push(observation.effectiveDateTime);
} else if (
coding?.code === `${configSchema.hivViralLoadQualitativeUuid._default}` &&
observation?.valueCodeableConcept
) {
acc[effectiveDateTime].displayArray.push(observation.valueCodeableConcept?.coding[0]?.display);
}

return acc;
}, {});

return groupedObservations;
}, [data]);

return {
observations: observationsByDate,
isLoading: isValidating,
isError: !!error,
mutate,
};
}
20 changes: 9 additions & 11 deletions packages/esm-care-panel-app/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
{
"dateConfirmedHivPositive": "Date Positive HIV Test Confirmed",
"artStartDate": "ART Start Date",
"whoStage": "WHO Stage",
"baselineRegimen": "Baseline Regimen",
"baselineCd4": "baseline CD4",
"lastArtVisitSummary": "Last ART Visit Summary",
"lastViralLoadResults": "Last Viral Load Results",
"encounterDate": "Encounter Date",
"viralLoadQual": "Viral Load Qualitative",
"hivViralLoad": "HIV Viral Load"
}
"dateConfirmedHivPositive": "Date Positive HIV Test Confirmed",
"artStartDate": "ART Start Date",
"whoStage": "WHO Stage",
"baselineRegimen": "Baseline Regimen",
"baselineCd4": "baseline CD4",
"lastArtVisitSummary": "Last ART Visit Summary",
"lastViralLoadResults": "Last Viral Load Results",
"encounterDate": "Encounter Date"
}
Loading
Loading