@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2758 → 5.4.2-pre.2764
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 +4 -4
- package/dist/127.js +1 -1
- package/dist/{805.js → 189.js} +1 -1
- package/dist/189.js.map +1 -0
- package/dist/40.js +1 -1
- package/dist/916.js +1 -1
- package/dist/kenyaemr-esm-patient-clinical-view-app.js +2 -2
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +36 -36
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +58 -36
- package/src/maternal-and-child-health/partography/components/temperature-graph.component.tsx +0 -4
- package/src/maternal-and-child-health/partography/components/uterine-contractions-graph.component.tsx +33 -11
- package/src/maternal-and-child-health/partography/forms/cervical-contractions-form.component.tsx +124 -136
- package/src/maternal-and-child-health/partography/forms/cervix-form.component.tsx +23 -14
- package/src/maternal-and-child-health/partography/forms/drugs-iv-fluids-form.component.tsx +6 -10
- package/src/maternal-and-child-health/partography/forms/fetal-heart-rate-form.component.tsx +36 -13
- package/src/maternal-and-child-health/partography/forms/time-picker-dropdown.component.tsx +27 -46
- package/src/maternal-and-child-health/partography/forms/useCervixData.ts +2 -2
- package/src/maternal-and-child-health/partography/graphs/cervix-graph.component.tsx +56 -18
- package/src/maternal-and-child-health/partography/graphs/fetal-heart-rate-graph.component.tsx +36 -23
- package/src/maternal-and-child-health/partography/graphs/pulse-bp-graph.component.tsx +10 -5
- package/src/maternal-and-child-health/partography/partograph.component.tsx +315 -371
- package/src/maternal-and-child-health/partography/partography.resource.ts +788 -230
- package/src/maternal-and-child-health/partography/partography.scss +68 -40
- package/src/maternal-and-child-health/partography/resources/cervix.resource.ts +79 -76
- package/src/maternal-and-child-health/partography/resources/uterine-contractions.resource.ts +33 -12
- package/src/maternal-and-child-health/partography/types/index.ts +94 -0
- package/translations/am.json +0 -8
- package/translations/en.json +0 -8
- package/translations/sw.json +0 -8
- package/dist/805.js.map +0 -1
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { Add, ChartColumn, Table as TableIcon } from '@carbon/react/icons';
|
|
20
20
|
import { openmrsFetch, useLayoutType, useSession } from '@openmrs/esm-framework';
|
|
21
21
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
22
|
+
import { codeToPlus, contractionLevelUuidMap, labelToUuid, contractionLevelUuidToLabel } from './types';
|
|
22
23
|
import { useTranslation } from 'react-i18next';
|
|
23
24
|
import {
|
|
24
25
|
CervicalContractionsForm,
|
|
@@ -65,7 +66,6 @@ enum ScaleTypes {
|
|
|
65
66
|
LINEAR = 'linear',
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
// --- INLINE TYPE DEFINITIONS ADDED FOR CONTEXT ---
|
|
69
69
|
type GraphDefinition = {
|
|
70
70
|
id: string;
|
|
71
71
|
title: string;
|
|
@@ -83,22 +83,19 @@ type ChartDataPoint = {
|
|
|
83
83
|
group: string;
|
|
84
84
|
value: number;
|
|
85
85
|
};
|
|
86
|
-
// --- END INLINE TYPE DEFINITIONS ---
|
|
87
86
|
|
|
88
|
-
// --- CERVIX CHART OPTIONS: MEDICAL PARTOGRAPH STYLING ---
|
|
89
87
|
const CERVIX_CHART_OPTIONS = {
|
|
90
88
|
axes: {
|
|
91
89
|
bottom: {
|
|
92
|
-
title: '',
|
|
90
|
+
title: '',
|
|
93
91
|
mapsTo: 'hour',
|
|
94
92
|
scaleType: ScaleTypes.LINEAR,
|
|
95
93
|
domain: [0, 10],
|
|
96
94
|
tick: {
|
|
97
|
-
count: 21,
|
|
95
|
+
count: 21,
|
|
98
96
|
rotation: 0,
|
|
99
|
-
values: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10],
|
|
97
|
+
values: [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10],
|
|
100
98
|
formatter: (hour) => {
|
|
101
|
-
// Format as hours with 30-minute intervals
|
|
102
99
|
if (hour === 0) {
|
|
103
100
|
return '0';
|
|
104
101
|
} else if (hour === 0.5) {
|
|
@@ -125,8 +122,6 @@ const CERVIX_CHART_OPTIONS = {
|
|
|
125
122
|
ticks: {
|
|
126
123
|
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
127
124
|
formatter: (value) => {
|
|
128
|
-
// Show both cervical dilation and descent of head values
|
|
129
|
-
// Direct mapping: 5=high position, 1=most descended
|
|
130
125
|
if (value >= 1 && value <= 5) {
|
|
131
126
|
return `${value}cm / D${value}`;
|
|
132
127
|
} else if (value === 0) {
|
|
@@ -173,13 +168,11 @@ const CERVIX_CHART_OPTIONS = {
|
|
|
173
168
|
clickable: false,
|
|
174
169
|
},
|
|
175
170
|
};
|
|
176
|
-
// --- END CERVIX CHART OPTIONS ---
|
|
177
171
|
|
|
178
172
|
type PartographyProps = {
|
|
179
173
|
patientUuid: string;
|
|
180
174
|
};
|
|
181
175
|
|
|
182
|
-
// Skeleton Components for Loading States with inline animation
|
|
183
176
|
const GraphSkeleton: React.FC = () => {
|
|
184
177
|
const skeletonStyle = {
|
|
185
178
|
background: 'linear-gradient(90deg, #f4f4f4 25%, #e0e0e0 50%, #f4f4f4 75%)',
|
|
@@ -188,7 +181,6 @@ const GraphSkeleton: React.FC = () => {
|
|
|
188
181
|
borderRadius: '4px',
|
|
189
182
|
};
|
|
190
183
|
|
|
191
|
-
// Add keyframes to head if not already added
|
|
192
184
|
React.useEffect(() => {
|
|
193
185
|
if (!document.querySelector('#skeleton-keyframes')) {
|
|
194
186
|
const style = document.createElement('style');
|
|
@@ -218,7 +210,6 @@ const GraphSkeleton: React.FC = () => {
|
|
|
218
210
|
marginBottom: '1rem',
|
|
219
211
|
}}
|
|
220
212
|
/>
|
|
221
|
-
{/* Skeleton for custom time labels (cervix specific) */}
|
|
222
213
|
<div style={{ marginTop: '1rem', borderTop: '1px solid #e0e0e0', paddingTop: '0.5rem' }}>
|
|
223
214
|
<div style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.25rem' }}>
|
|
224
215
|
{Array.from({ length: 11 }).map((_, index) => (
|
|
@@ -287,13 +278,10 @@ const TableSkeleton: React.FC = () => {
|
|
|
287
278
|
const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
288
279
|
const { t } = useTranslation();
|
|
289
280
|
|
|
290
|
-
// Development flag to enable dummy data (set to false for production)
|
|
291
281
|
const ENABLE_DUMMY_DATA = false;
|
|
292
282
|
|
|
293
|
-
// Local state for regular partography data (not saved to OpenMRS yet)
|
|
294
283
|
const [localPartographyData, setLocalPartographyData] = useState<Record<string, any[]>>({});
|
|
295
284
|
|
|
296
|
-
// Local state for fetal heart rate data
|
|
297
285
|
const [localFetalHeartRateData, setLocalFetalHeartRateData] = useState<
|
|
298
286
|
Array<{
|
|
299
287
|
hour: number;
|
|
@@ -303,7 +291,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
303
291
|
}>
|
|
304
292
|
>([]);
|
|
305
293
|
|
|
306
|
-
// Backend membrane amniotic fluid data
|
|
307
294
|
const {
|
|
308
295
|
membraneAmnioticFluidEntries,
|
|
309
296
|
isLoading: isMembraneAmnioticFluidLoading,
|
|
@@ -339,7 +326,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
339
326
|
}>
|
|
340
327
|
>([]);
|
|
341
328
|
|
|
342
|
-
// Pulse and BP backend data
|
|
343
329
|
const {
|
|
344
330
|
data: loadedPulseData,
|
|
345
331
|
isLoading: isPulseDataLoading,
|
|
@@ -353,7 +339,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
353
339
|
mutate: mutateBPData,
|
|
354
340
|
} = usePartographyData(patientUuid || '', 'blood-pressure');
|
|
355
341
|
|
|
356
|
-
// Temperature backend data
|
|
357
342
|
const {
|
|
358
343
|
data: loadedTemperatureData,
|
|
359
344
|
isLoading: isTemperatureDataLoading,
|
|
@@ -361,7 +346,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
361
346
|
mutate: mutateTemperatureData,
|
|
362
347
|
} = usePartographyData(patientUuid || '', 'temperature');
|
|
363
348
|
|
|
364
|
-
// Urine Test backend data
|
|
365
349
|
const {
|
|
366
350
|
data: urineTestEncounters = [],
|
|
367
351
|
isLoading: isUrineTestLoading,
|
|
@@ -369,34 +353,9 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
369
353
|
mutate: mutateUrineTestData,
|
|
370
354
|
} = usePartographyData(patientUuid || '', 'urine-analysis');
|
|
371
355
|
|
|
372
|
-
// Transform backend urine test data to UrineTestData[]
|
|
373
356
|
const urineTestData = useMemo(() => {
|
|
374
|
-
// Map coded values to +/++/+++ for protein/acetone
|
|
375
|
-
const codeToPlus = (code) => {
|
|
376
|
-
switch (code) {
|
|
377
|
-
case '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA':
|
|
378
|
-
case 'ZERO':
|
|
379
|
-
case '0':
|
|
380
|
-
return '0';
|
|
381
|
-
case '1362AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA':
|
|
382
|
-
case 'ONE PLUS':
|
|
383
|
-
case '+':
|
|
384
|
-
return '+';
|
|
385
|
-
case '1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA':
|
|
386
|
-
case 'TWO PLUS':
|
|
387
|
-
case '++':
|
|
388
|
-
return '++';
|
|
389
|
-
case '1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA':
|
|
390
|
-
case 'THREE PLUS':
|
|
391
|
-
case '+++':
|
|
392
|
-
return '+++';
|
|
393
|
-
default:
|
|
394
|
-
return code;
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
357
|
return (urineTestEncounters || []).map((encounter, index) => {
|
|
398
358
|
const obs = encounter.obs || [];
|
|
399
|
-
// Helper to get obs value by concept
|
|
400
359
|
const getObsValue = (conceptUuid) => {
|
|
401
360
|
const found = obs.find((o) => o.concept.uuid === conceptUuid);
|
|
402
361
|
if (!found) {
|
|
@@ -409,7 +368,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
409
368
|
}
|
|
410
369
|
return v != null ? String(v) : '';
|
|
411
370
|
};
|
|
412
|
-
|
|
371
|
+
|
|
413
372
|
const getTime = () => {
|
|
414
373
|
const timeObs = obs.find(
|
|
415
374
|
(o) =>
|
|
@@ -425,9 +384,8 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
425
384
|
}
|
|
426
385
|
return '';
|
|
427
386
|
};
|
|
428
|
-
|
|
387
|
+
|
|
429
388
|
const getTimeSlot = () => {
|
|
430
|
-
// Try concept for time-slot
|
|
431
389
|
const slotObs = obs.find(
|
|
432
390
|
(o) =>
|
|
433
391
|
o.concept.uuid === PARTOGRAPHY_CONCEPTS['time-slot'] ||
|
|
@@ -445,7 +403,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
445
403
|
}
|
|
446
404
|
return '';
|
|
447
405
|
};
|
|
448
|
-
|
|
406
|
+
|
|
449
407
|
const getSampleCollected = () => {
|
|
450
408
|
const found = obs.find(
|
|
451
409
|
(o) =>
|
|
@@ -468,7 +426,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
468
426
|
}
|
|
469
427
|
return '';
|
|
470
428
|
};
|
|
471
|
-
|
|
429
|
+
|
|
472
430
|
const getVolume = () => {
|
|
473
431
|
const found = obs.find(
|
|
474
432
|
(o) =>
|
|
@@ -494,7 +452,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
494
452
|
}
|
|
495
453
|
return '';
|
|
496
454
|
};
|
|
497
|
-
|
|
455
|
+
|
|
498
456
|
let timeSlot = '';
|
|
499
457
|
const eventDescObs = obs.find(
|
|
500
458
|
(o) =>
|
|
@@ -508,7 +466,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
508
466
|
timeSlot = match[1];
|
|
509
467
|
}
|
|
510
468
|
}
|
|
511
|
-
|
|
469
|
+
|
|
512
470
|
let volumeRaw = getVolume();
|
|
513
471
|
let volume: number | undefined = undefined;
|
|
514
472
|
if (typeof volumeRaw === 'number') {
|
|
@@ -518,7 +476,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
518
476
|
}
|
|
519
477
|
const sampleCollected = getSampleCollected();
|
|
520
478
|
const resultReturned = getResultReturned();
|
|
521
|
-
|
|
479
|
+
|
|
522
480
|
return {
|
|
523
481
|
id: `urine-test-${index}`,
|
|
524
482
|
date: new Date(encounter.encounterDatetime).toLocaleDateString(),
|
|
@@ -556,7 +514,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
556
514
|
});
|
|
557
515
|
};
|
|
558
516
|
|
|
559
|
-
// Load cervix data from OpenMRS
|
|
560
517
|
const {
|
|
561
518
|
cervixData: loadedCervixData,
|
|
562
519
|
existingTimeEntries,
|
|
@@ -567,7 +524,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
567
524
|
mutate: mutateCervixData,
|
|
568
525
|
} = useCervixFormData(patientUuid || '');
|
|
569
526
|
|
|
570
|
-
// Load fetal heart rate data from OpenMRS with null safety
|
|
571
527
|
const {
|
|
572
528
|
fetalHeartRateData: loadedFetalHeartRateData = [],
|
|
573
529
|
isLoading: isFetalHeartRateLoading = false,
|
|
@@ -575,7 +531,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
575
531
|
mutate: mutateFetalHeartRateData = () => {},
|
|
576
532
|
} = useFetalHeartRateData(patientUuid || '');
|
|
577
533
|
|
|
578
|
-
// Fetch actual drug orders from OpenMRS
|
|
579
534
|
const {
|
|
580
535
|
drugOrders: loadedDrugOrders = [],
|
|
581
536
|
isLoading: isDrugOrdersLoading = false,
|
|
@@ -583,11 +538,8 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
583
538
|
mutate: mutateDrugOrders = () => {},
|
|
584
539
|
} = useDrugOrders(patientUuid || '');
|
|
585
540
|
|
|
586
|
-
// Debug: Log drug orders data
|
|
587
541
|
useEffect(() => {
|
|
588
542
|
if (patientUuid) {
|
|
589
|
-
// Drug orders status logged in development only
|
|
590
|
-
|
|
591
543
|
if (drugOrdersError) {
|
|
592
544
|
console.error('Drug Orders Error:', drugOrdersError);
|
|
593
545
|
}
|
|
@@ -618,57 +570,93 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
618
570
|
const [pulseBPViewMode, setPulseBPViewMode] = useState<'graph' | 'table'>('graph');
|
|
619
571
|
const [temperatureViewMode, setTemperatureViewMode] = useState<'graph' | 'table'>('graph');
|
|
620
572
|
const [urineTestViewMode, setUrineTestViewMode] = useState<'graph' | 'table'>('graph');
|
|
573
|
+
function getInitialPageSize(key, fallback = 10) {
|
|
574
|
+
if (typeof window !== 'undefined') {
|
|
575
|
+
const stored = window.localStorage.getItem(key);
|
|
576
|
+
if (stored && !isNaN(Number(stored))) {
|
|
577
|
+
return Number(stored);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return fallback;
|
|
581
|
+
}
|
|
621
582
|
const [fetalHeartRateCurrentPage, setFetalHeartRateCurrentPage] = useState(1);
|
|
622
|
-
const [fetalHeartRatePageSize, setFetalHeartRatePageSize] = useState(
|
|
583
|
+
const [fetalHeartRatePageSize, setFetalHeartRatePageSize] = useState(() =>
|
|
584
|
+
getInitialPageSize('fetalHeartRatePageSize'),
|
|
585
|
+
);
|
|
623
586
|
const [membraneAmnioticFluidCurrentPage, setMembraneAmnioticFluidCurrentPage] = useState(1);
|
|
624
|
-
const [membraneAmnioticFluidPageSize, setMembraneAmnioticFluidPageSize] = useState(
|
|
587
|
+
const [membraneAmnioticFluidPageSize, setMembraneAmnioticFluidPageSize] = useState(() =>
|
|
588
|
+
getInitialPageSize('membraneAmnioticFluidPageSize'),
|
|
589
|
+
);
|
|
625
590
|
const [cervicalContractionsCurrentPage, setCervicalContractionsCurrentPage] = useState(1);
|
|
626
|
-
const [cervicalContractionsPageSize, setCervicalContractionsPageSize] = useState(
|
|
591
|
+
const [cervicalContractionsPageSize, setCervicalContractionsPageSize] = useState(() =>
|
|
592
|
+
getInitialPageSize('cervicalContractionsPageSize'),
|
|
593
|
+
);
|
|
627
594
|
const [oxytocinCurrentPage, setOxytocinCurrentPage] = useState(1);
|
|
628
|
-
const [oxytocinPageSize, setOxytocinPageSize] = useState(
|
|
595
|
+
const [oxytocinPageSize, setOxytocinPageSize] = useState(() => getInitialPageSize('oxytocinPageSize'));
|
|
629
596
|
const [drugsIVFluidsCurrentPage, setDrugsIVFluidsCurrentPage] = useState(1);
|
|
597
|
+
const [drugsIVFluidsPageSize, setDrugsIVFluidsPageSize] = useState(() => getInitialPageSize('drugsIVFluidsPageSize'));
|
|
630
598
|
const [pulseBPCurrentPage, setPulseBPCurrentPage] = useState(1);
|
|
599
|
+
const [pulseBPPageSize, setPulseBPPageSize] = useState(() => getInitialPageSize('pulseBPPageSize'));
|
|
631
600
|
const [temperatureCurrentPage, setTemperatureCurrentPage] = useState(1);
|
|
632
|
-
const [temperaturePageSize, setTemperaturePageSize] = useState(
|
|
601
|
+
const [temperaturePageSize, setTemperaturePageSize] = useState(() => getInitialPageSize('temperaturePageSize'));
|
|
633
602
|
const [urineTestCurrentPage, setUrineTestCurrentPage] = useState(1);
|
|
634
|
-
const [urineTestPageSize, setUrineTestPageSize] = useState(
|
|
635
|
-
|
|
636
|
-
|
|
603
|
+
const [urineTestPageSize, setUrineTestPageSize] = useState(() => getInitialPageSize('urineTestPageSize'));
|
|
604
|
+
|
|
605
|
+
// Persist page size changes
|
|
606
|
+
function persistPageSize(key, value) {
|
|
607
|
+
if (typeof window !== 'undefined') {
|
|
608
|
+
window.localStorage.setItem(key, String(value));
|
|
609
|
+
}
|
|
610
|
+
}
|
|
637
611
|
const [currentPage, setCurrentPage] = useState<Record<string, number>>({});
|
|
638
612
|
const [pageSize, setPageSize] = useState<Record<string, number>>({});
|
|
639
613
|
const [isLoading, setIsLoading] = useState<Record<string, boolean>>({});
|
|
640
614
|
|
|
641
|
-
// Transform cervix data to match the existing format expected by the chart
|
|
642
615
|
const cervixFormData = useMemo(() => {
|
|
643
|
-
// Use OpenMRS data if available
|
|
644
616
|
const dataToUse = loadedCervixData.length > 0 ? loadedCervixData : [];
|
|
645
617
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
618
|
+
// If all hours are the same, fallback to using the row index as the hour
|
|
619
|
+
let processedData = dataToUse
|
|
620
|
+
.filter((data) => {
|
|
621
|
+
const hasHour = data.hour !== null && data.hour !== undefined && !isNaN(data.hour);
|
|
622
|
+
// Accept empty time, but always show fallback in table
|
|
623
|
+
return (
|
|
624
|
+
hasHour &&
|
|
625
|
+
data.cervicalDilation !== null &&
|
|
626
|
+
!isNaN(data.cervicalDilation) &&
|
|
627
|
+
data.descentOfHead !== null &&
|
|
628
|
+
!isNaN(data.descentOfHead)
|
|
629
|
+
);
|
|
630
|
+
})
|
|
631
|
+
.map((data, idx, arr) => ({
|
|
632
|
+
hour: data.hour,
|
|
633
|
+
time: data.time && data.time.trim() !== '' ? data.time : '--:--',
|
|
634
|
+
cervicalDilation: data.cervicalDilation,
|
|
635
|
+
descentOfHead: data.descentOfHead,
|
|
652
636
|
entryDate: new Date(data.encounterDatetime).toLocaleDateString(),
|
|
653
637
|
entryTime: new Date(data.encounterDatetime).toLocaleTimeString(),
|
|
654
|
-
|
|
655
|
-
|
|
638
|
+
_originalHour: data.hour,
|
|
639
|
+
_rowIndex: idx,
|
|
640
|
+
}));
|
|
641
|
+
|
|
642
|
+
// If all non-null hours are the same, override hour with row index
|
|
643
|
+
const uniqueHours = Array.from(
|
|
644
|
+
new Set(processedData.map((d) => d.hour).filter((h) => h !== null && h !== undefined)),
|
|
645
|
+
);
|
|
646
|
+
if (uniqueHours.length === 1 && processedData.length > 1) {
|
|
647
|
+
processedData = processedData.map((d, idx) => ({ ...d, hour: idx }));
|
|
648
|
+
}
|
|
656
649
|
|
|
657
|
-
// Return dummy data if no processed data and dummy data is enabled, otherwise return processed data
|
|
658
650
|
return processedData.length > 0 ? processedData : ENABLE_DUMMY_DATA ? generateExtendedDummyData() : [];
|
|
659
651
|
}, [loadedCervixData, ENABLE_DUMMY_DATA]);
|
|
660
652
|
|
|
661
|
-
// Compute existingTimeEntries from both local and OpenMRS data
|
|
662
653
|
const computedExistingTimeEntries = useMemo(() => {
|
|
663
|
-
// Use the existing time entries from OpenMRS only
|
|
664
654
|
return existingTimeEntries;
|
|
665
655
|
}, [existingTimeEntries]);
|
|
666
656
|
|
|
667
|
-
// Compute combined fetal heart rate data from both local and OpenMRS sources
|
|
668
657
|
const computedFetalHeartRateData = useMemo(() => {
|
|
669
658
|
const combined = [...localFetalHeartRateData];
|
|
670
659
|
|
|
671
|
-
// Add OpenMRS data if available and not already in local data
|
|
672
660
|
if (loadedFetalHeartRateData?.length > 0) {
|
|
673
661
|
loadedFetalHeartRateData.forEach((openMrsEntry) => {
|
|
674
662
|
const exists = combined.find(
|
|
@@ -676,10 +664,9 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
676
664
|
);
|
|
677
665
|
|
|
678
666
|
if (!exists) {
|
|
679
|
-
// Transform OpenMRS data to match local data structure
|
|
680
667
|
const transformedEntry = {
|
|
681
668
|
hour: openMrsEntry.hour,
|
|
682
|
-
value: openMrsEntry.fetalHeartRate,
|
|
669
|
+
value: openMrsEntry.fetalHeartRate,
|
|
683
670
|
group: 'Fetal Heart Rate',
|
|
684
671
|
time: openMrsEntry.time,
|
|
685
672
|
};
|
|
@@ -688,7 +675,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
688
675
|
});
|
|
689
676
|
}
|
|
690
677
|
|
|
691
|
-
// Sort by hour and time
|
|
692
678
|
const sorted = combined.sort((a, b) => {
|
|
693
679
|
if (a.hour !== b.hour) {
|
|
694
680
|
return a.hour - b.hour;
|
|
@@ -729,9 +715,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
729
715
|
if (!isLoading) {
|
|
730
716
|
let chartData: ChartDataPoint[] = [];
|
|
731
717
|
|
|
732
|
-
// Special handling for pulse and BP combined encounters
|
|
733
718
|
if (graphType === 'maternal-pulse' || graphType === 'blood-pressure') {
|
|
734
|
-
// Collect all obs for pulse and BP from all encounters
|
|
735
719
|
chartData = [];
|
|
736
720
|
if (Array.isArray(encounters)) {
|
|
737
721
|
encounters.forEach((encounter) => {
|
|
@@ -772,7 +756,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
772
756
|
});
|
|
773
757
|
}
|
|
774
758
|
} else if (localPartographyData[graphType] && localPartographyData[graphType].length > 0) {
|
|
775
|
-
// Transform local data to chart format
|
|
776
759
|
chartData = localPartographyData[graphType].map((item, index) => ({
|
|
777
760
|
hour: index + 1, // Use index as hour for now
|
|
778
761
|
group: graphType,
|
|
@@ -802,7 +785,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
802
785
|
return { encounters, isLoading, mutate };
|
|
803
786
|
};
|
|
804
787
|
|
|
805
|
-
// Function to generate dummy data for different graph types
|
|
806
788
|
const generateDummyDataForGraph = (graphType: string): ChartDataPoint[] => {
|
|
807
789
|
const baseTimeEntries = [
|
|
808
790
|
{ hour: 0, time: '08:00' },
|
|
@@ -820,7 +802,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
820
802
|
hour: entry.hour,
|
|
821
803
|
time: entry.time,
|
|
822
804
|
group: 'Fetal Heart Rate',
|
|
823
|
-
value: 140 + Math.random() * 20,
|
|
805
|
+
value: 140 + Math.random() * 20,
|
|
824
806
|
}));
|
|
825
807
|
|
|
826
808
|
case 'maternal-pulse':
|
|
@@ -828,7 +810,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
828
810
|
hour: entry.hour,
|
|
829
811
|
time: entry.time,
|
|
830
812
|
group: 'Maternal Pulse',
|
|
831
|
-
value: 75 + Math.random() * 15,
|
|
813
|
+
value: 75 + Math.random() * 15,
|
|
832
814
|
}));
|
|
833
815
|
|
|
834
816
|
case 'blood-pressure':
|
|
@@ -837,13 +819,13 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
837
819
|
hour: entry.hour,
|
|
838
820
|
time: entry.time,
|
|
839
821
|
group: 'Systolic',
|
|
840
|
-
value: 115 + Math.random() * 10,
|
|
822
|
+
value: 115 + Math.random() * 10,
|
|
841
823
|
})),
|
|
842
824
|
...baseTimeEntries.map((entry) => ({
|
|
843
825
|
hour: entry.hour,
|
|
844
826
|
time: entry.time,
|
|
845
827
|
group: 'Diastolic',
|
|
846
|
-
value: 75 + Math.random() * 5,
|
|
828
|
+
value: 75 + Math.random() * 5,
|
|
847
829
|
})),
|
|
848
830
|
];
|
|
849
831
|
|
|
@@ -1181,31 +1163,16 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1181
1163
|
contractionCount: string;
|
|
1182
1164
|
timeSlot: string;
|
|
1183
1165
|
}) => {
|
|
1184
|
-
const contractionLevelUuidMap: Record<string, string> = {
|
|
1185
|
-
none: '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
1186
|
-
mild: '1498AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
1187
|
-
moderate: '1499AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
1188
|
-
strong: '166788AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
1189
|
-
};
|
|
1190
1166
|
const contractionLevel = formData.contractionLevel || 'none';
|
|
1191
1167
|
const contractionLevelValue = contractionLevelUuidMap[contractionLevel];
|
|
1192
|
-
const contractionLevelUuid = contractionLevelValue; // For coded obs, concept and value are the same
|
|
1193
|
-
const contractionCountConcept = '159682AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
1194
|
-
// Always send contractionCount as a number
|
|
1195
1168
|
const contractionCount = parseInt(formData.contractionCount || '1', 10);
|
|
1196
1169
|
const timeSlot = formData.timeSlot || new Date().toISOString().substring(11, 16);
|
|
1197
1170
|
|
|
1198
|
-
// Debug info removed for linting
|
|
1199
|
-
|
|
1200
|
-
// Always send both obs: count (numeric) and level (coded)
|
|
1201
1171
|
const encounterFormData = {
|
|
1202
|
-
contractionLevelValue, // UUID for level (none, mild, moderate, strong)
|
|
1203
|
-
contractionLevelUuid,
|
|
1204
1172
|
contractionCount,
|
|
1205
|
-
|
|
1173
|
+
contractionLevel: contractionLevelValue,
|
|
1206
1174
|
timeSlot,
|
|
1207
1175
|
};
|
|
1208
|
-
// Payload prepared for submission
|
|
1209
1176
|
try {
|
|
1210
1177
|
const saveResult = await createPartographyEncounter(patientUuid, 'uterine-contractions', encounterFormData);
|
|
1211
1178
|
if (saveResult.success) {
|
|
@@ -1370,7 +1337,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1370
1337
|
timeSampleCollected: string;
|
|
1371
1338
|
timeResultsReturned: string;
|
|
1372
1339
|
}) => {
|
|
1373
|
-
// Validate data before adding
|
|
1374
1340
|
if (
|
|
1375
1341
|
!formData.timeSlot ||
|
|
1376
1342
|
!formData.exactTime ||
|
|
@@ -1384,24 +1350,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1384
1350
|
return;
|
|
1385
1351
|
}
|
|
1386
1352
|
|
|
1387
|
-
// Map label to UUID for protein and acetone/ketone
|
|
1388
|
-
const labelToUuid = (label: string) => {
|
|
1389
|
-
switch (label) {
|
|
1390
|
-
case '0':
|
|
1391
|
-
return '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
1392
|
-
case '+':
|
|
1393
|
-
return '1362AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
1394
|
-
case '++':
|
|
1395
|
-
return '1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
1396
|
-
case '+++':
|
|
1397
|
-
return '1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
1398
|
-
default:
|
|
1399
|
-
return label;
|
|
1400
|
-
}
|
|
1401
|
-
};
|
|
1402
|
-
|
|
1403
1353
|
try {
|
|
1404
|
-
// Get current time in HH:mm format
|
|
1405
1354
|
const now = new Date();
|
|
1406
1355
|
const pad = (n) => n.toString().padStart(2, '0');
|
|
1407
1356
|
const currentTime = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
@@ -1419,7 +1368,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1419
1368
|
}
|
|
1420
1369
|
};
|
|
1421
1370
|
|
|
1422
|
-
// Generate table data for membrane amniotic fluid from backend only
|
|
1423
1371
|
const getMembraneAmnioticFluidTableData = () => {
|
|
1424
1372
|
return membraneAmnioticFluidEntries.map((data, index) => ({
|
|
1425
1373
|
id: data.id || `maf-${index}`,
|
|
@@ -1479,26 +1427,9 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1479
1427
|
if (obs.concept.uuid === '159682AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') {
|
|
1480
1428
|
contractionCount = String(obs.value);
|
|
1481
1429
|
}
|
|
1482
|
-
|
|
1483
|
-
if (
|
|
1484
|
-
|
|
1485
|
-
obs.concept.uuid === '1498AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' || // mild
|
|
1486
|
-
obs.concept.uuid === '1499AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' || // moderate
|
|
1487
|
-
obs.concept.uuid === '166788AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' // strong
|
|
1488
|
-
) {
|
|
1489
|
-
// Map UUID to label
|
|
1490
|
-
if (obs.concept.uuid === '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') {
|
|
1491
|
-
contractionLevel = 'none';
|
|
1492
|
-
}
|
|
1493
|
-
if (obs.concept.uuid === '1498AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') {
|
|
1494
|
-
contractionLevel = 'mild';
|
|
1495
|
-
}
|
|
1496
|
-
if (obs.concept.uuid === '1499AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') {
|
|
1497
|
-
contractionLevel = 'moderate';
|
|
1498
|
-
}
|
|
1499
|
-
if (obs.concept.uuid === '166788AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA') {
|
|
1500
|
-
contractionLevel = 'strong';
|
|
1501
|
-
}
|
|
1430
|
+
const contractionLabel = contractionLevelUuidToLabel(obs.concept.uuid);
|
|
1431
|
+
if (contractionLabel !== obs.concept.uuid) {
|
|
1432
|
+
contractionLevel = contractionLabel;
|
|
1502
1433
|
}
|
|
1503
1434
|
}
|
|
1504
1435
|
}
|
|
@@ -1512,12 +1443,8 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1512
1443
|
});
|
|
1513
1444
|
};
|
|
1514
1445
|
|
|
1515
|
-
// Generate table data for oxytocin (use backend data only)
|
|
1516
1446
|
const getOxytocinTableData = () => {
|
|
1517
|
-
// Only map oxytocin-specific fields, do not include any event-description or urine test fields
|
|
1518
1447
|
return loadedOxytocinData.map((data, index) => {
|
|
1519
|
-
// Defensive: Only use fields that are expected for oxytocin
|
|
1520
|
-
// If backend returns extra obs, ignore them
|
|
1521
1448
|
return {
|
|
1522
1449
|
id: `oxy-${index}`,
|
|
1523
1450
|
date: data.encounterDatetime ? new Date(data.encounterDatetime).toLocaleDateString() : '',
|
|
@@ -1560,22 +1487,23 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1560
1487
|
|
|
1561
1488
|
// Generate table data for pulse and BP from backend
|
|
1562
1489
|
const getPulseBPTableData = () => {
|
|
1563
|
-
//
|
|
1564
|
-
const
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1490
|
+
// Prepare BP data as array of {datetime, systolic, diastolic}
|
|
1491
|
+
const bpEntries = (loadedBPData || [])
|
|
1492
|
+
.map((encounter) => {
|
|
1493
|
+
const systolicObs = encounter.obs.find((obs) => obs.concept.uuid === PARTOGRAPHY_CONCEPTS['systolic-bp']);
|
|
1494
|
+
const diastolicObs = encounter.obs.find((obs) => obs.concept.uuid === PARTOGRAPHY_CONCEPTS['diastolic-bp']);
|
|
1495
|
+
if (systolicObs && diastolicObs) {
|
|
1496
|
+
return {
|
|
1497
|
+
datetime: new Date(encounter.encounterDatetime),
|
|
1498
|
+
systolicBP: typeof systolicObs.value === 'number' ? systolicObs.value : parseFloat(systolicObs.value),
|
|
1499
|
+
diastolicBP: typeof diastolicObs.value === 'number' ? diastolicObs.value : parseFloat(diastolicObs.value),
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
return null;
|
|
1503
|
+
})
|
|
1504
|
+
.filter(Boolean);
|
|
1577
1505
|
|
|
1578
|
-
// For each pulse,
|
|
1506
|
+
// For each pulse, find the closest BP entry in time (within 1 hour)
|
|
1579
1507
|
return (loadedPulseData || []).map((encounter, index) => {
|
|
1580
1508
|
const pulseObs = encounter.obs.find((obs) => obs.concept.uuid === PARTOGRAPHY_CONCEPTS['maternal-pulse']);
|
|
1581
1509
|
const pulse = pulseObs
|
|
@@ -1583,14 +1511,26 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1583
1511
|
? pulseObs.value
|
|
1584
1512
|
: parseFloat(pulseObs.value)
|
|
1585
1513
|
: null;
|
|
1586
|
-
const
|
|
1587
|
-
const
|
|
1588
|
-
const
|
|
1514
|
+
const pulseDate = new Date(encounter.encounterDatetime);
|
|
1515
|
+
const date = pulseDate.toLocaleDateString();
|
|
1516
|
+
const time = pulseDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
1517
|
+
|
|
1518
|
+
// Find closest BP entry within 1 hour
|
|
1519
|
+
let closestBP = null;
|
|
1520
|
+
let minDiff = 60 * 60 * 1000; // 1 hour in ms
|
|
1521
|
+
for (const bp of bpEntries) {
|
|
1522
|
+
const diff = Math.abs(bp.datetime.getTime() - pulseDate.getTime());
|
|
1523
|
+
if (diff < minDiff) {
|
|
1524
|
+
minDiff = diff;
|
|
1525
|
+
closestBP = bp;
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1589
1529
|
return {
|
|
1590
1530
|
id: `pulse-bp-${index}`,
|
|
1591
1531
|
pulse,
|
|
1592
|
-
systolicBP:
|
|
1593
|
-
diastolicBP:
|
|
1532
|
+
systolicBP: closestBP ? closestBP.systolicBP : '',
|
|
1533
|
+
diastolicBP: closestBP ? closestBP.diastolicBP : '',
|
|
1594
1534
|
date,
|
|
1595
1535
|
time,
|
|
1596
1536
|
};
|
|
@@ -1661,24 +1601,25 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1661
1601
|
if (graph.id === 'cervix') {
|
|
1662
1602
|
return loadedCervixData
|
|
1663
1603
|
.filter((data) => {
|
|
1664
|
-
//
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
!isNaN(data.descentOfHead) &&
|
|
1669
|
-
data.time &&
|
|
1670
|
-
data.time.trim() !== ''
|
|
1671
|
-
);
|
|
1604
|
+
// Include if either hour or time is present, and cervicalDilation is valid
|
|
1605
|
+
const hasHour = data.hour !== null && data.hour !== undefined && !isNaN(data.hour);
|
|
1606
|
+
const hasTime = data.time && data.time.trim() !== '';
|
|
1607
|
+
return (hasHour || hasTime) && data.cervicalDilation !== null && !isNaN(data.cervicalDilation);
|
|
1672
1608
|
})
|
|
1673
|
-
.map((data, index) =>
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1609
|
+
.map((data, index) => {
|
|
1610
|
+
let hourInput = data.hour !== null && data.hour !== undefined && !isNaN(data.hour) ? `${data.hour} hr` : '';
|
|
1611
|
+
// Always show the form time if available
|
|
1612
|
+
let formTime = data.time && data.time.trim() !== '' ? data.time : data.timeDisplay || '';
|
|
1613
|
+
return {
|
|
1614
|
+
id: `cervix-${index}`,
|
|
1615
|
+
date: new Date(data.encounterDatetime).toLocaleDateString() || 'N/A',
|
|
1616
|
+
actualTime: new Date(data.encounterDatetime).toLocaleTimeString() || 'N/A',
|
|
1617
|
+
cervicalDilation: `${data.cervicalDilation} cm`,
|
|
1618
|
+
descentOfHead: `${data.descentLabel || data.descentOfHead || ''}`,
|
|
1619
|
+
hourInput,
|
|
1620
|
+
formTime: formTime || 'N/A',
|
|
1621
|
+
};
|
|
1622
|
+
});
|
|
1682
1623
|
}
|
|
1683
1624
|
|
|
1684
1625
|
// Membrane amniotic fluid: use backend data only
|
|
@@ -1822,15 +1763,12 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1822
1763
|
const endIndex = startIndex + currentPageSize;
|
|
1823
1764
|
const paginatedData = tableData.slice(startIndex, endIndex);
|
|
1824
1765
|
|
|
1825
|
-
// Default chart data - declare once here
|
|
1826
1766
|
let finalChartData: ChartDataPoint[] = patientChartData;
|
|
1827
1767
|
let zeroTime: Date | undefined;
|
|
1828
1768
|
let maxChartTime: Date | undefined;
|
|
1829
1769
|
|
|
1830
|
-
// --- Data for custom time labels ---
|
|
1831
1770
|
let timeLabelsData: { hours: string; time: string; span: number }[] = [];
|
|
1832
1771
|
|
|
1833
|
-
// Default chart options with medical partograph styling
|
|
1834
1772
|
let chartOptions: any = {
|
|
1835
1773
|
title: graph.title,
|
|
1836
1774
|
axes: {
|
|
@@ -1893,47 +1831,40 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1893
1831
|
},
|
|
1894
1832
|
};
|
|
1895
1833
|
|
|
1896
|
-
// Hide X-axis title and labels for non-cervix graphs only
|
|
1897
1834
|
if (graph.id !== 'cervix') {
|
|
1898
1835
|
chartOptions.axes.bottom.title = undefined;
|
|
1899
1836
|
chartOptions.axes.bottom.tick = {
|
|
1900
|
-
formatter: () => '',
|
|
1837
|
+
formatter: () => '',
|
|
1901
1838
|
};
|
|
1902
1839
|
}
|
|
1903
1840
|
|
|
1904
|
-
// --- START LOGIC FOR CERVIX GRAPH ---
|
|
1905
1841
|
if (graph.id === 'cervix') {
|
|
1906
|
-
// 1. Apply custom axis and styling options
|
|
1907
1842
|
chartOptions = {
|
|
1908
1843
|
...chartOptions,
|
|
1909
1844
|
...CERVIX_CHART_OPTIONS,
|
|
1910
1845
|
title: graph.title,
|
|
1911
1846
|
color: {
|
|
1912
1847
|
scale: {
|
|
1913
|
-
'Alert Line': '#FFD700',
|
|
1914
|
-
'Action Line': '#FF0000',
|
|
1915
|
-
'Cervical Dilation': '#22C55E',
|
|
1916
|
-
'Descent of Head': '#2563EB',
|
|
1848
|
+
'Alert Line': '#FFD700',
|
|
1849
|
+
'Action Line': '#FF0000',
|
|
1850
|
+
'Cervical Dilation': '#22C55E',
|
|
1851
|
+
'Descent of Head': '#2563EB',
|
|
1917
1852
|
[graph.id]: getColorForGraph(graph.color),
|
|
1918
1853
|
},
|
|
1919
1854
|
},
|
|
1920
1855
|
legend: {
|
|
1921
|
-
position: 'top',
|
|
1856
|
+
position: 'top',
|
|
1922
1857
|
},
|
|
1923
1858
|
};
|
|
1924
1859
|
|
|
1925
|
-
|
|
1926
|
-
const ALERT_START_CM = 4; // Changed from 5cm to 4cm as requested
|
|
1860
|
+
const ALERT_START_CM = 4;
|
|
1927
1861
|
const CERVIX_DILATION_MAX = 10;
|
|
1928
|
-
const ALERT_ACTION_DIFFERENCE_HOURS = 4;
|
|
1929
|
-
const EXPECTED_LABOR_DURATION_HOURS = 6;
|
|
1862
|
+
const ALERT_ACTION_DIFFERENCE_HOURS = 4;
|
|
1863
|
+
const EXPECTED_LABOR_DURATION_HOURS = 6;
|
|
1930
1864
|
|
|
1931
1865
|
const staticLinesData: ChartDataPoint[] = [
|
|
1932
|
-
// Alert Line Points: (Hour 0, 4cm) -> (Hour 6, 10cm)
|
|
1933
1866
|
{ hour: 0, value: ALERT_START_CM, group: 'Alert Line' },
|
|
1934
1867
|
{ hour: EXPECTED_LABOR_DURATION_HOURS, value: CERVIX_DILATION_MAX, group: 'Alert Line' },
|
|
1935
|
-
|
|
1936
|
-
// Action Line Points: (Hour 4, 4cm) -> (Hour 10, 10cm)
|
|
1937
1868
|
{ hour: ALERT_ACTION_DIFFERENCE_HOURS, value: ALERT_START_CM, group: 'Action Line' },
|
|
1938
1869
|
{
|
|
1939
1870
|
hour: ALERT_ACTION_DIFFERENCE_HOURS + EXPECTED_LABOR_DURATION_HOURS,
|
|
@@ -1942,7 +1873,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1942
1873
|
},
|
|
1943
1874
|
];
|
|
1944
1875
|
|
|
1945
|
-
// 3. Add Cervical Dilation data points from form inputs
|
|
1946
1876
|
const cervicalDilationData: ChartDataPoint[] = cervixFormData.map((data) => ({
|
|
1947
1877
|
hour: data.hour,
|
|
1948
1878
|
value: data.cervicalDilation,
|
|
@@ -1950,40 +1880,86 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
1950
1880
|
time: data.time,
|
|
1951
1881
|
}));
|
|
1952
1882
|
|
|
1953
|
-
// 4. Add Descent of Head data points from form inputs
|
|
1954
|
-
// Medical reality: 5=high position → 4 → 3 → 2 → 1=most descended (head coming down)
|
|
1955
|
-
// Chart display: Show medical values directly (5 at top, 1 at bottom)
|
|
1956
1883
|
const descentOfHeadData: ChartDataPoint[] = cervixFormData.map((data) => ({
|
|
1957
1884
|
hour: data.hour,
|
|
1958
|
-
value: data.descentOfHead,
|
|
1885
|
+
value: data.descentOfHead,
|
|
1959
1886
|
group: 'Descent of Head',
|
|
1960
1887
|
time: data.time,
|
|
1961
1888
|
}));
|
|
1962
1889
|
|
|
1963
|
-
// 5. Combine all data - Alert/Action lines + patient data + form data
|
|
1964
1890
|
finalChartData = [...patientChartData, ...staticLinesData, ...cervicalDilationData, ...descentOfHeadData];
|
|
1965
1891
|
|
|
1966
|
-
// 6. Generate dynamic time labels for the custom footer (from form data)
|
|
1967
1892
|
timeLabelsData = [];
|
|
1968
1893
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1894
|
+
const allHours = [...cervixFormData.map((d) => d.hour), ...loadedCervixData.map((d) => d.hour)]
|
|
1895
|
+
.filter((h) => h !== null && h !== undefined && !isNaN(h))
|
|
1896
|
+
.map(Number);
|
|
1897
|
+
const uniqueSortedHours = Array.from(new Set(allHours)).sort((a, b) => a - b);
|
|
1898
|
+
|
|
1899
|
+
const usedTimeEntries: string[] = [];
|
|
1971
1900
|
|
|
1972
|
-
|
|
1973
|
-
const hourLabel =
|
|
1901
|
+
uniqueSortedHours.forEach((hourVal) => {
|
|
1902
|
+
const hourLabel = `${hourVal}`;
|
|
1903
|
+
let timeValue = '--:--';
|
|
1904
|
+
const formEntry = (cervixFormData as Array<{ hour: number; time: string /* etc. */ }>).find(
|
|
1905
|
+
(d) => d.hour === hourVal && typeof d.time === 'string' && d.time.trim() !== '',
|
|
1906
|
+
);
|
|
1974
1907
|
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1908
|
+
if (formEntry) {
|
|
1909
|
+
timeValue = formEntry.time;
|
|
1910
|
+
} else {
|
|
1911
|
+
const backendEntry = loadedCervixData.find(
|
|
1912
|
+
(d) =>
|
|
1913
|
+
d.hour === hourVal &&
|
|
1914
|
+
((d.time && d.time.trim() !== '') || (typeof d.timeDisplay === 'string' && d.timeDisplay.trim() !== '')),
|
|
1915
|
+
);
|
|
1916
|
+
if (backendEntry) {
|
|
1917
|
+
if (backendEntry.time && backendEntry.time.trim() !== '') {
|
|
1918
|
+
timeValue = backendEntry.time;
|
|
1919
|
+
} else if (typeof backendEntry.timeDisplay === 'string' && backendEntry.timeDisplay.trim() !== '') {
|
|
1920
|
+
timeValue = backendEntry.timeDisplay;
|
|
1921
|
+
}
|
|
1922
|
+
} else {
|
|
1923
|
+
const cervixFormArray = Array.isArray(cervixFormData) ? cervixFormData : [];
|
|
1924
|
+
const loadedCervixArray = Array.isArray(loadedCervixData) ? loadedCervixData : [];
|
|
1925
|
+
|
|
1926
|
+
const cervixFormFiltered = (cervixFormArray as Array<{ hour: number | null; time: string }>).filter(
|
|
1927
|
+
(d) => d.hour == null && d.time && d.time.trim() !== '' && !usedTimeEntries.includes(d.time),
|
|
1928
|
+
);
|
|
1929
|
+
|
|
1930
|
+
const loadedCervixFiltered = loadedCervixArray.filter(
|
|
1931
|
+
(d) =>
|
|
1932
|
+
d.hour == null &&
|
|
1933
|
+
((d.time && d.time.trim() !== '') ||
|
|
1934
|
+
(typeof d.timeDisplay === 'string' && d.timeDisplay.trim() !== '')) &&
|
|
1935
|
+
!usedTimeEntries.includes(d.time || d.timeDisplay),
|
|
1936
|
+
);
|
|
1937
|
+
const allTimeEntries = [...cervixFormFiltered, ...loadedCervixFiltered];
|
|
1938
|
+
if (allTimeEntries.length > 0) {
|
|
1939
|
+
const nextTimeEntry = allTimeEntries[0];
|
|
1940
|
+
if (nextTimeEntry.time && nextTimeEntry.time.trim() !== '') {
|
|
1941
|
+
timeValue = nextTimeEntry.time;
|
|
1942
|
+
} else if (
|
|
1943
|
+
'timeDisplay' in nextTimeEntry &&
|
|
1944
|
+
typeof nextTimeEntry.timeDisplay === 'string' &&
|
|
1945
|
+
nextTimeEntry.timeDisplay.trim() !== ''
|
|
1946
|
+
) {
|
|
1947
|
+
timeValue = nextTimeEntry.timeDisplay;
|
|
1948
|
+
} else {
|
|
1949
|
+
timeValue = '--:--';
|
|
1950
|
+
}
|
|
1951
|
+
usedTimeEntries.push(timeValue);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1978
1955
|
|
|
1979
1956
|
timeLabelsData.push({
|
|
1980
1957
|
hours: hourLabel,
|
|
1981
1958
|
time: timeValue,
|
|
1982
1959
|
span: 1,
|
|
1983
1960
|
});
|
|
1984
|
-
}
|
|
1961
|
+
});
|
|
1985
1962
|
}
|
|
1986
|
-
// --- END LOGIC FOR CERVIX GRAPH ---
|
|
1987
1963
|
|
|
1988
1964
|
const shouldRenderChart = finalChartData.length > 0;
|
|
1989
1965
|
|
|
@@ -2066,41 +2042,53 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2066
2042
|
</>
|
|
2067
2043
|
)}
|
|
2068
2044
|
</div>
|
|
2069
|
-
{
|
|
2070
|
-
{graph.id === 'cervix' && timeLabelsData.length > 0 && (
|
|
2045
|
+
{graph.id === 'cervix' && (
|
|
2071
2046
|
<div
|
|
2072
2047
|
className={styles.customTimeLabelsContainer}
|
|
2073
|
-
style={{
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
<
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2048
|
+
style={{
|
|
2049
|
+
overflowX: timeLabelsData.length > 14 ? 'auto' : 'hidden',
|
|
2050
|
+
width: 'fit-content',
|
|
2051
|
+
maxWidth: '100%',
|
|
2052
|
+
margin: '1rem auto',
|
|
2053
|
+
WebkitOverflowScrolling: 'touch',
|
|
2054
|
+
border: '1px solid #e0e0e0',
|
|
2055
|
+
borderRadius: '4px',
|
|
2056
|
+
background: '#fff',
|
|
2057
|
+
padding: 0,
|
|
2058
|
+
display: 'block',
|
|
2059
|
+
}}>
|
|
2060
|
+
<table
|
|
2061
|
+
style={{
|
|
2062
|
+
borderCollapse: 'collapse',
|
|
2063
|
+
width: '100%',
|
|
2064
|
+
minWidth:
|
|
2065
|
+
timeLabelsData.length > 14 ? `${100 * (Math.max(6, timeLabelsData.length) + 1)}px` : '100%',
|
|
2066
|
+
tableLayout: 'fixed',
|
|
2067
|
+
}}>
|
|
2068
|
+
<thead>
|
|
2069
|
+
<tr style={{ background: '#f4f4f4', fontWeight: 700 }}>
|
|
2070
|
+
<th style={{ width: 100, border: '1px solid #e0e0e0', padding: 8, textAlign: 'left' }}>Hour</th>
|
|
2071
|
+
{Array.from({ length: Math.max(6, timeLabelsData.length) }).map((_, idx) => (
|
|
2072
|
+
<th
|
|
2073
|
+
key={`hour-col-${idx}`}
|
|
2074
|
+
style={{ width: 100, border: '1px solid #e0e0e0', padding: 8, textAlign: 'left' }}>
|
|
2075
|
+
{timeLabelsData[idx]?.hours || ''}
|
|
2076
|
+
</th>
|
|
2077
|
+
))}
|
|
2078
|
+
</tr>
|
|
2079
|
+
</thead>
|
|
2080
|
+
<tbody>
|
|
2081
|
+
<tr style={{ background: '#fafafa' }}>
|
|
2082
|
+
<td style={{ width: 100, border: '1px solid #e0e0e0', padding: 8 }}>Time</td>
|
|
2083
|
+
{Array.from({ length: Math.max(6, timeLabelsData.length) }).map((_, idx) => (
|
|
2084
|
+
<td key={`time-col-${idx}`} style={{ width: 100, border: '1px solid #e0e0e0', padding: 8 }}>
|
|
2085
|
+
{timeLabelsData[idx]?.time || ''}
|
|
2086
|
+
</td>
|
|
2087
|
+
))}
|
|
2088
|
+
</tr>
|
|
2089
|
+
</tbody>
|
|
2090
|
+
</table>
|
|
2091
|
+
{timeLabelsData.length > 14 && (
|
|
2104
2092
|
<div
|
|
2105
2093
|
style={{
|
|
2106
2094
|
fontSize: '12px',
|
|
@@ -2115,7 +2103,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2115
2103
|
)}
|
|
2116
2104
|
</div>
|
|
2117
2105
|
)}
|
|
2118
|
-
{/* --- END Custom Time Labels --- */}
|
|
2119
2106
|
|
|
2120
2107
|
{patientChartData.length > 0 && !isGraphLoading && (
|
|
2121
2108
|
<div className={styles.chartStats}>
|
|
@@ -2139,7 +2126,7 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2139
2126
|
<div className={styles.tableContainer}>
|
|
2140
2127
|
{isGraphLoading ? (
|
|
2141
2128
|
<TableSkeleton />
|
|
2142
|
-
) :
|
|
2129
|
+
) : (
|
|
2143
2130
|
<>
|
|
2144
2131
|
<DataTable rows={paginatedData} headers={getTableHeaders(graph)}>
|
|
2145
2132
|
{({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
|
|
@@ -2155,34 +2142,43 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2155
2142
|
</TableRow>
|
|
2156
2143
|
</TableHead>
|
|
2157
2144
|
<TableBody>
|
|
2158
|
-
{rows.
|
|
2159
|
-
|
|
2160
|
-
{row
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
{
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2145
|
+
{rows.length > 0 ? (
|
|
2146
|
+
rows.map((row) => (
|
|
2147
|
+
<TableRow {...getRowProps({ row })} key={row.id}>
|
|
2148
|
+
{row.cells.map((cell) => {
|
|
2149
|
+
let cellContent = cell.value;
|
|
2150
|
+
|
|
2151
|
+
// Only apply value status logic for non-cervix graphs
|
|
2152
|
+
if (
|
|
2153
|
+
graph.id !== 'cervix' &&
|
|
2154
|
+
cell.info.header === 'value' &&
|
|
2155
|
+
row.cells.find((c) => c.info.header === 'value')
|
|
2156
|
+
) {
|
|
2157
|
+
const cellValue = cell.value;
|
|
2158
|
+
const status = getValueStatus(parseFloat(cellValue), graph);
|
|
2159
|
+
const statusClass =
|
|
2160
|
+
status === 'high' ? styles.highValue : status === 'low' ? styles.lowValue : '';
|
|
2161
|
+
cellContent = (
|
|
2162
|
+
<span className={statusClass}>
|
|
2163
|
+
{cellValue}
|
|
2164
|
+
{status === 'high' && <span className={styles.arrow}> ↑</span>}
|
|
2165
|
+
{status === 'low' && <span className={styles.arrow}> ↓</span>}
|
|
2166
|
+
</span>
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
return <TableCell key={cell.id}>{cellContent}</TableCell>;
|
|
2171
|
+
})}
|
|
2172
|
+
</TableRow>
|
|
2173
|
+
))
|
|
2174
|
+
) : // Always render an empty row for cervix table if no data
|
|
2175
|
+
graph.id === 'cervix' ? (
|
|
2176
|
+
<TableRow>
|
|
2177
|
+
{getTableHeaders(graph).map((header) => (
|
|
2178
|
+
<TableCell key={header.key}> </TableCell>
|
|
2179
|
+
))}
|
|
2184
2180
|
</TableRow>
|
|
2185
|
-
)
|
|
2181
|
+
) : null}
|
|
2186
2182
|
</TableBody>
|
|
2187
2183
|
</Table>
|
|
2188
2184
|
</TableContainer>
|
|
@@ -2215,13 +2211,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2215
2211
|
</span>
|
|
2216
2212
|
</div>
|
|
2217
2213
|
</>
|
|
2218
|
-
) : (
|
|
2219
|
-
<div className={styles.emptyState}>
|
|
2220
|
-
<p>{t('noDataAvailable', 'No data available for this graph')}</p>
|
|
2221
|
-
<Button kind="primary" size={controlSize} renderIcon={Add} onClick={() => handleAddDataPoint(graph.id)}>
|
|
2222
|
-
{t('addFirstDataPoint', 'Add first data point')}
|
|
2223
|
-
</Button>
|
|
2224
|
-
</div>
|
|
2225
2214
|
)}
|
|
2226
2215
|
</div>
|
|
2227
2216
|
)}
|
|
@@ -2234,7 +2223,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2234
2223
|
<Layer>
|
|
2235
2224
|
<Grid>
|
|
2236
2225
|
<Column lg={16} md={8} sm={4}>
|
|
2237
|
-
{/* Fetal Heart Rate Graph - Standalone */}
|
|
2238
2226
|
<FetalHeartRateGraph
|
|
2239
2227
|
data={computedFetalHeartRateData}
|
|
2240
2228
|
tableData={getFetalHeartRateTableData()}
|
|
@@ -2246,11 +2234,13 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2246
2234
|
onAddData={() => setIsFetalHeartRateFormOpen(true)}
|
|
2247
2235
|
onViewModeChange={setFetalHeartRateViewMode}
|
|
2248
2236
|
onPageChange={setFetalHeartRateCurrentPage}
|
|
2249
|
-
onPageSizeChange={
|
|
2237
|
+
onPageSizeChange={(size) => {
|
|
2238
|
+
setFetalHeartRatePageSize(size);
|
|
2239
|
+
persistPageSize('fetalHeartRatePageSize', size);
|
|
2240
|
+
}}
|
|
2250
2241
|
isAddButtonDisabled={false}
|
|
2251
2242
|
/>
|
|
2252
2243
|
|
|
2253
|
-
{/* Membrane Amniotic Fluid Graph - Standalone */}
|
|
2254
2244
|
<MembraneAmnioticFluidGraph
|
|
2255
2245
|
data={membraneAmnioticFluidEntries}
|
|
2256
2246
|
tableData={membraneAmnioticFluidEntries}
|
|
@@ -2262,16 +2252,17 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2262
2252
|
onAddData={() => setIsMembraneAmnioticFluidFormOpen(true)}
|
|
2263
2253
|
onViewModeChange={setMembraneAmnioticFluidViewMode}
|
|
2264
2254
|
onPageChange={setMembraneAmnioticFluidCurrentPage}
|
|
2265
|
-
onPageSizeChange={
|
|
2255
|
+
onPageSizeChange={(size) => {
|
|
2256
|
+
setMembraneAmnioticFluidPageSize(size);
|
|
2257
|
+
persistPageSize('membraneAmnioticFluidPageSize', size);
|
|
2258
|
+
}}
|
|
2266
2259
|
isAddButtonDisabled={false}
|
|
2267
2260
|
/>
|
|
2268
2261
|
|
|
2269
|
-
{/* Existing Partography Graphs - Contains Cervix Graph */}
|
|
2270
2262
|
<div className={styles.partographyGrid}>
|
|
2271
2263
|
{partographGraphs.map((graph, index) => renderGraph(graph, index, partographGraphs.length))}
|
|
2272
2264
|
</div>
|
|
2273
2265
|
|
|
2274
|
-
{/* Cervical Contractions Graph - Positioned below Cervix graph */}
|
|
2275
2266
|
<CervicalContractionsGraph
|
|
2276
2267
|
data={transformEncounterToTableData(cervicalContractionsData || [], 'uterine-contractions').map(
|
|
2277
2268
|
(row, index) => ({
|
|
@@ -2291,17 +2282,13 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2291
2282
|
onAddData={() => setIsCervicalContractionsFormOpen(true)}
|
|
2292
2283
|
onViewModeChange={setCervicalContractionsViewMode}
|
|
2293
2284
|
onPageChange={setCervicalContractionsCurrentPage}
|
|
2294
|
-
onPageSizeChange={
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
uuid: patientUuid,
|
|
2298
|
-
name: 'Patient Name',
|
|
2299
|
-
gender: 'F',
|
|
2300
|
-
age: '28',
|
|
2285
|
+
onPageSizeChange={(size) => {
|
|
2286
|
+
setCervicalContractionsPageSize(size);
|
|
2287
|
+
persistPageSize('cervicalContractionsPageSize', size);
|
|
2301
2288
|
}}
|
|
2289
|
+
isAddButtonDisabled={false}
|
|
2302
2290
|
/>
|
|
2303
2291
|
|
|
2304
|
-
{/* Oxytocin Graph - Positioned below Cervical Contractions */}
|
|
2305
2292
|
<OxytocinGraph
|
|
2306
2293
|
data={loadedOxytocinData.map((item) => ({
|
|
2307
2294
|
timeSlot: item.time ?? '',
|
|
@@ -2325,11 +2312,13 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2325
2312
|
onAddData={() => setIsOxytocinFormOpen(true)}
|
|
2326
2313
|
onViewModeChange={setOxytocinViewMode}
|
|
2327
2314
|
onPageChange={setOxytocinCurrentPage}
|
|
2328
|
-
onPageSizeChange={
|
|
2315
|
+
onPageSizeChange={(size) => {
|
|
2316
|
+
setOxytocinPageSize(size);
|
|
2317
|
+
persistPageSize('oxytocinPageSize', size);
|
|
2318
|
+
}}
|
|
2329
2319
|
isAddButtonDisabled={false}
|
|
2330
2320
|
/>
|
|
2331
2321
|
|
|
2332
|
-
{/* Drugs and IV Fluids Graph - Positioned below Oxytocin */}
|
|
2333
2322
|
<DrugsIVFluidsGraph
|
|
2334
2323
|
data={getDrugsIVFluidsTableData()}
|
|
2335
2324
|
tableData={getDrugsIVFluidsTableData()}
|
|
@@ -2338,22 +2327,18 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2338
2327
|
pageSize={drugsIVFluidsPageSize}
|
|
2339
2328
|
totalItems={getDrugsIVFluidsTableData().length}
|
|
2340
2329
|
controlSize={controlSize}
|
|
2341
|
-
onAddData={() => {}}
|
|
2330
|
+
onAddData={() => {}}
|
|
2342
2331
|
onViewModeChange={setDrugsIVFluidsViewMode}
|
|
2343
2332
|
onPageChange={setDrugsIVFluidsCurrentPage}
|
|
2344
|
-
onPageSizeChange={
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
uuid: patientUuid,
|
|
2348
|
-
name: 'Patient Name',
|
|
2349
|
-
gender: 'F',
|
|
2350
|
-
age: '28',
|
|
2333
|
+
onPageSizeChange={(size) => {
|
|
2334
|
+
setDrugsIVFluidsPageSize(size);
|
|
2335
|
+
persistPageSize('drugsIVFluidsPageSize', size);
|
|
2351
2336
|
}}
|
|
2337
|
+
isAddButtonDisabled={false}
|
|
2352
2338
|
onDrugsIVFluidsSubmit={handleDrugsIVFluidsFormSubmit}
|
|
2353
2339
|
onDataSaved={handleDrugOrderDataSaved}
|
|
2354
2340
|
/>
|
|
2355
2341
|
|
|
2356
|
-
{/* Pulse and BP Graph - Positioned below Drugs and IV Fluids */}
|
|
2357
2342
|
<PulseBPGraph
|
|
2358
2343
|
data={getPulseBPTableData()}
|
|
2359
2344
|
tableData={getPulseBPTableData()}
|
|
@@ -2365,18 +2350,14 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2365
2350
|
onAddData={() => {}}
|
|
2366
2351
|
onViewModeChange={setPulseBPViewMode}
|
|
2367
2352
|
onPageChange={setPulseBPCurrentPage}
|
|
2368
|
-
onPageSizeChange={
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
uuid: patientUuid,
|
|
2372
|
-
name: 'Patient Name',
|
|
2373
|
-
gender: 'F',
|
|
2374
|
-
age: '28',
|
|
2353
|
+
onPageSizeChange={(size) => {
|
|
2354
|
+
setPulseBPPageSize(size);
|
|
2355
|
+
persistPageSize('pulseBPPageSize', size);
|
|
2375
2356
|
}}
|
|
2357
|
+
isAddButtonDisabled={false}
|
|
2376
2358
|
onPulseBPSubmit={handlePulseBPFormSubmit}
|
|
2377
2359
|
/>
|
|
2378
2360
|
|
|
2379
|
-
{/* Temperature Graph - Positioned below Pulse and BP */}
|
|
2380
2361
|
<TemperatureGraph
|
|
2381
2362
|
data={getTemperatureTableData()}
|
|
2382
2363
|
tableData={getTemperatureTableData()}
|
|
@@ -2394,11 +2375,13 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2394
2375
|
}}
|
|
2395
2376
|
onViewModeChange={setTemperatureViewMode}
|
|
2396
2377
|
onPageChange={setTemperatureCurrentPage}
|
|
2397
|
-
onPageSizeChange={
|
|
2378
|
+
onPageSizeChange={(size) => {
|
|
2379
|
+
setTemperaturePageSize(size);
|
|
2380
|
+
persistPageSize('temperaturePageSize', size);
|
|
2381
|
+
}}
|
|
2398
2382
|
isAddButtonDisabled={false}
|
|
2399
2383
|
/>
|
|
2400
2384
|
|
|
2401
|
-
{/* Urine Test Graph - Now using backend data */}
|
|
2402
2385
|
<UrineTestGraph
|
|
2403
2386
|
data={urineTestData}
|
|
2404
2387
|
tableData={urineTestData}
|
|
@@ -2410,7 +2393,10 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2410
2393
|
onAddData={() => setIsUrineTestFormOpen(true)}
|
|
2411
2394
|
onViewModeChange={setUrineTestViewMode}
|
|
2412
2395
|
onPageChange={setUrineTestCurrentPage}
|
|
2413
|
-
onPageSizeChange={
|
|
2396
|
+
onPageSizeChange={(size) => {
|
|
2397
|
+
setUrineTestPageSize(size);
|
|
2398
|
+
persistPageSize('urineTestPageSize', size);
|
|
2399
|
+
}}
|
|
2414
2400
|
isAddButtonDisabled={false}
|
|
2415
2401
|
/>
|
|
2416
2402
|
|
|
@@ -2432,12 +2418,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2432
2418
|
selectedHours={selectedHours}
|
|
2433
2419
|
existingTimeEntries={computedExistingTimeEntries}
|
|
2434
2420
|
existingCervixData={existingCervixData}
|
|
2435
|
-
patient={{
|
|
2436
|
-
uuid: patientUuid,
|
|
2437
|
-
name: 'Patient',
|
|
2438
|
-
gender: 'Female',
|
|
2439
|
-
age: '40 Years',
|
|
2440
|
-
}}
|
|
2441
2421
|
/>
|
|
2442
2422
|
)}
|
|
2443
2423
|
{isFetalHeartRateFormOpen && (
|
|
@@ -2447,12 +2427,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2447
2427
|
onSubmit={handleFetalHeartRateFormSubmit}
|
|
2448
2428
|
onDataSaved={handleFetalHeartRateDataSaved}
|
|
2449
2429
|
existingTimeEntries={computedExistingTimeEntries}
|
|
2450
|
-
patient={{
|
|
2451
|
-
uuid: patientUuid,
|
|
2452
|
-
name: 'Patient',
|
|
2453
|
-
gender: 'Female',
|
|
2454
|
-
age: '40 Years',
|
|
2455
|
-
}}
|
|
2456
2430
|
/>
|
|
2457
2431
|
)}
|
|
2458
2432
|
{isMembraneAmnioticFluidFormOpen && (
|
|
@@ -2460,12 +2434,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2460
2434
|
isOpen={isMembraneAmnioticFluidFormOpen}
|
|
2461
2435
|
onClose={handleMembraneAmnioticFluidFormClose}
|
|
2462
2436
|
onSubmit={handleMembraneAmnioticFluidFormSubmit}
|
|
2463
|
-
patient={{
|
|
2464
|
-
uuid: patientUuid,
|
|
2465
|
-
name: 'Patient',
|
|
2466
|
-
gender: 'Female',
|
|
2467
|
-
age: '40 Years',
|
|
2468
|
-
}}
|
|
2469
2437
|
/>
|
|
2470
2438
|
)}
|
|
2471
2439
|
{isCervicalContractionsFormOpen && (
|
|
@@ -2473,12 +2441,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2473
2441
|
isOpen={isCervicalContractionsFormOpen}
|
|
2474
2442
|
onClose={handleCervicalContractionsFormClose}
|
|
2475
2443
|
onSubmit={handleCervicalContractionsFormSubmit}
|
|
2476
|
-
patient={{
|
|
2477
|
-
uuid: patientUuid,
|
|
2478
|
-
name: 'Patient',
|
|
2479
|
-
gender: 'Female',
|
|
2480
|
-
age: '40 Years',
|
|
2481
|
-
}}
|
|
2482
2444
|
/>
|
|
2483
2445
|
)}
|
|
2484
2446
|
{isOxytocinFormOpen && (
|
|
@@ -2487,12 +2449,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2487
2449
|
onClose={handleOxytocinFormClose}
|
|
2488
2450
|
onSubmit={handleOxytocinFormSubmit}
|
|
2489
2451
|
existingTimeEntries={existingTimeEntries}
|
|
2490
|
-
patient={{
|
|
2491
|
-
uuid: patientUuid,
|
|
2492
|
-
name: 'Patient',
|
|
2493
|
-
gender: 'F',
|
|
2494
|
-
age: '28',
|
|
2495
|
-
}}
|
|
2496
2452
|
/>
|
|
2497
2453
|
)}
|
|
2498
2454
|
{isTemperatureFormOpen && (
|
|
@@ -2502,12 +2458,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2502
2458
|
onSubmit={handleTemperatureFormSubmit}
|
|
2503
2459
|
initialTime={temperatureFormInitialTime}
|
|
2504
2460
|
existingTimeEntries={existingTimeEntries}
|
|
2505
|
-
patient={{
|
|
2506
|
-
uuid: patientUuid,
|
|
2507
|
-
name: 'Patient',
|
|
2508
|
-
gender: 'F',
|
|
2509
|
-
age: '28',
|
|
2510
|
-
}}
|
|
2511
2461
|
/>
|
|
2512
2462
|
)}
|
|
2513
2463
|
{isUrineTestFormOpen && (
|
|
@@ -2516,12 +2466,6 @@ const Partograph: React.FC<PartographyProps> = ({ patientUuid }) => {
|
|
|
2516
2466
|
onClose={() => setIsUrineTestFormOpen(false)}
|
|
2517
2467
|
onSubmit={handleUrineTestFormSubmit}
|
|
2518
2468
|
existingTimeEntries={existingTimeEntries}
|
|
2519
|
-
patient={{
|
|
2520
|
-
uuid: patientUuid,
|
|
2521
|
-
name: 'Patient',
|
|
2522
|
-
gender: 'F',
|
|
2523
|
-
age: '28',
|
|
2524
|
-
}}
|
|
2525
2469
|
/>
|
|
2526
2470
|
)}
|
|
2527
2471
|
</Column>
|