diff --git a/packages/esm-patient-tests-app/src/test-results/filter/filter-context.tsx b/packages/esm-patient-tests-app/src/test-results/filter/filter-context.tsx index 321d0ebdd7..87e521785d 100644 --- a/packages/esm-patient-tests-app/src/test-results/filter/filter-context.tsx +++ b/packages/esm-patient-tests-app/src/test-results/filter/filter-context.tsx @@ -9,6 +9,7 @@ import { type TimelineData, } from './filter-types'; import reducer from './filter-reducer'; +import { type MappedObservation, type TestResult, type GroupedObservation, type Observation } from '../../types'; const initialState: ReducerState = { checkboxes: {}, @@ -22,6 +23,7 @@ const initialContext = { state: initialState, ...initialState, timelineData: null, + tableData: null, trendlineData: null, activeTests: [], someChecked: false, @@ -93,6 +95,50 @@ const FilterProvider = ({ roots, children }: FilterProviderProps) => { }; }, [activeTests, state.tests]); + const tableData = useMemo(() => { + const flattenedObs: Observation[] = []; + + for (const key in state.tests) { + const test = state.tests[key] as TestResult; + if (test.obs && Array.isArray(test.obs)) { + test.obs.forEach((obs) => { + const flattenedEntry = { + ...obs, + key: key, + ...test, + }; + flattenedObs.push(flattenedEntry); + }); + } + } + + const groupedObs: Record = {}; + + flattenedObs.forEach((curr: MappedObservation) => { + const flatNameParts = curr.flatName.split('-'); + const groupKey = flatNameParts.length > 1 ? flatNameParts[1].trim() : flatNameParts[0].trim(); + const dateKey = new Date(curr.obsDatetime).toISOString().split('T')[0]; + + const compositeKey = `${groupKey}__${dateKey}`; + if (!groupedObs[compositeKey]) { + groupedObs[compositeKey] = { + key: groupKey, + date: dateKey, + flatName: curr.flatName, + entries: [], + }; + } + + groupedObs[compositeKey].entries.push(curr); + }); + + const resultArray = Object.values(groupedObs).sort( + (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(), + ); + + return resultArray; + }, [state.tests]); + useEffect(() => { if (roots?.length && !Object.keys(state?.parents).length) { actions.initialize(roots); @@ -113,6 +159,7 @@ const FilterProvider = ({ roots, children }: FilterProviderProps) => { value={{ ...state, timelineData, + tableData, activeTests, someChecked, totalResultsCount, diff --git a/packages/esm-patient-tests-app/src/test-results/filter/filter-types.ts b/packages/esm-patient-tests-app/src/test-results/filter/filter-types.ts index 10bf6d4ebe..e72d8cadba 100644 --- a/packages/esm-patient-tests-app/src/test-results/filter/filter-types.ts +++ b/packages/esm-patient-tests-app/src/test-results/filter/filter-types.ts @@ -101,6 +101,7 @@ export interface TimelineData { export interface FilterContextProps extends ReducerState { timelineData: TimelineData; + tableData?: any; activeTests: string[]; someChecked: boolean; totalResultsCount: number; diff --git a/packages/esm-patient-tests-app/src/test-results/individual-results-table/individual-results-table.component.tsx b/packages/esm-patient-tests-app/src/test-results/individual-results-table/individual-results-table.component.tsx index 934c784ee2..0977f87db6 100644 --- a/packages/esm-patient-tests-app/src/test-results/individual-results-table/individual-results-table.component.tsx +++ b/packages/esm-patient-tests-app/src/test-results/individual-results-table/individual-results-table.component.tsx @@ -13,18 +13,16 @@ import { TableHeader, TableRow, } from '@carbon/react'; -import { ArrowRightIcon, showModal, useLayoutType, isDesktop, formatDate } from '@openmrs/esm-framework'; +import { ArrowRightIcon, showModal, useLayoutType, isDesktop, formatDatetime } from '@openmrs/esm-framework'; import { getPatientUuidFromUrl, type OBSERVATION_INTERPRETATION } from '@openmrs/esm-patient-common-lib'; -import { type RowData } from '../filter/filter-types'; import styles from './individual-results-table.scss'; +import { type GroupedObservation } from '../../types'; interface IndividualResultsTableProps { isLoading: boolean; - parent: { - display: string; - }; - subRows: Array; + subRows: GroupedObservation; index: number; + title: string; } const getClasses = (interpretation: OBSERVATION_INTERPRETATION) => { @@ -53,12 +51,12 @@ const getClasses = (interpretation: OBSERVATION_INTERPRETATION) => { } }; -const IndividualResultsTable: React.FC = ({ isLoading, parent, subRows, index }) => { +const IndividualResultsTable: React.FC = ({ isLoading, subRows, index, title }) => { const { t } = useTranslation(); const layout = useLayoutType(); const patientUuid = getPatientUuidFromUrl(); - const headerTitle = t(parent.display); + const headerTitle = t(title); const launchResultsDialog = useCallback( (title: string, testUuid: string) => { @@ -85,9 +83,9 @@ const IndividualResultsTable: React.FC = ({ isLoadi const tableRows = useMemo( () => - subRows.map((row, i) => { - const { units = '', range = '', obs: values } = row; - const isString = isNaN(parseFloat(values?.[0]?.value)); + subRows.entries.map((row, i) => { + const { units = '', range = '' } = row; + const isString = isNaN(parseFloat(row.value)); return { ...row, @@ -107,8 +105,8 @@ const IndividualResultsTable: React.FC = ({ isLoadi ), value: { - value: `${row.obs[0]?.value ?? ''} ${row.units ?? ''}`, - interpretation: row.obs[0]?.interpretation, + value: `${row.value} ${row.units ?? ''}`, + interpretation: row?.interpretation, }, referenceRange: `${range || '--'} ${units || '--'}`, }; @@ -118,7 +116,7 @@ const IndividualResultsTable: React.FC = ({ isLoadi if (isLoading) return ; - if (subRows?.length) { + if (subRows.entries?.length) { return ( {({ rows, headers, getHeaderProps, getTableProps }) => ( @@ -126,11 +124,7 @@ const IndividualResultsTable: React.FC = ({ isLoadi

{headerTitle}

- - {subRows[0]?.obs[0]?.obsDatetime - ? formatDate(new Date(subRows[0]?.obs[0]?.obsDatetime), { mode: 'standard' }) - : ''} - + {subRows.date ?? ''}
) : view === 'over-time' ? ( - panels.map((panel) => ( -
- -
- )) + ) : null}
diff --git a/packages/esm-patient-tests-app/src/types.ts b/packages/esm-patient-tests-app/src/types.ts index 4830297ebb..60842080e1 100644 --- a/packages/esm-patient-tests-app/src/types.ts +++ b/packages/esm-patient-tests-app/src/types.ts @@ -137,3 +137,49 @@ export interface ObservationSet { } export type viewOpts = 'individual-test' | 'over-time' | 'full'; + +export type Observation = { + obsDatetime: string; + value: string; + interpretation: OBSERVATION_INTERPRETATION; +}; + +export type TestResult = { + obs: Observation[]; + datatype: string; + lowAbsolute: number; + display: string; + conceptUuid: string; + lowNormal: number; + units: string; + lowCritical: number; + hiNormal: number; + flatName: string; + hasData: boolean; + range: string; +}; + +export type MappedObservation = { + datatype: string; + lowAbsolute: number; + display: string; + conceptUuid: string; + lowNormal: number; + units: string; + lowCritical: number; + hiNormal: number; + flatName: string; + hasData: boolean; + range: string; + obsDatetime: string; + value: string; + interpretation: OBSERVATION_INTERPRETATION; + key: string; +}; + +export interface GroupedObservation { + key: string; + date: string; + flatName: string; + entries: MappedObservation[]; +} diff --git a/yarn.lock b/yarn.lock index d5e38d3c4d..921ddc8bb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11316,7 +11316,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.3": +"body-parser@npm:1.20.3, body-parser@npm:^1.19.0": version: 1.20.3 resolution: "body-parser@npm:1.20.3" dependencies: @@ -11336,26 +11336,6 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:^1.19.0": - version: 1.20.2 - resolution: "body-parser@npm:1.20.2" - dependencies: - bytes: "npm:3.1.2" - content-type: "npm:~1.0.5" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - on-finished: "npm:2.4.1" - qs: "npm:6.11.0" - raw-body: "npm:2.5.2" - type-is: "npm:~1.6.18" - unpipe: "npm:1.0.0" - checksum: 10/3cf171b82190cf91495c262b073e425fc0d9e25cc2bf4540d43f7e7bbca27d6a9eae65ca367b6ef3993eea261159d9d2ab37ce444e8979323952e12eb3df319a - languageName: node - linkType: hard - "bonjour-service@npm:^1.0.11": version: 1.0.13 resolution: "bonjour-service@npm:1.0.13" @@ -22171,15 +22151,6 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" - dependencies: - side-channel: "npm:^1.0.4" - checksum: 10/5a3bfea3e2f359ede1bfa5d2f0dbe54001aa55e40e27dc3e60fab814362d83a9b30758db057c2011b6f53a2d4e4e5150194b5bac45372652aecb3e3c0d4b256e - languageName: node - linkType: hard - "qs@npm:6.13.0": version: 6.13.0 resolution: "qs@npm:6.13.0"