@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2823 → 5.4.2-pre.2825
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/{791.js → 343.js} +1 -1
- package/dist/343.js.map +1 -0
- package/dist/kenyaemr-esm-patient-clinical-view-app.js +3 -3
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +27 -27
- package/dist/main.js +17 -17
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/maternal-and-child-health/partography/forms/cervix-form.component.tsx +60 -9
- package/src/maternal-and-child-health/partography/forms/drugs-iv-fluids-form.component.tsx +21 -17
- package/src/maternal-and-child-health/partography/forms/fetal-heart-rate-form.component.tsx +70 -6
- package/src/maternal-and-child-health/partography/forms/membrane-amniotic-fluid-form.component.tsx +30 -7
- package/src/maternal-and-child-health/partography/forms/urine-test-form.component.tsx +63 -6
- package/src/maternal-and-child-health/partography/graphs/cervix-graph.component.tsx +100 -46
- package/src/maternal-and-child-health/partography/graphs/oxytocin-graph.component.tsx +2 -1
- package/src/maternal-and-child-health/partography/graphs/pulse-bp-graph.component.tsx +231 -133
- package/src/maternal-and-child-health/partography/partograph.component.tsx +141 -30
- package/src/maternal-and-child-health/partography/partography-data-form.scss +31 -12
- package/src/maternal-and-child-health/partography/partography.scss +22 -86
- package/src/maternal-and-child-health/partography/resources/cervix.resource.ts +15 -1
- package/src/maternal-and-child-health/partography/resources/membrane-amniotic-fluid.resource.ts +170 -1
- package/src/maternal-and-child-health/partography/resources/oxytocin.resource.ts +88 -15
- package/src/maternal-and-child-health/partography/resources/temperature.resource.ts +138 -1
- package/dist/791.js.map +0 -1
|
@@ -80,18 +80,13 @@
|
|
|
80
80
|
justify-content: space-between;
|
|
81
81
|
align-items: center;
|
|
82
82
|
margin-bottom: layout.$spacing-05;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.graphsSection {
|
|
91
|
-
margin-bottom: layout.$spacing-08;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.graphContainer {
|
|
83
|
+
/* Allow cell to expand and wrap text */
|
|
84
|
+
width: auto;
|
|
85
|
+
min-width: 0;
|
|
86
|
+
max-width: none;
|
|
87
|
+
white-space: normal;
|
|
88
|
+
word-break: break-word;
|
|
89
|
+
overflow-wrap: anywhere;
|
|
95
90
|
padding: layout.$spacing-04;
|
|
96
91
|
background-color: colors.$white;
|
|
97
92
|
border-radius: layout.$spacing-02;
|
|
@@ -664,7 +659,7 @@
|
|
|
664
659
|
display: flex;
|
|
665
660
|
align-items: center;
|
|
666
661
|
justify-content: center;
|
|
667
|
-
min-width: 60px;
|
|
662
|
+
min-width: 60px;
|
|
668
663
|
|
|
669
664
|
&:last-child {
|
|
670
665
|
border-right: none;
|
|
@@ -675,21 +670,12 @@
|
|
|
675
670
|
}
|
|
676
671
|
}
|
|
677
672
|
|
|
678
|
-
// Optional: Adjust chart's axis label styling if needed to make space or match font
|
|
679
673
|
.cds--chart-wrapper {
|
|
680
|
-
// You might need to add specific CSS here to the Carbon Chart itself
|
|
681
|
-
// to fine-tune the bottom axis's appearance or padding if it overlaps
|
|
682
|
-
// or leaves too much space. This can be complex due to shadow DOM.
|
|
683
|
-
// E.g., .cds--chart-wrapper .cds--bottom-axis .cds--axis-labels { display: none; }
|
|
684
|
-
// or .cds--chart-wrapper .cds--bottom-axis .cds--axis-title { padding-bottom: 0; }
|
|
685
|
-
|
|
686
674
|
.cds--bottom-axis .cds--axis-title {
|
|
687
675
|
padding-bottom: 0;
|
|
688
676
|
}
|
|
689
677
|
|
|
690
|
-
// Override line colors for Alert and Action lines
|
|
691
678
|
.cds--line-path {
|
|
692
|
-
// Alert Line - Yellow dotted line
|
|
693
679
|
&[data-group-id='Alert Line'],
|
|
694
680
|
&[aria-label*='Alert Line'] {
|
|
695
681
|
stroke: #ffd700 !important;
|
|
@@ -697,7 +683,6 @@
|
|
|
697
683
|
stroke-dasharray: 8, 4 !important;
|
|
698
684
|
}
|
|
699
685
|
|
|
700
|
-
// Action Line - Red dotted line
|
|
701
686
|
&[data-group-id='Action Line'],
|
|
702
687
|
&[aria-label*='Action Line'] {
|
|
703
688
|
stroke: #ff0000 !important;
|
|
@@ -706,7 +691,6 @@
|
|
|
706
691
|
}
|
|
707
692
|
}
|
|
708
693
|
|
|
709
|
-
// Alternative selector for different Carbon Charts versions
|
|
710
694
|
svg path {
|
|
711
695
|
&[data-name='Alert Line'] {
|
|
712
696
|
stroke: #ffd700 !important;
|
|
@@ -786,9 +770,7 @@
|
|
|
786
770
|
}
|
|
787
771
|
}
|
|
788
772
|
|
|
789
|
-
// Global overrides for Alert and Action lines (outside any wrapper)
|
|
790
773
|
:global {
|
|
791
|
-
// Try to target lines by data attributes
|
|
792
774
|
[data-group='Alert Line'] {
|
|
793
775
|
stroke: #ffd700 !important;
|
|
794
776
|
stroke-width: 3px !important;
|
|
@@ -801,10 +783,7 @@
|
|
|
801
783
|
stroke-dasharray: 8, 4 !important;
|
|
802
784
|
}
|
|
803
785
|
|
|
804
|
-
// Try broad SVG path targeting in cervix chart
|
|
805
786
|
[data-chart-id='cervix'] svg path {
|
|
806
|
-
// If there are 3 or more lines (cervix data + alert + action)
|
|
807
|
-
// Target the last two as Alert and Action lines
|
|
808
787
|
&:nth-last-child(2) {
|
|
809
788
|
stroke: #ffd700 !important;
|
|
810
789
|
stroke-width: 3px !important;
|
|
@@ -819,14 +798,10 @@
|
|
|
819
798
|
}
|
|
820
799
|
}
|
|
821
800
|
|
|
822
|
-
// Optional: Adjust the height of the chart if the new labels cause overflow
|
|
823
801
|
.chartContainer {
|
|
824
|
-
height: 500px;
|
|
825
|
-
// If the new labels cause overlap, you might need to make the chart slightly shorter
|
|
826
|
-
// e.g., height: 450px; and then adjust overall graphContainer height.
|
|
802
|
+
height: 500px;
|
|
827
803
|
}
|
|
828
804
|
|
|
829
|
-
/* Fetal Heart Rate Section Styles */
|
|
830
805
|
.fetalHeartRateSection {
|
|
831
806
|
margin-bottom: layout.$spacing-07;
|
|
832
807
|
width: 100%;
|
|
@@ -888,7 +863,6 @@
|
|
|
888
863
|
flex-wrap: wrap;
|
|
889
864
|
}
|
|
890
865
|
|
|
891
|
-
// Orange tag style for low range
|
|
892
866
|
.tagLowRange {
|
|
893
867
|
background-color: #ff9800 !important;
|
|
894
868
|
color: #fff !important;
|
|
@@ -896,57 +870,46 @@
|
|
|
896
870
|
}
|
|
897
871
|
|
|
898
872
|
.fetalHeartRateChart {
|
|
899
|
-
min-height: 600px;
|
|
873
|
+
min-height: 600px;
|
|
900
874
|
width: 100%;
|
|
901
875
|
margin-top: layout.$spacing-04;
|
|
902
876
|
|
|
903
|
-
// Override Carbon chart styles for this specific chart
|
|
904
877
|
:global(.cds--cc--chart-svg) {
|
|
905
878
|
border: 1px solid colors.$gray-30;
|
|
906
879
|
border-radius: layout.$spacing-02;
|
|
907
|
-
min-height: 600px;
|
|
880
|
+
min-height: 600px;
|
|
908
881
|
}
|
|
909
882
|
|
|
910
|
-
// Chart wrapper to ensure proper sizing
|
|
911
883
|
:global(.cds--cc--chart-wrapper) {
|
|
912
884
|
min-height: 600px;
|
|
913
|
-
padding-bottom: layout.$spacing-06;
|
|
885
|
+
padding-bottom: layout.$spacing-06;
|
|
914
886
|
}
|
|
915
|
-
|
|
916
|
-
// Grid line styling to match cervix graph
|
|
917
887
|
:global(.cds--cc--grid-line) {
|
|
918
888
|
stroke: colors.$gray-30;
|
|
919
889
|
stroke-opacity: 0.3;
|
|
920
890
|
}
|
|
921
|
-
|
|
922
|
-
// Ensure x-axis labels have proper spacing and are horizontal
|
|
923
891
|
:global(.cds--cc--axis-tick-label) {
|
|
924
892
|
font-size: 12px;
|
|
925
893
|
fill: colors.$gray-70;
|
|
926
894
|
}
|
|
927
895
|
|
|
928
|
-
// X-axis label positioning - ensure they are horizontal
|
|
929
896
|
:global(.cds--cc--axis.cds--cc--axis--bottom .cds--cc--axis-tick-label) {
|
|
930
897
|
text-anchor: middle;
|
|
931
|
-
transform: none !important;
|
|
898
|
+
transform: none !important;
|
|
932
899
|
}
|
|
933
900
|
|
|
934
|
-
// Y-axis styling
|
|
935
901
|
:global(.cds--cc--axis.cds--cc--axis--left .cds--cc--axis-tick-label) {
|
|
936
902
|
text-anchor: end;
|
|
937
903
|
}
|
|
938
904
|
|
|
939
|
-
// Ensure chart container has enough bottom padding for labels
|
|
940
905
|
:global(.cds--cc--chart-holder) {
|
|
941
906
|
padding-bottom: layout.$spacing-08 !important;
|
|
942
907
|
}
|
|
943
908
|
|
|
944
|
-
// Disable any text rotation on bottom axis
|
|
945
909
|
:global(.cds--cc--axis--bottom text) {
|
|
946
910
|
transform: rotate(0deg) !important;
|
|
947
911
|
}
|
|
948
912
|
|
|
949
|
-
// Axis styling
|
|
950
913
|
:global(.cds--cc--axis) {
|
|
951
914
|
.tick text {
|
|
952
915
|
font-size: 12px;
|
|
@@ -959,7 +922,6 @@
|
|
|
959
922
|
}
|
|
960
923
|
}
|
|
961
924
|
|
|
962
|
-
// Fetal Heart Rate Table Value Styling
|
|
963
925
|
.fetalHeartRateValue {
|
|
964
926
|
display: inline-flex;
|
|
965
927
|
align-items: center;
|
|
@@ -994,7 +956,6 @@
|
|
|
994
956
|
}
|
|
995
957
|
}
|
|
996
958
|
|
|
997
|
-
/* Membrane Amniotic Fluid Grid Styles */
|
|
998
959
|
.membraneGrid {
|
|
999
960
|
width: 100%;
|
|
1000
961
|
margin-top: layout.$spacing-04;
|
|
@@ -1002,14 +963,16 @@
|
|
|
1002
963
|
border: 1px solid colors.$gray-30;
|
|
1003
964
|
border-radius: layout.$spacing-02;
|
|
1004
965
|
overflow-x: auto;
|
|
1005
|
-
max-height: 300px;
|
|
1006
|
-
max-width: 1540px;
|
|
966
|
+
max-height: 300px;
|
|
967
|
+
max-width: 1540px;
|
|
1007
968
|
}
|
|
1008
969
|
|
|
1009
970
|
.gridContainer {
|
|
1010
971
|
display: flex;
|
|
1011
972
|
flex-direction: column;
|
|
1012
|
-
min-width:
|
|
973
|
+
min-width: 0;
|
|
974
|
+
width: auto;
|
|
975
|
+
max-width: 100%;
|
|
1013
976
|
}
|
|
1014
977
|
|
|
1015
978
|
.gridHeader {
|
|
@@ -1029,7 +992,7 @@
|
|
|
1029
992
|
}
|
|
1030
993
|
|
|
1031
994
|
.gridCell {
|
|
1032
|
-
flex: 0 0 70px;
|
|
995
|
+
flex: 0 0 70px;
|
|
1033
996
|
min-width: 70px;
|
|
1034
997
|
padding: layout.$spacing-03;
|
|
1035
998
|
border-right: 1px solid colors.$gray-20;
|
|
@@ -1071,7 +1034,6 @@
|
|
|
1071
1034
|
font-style: italic;
|
|
1072
1035
|
}
|
|
1073
1036
|
|
|
1074
|
-
// Contraction Level Selector - Simple colored buttons
|
|
1075
1037
|
.contractionLevelSelector {
|
|
1076
1038
|
display: flex;
|
|
1077
1039
|
flex-direction: row;
|
|
@@ -1141,14 +1103,12 @@
|
|
|
1141
1103
|
cursor: pointer;
|
|
1142
1104
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
|
|
1143
1105
|
|
|
1144
|
-
// None - Light gray background
|
|
1145
1106
|
&.none {
|
|
1146
1107
|
background-color: colors.$gray-30;
|
|
1147
1108
|
color: colors.$gray-100;
|
|
1148
1109
|
border-color: colors.$gray-50;
|
|
1149
1110
|
}
|
|
1150
1111
|
|
|
1151
|
-
// Mild - Black dots pattern
|
|
1152
1112
|
&.mild {
|
|
1153
1113
|
background-color: #fff;
|
|
1154
1114
|
color: #111;
|
|
@@ -1157,7 +1117,6 @@
|
|
|
1157
1117
|
background-size: 12px 12px;
|
|
1158
1118
|
}
|
|
1159
1119
|
|
|
1160
|
-
// Moderate - Diagonal black lines pattern (tuned)
|
|
1161
1120
|
&.moderate {
|
|
1162
1121
|
background-color: #fff;
|
|
1163
1122
|
color: #111;
|
|
@@ -1166,7 +1125,6 @@
|
|
|
1166
1125
|
background-size: 16px 16px;
|
|
1167
1126
|
}
|
|
1168
1127
|
|
|
1169
|
-
// Strong - Solid black
|
|
1170
1128
|
&.strong {
|
|
1171
1129
|
background-color: #111;
|
|
1172
1130
|
color: #fff;
|
|
@@ -1182,7 +1140,6 @@
|
|
|
1182
1140
|
text-align: center;
|
|
1183
1141
|
}
|
|
1184
1142
|
|
|
1185
|
-
// Contractions Form Container
|
|
1186
1143
|
.contractionsFormContainer {
|
|
1187
1144
|
padding: layout.$spacing-03 layout.$spacing-03;
|
|
1188
1145
|
max-width: 700px;
|
|
@@ -1272,7 +1229,6 @@
|
|
|
1272
1229
|
}
|
|
1273
1230
|
}
|
|
1274
1231
|
|
|
1275
|
-
// Detailed Contractions Grid - Partograph Format
|
|
1276
1232
|
.contractionsContainer {
|
|
1277
1233
|
display: flex;
|
|
1278
1234
|
flex-direction: column;
|
|
@@ -1357,7 +1313,6 @@
|
|
|
1357
1313
|
color: colors.$gray-100;
|
|
1358
1314
|
position: relative;
|
|
1359
1315
|
|
|
1360
|
-
// Ensure the numbers are clearly visible
|
|
1361
1316
|
&::before {
|
|
1362
1317
|
content: attr(data-label);
|
|
1363
1318
|
position: absolute;
|
|
@@ -1424,7 +1379,6 @@
|
|
|
1424
1379
|
}
|
|
1425
1380
|
}
|
|
1426
1381
|
|
|
1427
|
-
// Contraction Bar Visual Indicators
|
|
1428
1382
|
.contractionBar {
|
|
1429
1383
|
width: 100%;
|
|
1430
1384
|
height: 100%;
|
|
@@ -1466,7 +1420,6 @@
|
|
|
1466
1420
|
box-shadow: none;
|
|
1467
1421
|
}
|
|
1468
1422
|
|
|
1469
|
-
// Oxytocin Bar Visual Indicators
|
|
1470
1423
|
.oxytocinBarLow {
|
|
1471
1424
|
background-color: colors.$green-40;
|
|
1472
1425
|
border: 2px solid colors.$green-60;
|
|
@@ -1522,13 +1475,11 @@
|
|
|
1522
1475
|
color: colors.$gray-80;
|
|
1523
1476
|
}
|
|
1524
1477
|
|
|
1525
|
-
// Grid container for contractions
|
|
1526
1478
|
.contractionsGrid {
|
|
1527
1479
|
position: relative;
|
|
1528
1480
|
margin: layout.$spacing-04 0;
|
|
1529
1481
|
}
|
|
1530
1482
|
|
|
1531
|
-
// Table view styles for contractions
|
|
1532
1483
|
.contractionsTable {
|
|
1533
1484
|
background-color: colors.$white;
|
|
1534
1485
|
border: 1px solid colors.$gray-30;
|
|
@@ -1590,7 +1541,6 @@
|
|
|
1590
1541
|
}
|
|
1591
1542
|
}
|
|
1592
1543
|
|
|
1593
|
-
// ===== DRUGS AND IV FLUIDS GRAPH STYLES =====
|
|
1594
1544
|
.drugsIVFluidsGraph {
|
|
1595
1545
|
width: 100%;
|
|
1596
1546
|
margin: layout.$spacing-05 0;
|
|
@@ -1628,7 +1578,6 @@
|
|
|
1628
1578
|
}
|
|
1629
1579
|
}
|
|
1630
1580
|
|
|
1631
|
-
// Oxytocin specific styling when inside fetalHeartRateContainer
|
|
1632
1581
|
.fetalHeartRateContainer {
|
|
1633
1582
|
.membraneGrid {
|
|
1634
1583
|
margin: 0;
|
|
@@ -1660,12 +1609,13 @@
|
|
|
1660
1609
|
text-align: center;
|
|
1661
1610
|
font-size: 12px;
|
|
1662
1611
|
line-height: 1.2;
|
|
1612
|
+
white-space: normal;
|
|
1613
|
+
word-break: break-word;
|
|
1663
1614
|
|
|
1664
1615
|
&:hover {
|
|
1665
1616
|
background-color: colors.$gray-10;
|
|
1666
1617
|
}
|
|
1667
1618
|
}
|
|
1668
|
-
|
|
1669
1619
|
.drugInfo {
|
|
1670
1620
|
display: flex;
|
|
1671
1621
|
flex-direction: column;
|
|
@@ -1677,16 +1627,10 @@
|
|
|
1677
1627
|
color: colors.$gray-100;
|
|
1678
1628
|
font-size: 11px;
|
|
1679
1629
|
line-height: 1.2;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
.drugDosage {
|
|
1683
|
-
font-weight: 400;
|
|
1684
|
-
color: colors.$gray-70;
|
|
1685
1630
|
font-size: 10px;
|
|
1686
1631
|
line-height: 1.1;
|
|
1687
1632
|
}
|
|
1688
1633
|
|
|
1689
|
-
// Pulse and BP Graph Styling
|
|
1690
1634
|
.pulseBPGraph {
|
|
1691
1635
|
width: 100%;
|
|
1692
1636
|
margin: layout.$spacing-05 0;
|
|
@@ -1698,28 +1642,20 @@
|
|
|
1698
1642
|
border: 2px solid colors.$gray-40;
|
|
1699
1643
|
margin-bottom: layout.$spacing-04;
|
|
1700
1644
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
1701
|
-
min-height: 650px;
|
|
1702
|
-
|
|
1703
|
-
// Medical chart styling
|
|
1645
|
+
min-height: 650px;
|
|
1704
1646
|
:global(.cds--chart-wrapper) {
|
|
1705
1647
|
border: 1px solid colors.$gray-30;
|
|
1706
1648
|
border-radius: layout.$spacing-02;
|
|
1707
1649
|
overflow: hidden;
|
|
1708
|
-
|
|
1709
|
-
// Enhanced grid lines for medical chart appearance
|
|
1710
1650
|
:global(.cds--chart) {
|
|
1711
1651
|
background-color: colors.$white;
|
|
1712
|
-
|
|
1713
|
-
// Grid styling for medical charts
|
|
1714
1652
|
:global(.cds--chart-grid-line) {
|
|
1715
1653
|
stroke: colors.$gray-30;
|
|
1716
1654
|
stroke-width: 1;
|
|
1717
1655
|
}
|
|
1718
|
-
|
|
1719
1656
|
:global(.cds--chart-axis) {
|
|
1720
1657
|
stroke: colors.$gray-50;
|
|
1721
1658
|
}
|
|
1722
|
-
|
|
1723
1659
|
:global(.cds--chart-axis text) {
|
|
1724
1660
|
fill: colors.$gray-90;
|
|
1725
1661
|
font-size: 12px;
|
|
@@ -183,7 +183,21 @@ export function useCervixData(patientUuid: string) {
|
|
|
183
183
|
openmrsFetch,
|
|
184
184
|
);
|
|
185
185
|
const cervixData = data?.data?.results || [];
|
|
186
|
-
|
|
186
|
+
|
|
187
|
+
// Filter encounters to only include those with cervix-specific concepts
|
|
188
|
+
const cervixSpecificEncounters = cervixData.filter((encounter) => {
|
|
189
|
+
if (!encounter.obs || !Array.isArray(encounter.obs)) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
// An encounter is cervix-specific if it contains cervical dilation OR descent of head concepts
|
|
193
|
+
return encounter.obs.some(
|
|
194
|
+
(obs) =>
|
|
195
|
+
obs.concept?.uuid === CERVIX_FORM_CONCEPTS.cervicalDilation ||
|
|
196
|
+
obs.concept?.uuid === CERVIX_FORM_CONCEPTS.descentOfHead,
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const sortedEncounters = cervixSpecificEncounters.sort(
|
|
187
201
|
(a, b) => new Date(b.encounterDatetime).getTime() - new Date(a.encounterDatetime).getTime(),
|
|
188
202
|
);
|
|
189
203
|
const transformedData = sortedEncounters.map((encounter) => {
|
package/src/maternal-and-child-health/partography/resources/membrane-amniotic-fluid.resource.ts
CHANGED
|
@@ -2,9 +2,26 @@ import { useMemo } from 'react';
|
|
|
2
2
|
import useSWR from 'swr';
|
|
3
3
|
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
4
4
|
import { PARTOGRAPHY_CONCEPTS, MCH_PARTOGRAPHY_ENCOUNTER_UUID } from '../types';
|
|
5
|
-
import { createPartographyEncounter } from '../partography.resource';
|
|
5
|
+
import { createPartographyEncounter, usePartographyData } from '../partography.resource';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
|
+
export interface MembraneAmnioticFluidTimeEntry {
|
|
9
|
+
hour: number;
|
|
10
|
+
time: string;
|
|
11
|
+
timeSlot: string;
|
|
12
|
+
encounterDatetime: string;
|
|
13
|
+
amnioticFluid?: string;
|
|
14
|
+
moulding?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface UseMembraneAmnioticFluidFormDataResult {
|
|
18
|
+
membraneAmnioticFluidData: any[];
|
|
19
|
+
membraneAmnioticFluidTimeEntries: MembraneAmnioticFluidTimeEntry[];
|
|
20
|
+
isLoading: boolean;
|
|
21
|
+
error: any;
|
|
22
|
+
mutate: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
export function useMembraneAmnioticFluidData(patientUuid: string) {
|
|
9
26
|
const { t } = useTranslation();
|
|
10
27
|
const fetcher = (url: string) => openmrsFetch(url).then((res) => res.json());
|
|
@@ -76,6 +93,115 @@ export function useMembraneAmnioticFluidData(patientUuid: string) {
|
|
|
76
93
|
};
|
|
77
94
|
}
|
|
78
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Custom hook for membrane amniotic fluid form-specific data isolation
|
|
98
|
+
* This ensures membrane amniotic fluid form validations only consider membrane amniotic fluid data
|
|
99
|
+
*/
|
|
100
|
+
export const useMembraneAmnioticFluidFormData = (patientUuid: string): UseMembraneAmnioticFluidFormDataResult => {
|
|
101
|
+
const {
|
|
102
|
+
data: membraneAmnioticFluidEncounters = [],
|
|
103
|
+
isLoading,
|
|
104
|
+
error,
|
|
105
|
+
mutate,
|
|
106
|
+
} = usePartographyData(patientUuid, 'membrane-amniotic-fluid');
|
|
107
|
+
|
|
108
|
+
// Extract membrane amniotic fluid-specific time entries for form validation
|
|
109
|
+
const membraneAmnioticFluidTimeEntries = useMemo(() => {
|
|
110
|
+
if (!membraneAmnioticFluidEncounters || membraneAmnioticFluidEncounters.length === 0) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return membraneAmnioticFluidEncounters
|
|
115
|
+
.map((encounter) => {
|
|
116
|
+
// Find amniotic fluid observation
|
|
117
|
+
const amnioticFluidObs = encounter.obs.find(
|
|
118
|
+
(obs) => obs.concept.uuid === PARTOGRAPHY_CONCEPTS['amniotic-fluid'],
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Find moulding observation
|
|
122
|
+
const mouldingObs = encounter.obs.find((obs) => obs.concept.uuid === PARTOGRAPHY_CONCEPTS['moulding']);
|
|
123
|
+
|
|
124
|
+
// Find time observation
|
|
125
|
+
const timeObs = encounter.obs.find(
|
|
126
|
+
(obs) =>
|
|
127
|
+
obs.concept.uuid === PARTOGRAPHY_CONCEPTS['fetal-heart-rate-time'] &&
|
|
128
|
+
typeof obs.value === 'string' &&
|
|
129
|
+
obs.value.startsWith('Time:'),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (!amnioticFluidObs && !mouldingObs) {
|
|
133
|
+
return null; // Skip if no membrane amniotic fluid data
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Extract time from observation value
|
|
137
|
+
let time = '';
|
|
138
|
+
if (timeObs && typeof timeObs.value === 'string') {
|
|
139
|
+
const timeMatch = timeObs.value.match(/Time:\s*(.+)/);
|
|
140
|
+
if (timeMatch) {
|
|
141
|
+
time = timeMatch[1].trim();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!time || !time.match(/^\d{1,2}:\d{2}$/)) {
|
|
146
|
+
return null; // Skip if invalid time format
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Convert time to hour value for progressive validation
|
|
150
|
+
const [hours, minutes] = time.split(':').map(Number);
|
|
151
|
+
const hourValue = hours + minutes / 60; // Convert to decimal hour
|
|
152
|
+
|
|
153
|
+
// Create timeSlot from hour (for backward compatibility with existing form logic)
|
|
154
|
+
const timeSlot = hourValue.toString();
|
|
155
|
+
|
|
156
|
+
// Extract amniotic fluid value
|
|
157
|
+
let amnioticFluid: string | undefined;
|
|
158
|
+
if (amnioticFluidObs?.value) {
|
|
159
|
+
if (
|
|
160
|
+
typeof amnioticFluidObs.value === 'object' &&
|
|
161
|
+
amnioticFluidObs.value &&
|
|
162
|
+
'display' in amnioticFluidObs.value
|
|
163
|
+
) {
|
|
164
|
+
amnioticFluid = (amnioticFluidObs.value as any).display;
|
|
165
|
+
} else {
|
|
166
|
+
amnioticFluid = String(amnioticFluidObs.value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Extract moulding value
|
|
171
|
+
let moulding: string | undefined;
|
|
172
|
+
if (mouldingObs?.value) {
|
|
173
|
+
if (typeof mouldingObs.value === 'object' && mouldingObs.value && 'display' in mouldingObs.value) {
|
|
174
|
+
moulding = (mouldingObs.value as any).display;
|
|
175
|
+
} else {
|
|
176
|
+
moulding = String(mouldingObs.value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
hour: hourValue,
|
|
182
|
+
time: time,
|
|
183
|
+
timeSlot: timeSlot,
|
|
184
|
+
encounterDatetime: encounter.encounterDatetime,
|
|
185
|
+
amnioticFluid,
|
|
186
|
+
moulding,
|
|
187
|
+
};
|
|
188
|
+
})
|
|
189
|
+
.filter((entry) => entry !== null)
|
|
190
|
+
.sort((a, b) => {
|
|
191
|
+
// Sort by encounter datetime for chronological order
|
|
192
|
+
return new Date(a!.encounterDatetime).getTime() - new Date(b!.encounterDatetime).getTime();
|
|
193
|
+
}) as MembraneAmnioticFluidTimeEntry[];
|
|
194
|
+
}, [membraneAmnioticFluidEncounters]);
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
membraneAmnioticFluidData: membraneAmnioticFluidEncounters,
|
|
198
|
+
membraneAmnioticFluidTimeEntries,
|
|
199
|
+
isLoading,
|
|
200
|
+
error,
|
|
201
|
+
mutate,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
|
|
79
205
|
export async function saveMembraneAmnioticFluidData(
|
|
80
206
|
patientUuid: string,
|
|
81
207
|
formData: { amnioticFluid: string; moulding: string; time: string },
|
|
@@ -106,3 +232,46 @@ export async function saveMembraneAmnioticFluidData(
|
|
|
106
232
|
};
|
|
107
233
|
}
|
|
108
234
|
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Helper function to convert time string to decimal hour
|
|
238
|
+
* Example: "14:30" -> 14.5
|
|
239
|
+
*/
|
|
240
|
+
export const convertMembraneTimeToHour = (timeString: string): number => {
|
|
241
|
+
if (!timeString || !timeString.match(/^\d{1,2}:\d{2}$/)) {
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const [hours, minutes] = timeString.split(':').map(Number);
|
|
246
|
+
return hours + minutes / 60;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Helper function to extract time from membrane amniotic fluid observation value
|
|
251
|
+
*/
|
|
252
|
+
export const extractTimeFromMembraneObs = (obsValue: any): string => {
|
|
253
|
+
if (!obsValue) {
|
|
254
|
+
return '';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (typeof obsValue === 'string') {
|
|
258
|
+
// Handle "Time: HH:MM" format
|
|
259
|
+
if (obsValue.startsWith('Time:')) {
|
|
260
|
+
const match = obsValue.match(/Time:\s*(.+)/);
|
|
261
|
+
if (match) {
|
|
262
|
+
const time = match[1].trim();
|
|
263
|
+
// Validate HH:MM format
|
|
264
|
+
if (time.match(/^\d{1,2}:\d{2}$/)) {
|
|
265
|
+
return time;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Handle direct HH:MM format
|
|
271
|
+
if (obsValue.match(/^\d{1,2}:\d{2}$/)) {
|
|
272
|
+
return obsValue;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return '';
|
|
277
|
+
};
|