@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2714 → 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,84 @@
1
+ import useSWR from 'swr';
2
+ import { usePartographyEncounters } from '../partography.resource';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ export function useTemperatureData(patientUuid: string) {
6
+ const { encounters, isLoading, error, mutate } = usePartographyEncounters(patientUuid, 'temperature');
7
+ return { data: encounters, isLoading, error, mutate };
8
+ }
9
+
10
+ import { PARTOGRAPHY_CONCEPTS } from '../types';
11
+ import { toOmrsIsoString } from '@openmrs/esm-framework';
12
+
13
+ export function buildTemperatureObservation(formData: any): any[] {
14
+ const timeConfig = { defaultEncounterOffset: 0 };
15
+ const obsDatetime = toOmrsIsoString(new Date(Date.now() - timeConfig.defaultEncounterOffset));
16
+ const observations = [];
17
+ const tempValue =
18
+ formData.temperature !== undefined && formData.temperature !== null
19
+ ? formData.temperature
20
+ : formData.value !== undefined && formData.value !== null
21
+ ? formData.value
22
+ : formData.measurementValue;
23
+ if (tempValue !== undefined && tempValue !== null && tempValue !== '') {
24
+ observations.push({
25
+ concept: PARTOGRAPHY_CONCEPTS['temperature'],
26
+ value: parseFloat(tempValue),
27
+ obsDatetime,
28
+ });
29
+ }
30
+ // Add time observation if present
31
+ const timeValue = formData.exactTime || formData.timeSlot || formData.time;
32
+ if (timeValue) {
33
+ observations.push({
34
+ concept: PARTOGRAPHY_CONCEPTS['fetal-heart-rate-time'],
35
+ value: `Time: ${timeValue}`,
36
+ obsDatetime,
37
+ });
38
+ }
39
+ return observations;
40
+ }
41
+
42
+ export function transformTemperatureEncounterToChartData(encounters: any[]): any[] {
43
+ const chartData = [];
44
+ encounters.forEach((encounter) => {
45
+ const encounterTime = new Date(encounter.encounterDatetime).toLocaleTimeString('en-US', {
46
+ hour: '2-digit',
47
+ minute: '2-digit',
48
+ hour12: false,
49
+ });
50
+ encounter.obs?.forEach((obs) => {
51
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['temperature']) {
52
+ chartData.push({
53
+ group: 'Temperature',
54
+ time: encounterTime,
55
+ value: parseFloat(obs.value),
56
+ });
57
+ }
58
+ });
59
+ });
60
+ return chartData;
61
+ }
62
+
63
+ export function transformTemperatureEncounterToTableData(encounters: any[]): any[] {
64
+ const tableData = [];
65
+ encounters.forEach((encounter, index) => {
66
+ const encounterDate = new Date(encounter.encounterDatetime);
67
+ const dateTime = `${encounterDate.toLocaleDateString()} — ${encounterDate.toLocaleTimeString('en-US', {
68
+ hour: '2-digit',
69
+ minute: '2-digit',
70
+ hour12: false,
71
+ })}`;
72
+ encounter.obs?.forEach((obs, obsIndex) => {
73
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['temperature']) {
74
+ tableData.push({
75
+ id: `temperature-${index}-${obsIndex}`,
76
+ dateTime,
77
+ value: parseFloat(obs.value),
78
+ unit: '°C',
79
+ });
80
+ }
81
+ });
82
+ });
83
+ return tableData;
84
+ }
@@ -0,0 +1,173 @@
1
+ import { PARTOGRAPHY_CONCEPTS } from '../types';
2
+ import {
3
+ CONTRACTION_LEVEL_MILD_CONCEPT,
4
+ CONTRACTION_LEVEL_MODERATE_CONCEPT,
5
+ CONTRACTION_LEVEL_STRONG_CONCEPT,
6
+ MOULDING_NONE_CONCEPT,
7
+ MOULDING_SLIGHT_CONCEPT,
8
+ MOULDING_MODERATE_CONCEPT,
9
+ MOULDING_SEVERE_CONCEPT,
10
+ CONTRACTION_COUNT_CONCEPT,
11
+ URINE_VOLUME_CONCEPT,
12
+ } from '../../../config-schema';
13
+ import { toOmrsIsoString } from '@openmrs/esm-framework';
14
+ import { useTranslation } from 'react-i18next';
15
+
16
+ export function buildUterineContractionsObservation(formData: any): any[] {
17
+ const timeConfig = { defaultEncounterOffset: 0 };
18
+ const obsDatetime = toOmrsIsoString(new Date(Date.now() - timeConfig.defaultEncounterOffset));
19
+ const observations = [];
20
+ if (formData.value || formData.measurementValue) {
21
+ observations.push({
22
+ concept: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
23
+ value: parseFloat(formData.value || formData.measurementValue),
24
+ obsDatetime,
25
+ });
26
+ }
27
+ return observations;
28
+ }
29
+
30
+ export function transformUterineContractionsEncounterToChartData(
31
+ encounters: any[],
32
+ t: (key: string, defaultValue?: string, options?: any) => string,
33
+ ): any[] {
34
+ const chartData = [];
35
+ encounters.forEach((encounter) => {
36
+ const encounterTime = new Date(encounter.encounterDatetime).toLocaleTimeString('en-US', {
37
+ hour: '2-digit',
38
+ minute: '2-digit',
39
+ hour12: false,
40
+ });
41
+ encounter.obs?.forEach((obs) => {
42
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['uterine-contractions']) {
43
+ chartData.push({
44
+ group: t('Uterine Contractions'),
45
+ time: encounterTime,
46
+ value: parseFloat(obs.value),
47
+ });
48
+ }
49
+ });
50
+ });
51
+ return chartData;
52
+ }
53
+
54
+ export function transformUterineContractionsEncounterToTableData(
55
+ encounters: any[],
56
+ t: (key: string, defaultValue?: string, options?: any) => string,
57
+ ): any[] {
58
+ const tableData = [];
59
+ // Helper to map protein/acetone values to display string
60
+ const codeToPlus = (code) => {
61
+ // Accept both string and number
62
+ if (!code) {
63
+ return '';
64
+ }
65
+ if (code === MOULDING_NONE_CONCEPT || code === '0' || code === 0) {
66
+ return '0';
67
+ }
68
+ if (code === MOULDING_SLIGHT_CONCEPT || code === '+' || code === 1) {
69
+ return '+';
70
+ }
71
+ if (code === MOULDING_MODERATE_CONCEPT || code === '++' || code === 2) {
72
+ return '++';
73
+ }
74
+ if (code === MOULDING_SEVERE_CONCEPT || code === '+++' || code === 3) {
75
+ return '+++';
76
+ }
77
+ return String(code);
78
+ };
79
+
80
+ encounters.forEach((encounter, index) => {
81
+ const encounterDate = new Date(encounter.encounterDatetime);
82
+ const date = encounterDate.toLocaleDateString();
83
+ // Find all relevant obs for this encounter
84
+ let timeSlot = '';
85
+ let contractionCount = '';
86
+ let contractionLevel = '';
87
+ let protein = '';
88
+ let acetone = '';
89
+ let volume = '';
90
+
91
+ if (Array.isArray(encounter.obs)) {
92
+ for (const obs of encounter.obs) {
93
+ // Time Slot: use concept or value string
94
+ if (
95
+ obs.concept.uuid === PARTOGRAPHY_CONCEPTS['time-slot'] ||
96
+ (typeof obs.value === 'string' && obs.value.startsWith('TimeSlot:'))
97
+ ) {
98
+ if (typeof obs.value === 'string') {
99
+ const match = obs.value.match(/TimeSlot:\s*(.+)/);
100
+ if (match) {
101
+ timeSlot = match[1].trim();
102
+ } else {
103
+ timeSlot = obs.value;
104
+ }
105
+ } else {
106
+ timeSlot = String(obs.value);
107
+ }
108
+ }
109
+ // Contraction count
110
+ if (obs.concept.uuid === CONTRACTION_COUNT_CONCEPT) {
111
+ contractionCount = String(obs.value);
112
+ }
113
+ // Contraction level (none, mild, moderate, strong)
114
+ if (
115
+ obs.concept.uuid === MOULDING_NONE_CONCEPT || // none
116
+ obs.concept.uuid === CONTRACTION_LEVEL_MILD_CONCEPT || // mild
117
+ obs.concept.uuid === CONTRACTION_LEVEL_MODERATE_CONCEPT || // moderate
118
+ obs.concept.uuid === CONTRACTION_LEVEL_STRONG_CONCEPT // strong
119
+ ) {
120
+ if (obs.concept.uuid === MOULDING_NONE_CONCEPT) {
121
+ contractionLevel = 'none';
122
+ }
123
+ if (obs.concept.uuid === CONTRACTION_LEVEL_MILD_CONCEPT) {
124
+ contractionLevel = 'mild';
125
+ }
126
+ if (obs.concept.uuid === CONTRACTION_LEVEL_MODERATE_CONCEPT) {
127
+ contractionLevel = 'moderate';
128
+ }
129
+ if (obs.concept.uuid === CONTRACTION_LEVEL_STRONG_CONCEPT) {
130
+ contractionLevel = 'strong';
131
+ }
132
+ }
133
+ // Protein
134
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['protein-level']) {
135
+ protein = codeToPlus(obs.value);
136
+ }
137
+ // Acetone (ketone)
138
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['ketone-level']) {
139
+ acetone = codeToPlus(obs.value);
140
+ }
141
+ // Volume
142
+ if (obs.concept.uuid === PARTOGRAPHY_CONCEPTS['urine-volume'] || obs.concept.uuid === URINE_VOLUME_CONCEPT) {
143
+ volume = String(obs.value);
144
+ }
145
+ }
146
+ }
147
+ // Show row if date is present (do not require timeSlot/volume)
148
+ if (date) {
149
+ tableData.push({
150
+ id: `uterine-contractions-${index}`,
151
+ date,
152
+ timeSlot,
153
+ contractionCount,
154
+ contractionLevel,
155
+ protein,
156
+ acetone,
157
+ volume,
158
+ });
159
+ }
160
+ });
161
+ return tableData;
162
+ }
163
+
164
+ import { usePartographyEncounters } from '../partography.resource';
165
+ export function useUterineContractionsData(patientUuid: string) {
166
+ const { t } = useTranslation();
167
+ const { encounters, isLoading, error, mutate } = usePartographyEncounters(patientUuid, 'uterine-contractions');
168
+ let localizedError = error;
169
+ if (error) {
170
+ localizedError = t('Failed to load uterine contractions data');
171
+ }
172
+ return { data: encounters, isLoading, error: localizedError, mutate };
173
+ }
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import {
3
+ DataTable,
4
+ TableContainer,
5
+ Table,
6
+ TableHead,
7
+ TableRow,
8
+ TableHeader,
9
+ TableBody,
10
+ TableCell,
11
+ Pagination,
12
+ } from '@carbon/react';
13
+
14
+ interface TemperatureTableRow {
15
+ id: string;
16
+ date: string;
17
+ timeSlot: string;
18
+ exactTime: string;
19
+ temperature: number;
20
+ }
21
+
22
+ interface TemperatureTableProps {
23
+ tableData: TemperatureTableRow[];
24
+ currentPage: number;
25
+ pageSize: number;
26
+ totalItems: number;
27
+ controlSize: 'sm' | 'md';
28
+ onPageChange: (page: number) => void;
29
+ onPageSizeChange: (size: number) => void;
30
+ }
31
+
32
+ const TemperatureTable: React.FC<TemperatureTableProps> = ({
33
+ tableData,
34
+ currentPage,
35
+ pageSize,
36
+ totalItems,
37
+ controlSize,
38
+ onPageChange,
39
+ onPageSizeChange,
40
+ }) => {
41
+ // Calculate pagination
42
+ const startIndex = (currentPage - 1) * pageSize;
43
+ const endIndex = startIndex + pageSize;
44
+ const paginatedData = tableData.slice(startIndex, endIndex);
45
+
46
+ const tableHeaders = [
47
+ { key: 'date', header: 'Date' },
48
+ { key: 'exactTime', header: 'Time' },
49
+ { key: 'temperature', header: 'Temperature (°C)' },
50
+ ];
51
+
52
+ return (
53
+ <div>
54
+ <DataTable rows={paginatedData} headers={tableHeaders}>
55
+ {({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
56
+ <TableContainer title="" description="">
57
+ <Table {...getTableProps()} size="sm">
58
+ <TableHead>
59
+ <TableRow>
60
+ {headers.map((header) => (
61
+ <TableHeader {...getHeaderProps({ header })} key={header.key}>
62
+ {header.header}
63
+ </TableHeader>
64
+ ))}
65
+ </TableRow>
66
+ </TableHead>
67
+ <TableBody>
68
+ {rows.map((row) => (
69
+ <TableRow {...getRowProps({ row })} key={row.id}>
70
+ {row.cells.map((cell) => (
71
+ <TableCell key={cell.id}>{cell.value}</TableCell>
72
+ ))}
73
+ </TableRow>
74
+ ))}
75
+ </TableBody>
76
+ </Table>
77
+ </TableContainer>
78
+ )}
79
+ </DataTable>
80
+ {totalItems > 0 && (
81
+ <Pagination
82
+ page={currentPage}
83
+ totalItems={totalItems}
84
+ pageSize={pageSize}
85
+ pageSizes={[5, 10, 20, 50]}
86
+ onChange={(event) => {
87
+ onPageChange(event.page);
88
+ if (event.pageSize !== pageSize) {
89
+ onPageSizeChange(event.pageSize);
90
+ }
91
+ }}
92
+ size={controlSize}
93
+ />
94
+ )}
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default TemperatureTable;
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import {
3
+ DataTable,
4
+ Table,
5
+ TableBody,
6
+ TableCell,
7
+ TableContainer,
8
+ TableHead,
9
+ TableHeader,
10
+ TableRow,
11
+ Pagination,
12
+ } from '@carbon/react';
13
+
14
+ export interface UterineContractionsTableRow {
15
+ id: string;
16
+ date: string;
17
+ timeSlot: string;
18
+ contractionCount: string;
19
+ contractionLevel: string;
20
+ protein?: string;
21
+ acetone?: string;
22
+ volume?: string;
23
+ }
24
+
25
+ interface UterineContractionsTableProps {
26
+ tableData: UterineContractionsTableRow[];
27
+ currentPage: number;
28
+ pageSize: number;
29
+ totalItems: number;
30
+ controlSize: 'sm' | 'md';
31
+ onPageChange: (page: number) => void;
32
+ onPageSizeChange: (size: number) => void;
33
+ }
34
+
35
+ const UterineContractionsTable: React.FC<UterineContractionsTableProps> = ({
36
+ tableData,
37
+ currentPage,
38
+ pageSize,
39
+ totalItems,
40
+ controlSize,
41
+ onPageChange,
42
+ onPageSizeChange,
43
+ }) => {
44
+ return (
45
+ <TableContainer>
46
+ <Table size={controlSize} useZebraStyles>
47
+ <TableHead>
48
+ <TableRow>
49
+ <TableHeader>Date</TableHeader>
50
+ <TableHeader>Time Slot</TableHeader>
51
+ <TableHeader>Contraction Count</TableHeader>
52
+ <TableHeader>Contraction Level</TableHeader>
53
+ <TableHeader>Protein</TableHeader>
54
+ <TableHeader>Acetone</TableHeader>
55
+ <TableHeader>Volume (ml)</TableHeader>
56
+ </TableRow>
57
+ </TableHead>
58
+ <TableBody>
59
+ {tableData.map((row) => (
60
+ <TableRow key={row.id}>
61
+ <TableCell>{row.date}</TableCell>
62
+ <TableCell>{row.timeSlot}</TableCell>
63
+ <TableCell>{row.contractionCount}</TableCell>
64
+ <TableCell>{row.contractionLevel}</TableCell>
65
+ <TableCell>{row.protein || ''}</TableCell>
66
+ <TableCell>{row.acetone || ''}</TableCell>
67
+ <TableCell>{row.volume || ''}</TableCell>
68
+ </TableRow>
69
+ ))}
70
+ </TableBody>
71
+ </Table>
72
+ <Pagination
73
+ page={currentPage}
74
+ pageSize={pageSize}
75
+ totalItems={totalItems}
76
+ pageSizes={[5, 10, 20, 50]}
77
+ onChange={({ page, pageSize }) => {
78
+ onPageChange(page);
79
+ onPageSizeChange(pageSize);
80
+ }}
81
+ />
82
+ </TableContainer>
83
+ );
84
+ };
85
+
86
+ export default UterineContractionsTable;