Skip to content

Commit

Permalink
code review
Browse files Browse the repository at this point in the history
  • Loading branch information
CynthiaKamau committed Nov 26, 2024
1 parent 7a6c637 commit 8dcedbb
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { useMemo } from 'react';
import React, { memo, useMemo } from 'react';

import { useTranslation } from 'react-i18next';
import { EncounterTile } from './encounter-tile/encounter-tile.component';
import { type ConfigObject, useConfig } from '@openmrs/esm-framework';
import { getEncounterTileColumns, type MenuCardProps } from '../utils/encounter-tile-config-builder';
import { getEncounterTileColumns, type MenuCardProps } from '../utils';

interface OverviewListProps {
patientUuid: string;
}

const ClinicalViewsSummary: React.FC<OverviewListProps> = ({ patientUuid }) => {
const ClinicalViewsSummary: React.FC<OverviewListProps> = memo(({ patientUuid }) => {
const config = useConfig<ConfigObject>();
const { t } = useTranslation();
const tileDefinitions = config.tilesDefinitions;
Expand All @@ -29,6 +29,6 @@ const ClinicalViewsSummary: React.FC<OverviewListProps> = ({ patientUuid }) => {
))}
</>
);
};
});

export default ClinicalViewsSummary;
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { CodeSnippetSkeleton, Tile, Column, Layer } from '@carbon/react';
import React, { useMemo } from 'react';
import { useLayoutType } from '@openmrs/esm-framework';
import { CodeSnippetSkeleton, Tile, Column, Layer } from '@carbon/react';
import styles from './tile.scss';
import { groupColumnsByEncounterType } from '../../utils/helpers';
import { useLastEncounter } from '../../hooks/useLastEncounter';
import { LazyCell } from '../../../lazy-cell/lazy-cell.component';
import { useTranslation } from 'react-i18next';
import { type FormattedCardColumn } from '../../utils/encounter-tile-config-builder';
import { useLayoutType } from '@openmrs/esm-framework';

export interface EncounterTileColumn {
key: string;
header: string;
encounterUuid: string;
concept: string;
title?: string;
getObsValue: (encounter: any) => string | Promise<string>;
getSummaryObsValue?: (encounter: any) => string | Promise<string>;
encounter?: any;
Expand All @@ -28,7 +29,7 @@ export interface EncounterValuesTileProps {
column: any;
}

const EncounterTileInternal: React.FC<EncounterTileProps> = ({ patientUuid, columns, headerTitle }) => {
export const EncounterTile = React.memo(({ patientUuid, columns, headerTitle }: EncounterTileProps) => {
const columnsByEncounterType = useMemo(() => groupColumnsByEncounterType(columns), [columns]);
const isTablet = useLayoutType() === 'tablet';

Expand All @@ -39,41 +40,39 @@ const EncounterTileInternal: React.FC<EncounterTileProps> = ({ patientUuid, colu
<h4 className={styles.title}>{headerTitle}</h4>
</div>
<Column className={styles.columnContainer}>
{Object.entries(columnsByEncounterType).map(([encounterType, columns]) => (
{Object.entries(columnsByEncounterType).map(([encounterUuid, columns]) => (
<EncounterData
key={encounterType}
key={encounterUuid}
patientUuid={patientUuid}
encounterType={encounterType}
columns={columns as FormattedCardColumn[]}
encounterType={encounterUuid}
columns={columns}
/>
))}
</Column>
</Tile>
</Layer>
);
};

export const EncounterTile = React.memo(EncounterTileInternal);
});

const EncounterData: React.FC<{
patientUuid: string;
encounterType: string;
columns: FormattedCardColumn[];
columns: EncounterTileColumn[];
}> = ({ patientUuid, encounterType, columns }) => {
const { lastEncounter, isLoading, error, isValidating } = useLastEncounter(patientUuid, encounterType);
const { t } = useTranslation();

if (isLoading || isValidating) {
return <CodeSnippetSkeleton type="multi" data-testid="skeleton-text" />;
return <CodeSnippetSkeleton type="multi" role="progressbar" />;
}

if (error || lastEncounter === undefined) {
if (error || lastEncounter == undefined) {
return (
<div className={styles.tileBox}>
{columns.map((column, ind) => (
<div key={ind} className={styles.tileBoxColumn}>
<div key={ind}>
<span className={styles.tileTitle}>{t(column.title)}</span>
<span className={styles.tileValue}>--</span>
<span className={styles.tileValue}>{error?.message}</span>
</div>
))}
</div>
Expand All @@ -83,15 +82,20 @@ const EncounterData: React.FC<{
return (
<div className={styles.tileBox}>
{columns.map((column, ind) => (
<div key={ind} className={styles.tileBoxColumn}>
<span className={styles.tileTitle}>{column.title}</span>
<div key={ind}>
<span className={styles.tileTitle}>{column.header}</span>
<span className={styles.tileValue}>
<LazyCell lazyValue={column.getObsValue(lastEncounter)} />
</span>
{column.hasSummary && (
<span className={styles.tileTitle}>
<LazyCell lazyValue={column.getSummaryObsValue(lastEncounter)} />
</span>
<>
<span className={styles.tileValue}>
<LazyCell lazyValue={column.getSummaryObsValue(lastEncounter)} />
</span>
<span className={styles.tileValue}>
<LazyCell lazyValue={column.getObsValue(lastEncounter)} />
</span>
</>
)}
</div>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,29 @@
}

.tileTitle {
@include type.type-style('label-01');
@include type.type-style('body-long-01');
display: block;
padding-top: layout.$spacing-05;
}

.columnContainer {
margin: 0px 0px layout.$spacing-06 layout.$spacing-06;
display: flex;
flex-direction: row;
}

.tileBoxColumn {
width: 100%;
display: 'flex';
flex-direction: 'row';
}

.tileSubTitle {
@include type.type-style('body-compact-01');
}

.tileValue {
@include type.type-style('body-long-01');
margin: layout.$spacing-05 layout.$spacing-10 layout.$spacing-06 0;
@include type.type-style('label-01');
margin: layout.$spacing-04 0 layout.$spacing-04;
display: block;
}

.tileBox {
width: 25%;
display: flex;
flex-direction: row;
flex: 1;
gap: layout.$spacing-04;
}

.desktopHeading {
Expand All @@ -72,7 +64,7 @@
content: '';
display: block;
width: layout.$spacing-07;
padding-top: 0.188rem;
padding-top: layout.$spacing-01;
border-bottom: 0.375rem solid var(--brand-03);
}
}
Expand All @@ -81,7 +73,7 @@
content: '';
display: block;
width: layout.$spacing-07;
padding-top: 0.188rem;
padding-top: layout.$spacing-01;
border-bottom: 0.375rem solid var(--brand-03);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,41 @@ export const encounterRepresentation =
'obs:(uuid,obsDatetime,voided,groupMembers,concept:(uuid,display,name:(uuid,name)),value:(uuid,name:(uuid,name,display),' +
'names:(uuid,conceptNameType,name,display))),form:(uuid,name))';

const cache = new Map();

export function useLastEncounter(patientUuid: string, encounterType: string) {
const query = `encounterType=${encounterType}&patient=${patientUuid}&limit=1&order=desc&startIndex=0`;
const endpointUrl = `/ws/rest/v1/encounter?${query}&v=${encounterRepresentation}`;
const endpointUrl =
patientUuid && encounterType ? `/ws/rest/v1/encounter?${query}&v=${encounterRepresentation}` : null;

const cacheKey = endpointUrl;

const { data, error, isValidating } = useSWR<{ data: { results: Array<OpenmrsEncounter> } }, Error>(
endpointUrl,
openmrsFetch,
{ dedupingInterval: 5000, refreshInterval: 0 },
const { data, error, isValidating, isLoading } = useSWR<{ results: Array<OpenmrsEncounter> }, Error>(
cacheKey,
async (url) => {
const cachedData = cache.get(url);
if (cachedData) {
return cachedData;
}
const response = await openmrsFetch(url);

if (!response.ok) {
throw new Error('Failed to fetch data');
}
const responseData = await response.json();
cache.set(url, responseData);
return responseData;
},
{
dedupingInterval: 50000,
refreshInterval: 0,
},
);

return {
lastEncounter: data ? data?.data?.results.shift() : null,
lastEncounter: data ? data.results?.length > 0 && data.results[0] : null,
error,
isLoading: !data && !error,
isLoading,
isValidating,
};
}
70 changes: 37 additions & 33 deletions packages/esm-patient-chart-app/src/clinical-views/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { age, formatDate, type OpenmrsResource, parseDate } from '@openmrs/esm-framework';
import { type TFunction } from 'i18next';
import { esmPatientChartSchema } from '../../config-schema';
import { type EncounterTileColumn } from '../components/encounter-tile/encounter-tile.component';

export interface Observation {
uuid: string;
Expand Down Expand Up @@ -41,9 +41,16 @@ export interface Encounter extends OpenmrsResource {
visit?: string;
}

export enum EncounterPropertyType {
location = 'location',
provider = 'provider',
visitType = 'visitType',
ageAtEncounter = 'ageAtEncounter',
}

export function getEncounterValues(encounter: Encounter, param: string, isDate?: Boolean) {
if (isDate) return formatDate(encounter[param]);
else return encounter[param] ? encounter[param] : '--';
else return encounter[param] ?? '--';
}

export function obsArrayDateComparator(left: Observation, right: Observation) {
Expand All @@ -52,7 +59,7 @@ export function obsArrayDateComparator(left: Observation, right: Observation) {

export function findObs(encounter: Encounter, obsConcept: string): Observation {
const allObs = encounter?.obs?.filter((observation) => observation.concept.uuid === obsConcept) || [];
return allObs?.length == 1 ? allObs[0] : allObs?.sort(obsArrayDateComparator)[0];
return allObs?.length == 1 ? allObs[0] : allObs.sort(obsArrayDateComparator)[0];
}

export function getObsFromEncounters(encounters: Encounter, obsConcept: string) {
Expand Down Expand Up @@ -106,7 +113,7 @@ export function getObsFromEncounter(
obsConcept: string,
isDate?: Boolean,
isTrueFalseConcept?: Boolean,
type?: string,
type?: EncounterPropertyType,
fallbackConcepts?: Array<string>,
secondaryConcept?: string,
t?: TFunction,
Expand All @@ -118,33 +125,12 @@ export function getObsFromEncounter(

if (isTrueFalseConcept) {
if (typeof obs?.value === 'object') {
if (
(obs?.value?.uuid != esmPatientChartSchema.trueConceptUuid._default && obs?.value?.name?.name !== 'Unknown') ||
obs?.value?.name?.name === t('FALSE')
) {
return t('No');
} else if (obs?.value?.uuid == esmPatientChartSchema.trueConceptUuid._default) {
return t('Yes');
} else {
return obs?.value?.name?.name;
}
return obs?.value?.name?.name;
}
}

if (type === 'location') {
return encounter.location.display;
}

if (type === 'provider') {
return encounter.encounterProviders.map((p) => p.provider.name).join(' | ');
}

if (type === 'visitType') {
return encounter.encounterType.name;
}

if (type === 'ageAtHivTest') {
return age(encounter.patient.birthDate, encounter.encounterDatetime);
if (type) {
getEncounterProperty(encounter, type);
}

if (secondaryConcept && typeof obs.value === 'object' && obs.value.names) {
Expand Down Expand Up @@ -178,12 +164,30 @@ export function getObsFromEncounter(
return obs.value;
}

export const groupColumnsByEncounterType = (columns) => {
return columns.reduce((acc, column) => {
if (!acc[column.encounterType]) {
acc[column.encounterType] = [];
export const groupColumnsByEncounterType = (columns: EncounterTileColumn[]): Record<string, EncounterTileColumn[]> => {
return columns.reduce((acc: Record<string, EncounterTileColumn[]>, column) => {
if (!acc[column.encounterUuid]) {
acc[column.encounterUuid] = [];
}
acc[column.encounterType].push(column);
acc[column.encounterUuid].push(column);
return acc;
}, {});
};

export const getEncounterProperty = (encounter: Encounter, type: EncounterPropertyType) => {
if (type === 'location') {
return encounter.location.display;
}

if (type === 'provider') {
return encounter.encounterProviders.map((p) => p.provider.name).join(' | ');
}

if (type === 'visitType') {
return encounter.encounterType.name;
}

if (type === 'ageAtEncounter') {
return age(encounter.patient.birthDate, encounter.encounterDatetime);
}
};
Loading

0 comments on commit 8dcedbb

Please sign in to comment.