@openmrs/esm-patient-tests-app 11.3.1-patch.9064 → 11.3.1-patch.9508
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +22 -22
- package/dist/1119.js +1 -1
- package/dist/1197.js +1 -1
- package/dist/{6231.js → 1477.js} +1 -1
- package/dist/1477.js.map +1 -0
- package/dist/1638.js +1 -1
- package/dist/1638.js.map +1 -1
- package/dist/1935.js +1 -1
- package/dist/1935.js.map +1 -1
- package/dist/2146.js +1 -1
- package/dist/2690.js +1 -1
- package/dist/3099.js +1 -1
- package/dist/34.js +1 -1
- package/dist/34.js.map +1 -1
- package/dist/3509.js +1 -1
- package/dist/3509.js.map +1 -1
- package/dist/3584.js +1 -1
- package/dist/4055.js +1 -1
- package/dist/4132.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4335.js +1 -1
- package/dist/439.js +1 -0
- package/dist/4618.js +1 -1
- package/dist/4652.js +1 -1
- package/dist/4944.js +1 -1
- package/dist/5173.js +1 -1
- package/dist/5241.js +1 -1
- package/dist/5442.js +1 -1
- package/dist/5661.js +1 -1
- package/dist/5670.js +1 -1
- package/dist/5670.js.map +1 -1
- package/dist/6022.js +1 -1
- package/dist/6113.js +1 -0
- package/dist/6113.js.map +1 -0
- package/dist/6301.js +1 -1
- package/dist/6301.js.map +1 -1
- package/dist/6336.js +1 -0
- package/dist/6336.js.map +1 -0
- package/dist/6468.js +1 -1
- package/dist/6589.js +1 -0
- package/dist/6679.js +1 -1
- package/dist/6840.js +1 -1
- package/dist/6859.js +1 -1
- package/dist/7097.js +1 -1
- package/dist/7159.js +1 -1
- package/dist/7202.js +1 -0
- package/dist/7202.js.map +1 -0
- package/dist/723.js +1 -1
- package/dist/7617.js +1 -1
- package/dist/790.js +1 -1
- package/dist/790.js.map +1 -1
- package/dist/795.js +1 -1
- package/dist/8163.js +1 -1
- package/dist/8307.js +2 -0
- package/dist/8307.js.map +1 -0
- package/dist/8349.js +1 -1
- package/dist/8371.js +1 -0
- package/dist/8555.js +2 -0
- package/dist/8555.js.map +1 -0
- package/dist/8618.js +1 -1
- package/dist/890.js +1 -1
- package/dist/9214.js +1 -1
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/986.js +1 -1
- package/dist/9879.js +1 -1
- package/dist/9895.js +1 -1
- package/dist/9900.js +1 -1
- package/dist/9913.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-tests-app.js +1 -1
- package/dist/openmrs-esm-patient-tests-app.js.buildmanifest.json +319 -249
- package/dist/openmrs-esm-patient-tests-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -3
- package/src/edit-test-results/modal/edit-lab-results.modal.tsx +6 -2
- package/src/index.ts +1 -1
- package/src/routes.json +2 -2
- package/src/test-orders/add-test-order/add-test-order.test.tsx +13 -10
- package/src/test-orders/add-test-order/add-test-order.workspace.tsx +43 -7
- package/src/test-orders/add-test-order/test-order-form.component.tsx +41 -7
- package/src/test-orders/add-test-order/test-type-search.component.tsx +56 -8
- package/src/test-orders/lab-order-basket-panel/lab-icon.component.tsx +27 -0
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.extension.tsx +62 -15
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.scss +26 -11
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.test.tsx +18 -5
- package/src/test-results/filter/filter-context.test.tsx +556 -0
- package/src/test-results/filter/filter-context.tsx +1 -1
- package/src/test-results/filter/filter-reducer.test.ts +540 -0
- package/src/test-results/filter/filter-reducer.ts +1 -1
- package/src/test-results/filter/filter-set.component.tsx +75 -48
- package/src/test-results/filter/filter-set.test.tsx +694 -0
- package/src/test-results/filter/filter-types.ts +24 -1
- package/src/test-results/grouped-timeline/grid.component.tsx +4 -2
- package/src/test-results/grouped-timeline/grouped-timeline.component.tsx +20 -22
- package/src/test-results/grouped-timeline/grouped-timeline.test.tsx +52 -2
- package/src/test-results/grouped-timeline/reference-range-helpers.test.ts +308 -0
- package/src/test-results/grouped-timeline/reference-range-helpers.ts +161 -0
- package/src/test-results/grouped-timeline/timeline-data-group.component.tsx +13 -6
- package/src/test-results/grouped-timeline/useObstreeData.test.ts +471 -0
- package/src/test-results/grouped-timeline/useObstreeData.ts +108 -13
- package/src/test-results/individual-results-table/individual-results-table.component.tsx +18 -6
- package/src/test-results/individual-results-table/individual-results-table.test.tsx +65 -3
- package/src/test-results/individual-results-table-tablet/helper.tsx +8 -2
- package/src/test-results/individual-results-table-tablet/individual-results-table-tablet.component.tsx +5 -5
- package/src/test-results/individual-results-table-tablet/lab-set-panel.component.tsx +2 -1
- package/src/test-results/individual-results-table-tablet/usePanelData.tsx +40 -26
- package/src/test-results/loadPatientTestData/helpers.test.ts +834 -0
- package/src/test-results/loadPatientTestData/helpers.ts +143 -12
- package/src/test-results/loadPatientTestData/loadPatientData.ts +66 -11
- package/src/test-results/loadPatientTestData/usePatientResultsData.ts +20 -9
- package/src/test-results/overview/common-datatable.component.tsx +1 -1
- package/src/test-results/overview/external-overview.extension.tsx +1 -2
- package/src/test-results/overview/useOverviewData.ts +22 -10
- package/src/test-results/print-modal/print-modal.extension.tsx +1 -1
- package/src/test-results/results-viewer/results-viewer.extension.tsx +12 -7
- package/src/test-results/tree-view/tree-view.component.tsx +31 -8
- package/src/test-results/tree-view/tree-view.test.tsx +119 -2
- package/src/test-results/trendline/trendline-resource.tsx +48 -5
- package/src/test-results/trendline/trendline.component.tsx +88 -52
- package/src/test-results/ui-elements/{resetFiltersEmptyState → reset-filters-empty-state}/filter-empty-data-illustration.tsx +2 -2
- package/src/test-results/ui-elements/{resetFiltersEmptyState → reset-filters-empty-state}/filter-empty-state.component.tsx +5 -6
- package/src/types.ts +20 -1
- package/translations/am.json +3 -4
- package/translations/ar.json +3 -4
- package/translations/ar_SY.json +3 -4
- package/translations/bn.json +3 -4
- package/translations/cs.json +119 -0
- package/translations/de.json +3 -4
- package/translations/en.json +3 -2
- package/translations/en_US.json +3 -4
- package/translations/es.json +3 -4
- package/translations/es_MX.json +3 -4
- package/translations/fr.json +5 -6
- package/translations/he.json +3 -4
- package/translations/hi.json +3 -4
- package/translations/hi_IN.json +3 -4
- package/translations/id.json +3 -4
- package/translations/it.json +3 -4
- package/translations/ka.json +3 -4
- package/translations/km.json +3 -4
- package/translations/ku.json +3 -4
- package/translations/ky.json +3 -4
- package/translations/lg.json +3 -4
- package/translations/ne.json +3 -4
- package/translations/pl.json +3 -4
- package/translations/pt.json +3 -4
- package/translations/pt_BR.json +3 -4
- package/translations/qu.json +3 -4
- package/translations/ro_RO.json +3 -4
- package/translations/ru_RU.json +3 -4
- package/translations/si.json +3 -4
- package/translations/sq.json +119 -0
- package/translations/sw.json +3 -4
- package/translations/sw_KE.json +3 -4
- package/translations/tr.json +3 -4
- package/translations/tr_TR.json +3 -4
- package/translations/uk.json +3 -4
- package/translations/uz.json +3 -4
- package/translations/uz@Latn.json +3 -4
- package/translations/uz_UZ.json +3 -4
- package/translations/vi.json +3 -4
- package/translations/zh.json +3 -4
- package/translations/zh_CN.json +3 -4
- package/translations/zh_TW.json +119 -0
- package/dist/1479.js +0 -1
- package/dist/1479.js.map +0 -1
- package/dist/2537.js +0 -1
- package/dist/2537.js.map +0 -1
- package/dist/4918.js +0 -1
- package/dist/4918.js.map +0 -1
- package/dist/5836.js +0 -2
- package/dist/5836.js.map +0 -1
- package/dist/6231.js.map +0 -1
- package/dist/7053.js +0 -2
- package/dist/7053.js.map +0 -1
- /package/dist/{7053.js.LICENSE.txt → 8307.js.LICENSE.txt} +0 -0
- /package/dist/{5836.js.LICENSE.txt → 8555.js.LICENSE.txt} +0 -0
- /package/src/test-results/ui-elements/{resetFiltersEmptyState/index.scss → reset-filters-empty-state/filter-empty-state.scss} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { formatRangeWithUnits } from '../grouped-timeline/reference-range-helpers';
|
|
4
5
|
import {
|
|
5
6
|
DataTable,
|
|
6
7
|
DataTableSkeleton,
|
|
@@ -13,11 +14,12 @@ import {
|
|
|
13
14
|
TableRow,
|
|
14
15
|
} from '@carbon/react';
|
|
15
16
|
import { showModal, useLayoutType, formatDate, parseDate } from '@openmrs/esm-framework';
|
|
16
|
-
import {
|
|
17
|
+
import { type OBSERVATION_INTERPRETATION } from '@openmrs/esm-patient-common-lib';
|
|
17
18
|
import { type GroupedObservation } from '../../types';
|
|
18
19
|
import styles from './individual-results-table.scss';
|
|
19
20
|
|
|
20
21
|
interface IndividualResultsTableProps {
|
|
22
|
+
patientUuid;
|
|
21
23
|
isLoading: boolean;
|
|
22
24
|
subRows: GroupedObservation;
|
|
23
25
|
index: number;
|
|
@@ -50,10 +52,15 @@ const getClasses = (interpretation: OBSERVATION_INTERPRETATION) => {
|
|
|
50
52
|
}
|
|
51
53
|
};
|
|
52
54
|
|
|
53
|
-
const IndividualResultsTable: React.FC<IndividualResultsTableProps> = ({
|
|
55
|
+
const IndividualResultsTable: React.FC<IndividualResultsTableProps> = ({
|
|
56
|
+
patientUuid,
|
|
57
|
+
isLoading,
|
|
58
|
+
subRows,
|
|
59
|
+
index,
|
|
60
|
+
title,
|
|
61
|
+
}) => {
|
|
54
62
|
const { t } = useTranslation();
|
|
55
63
|
const layout = useLayoutType();
|
|
56
|
-
const patientUuid = getPatientUuidFromStore();
|
|
57
64
|
const isDesktop = layout === 'small-desktop' || layout === 'large-desktop';
|
|
58
65
|
|
|
59
66
|
const headerTitle = t(title);
|
|
@@ -85,9 +92,14 @@ const IndividualResultsTable: React.FC<IndividualResultsTableProps> = ({ isLoadi
|
|
|
85
92
|
() =>
|
|
86
93
|
subRows?.entries.length &&
|
|
87
94
|
subRows.entries.map((row, i) => {
|
|
88
|
-
|
|
95
|
+
// Use observation-level range/units if available, otherwise fallback to node-level
|
|
96
|
+
// MappedObservation has range and units fields, but they may come from node-level
|
|
97
|
+
const displayRange = row.range ?? '';
|
|
98
|
+
const displayUnits = row.units ?? '';
|
|
89
99
|
const isString = isNaN(parseFloat(row.value));
|
|
90
100
|
|
|
101
|
+
const referenceRangeDisplay = formatRangeWithUnits(displayRange, displayUnits);
|
|
102
|
+
|
|
91
103
|
return {
|
|
92
104
|
...row,
|
|
93
105
|
id: `${i}-${index}`,
|
|
@@ -106,10 +118,10 @@ const IndividualResultsTable: React.FC<IndividualResultsTableProps> = ({ isLoadi
|
|
|
106
118
|
</span>
|
|
107
119
|
),
|
|
108
120
|
value: {
|
|
109
|
-
value: `${row.value} ${
|
|
121
|
+
value: `${row.value} ${displayUnits}`,
|
|
110
122
|
interpretation: row?.interpretation,
|
|
111
123
|
},
|
|
112
|
-
referenceRange:
|
|
124
|
+
referenceRange: referenceRangeDisplay,
|
|
113
125
|
};
|
|
114
126
|
}),
|
|
115
127
|
[index, subRows, launchResultsDialog],
|
|
@@ -21,10 +21,41 @@ describe('IndividualResultsTable', () => {
|
|
|
21
21
|
units: 'copies/ml',
|
|
22
22
|
flatName: 'HIV viral load-HIV viral load',
|
|
23
23
|
hasData: true,
|
|
24
|
+
range: '0 – 50', // Node-level range
|
|
25
|
+
lowNormal: 0,
|
|
26
|
+
hiNormal: 50,
|
|
24
27
|
},
|
|
25
28
|
],
|
|
26
29
|
} as GroupedObservation;
|
|
27
30
|
|
|
31
|
+
const mockSubRowsWithObservationRange = {
|
|
32
|
+
key: 'Alkaline phosphatase',
|
|
33
|
+
date: '2024-10-15',
|
|
34
|
+
flatName: 'Alkaline phosphatase',
|
|
35
|
+
entries: [
|
|
36
|
+
{
|
|
37
|
+
obsDatetime: '2024-10-15 03:20:19.0',
|
|
38
|
+
value: '15',
|
|
39
|
+
interpretation: 'CRITICALLY_LOW',
|
|
40
|
+
key: 'Alkaline phosphatase',
|
|
41
|
+
datatype: 'Numeric',
|
|
42
|
+
lowAbsolute: 0,
|
|
43
|
+
display: 'Alkaline phosphatase',
|
|
44
|
+
conceptUuid: '785AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
45
|
+
units: 'U/L',
|
|
46
|
+
flatName: 'Alkaline phosphatase',
|
|
47
|
+
hasData: true,
|
|
48
|
+
range: '35 – 147', // Observation-level range (different from node-level)
|
|
49
|
+
lowNormal: 35,
|
|
50
|
+
hiNormal: 147,
|
|
51
|
+
lowCritical: 25,
|
|
52
|
+
hiCritical: 200,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
range: '0 – 270', // Node-level range (fallback)
|
|
56
|
+
units: 'U/L',
|
|
57
|
+
} as GroupedObservation;
|
|
58
|
+
|
|
28
59
|
const mockEmptySubRows = {
|
|
29
60
|
key: 'HIV viral load',
|
|
30
61
|
date: '2024-10-15',
|
|
@@ -33,18 +64,49 @@ describe('IndividualResultsTable', () => {
|
|
|
33
64
|
} as GroupedObservation;
|
|
34
65
|
|
|
35
66
|
it('renders a loading skeleton when fetching results data', () => {
|
|
36
|
-
render(
|
|
67
|
+
render(
|
|
68
|
+
<IndividualResultsTable
|
|
69
|
+
patientUuid={'patient-uuid'}
|
|
70
|
+
isLoading={true}
|
|
71
|
+
subRows={mockEmptySubRows}
|
|
72
|
+
index={0}
|
|
73
|
+
title={'HIV viral load'}
|
|
74
|
+
/>,
|
|
75
|
+
);
|
|
37
76
|
|
|
38
77
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
|
39
78
|
});
|
|
40
79
|
|
|
41
80
|
it('renders a tabular overview of the available test result data', () => {
|
|
42
|
-
render(
|
|
81
|
+
render(
|
|
82
|
+
<IndividualResultsTable
|
|
83
|
+
patientUuid={'patient-uuid'}
|
|
84
|
+
isLoading={false}
|
|
85
|
+
subRows={mockSubRows}
|
|
86
|
+
index={0}
|
|
87
|
+
title={'HIV viral load'}
|
|
88
|
+
/>,
|
|
89
|
+
);
|
|
43
90
|
|
|
44
91
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
|
45
92
|
expect(screen.getByText(/15-Oct-2024/i)).toBeInTheDocument();
|
|
46
93
|
expect(screen.getByText(/test name/i)).toBeInTheDocument();
|
|
47
94
|
expect(screen.getByText(/reference range/i)).toBeInTheDocument();
|
|
48
|
-
expect(screen.getByRole('row', { name: /hiv viral load 45 copies\/ml
|
|
95
|
+
expect(screen.getByRole('row', { name: /hiv viral load 45 copies\/ml 0 – 50 copies\/ml/i })).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('uses observation-level range when available', () => {
|
|
99
|
+
render(
|
|
100
|
+
<IndividualResultsTable
|
|
101
|
+
patientUuid={'patient-uuid'}
|
|
102
|
+
isLoading={false}
|
|
103
|
+
subRows={mockSubRowsWithObservationRange}
|
|
104
|
+
index={0}
|
|
105
|
+
title={'Alkaline phosphatase'}
|
|
106
|
+
/>,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Should display observation-level range (35 – 147) not node-level (0 – 270)
|
|
110
|
+
expect(screen.getByRole('row', { name: /alkaline phosphatase 15 u\/l 35 – 147 u\/l/i })).toBeInTheDocument();
|
|
49
111
|
});
|
|
50
112
|
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { type OBSERVATION_INTERPRETATION } from '@openmrs/esm-patient-common-lib';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type Concept,
|
|
4
|
+
type ConceptMeta,
|
|
5
|
+
type FHIRObservationResource,
|
|
6
|
+
type ObsRecord,
|
|
7
|
+
observationInterpretation,
|
|
8
|
+
} from '../../types';
|
|
3
9
|
import styles from './lab-set-panel.scss';
|
|
4
10
|
|
|
5
|
-
export const getConceptUuid = (obs: FHIRObservationResource) => obs?.code.coding[0]
|
|
11
|
+
export const getConceptUuid = (obs: FHIRObservationResource | ObsRecord) => obs?.code.coding?.[0]?.code;
|
|
6
12
|
|
|
7
13
|
export const getClass = (interpretation: OBSERVATION_INTERPRETATION) => {
|
|
8
14
|
switch (interpretation) {
|
|
@@ -4,12 +4,12 @@ import { useTranslation } from 'react-i18next';
|
|
|
4
4
|
import { DataTableSkeleton, Button, Search, Form } from '@carbon/react';
|
|
5
5
|
import { CloseIcon, SearchIcon, useLayoutType } from '@openmrs/esm-framework';
|
|
6
6
|
import { EmptyState } from '@openmrs/esm-patient-common-lib';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import FilterContext from '../filter/filter-context';
|
|
8
|
+
import FilterEmptyState from '../ui-elements/reset-filters-empty-state/filter-empty-state.component';
|
|
9
9
|
import LabSetPanel from './lab-set-panel.component';
|
|
10
10
|
import Overlay from '../tablet-overlay/tablet-overlay.component';
|
|
11
|
-
import FilterContext from '../filter/filter-context';
|
|
12
11
|
import TimelineDataGroup from '../grouped-timeline/timeline-data-group.component';
|
|
12
|
+
import type { GroupedObservation } from '../../types';
|
|
13
13
|
import styles from './individual-results-table-tablet.scss';
|
|
14
14
|
|
|
15
15
|
interface IndividualResultsTableTabletProps {
|
|
@@ -233,7 +233,7 @@ const IndividualResultsTableTabletHeader: React.FC<IndividualResultsTableTabletH
|
|
|
233
233
|
<Form onSubmit={handleSearchTerm} className={styles.flexBaseline}>
|
|
234
234
|
<Search
|
|
235
235
|
autoFocus
|
|
236
|
-
labelText=
|
|
236
|
+
labelText={t('searchByTestName', 'Search by test name')}
|
|
237
237
|
onChange={(e) => setLocalSearchTerm(e.target.value)}
|
|
238
238
|
placeholder={t('searchByTestName', 'Search by test name')}
|
|
239
239
|
size="sm"
|
|
@@ -263,7 +263,7 @@ const IndividualResultsTableTabletHeader: React.FC<IndividualResultsTableTabletH
|
|
|
263
263
|
<Form onSubmit={handleSearchTerm} className={classNames(styles.flex)}>
|
|
264
264
|
<Search
|
|
265
265
|
autoFocus
|
|
266
|
-
labelText=
|
|
266
|
+
labelText={t('searchByTestName', 'Search by test name')}
|
|
267
267
|
onChange={(e) => setLocalSearchTerm(e.target.value)}
|
|
268
268
|
placeholder={t('searchByTestName', 'Search by test name')}
|
|
269
269
|
size="lg"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { formatRangeWithUnits } from '../grouped-timeline/reference-range-helpers';
|
|
4
5
|
import {
|
|
5
6
|
DataTable,
|
|
6
7
|
TableContainer,
|
|
@@ -70,7 +71,7 @@ const LabSetPanel: React.FC<LabSetPanelProps> = ({ panel, activePanel, setActive
|
|
|
70
71
|
hasRange
|
|
71
72
|
? panel.entries.map((test) => {
|
|
72
73
|
const units = test.units ?? '';
|
|
73
|
-
const range = test.range
|
|
74
|
+
const range = formatRangeWithUnits(test.range, units);
|
|
74
75
|
return {
|
|
75
76
|
id: test.conceptUuid,
|
|
76
77
|
testName: test.display,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo } from 'react';
|
|
2
|
-
import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
3
2
|
import useSWRInfinite from 'swr/infinite';
|
|
3
|
+
import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
4
4
|
import { extractMetaInformation, getConceptUuid } from './helper';
|
|
5
5
|
import {
|
|
6
6
|
type Concept,
|
|
@@ -159,32 +159,46 @@ export default function usePanelData(patientUuid: string) {
|
|
|
159
159
|
[observations],
|
|
160
160
|
);
|
|
161
161
|
|
|
162
|
-
const setObservations: Array<ObsRecord> = useMemo(
|
|
163
|
-
()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
162
|
+
const setObservations: Array<ObsRecord> = useMemo(() => {
|
|
163
|
+
if (!observations) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Create a map of individual observations for efficient lookup
|
|
168
|
+
const individualObsMap = new Map(individualObservations.map((obs) => [obs.id, obs]));
|
|
169
|
+
const usedIndividualObsIds = new Set<string>();
|
|
170
|
+
|
|
171
|
+
return observations
|
|
172
|
+
.filter((obs) => !!obs.hasMember)
|
|
173
|
+
.map((obs) => {
|
|
174
|
+
const relatedObs: Array<ObsRecord> = [];
|
|
175
|
+
obs.hasMember.forEach((memb) => {
|
|
176
|
+
const membUuid = memb.reference.split('/')[1];
|
|
177
|
+
const memberObs = individualObsMap.get(membUuid);
|
|
178
|
+
if (memberObs && !usedIndividualObsIds.has(membUuid)) {
|
|
179
|
+
relatedObs.push(memberObs);
|
|
180
|
+
usedIndividualObsIds.add(membUuid);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
...obs,
|
|
185
|
+
relatedObs,
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
}, [individualObservations, observations]);
|
|
189
|
+
|
|
190
|
+
const remainingIndividualObservations = useMemo(() => {
|
|
191
|
+
const usedIds = new Set<string>();
|
|
192
|
+
setObservations.forEach((setObs) => {
|
|
193
|
+
setObs.relatedObs.forEach((relatedObs) => {
|
|
194
|
+
usedIds.add(relatedObs.id);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
return individualObservations.filter((obs) => !usedIds.has(obs.id));
|
|
198
|
+
}, [individualObservations, setObservations]);
|
|
185
199
|
|
|
186
200
|
const panels = useMemo(() => {
|
|
187
|
-
const allPanels = [...
|
|
201
|
+
const allPanels = [...remainingIndividualObservations, ...setObservations].sort(
|
|
188
202
|
(obs1, obs2) => Date.parse(obs2.effectiveDateTime) - Date.parse(obs1.effectiveDateTime),
|
|
189
203
|
);
|
|
190
204
|
const usedConcepts: Set<string> = new Set();
|
|
@@ -195,7 +209,7 @@ export default function usePanelData(patientUuid: string) {
|
|
|
195
209
|
latestPanels.push(panel);
|
|
196
210
|
});
|
|
197
211
|
return latestPanels;
|
|
198
|
-
}, [
|
|
212
|
+
}, [remainingIndividualObservations, setObservations]);
|
|
199
213
|
|
|
200
214
|
const panelsData = useMemo(
|
|
201
215
|
() => ({
|