@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2716 → 5.4.2-pre.2722

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.
Files changed (66) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/dist/805.js +1 -0
  3. package/dist/805.js.map +1 -0
  4. package/dist/kenyaemr-esm-patient-clinical-view-app.js +2 -2
  5. package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +27 -27
  6. package/dist/main.js +27 -27
  7. package/dist/main.js.map +1 -1
  8. package/dist/routes.json +1 -1
  9. package/package.json +1 -1
  10. package/src/config-schema.ts +97 -0
  11. package/src/contact-list/contact-tracing-history.component.tsx +18 -15
  12. package/src/maternal-and-child-health/partography/components/pulse-bp-graph.component.tsx +1 -0
  13. package/src/maternal-and-child-health/partography/components/temperature-graph.component.tsx +218 -0
  14. package/src/maternal-and-child-health/partography/components/uterine-contractions-graph.component.tsx +209 -0
  15. package/src/maternal-and-child-health/partography/forms/cervical-contractions-form.component.tsx +211 -0
  16. package/src/maternal-and-child-health/partography/forms/cervix-form.component.tsx +354 -0
  17. package/src/maternal-and-child-health/partography/forms/drugs-iv-fluids-form.component.tsx +321 -0
  18. package/src/maternal-and-child-health/partography/forms/fetal-heart-rate-form.component.tsx +275 -0
  19. package/src/maternal-and-child-health/partography/forms/index.ts +9 -0
  20. package/src/maternal-and-child-health/partography/forms/membrane-amniotic-fluid-form.component.tsx +330 -0
  21. package/src/maternal-and-child-health/partography/forms/oxytocin-form.component.tsx +207 -0
  22. package/src/maternal-and-child-health/partography/forms/pulse-bp-form.component.tsx +174 -0
  23. package/src/maternal-and-child-health/partography/forms/temperature-form.component.tsx +210 -0
  24. package/src/maternal-and-child-health/partography/forms/time-picker-dropdown.component.tsx +218 -0
  25. package/src/maternal-and-child-health/partography/forms/time-picker-dropdown.scss +107 -0
  26. package/src/maternal-and-child-health/partography/forms/time-picker-with-clock.component.tsx +174 -0
  27. package/src/maternal-and-child-health/partography/forms/time-picker-with-clock.scss +178 -0
  28. package/src/maternal-and-child-health/partography/forms/urine-test-form.component.tsx +255 -0
  29. package/src/maternal-and-child-health/partography/forms/useCervixData.ts +16 -0
  30. package/src/maternal-and-child-health/partography/graphs/cervical-contractions-graph.component.tsx +266 -0
  31. package/src/maternal-and-child-health/partography/graphs/cervix-graph.component.tsx +429 -0
  32. package/src/maternal-and-child-health/partography/graphs/drugs-iv-fluids-graph-wrapper.component.tsx +163 -0
  33. package/src/maternal-and-child-health/partography/graphs/drugs-iv-fluids-graph.component.tsx +82 -0
  34. package/src/maternal-and-child-health/partography/graphs/fetal-heart-rate-graph.component.tsx +359 -0
  35. package/src/maternal-and-child-health/partography/graphs/index.ts +10 -0
  36. package/src/maternal-and-child-health/partography/graphs/membrane-amniotic-fluid-graph.component.tsx +266 -0
  37. package/src/maternal-and-child-health/partography/graphs/oxytocin-graph-wrapper.component.tsx +190 -0
  38. package/src/maternal-and-child-health/partography/graphs/oxytocin-graph.component.tsx +126 -0
  39. package/src/maternal-and-child-health/partography/graphs/partograph-graph.component.tsx +266 -0
  40. package/src/maternal-and-child-health/partography/graphs/pulse-bp-graph-wrapper.component.tsx +298 -0
  41. package/src/maternal-and-child-health/partography/graphs/pulse-bp-graph.component.tsx +267 -0
  42. package/src/maternal-and-child-health/partography/graphs/temperature-graph.component.tsx +242 -0
  43. package/src/maternal-and-child-health/partography/graphs/urine-test-graph.component.tsx +246 -0
  44. package/src/maternal-and-child-health/partography/partograph.component.tsx +2141 -118
  45. package/src/maternal-and-child-health/partography/partography-dashboard.meta.ts +8 -0
  46. package/src/maternal-and-child-health/partography/partography-data-form.scss +163 -0
  47. package/src/maternal-and-child-health/partography/partography.resource.ts +233 -326
  48. package/src/maternal-and-child-health/partography/partography.scss +1341 -3
  49. package/src/maternal-and-child-health/partography/resources/blood-pressure.resource.ts +96 -0
  50. package/src/maternal-and-child-health/partography/resources/cervical-dilation.resource.ts +109 -0
  51. package/src/maternal-and-child-health/partography/resources/cervix.resource.ts +362 -0
  52. package/src/maternal-and-child-health/partography/resources/descent-of-head.resource.ts +101 -0
  53. package/src/maternal-and-child-health/partography/resources/drugs-fluids.resource.ts +88 -0
  54. package/src/maternal-and-child-health/partography/resources/fetal-heart-rate.resource.ts +122 -0
  55. package/src/maternal-and-child-health/partography/resources/maternal-pulse.resource.ts +77 -0
  56. package/src/maternal-and-child-health/partography/resources/membrane-amniotic-fluid.resource.ts +108 -0
  57. package/src/maternal-and-child-health/partography/resources/oxytocin.resource.ts +159 -0
  58. package/src/maternal-and-child-health/partography/resources/progress-events.resource.ts +6 -0
  59. package/src/maternal-and-child-health/partography/resources/pulse-bp-combined.resource.ts +53 -0
  60. package/src/maternal-and-child-health/partography/resources/temperature.resource.ts +84 -0
  61. package/src/maternal-and-child-health/partography/resources/uterine-contractions.resource.ts +173 -0
  62. package/src/maternal-and-child-health/partography/table/temperature-table.component.tsx +99 -0
  63. package/src/maternal-and-child-health/partography/table/uterine-contractions-table.component.tsx +86 -0
  64. package/src/maternal-and-child-health/partography/types/index.ts +319 -101
  65. package/dist/397.js +0 -1
  66. package/dist/397.js.map +0 -1
@@ -0,0 +1,242 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ Button,
5
+ DataTable,
6
+ TableContainer,
7
+ Table,
8
+ TableHead,
9
+ TableRow,
10
+ TableHeader,
11
+ TableBody,
12
+ TableCell,
13
+ Pagination,
14
+ } from '@carbon/react';
15
+ import { Add, ChartColumn, Table as TableIcon } from '@carbon/react/icons';
16
+ import styles from '../partography.scss';
17
+ import { usePaginationInfo } from '@openmrs/esm-patient-common-lib';
18
+
19
+ interface TemperatureData {
20
+ timeSlot: string;
21
+ exactTime: string;
22
+ temperature: number;
23
+ date?: string;
24
+ id?: string;
25
+ }
26
+
27
+ interface TemperatureGraphProps {
28
+ data?: TemperatureData[];
29
+ tableData?: Array<{
30
+ id: string;
31
+ date: string;
32
+ timeSlot: string;
33
+ exactTime: string;
34
+ temperature: number;
35
+ }>;
36
+ viewMode?: 'graph' | 'table';
37
+ currentPage?: number;
38
+ pageSize?: number;
39
+ totalItems?: number;
40
+ controlSize?: 'sm' | 'md';
41
+ onAddData?: () => void;
42
+ onViewModeChange?: (mode: 'graph' | 'table') => void;
43
+ onPageChange?: (page: number) => void;
44
+ onPageSizeChange?: (size: number) => void;
45
+ isAddButtonDisabled?: boolean;
46
+ }
47
+
48
+ const TemperatureGraph: React.FC<TemperatureGraphProps> = ({
49
+ data = [],
50
+ tableData = [],
51
+ viewMode = 'graph',
52
+ currentPage = 1,
53
+ pageSize = 5,
54
+ totalItems = 0,
55
+ controlSize = 'sm',
56
+ onAddData,
57
+ onViewModeChange,
58
+ onPageChange,
59
+ onPageSizeChange,
60
+ isAddButtonDisabled = true,
61
+ }) => {
62
+ const { t } = useTranslation();
63
+
64
+ const startIndex = (currentPage - 1) * pageSize;
65
+ const endIndex = startIndex + pageSize;
66
+ const paginatedData = tableData.slice(startIndex, endIndex);
67
+ const { pageSizes: calculatedPageSizes, itemsDisplayed } = usePaginationInfo(
68
+ pageSize,
69
+ Math.ceil(totalItems / pageSize),
70
+ currentPage,
71
+ totalItems,
72
+ );
73
+
74
+ const tableHeaders = [
75
+ { key: 'date', header: t('date', 'Date') },
76
+ { key: 'exactTime', header: t('exactTime', 'Time') },
77
+ { key: 'temperature', header: t('temperature', 'Temperature (°C)') },
78
+ ];
79
+
80
+ const timeColumns = data.map((item, idx) =>
81
+ item.exactTime || item.timeSlot ? item.exactTime || item.timeSlot : '--',
82
+ );
83
+
84
+ const getTemperatureStatus = (temperature: number): string => {
85
+ if (temperature < 36.1) {
86
+ return styles.temperatureLow;
87
+ }
88
+ if (temperature >= 36.1 && temperature <= 37.2) {
89
+ return styles.temperatureNormal;
90
+ }
91
+ if (temperature > 37.2) {
92
+ return styles.temperatureHigh;
93
+ }
94
+ return '';
95
+ };
96
+
97
+ const createGridData = () => {
98
+ const gridData: Record<string, { temperature: number }> = {};
99
+ data.forEach((item) => {
100
+ const key = item.timeSlot;
101
+ gridData[key] = {
102
+ temperature: item.temperature,
103
+ };
104
+ });
105
+ return gridData;
106
+ };
107
+ const gridData = createGridData();
108
+
109
+ return (
110
+ <div className={styles.fetalHeartRateSection}>
111
+ <div className={styles.fetalHeartRateContainer}>
112
+ <div className={styles.fetalHeartRateHeader}>
113
+ <div className={styles.fetalHeartRateHeaderLeft}>
114
+ <h3 className={styles.fetalHeartRateTitle}>Temperature</h3>
115
+ <div className={styles.fetalHeartRateControls}>
116
+ <span className={styles.legendText}>Normal: 36.1-37.2°C | Low: &lt;36.1°C | High: &gt;37.2°C</span>
117
+ </div>
118
+ </div>
119
+ <div className={styles.fetalHeartRateHeaderRight}>
120
+ <div className={styles.fetalHeartRateActions}>
121
+ <div className={styles.viewSwitcher}>
122
+ <Button
123
+ kind={viewMode === 'graph' ? 'primary' : 'secondary'}
124
+ size={controlSize}
125
+ hasIconOnly
126
+ iconDescription={t('graphView', 'Graph View')}
127
+ onClick={() => onViewModeChange?.('graph')}
128
+ className={styles.viewButton}>
129
+ <ChartColumn />
130
+ </Button>
131
+ <Button
132
+ kind={viewMode === 'table' ? 'primary' : 'secondary'}
133
+ size={controlSize}
134
+ hasIconOnly
135
+ iconDescription={t('tableView', 'Table View')}
136
+ onClick={() => onViewModeChange?.('table')}
137
+ className={styles.viewButton}>
138
+ <TableIcon />
139
+ </Button>
140
+ </div>
141
+ <Button
142
+ kind="primary"
143
+ size={controlSize}
144
+ renderIcon={Add}
145
+ iconDescription="Add temperature data"
146
+ disabled={isAddButtonDisabled}
147
+ onClick={onAddData}
148
+ className={styles.addButton}>
149
+ Add
150
+ </Button>
151
+ </div>
152
+ </div>
153
+ </div>
154
+
155
+ {viewMode === 'graph' ? (
156
+ <div className={styles.membraneGrid}>
157
+ <div className={styles.gridContainer}>
158
+ <div className={styles.gridHeader}>
159
+ <div className={styles.gridCell}>{t('time', 'Time')}</div>
160
+ {timeColumns.map((timeColumn) => (
161
+ <div key={timeColumn} className={styles.gridCell}>
162
+ {timeColumn}
163
+ </div>
164
+ ))}
165
+ </div>
166
+
167
+ <div className={styles.gridRow}>
168
+ <div className={styles.gridRowLabel}>{t('temperature', 'Temp °C')}</div>
169
+ {data.map((item, idx) => (
170
+ <div
171
+ key={`temp-${idx}`}
172
+ className={`${styles.gridCell} ${item.temperature ? getTemperatureStatus(item.temperature) : ''}`}>
173
+ {item.temperature !== undefined && item.temperature !== null ? item.temperature : '--'}
174
+ </div>
175
+ ))}
176
+ </div>
177
+ </div>
178
+ </div>
179
+ ) : (
180
+ <div className={styles.tableContainer}>
181
+ {paginatedData.length > 0 ? (
182
+ <>
183
+ <DataTable rows={paginatedData} headers={tableHeaders}>
184
+ {({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
185
+ <TableContainer title="" description="">
186
+ <Table {...getTableProps()} size="sm">
187
+ <TableHead>
188
+ <TableRow>
189
+ {headers.map((header) => (
190
+ <TableHeader {...getHeaderProps({ header })} key={header.key}>
191
+ {header.header}
192
+ </TableHeader>
193
+ ))}
194
+ </TableRow>
195
+ </TableHead>
196
+ <TableBody>
197
+ {rows.map((row) => (
198
+ <TableRow {...getRowProps({ row })} key={row.id}>
199
+ {row.cells.map((cell) => (
200
+ <TableCell key={cell.id}>{cell.value}</TableCell>
201
+ ))}
202
+ </TableRow>
203
+ ))}
204
+ </TableBody>
205
+ </Table>
206
+ </TableContainer>
207
+ )}
208
+ </DataTable>
209
+
210
+ {totalItems > 0 && (
211
+ <Pagination
212
+ page={currentPage}
213
+ totalItems={totalItems}
214
+ pageSize={pageSize}
215
+ pageSizes={calculatedPageSizes}
216
+ onChange={(event) => {
217
+ onPageChange?.(event.page);
218
+ if (event.pageSize !== pageSize) {
219
+ onPageSizeChange?.(event.pageSize);
220
+ }
221
+ }}
222
+ size={controlSize}
223
+ />
224
+ )}
225
+ {totalItems > 0 && <div className={styles.paginationInfo}>{itemsDisplayed}</div>}
226
+ </>
227
+ ) : (
228
+ <div className={styles.emptyState}>
229
+ <p>{t('noDataAvailable', 'No temperature data available')}</p>
230
+ <Button kind="primary" size={controlSize} renderIcon={Add} onClick={onAddData}>
231
+ {t('addFirstDataPoint', 'Add first data point')}
232
+ </Button>
233
+ </div>
234
+ )}
235
+ </div>
236
+ )}
237
+ </div>
238
+ </div>
239
+ );
240
+ };
241
+
242
+ export default TemperatureGraph;
@@ -0,0 +1,246 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ Button,
5
+ DataTable,
6
+ TableContainer,
7
+ Table,
8
+ TableHead,
9
+ TableRow,
10
+ TableHeader,
11
+ TableBody,
12
+ TableCell,
13
+ Pagination,
14
+ } from '@carbon/react';
15
+ import { Add, ChartColumn, Table as TableIcon } from '@carbon/react/icons';
16
+ import styles from '../partography.scss';
17
+ import { usePaginationInfo } from '@openmrs/esm-patient-common-lib';
18
+
19
+ interface UrineTestData {
20
+ timeSlot: string;
21
+ exactTime: string;
22
+ protein: string;
23
+ acetone: string;
24
+ volume: number;
25
+ timeSampleCollected: string;
26
+ timeResultsReturned: string;
27
+ date?: string;
28
+ id?: string;
29
+ }
30
+
31
+ interface UrineTestGraphProps {
32
+ data?: UrineTestData[];
33
+ tableData?: Array<{
34
+ id: string;
35
+ date: string;
36
+ timeSlot: string;
37
+ exactTime: string;
38
+ protein: string;
39
+ acetone: string;
40
+ volume: number;
41
+ timeSampleCollected: string;
42
+ timeResultsReturned: string;
43
+ }>;
44
+ viewMode?: 'graph' | 'table';
45
+ currentPage?: number;
46
+ pageSize?: number;
47
+ totalItems?: number;
48
+ controlSize?: 'sm' | 'md';
49
+ onAddData?: () => void;
50
+ onViewModeChange?: (mode: 'graph' | 'table') => void;
51
+ onPageChange?: (page: number) => void;
52
+ onPageSizeChange?: (size: number) => void;
53
+ isAddButtonDisabled?: boolean;
54
+ }
55
+
56
+ const UrineTestGraph: React.FC<UrineTestGraphProps> = ({
57
+ data = [],
58
+ tableData = [],
59
+ viewMode = 'graph',
60
+ currentPage = 1,
61
+ pageSize = 5,
62
+ totalItems = 0,
63
+ controlSize = 'sm',
64
+ onAddData,
65
+ onViewModeChange,
66
+ onPageChange,
67
+ onPageSizeChange,
68
+ isAddButtonDisabled = true,
69
+ }) => {
70
+ const { t } = useTranslation();
71
+
72
+ const startIndex = (currentPage - 1) * pageSize;
73
+ const endIndex = startIndex + pageSize;
74
+ const paginatedData = tableData.slice(startIndex, endIndex);
75
+ const { pageSizes: calculatedPageSizes, itemsDisplayed } = usePaginationInfo(
76
+ pageSize,
77
+ Math.ceil(totalItems / pageSize),
78
+ currentPage,
79
+ totalItems,
80
+ );
81
+
82
+ const tableHeaders = [
83
+ { key: 'date', header: t('date', 'Date') },
84
+ { key: 'timeSlot', header: t('timeSlot', 'Time Slot') },
85
+ { key: 'protein', header: t('protein', 'Protein') },
86
+ { key: 'acetone', header: t('acetone', 'Acetone') },
87
+ { key: 'volume', header: t('volume', 'Volume (ml)') },
88
+ { key: 'timeSampleCollected', header: t('timeSampleCollected', 'Sample Collected') },
89
+ { key: 'timeResultsReturned', header: t('timeResultsReturned', 'Results Returned') },
90
+ ];
91
+
92
+ const timeColumns = Array.from(
93
+ { length: Math.max(13, data.length) },
94
+ (_, colIndex) => data[colIndex]?.timeSlot || '',
95
+ );
96
+
97
+ const gridData = data;
98
+
99
+ return (
100
+ <div className={styles.fetalHeartRateSection}>
101
+ <div className={styles.fetalHeartRateContainer}>
102
+ <div className={styles.fetalHeartRateHeader}>
103
+ <div className={styles.fetalHeartRateHeaderLeft}>
104
+ <h3 className={styles.fetalHeartRateTitle}>Urine Test</h3>
105
+ <div className={styles.fetalHeartRateControls}>
106
+ <span className={styles.legendText}>Protein & Acetone: 0, +, ++, +++ | Volume in ml</span>
107
+ </div>
108
+ </div>
109
+ <div className={styles.fetalHeartRateHeaderRight}>
110
+ <div className={styles.fetalHeartRateActions}>
111
+ <div className={styles.viewSwitcher}>
112
+ <Button
113
+ kind={viewMode === 'graph' ? 'primary' : 'secondary'}
114
+ size={controlSize}
115
+ hasIconOnly
116
+ iconDescription={t('graphView', 'Graph View')}
117
+ onClick={() => onViewModeChange?.('graph')}
118
+ className={styles.viewButton}>
119
+ <ChartColumn />
120
+ </Button>
121
+ <Button
122
+ kind={viewMode === 'table' ? 'primary' : 'secondary'}
123
+ size={controlSize}
124
+ hasIconOnly
125
+ iconDescription={t('tableView', 'Table View')}
126
+ onClick={() => onViewModeChange?.('table')}
127
+ className={styles.viewButton}>
128
+ <TableIcon />
129
+ </Button>
130
+ </div>
131
+ <Button
132
+ kind="primary"
133
+ size={controlSize}
134
+ renderIcon={Add}
135
+ iconDescription="Add urine test data"
136
+ disabled={isAddButtonDisabled}
137
+ onClick={onAddData}
138
+ className={styles.addButton}>
139
+ Add
140
+ </Button>
141
+ </div>
142
+ </div>
143
+ </div>
144
+
145
+ {viewMode === 'graph' ? (
146
+ <div className={styles.membraneGrid}>
147
+ <div className={styles.gridContainer}>
148
+ <div className={styles.gridRow}>
149
+ <div className={styles.gridRowLabel}>{t('protein', 'Protein')}</div>
150
+ {timeColumns.map((_, colIndex) => {
151
+ const cellData = gridData[colIndex];
152
+ return (
153
+ <div key={`protein-${colIndex}`} className={styles.gridCell}>
154
+ {cellData?.protein || ''}
155
+ </div>
156
+ );
157
+ })}
158
+ </div>
159
+ <div className={styles.gridRow}>
160
+ <div className={styles.gridRowLabel}>{t('acetone', 'Acetone')}</div>
161
+ {timeColumns.map((_, colIndex) => {
162
+ const cellData = gridData[colIndex];
163
+ return (
164
+ <div key={`acetone-${colIndex}`} className={styles.gridCell}>
165
+ {cellData?.acetone || ''}
166
+ </div>
167
+ );
168
+ })}
169
+ </div>
170
+ <div className={styles.gridRow}>
171
+ <div className={styles.gridRowLabel}>{t('volume', 'Volume')}</div>
172
+ {timeColumns.map((_, colIndex) => {
173
+ const cellData = gridData[colIndex];
174
+ return (
175
+ <div key={`volume-${colIndex}`} className={styles.gridCell}>
176
+ {cellData?.volume != null ? String(cellData.volume) : ''}
177
+ </div>
178
+ );
179
+ })}
180
+ </div>
181
+ </div>
182
+ </div>
183
+ ) : (
184
+ <div className={styles.tableContainer}>
185
+ {paginatedData.length > 0 ? (
186
+ <>
187
+ <DataTable rows={paginatedData} headers={tableHeaders}>
188
+ {({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
189
+ <TableContainer title="" description="">
190
+ <Table {...getTableProps()} size="sm">
191
+ <TableHead>
192
+ <TableRow>
193
+ {headers.map((header) => (
194
+ <TableHeader {...getHeaderProps({ header })} key={header.key}>
195
+ {header.header}
196
+ </TableHeader>
197
+ ))}
198
+ </TableRow>
199
+ </TableHead>
200
+ <TableBody>
201
+ {rows.map((row) => (
202
+ <TableRow {...getRowProps({ row })} key={row.id}>
203
+ {row.cells.map((cell) => (
204
+ <TableCell key={cell.id}>{cell.value}</TableCell>
205
+ ))}
206
+ </TableRow>
207
+ ))}
208
+ </TableBody>
209
+ </Table>
210
+ </TableContainer>
211
+ )}
212
+ </DataTable>
213
+
214
+ {totalItems > 0 && (
215
+ <Pagination
216
+ page={currentPage}
217
+ totalItems={totalItems}
218
+ pageSize={pageSize}
219
+ pageSizes={calculatedPageSizes}
220
+ onChange={(event) => {
221
+ onPageChange?.(event.page);
222
+ if (event.pageSize !== pageSize) {
223
+ onPageSizeChange?.(event.pageSize);
224
+ }
225
+ }}
226
+ size={controlSize}
227
+ />
228
+ )}
229
+ {totalItems > 0 && <div className={styles.paginationInfo}>{itemsDisplayed}</div>}
230
+ </>
231
+ ) : (
232
+ <div className={styles.emptyState}>
233
+ <p>{t('noDataAvailable', 'No urine test data available')}</p>
234
+ <Button kind="primary" size={controlSize} renderIcon={Add} onClick={onAddData}>
235
+ {t('addFirstDataPoint', 'Add first data point')}
236
+ </Button>
237
+ </div>
238
+ )}
239
+ </div>
240
+ )}
241
+ </div>
242
+ </div>
243
+ );
244
+ };
245
+
246
+ export default UrineTestGraph;