@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2592 → 5.4.2-pre.2598
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 +6 -6
- package/dist/127.js +1 -1
- package/dist/152.js +3 -3
- package/dist/152.js.map +1 -1
- package/dist/481.js +66 -0
- package/dist/481.js.map +1 -0
- package/dist/671.js +1 -1
- package/dist/671.js.map +1 -1
- package/dist/941.js +1 -0
- package/dist/941.js.map +1 -0
- package/dist/kenyaemr-esm-patient-clinical-view-app.js +2 -2
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +55 -55
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.map +1 -1
- package/dist/main.js +87 -14
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +144 -0
- package/src/index.ts +2 -2
- package/src/maternal-and-child-health/partography/labour-delivery.scss +6 -7
- package/src/maternal-and-child-health/partography/partograph.component.tsx +487 -151
- package/src/maternal-and-child-health/partography/partography-data-form.component.tsx +434 -0
- package/src/maternal-and-child-health/partography/partography-data-form.scss +50 -0
- package/src/maternal-and-child-health/partography/partography-link.component.tsx +21 -0
- package/src/maternal-and-child-health/partography/partography.resource.ts +1024 -0
- package/src/maternal-and-child-health/partography/partography.scss +378 -0
- package/src/maternal-and-child-health/partography/types/index.ts +980 -0
- package/translations/en.json +11 -1
- package/dist/287.js +0 -1
- package/dist/287.js.map +0 -1
- package/dist/98.js +0 -1
- package/dist/98.js.map +0 -1
- package/src/maternal-and-child-health/partography/cervical-dilation.component.tsx +0 -16
- package/src/maternal-and-child-health/partography/contraction-level.component.tsx +0 -16
- package/src/maternal-and-child-health/partography/descent-of-head.component.tsx +0 -16
- package/src/maternal-and-child-health/partography/foetal-heart-rate.component.tsx +0 -17
- package/src/maternal-and-child-health/partography/membrane-amniotic-fluid-moulding.component.tsx +0 -17
- package/src/maternal-and-child-health/partography/partograph-chart.scss +0 -94
- package/src/maternal-and-child-health/partography/partograph-chart.tsx +0 -176
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
export const PARTOGRAPHY_CONCEPTS = {
|
|
2
|
+
'fetal-heart-rate': '1440AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
3
|
+
'cervical-dilation': '162261AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
4
|
+
'descent-of-head': '1810AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
5
|
+
'uterine-contractions': '163750AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
6
|
+
'uterine-contraction-frequency': '166529AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
7
|
+
'uterine-contraction-duration': '159368AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
8
|
+
'maternal-pulse': '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
9
|
+
'systolic-bp': '5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
10
|
+
'diastolic-bp': '5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
11
|
+
temperature: '5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
12
|
+
'protein-level': '161442AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
13
|
+
'glucose-level': '887AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
14
|
+
'ketone-level': '165438AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
15
|
+
'urine-volume': '159660AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
16
|
+
'urine-characteristics': '56AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
17
|
+
medication: '1282AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
18
|
+
'medication-name': '164231AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
19
|
+
'oxytocin-dose': '166531AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
20
|
+
'iv-fluids': '161911AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
21
|
+
dosage: '1443AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
22
|
+
'event-type': '162879AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
23
|
+
'event-description': '160632AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
24
|
+
'amniotic-fluid': '162653AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
25
|
+
moulding: '166527AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
26
|
+
'blood-group': '300AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
27
|
+
'time-slot': '163286AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
28
|
+
'labor-pattern': '164135AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
29
|
+
'hours-since-rupture': '167149AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
30
|
+
'ruptured-membranes': '164900AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
31
|
+
'date-of-admission': '1640AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
32
|
+
'gestation-weeks': '1789AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
33
|
+
'estimated-delivery-date': '5596AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
34
|
+
'last-menstrual-period': '1427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
export const MCH_PARTOGRAPHY_ENCOUNTER_UUID = '022d62af-e2a5-4282-953b-52dd5cba3296';
|
|
38
|
+
|
|
39
|
+
export const PARTOGRAPHY_GRAPH_TYPES = [
|
|
40
|
+
'fetal-heart-rate',
|
|
41
|
+
'cervical-dilation',
|
|
42
|
+
'descent-of-head',
|
|
43
|
+
'uterine-contractions',
|
|
44
|
+
'maternal-pulse',
|
|
45
|
+
'blood-pressure',
|
|
46
|
+
'temperature',
|
|
47
|
+
'urine-analysis',
|
|
48
|
+
'drugs-fluids',
|
|
49
|
+
'progress-events',
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
export const PARTOGRAPHY_ENCOUNTER_TYPES = Object.fromEntries(
|
|
53
|
+
PARTOGRAPHY_GRAPH_TYPES.map((type) => [type, MCH_PARTOGRAPHY_ENCOUNTER_UUID]),
|
|
54
|
+
) as Record<(typeof PARTOGRAPHY_GRAPH_TYPES)[number], string>;
|
|
55
|
+
|
|
56
|
+
export interface OpenMRSResponse<T> {
|
|
57
|
+
results: T[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface PartographyObservation {
|
|
61
|
+
uuid: string;
|
|
62
|
+
concept: {
|
|
63
|
+
uuid: string;
|
|
64
|
+
display: string;
|
|
65
|
+
};
|
|
66
|
+
value: string | number;
|
|
67
|
+
obsDatetime: string;
|
|
68
|
+
encounter: {
|
|
69
|
+
uuid: string;
|
|
70
|
+
encounterType: {
|
|
71
|
+
uuid: string;
|
|
72
|
+
display: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface PartographyEncounter {
|
|
78
|
+
uuid: string;
|
|
79
|
+
encounterDatetime: string;
|
|
80
|
+
encounterType: {
|
|
81
|
+
uuid: string;
|
|
82
|
+
display: string;
|
|
83
|
+
};
|
|
84
|
+
obs: PartographyObservation[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type PartographyGraphType = keyof typeof PARTOGRAPHY_ENCOUNTER_TYPES;
|
|
88
|
+
|
|
89
|
+
export interface PartographyGraph {
|
|
90
|
+
id: PartographyGraphType;
|
|
91
|
+
titleKey: string;
|
|
92
|
+
titleDefault: string;
|
|
93
|
+
descriptionKey: string;
|
|
94
|
+
descriptionDefault: string;
|
|
95
|
+
yAxisLabel: string;
|
|
96
|
+
normalRange: string;
|
|
97
|
+
color: string;
|
|
98
|
+
yMin: number;
|
|
99
|
+
yMax: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const PARTOGRAPHY_UNITS = {
|
|
103
|
+
'fetal-heart-rate': 'BPM',
|
|
104
|
+
'cervical-dilation': 'cm',
|
|
105
|
+
'descent-of-head': 'Station',
|
|
106
|
+
'uterine-contractions': 'per 10min',
|
|
107
|
+
'maternal-pulse': 'BPM',
|
|
108
|
+
'blood-pressure': 'mmHg',
|
|
109
|
+
temperature: '°C',
|
|
110
|
+
'urine-analysis': 'Level',
|
|
111
|
+
'drugs-fluids': 'ml/hr',
|
|
112
|
+
'progress-events': 'Value',
|
|
113
|
+
} as const;
|
|
114
|
+
|
|
115
|
+
export const PARTOGRAPHY_NORMAL_RANGES = {
|
|
116
|
+
'fetal-heart-rate': '110-160 BPM',
|
|
117
|
+
'cervical-dilation': '0-10 cm',
|
|
118
|
+
'descent-of-head': '-3 to +3',
|
|
119
|
+
'uterine-contractions': '2-5 per 10min',
|
|
120
|
+
'maternal-pulse': '60-100 BPM',
|
|
121
|
+
'blood-pressure': '90/60-140/90',
|
|
122
|
+
temperature: '36-37.5°C',
|
|
123
|
+
'urine-analysis': 'Negative/Trace',
|
|
124
|
+
'drugs-fluids': 'As prescribed',
|
|
125
|
+
'progress-events': 'Timeline based',
|
|
126
|
+
} as const;
|
|
127
|
+
|
|
128
|
+
export const PARTOGRAPHY_COLORS = {
|
|
129
|
+
'fetal-heart-rate': 'red',
|
|
130
|
+
'cervical-dilation': 'blue',
|
|
131
|
+
'descent-of-head': 'green',
|
|
132
|
+
'uterine-contractions': 'purple',
|
|
133
|
+
'maternal-pulse': 'orange',
|
|
134
|
+
'blood-pressure': 'cyan',
|
|
135
|
+
temperature: 'teal',
|
|
136
|
+
'urine-analysis': 'yellow',
|
|
137
|
+
'drugs-fluids': 'magenta',
|
|
138
|
+
'progress-events': 'gray',
|
|
139
|
+
} as const;
|
|
140
|
+
|
|
141
|
+
export const PARTOGRAPHY_Y_RANGES = {
|
|
142
|
+
'fetal-heart-rate': { min: 80, max: 200 },
|
|
143
|
+
'cervical-dilation': { min: 0, max: 10 },
|
|
144
|
+
'descent-of-head': { min: -4, max: 4 },
|
|
145
|
+
'uterine-contractions': { min: 0, max: 6 },
|
|
146
|
+
'maternal-pulse': { min: 50, max: 120 },
|
|
147
|
+
'blood-pressure': { min: 50, max: 180 },
|
|
148
|
+
temperature: { min: 35, max: 39 },
|
|
149
|
+
'urine-analysis': { min: 0, max: 4 },
|
|
150
|
+
'drugs-fluids': { min: 0, max: 500 },
|
|
151
|
+
'progress-events': { min: 0, max: 10 },
|
|
152
|
+
} as const;
|
|
153
|
+
|
|
154
|
+
export const PARTOGRAPHY_COLOR_MAPPINGS = {
|
|
155
|
+
red: '#da1e28',
|
|
156
|
+
blue: '#0f62fe',
|
|
157
|
+
green: '#24a148',
|
|
158
|
+
purple: '#8a3ffc',
|
|
159
|
+
orange: '#ff832b',
|
|
160
|
+
cyan: '#1192e8',
|
|
161
|
+
teal: '#009d9a',
|
|
162
|
+
yellow: '#f1c21b',
|
|
163
|
+
magenta: '#d12771',
|
|
164
|
+
gray: '#525252',
|
|
165
|
+
} as const;
|
|
166
|
+
|
|
167
|
+
export const isValidPartographyGraphType = (type: string): type is PartographyGraphType => {
|
|
168
|
+
return PARTOGRAPHY_GRAPH_TYPES.includes(type as PartographyGraphType);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const getPartographyUnit = (graphType: PartographyGraphType): string => {
|
|
172
|
+
return PARTOGRAPHY_UNITS[graphType];
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const getPartographyNormalRange = (graphType: PartographyGraphType): string => {
|
|
176
|
+
return PARTOGRAPHY_NORMAL_RANGES[graphType];
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const getPartographyColor = (graphType: PartographyGraphType): string => {
|
|
180
|
+
return PARTOGRAPHY_COLORS[graphType];
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const getPartographyYRange = (graphType: PartographyGraphType): { min: number; max: number } => {
|
|
184
|
+
return PARTOGRAPHY_Y_RANGES[graphType];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const PARTOGRAPHY_GRAPH_CONFIGS: PartographyGraph[] = [
|
|
188
|
+
{
|
|
189
|
+
id: 'fetal-heart-rate',
|
|
190
|
+
titleKey: 'fetalHeartRate',
|
|
191
|
+
titleDefault: 'Fetal Heart Rate',
|
|
192
|
+
descriptionKey: 'fetalHeartRateDesc',
|
|
193
|
+
descriptionDefault: 'Monitor fetal well-being during labor',
|
|
194
|
+
yAxisLabel: 'BPM',
|
|
195
|
+
normalRange: '110-160 BPM',
|
|
196
|
+
color: 'red',
|
|
197
|
+
yMin: 80,
|
|
198
|
+
yMax: 200,
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'cervical-dilation',
|
|
202
|
+
titleKey: 'cervicalDilation',
|
|
203
|
+
titleDefault: 'Cervical Dilation',
|
|
204
|
+
descriptionKey: 'cervicalDilationDesc',
|
|
205
|
+
descriptionDefault: 'Progress of cervical opening during labor',
|
|
206
|
+
yAxisLabel: 'cm',
|
|
207
|
+
normalRange: '0-10 cm',
|
|
208
|
+
color: 'blue',
|
|
209
|
+
yMin: 0,
|
|
210
|
+
yMax: 10,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: 'descent-of-head',
|
|
214
|
+
titleKey: 'descentOfHead',
|
|
215
|
+
titleDefault: 'Descent of Head',
|
|
216
|
+
descriptionKey: 'descentOfHeadDesc',
|
|
217
|
+
descriptionDefault: 'Fetal head position relative to ischial spines',
|
|
218
|
+
yAxisLabel: 'Station',
|
|
219
|
+
normalRange: '-3 to +3',
|
|
220
|
+
color: 'green',
|
|
221
|
+
yMin: -4,
|
|
222
|
+
yMax: 4,
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: 'uterine-contractions',
|
|
226
|
+
titleKey: 'uterineContractions',
|
|
227
|
+
titleDefault: 'Uterine Contractions',
|
|
228
|
+
descriptionKey: 'uterineContractionsDesc',
|
|
229
|
+
descriptionDefault: 'Frequency and intensity of contractions',
|
|
230
|
+
yAxisLabel: 'Contractions/10min',
|
|
231
|
+
normalRange: '2-5 per 10min',
|
|
232
|
+
color: 'purple',
|
|
233
|
+
yMin: 0,
|
|
234
|
+
yMax: 6,
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: 'maternal-pulse',
|
|
238
|
+
titleKey: 'maternalPulse',
|
|
239
|
+
titleDefault: 'Maternal Pulse',
|
|
240
|
+
descriptionKey: 'maternalPulseDesc',
|
|
241
|
+
descriptionDefault: 'Heart rate monitoring during labor',
|
|
242
|
+
yAxisLabel: 'BPM',
|
|
243
|
+
normalRange: '60-100 BPM',
|
|
244
|
+
color: 'orange',
|
|
245
|
+
yMin: 50,
|
|
246
|
+
yMax: 120,
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: 'blood-pressure',
|
|
250
|
+
titleKey: 'bloodPressure',
|
|
251
|
+
titleDefault: 'Blood Pressure',
|
|
252
|
+
descriptionKey: 'bloodPressureDesc',
|
|
253
|
+
descriptionDefault: 'Systolic and diastolic blood pressure',
|
|
254
|
+
yAxisLabel: 'mmHg',
|
|
255
|
+
normalRange: '90/60-140/90',
|
|
256
|
+
color: 'cyan',
|
|
257
|
+
yMin: 50,
|
|
258
|
+
yMax: 180,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: 'temperature',
|
|
262
|
+
titleKey: 'temperature',
|
|
263
|
+
titleDefault: 'Temperature',
|
|
264
|
+
descriptionKey: 'temperatureDesc',
|
|
265
|
+
descriptionDefault: 'Maternal body temperature monitoring',
|
|
266
|
+
yAxisLabel: '°C',
|
|
267
|
+
normalRange: '36-37.5°C',
|
|
268
|
+
color: 'teal',
|
|
269
|
+
yMin: 35,
|
|
270
|
+
yMax: 39,
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: 'urine-analysis',
|
|
274
|
+
titleKey: 'urineAnalysis',
|
|
275
|
+
titleDefault: 'Urine Analysis',
|
|
276
|
+
descriptionKey: 'urineAnalysisDesc',
|
|
277
|
+
descriptionDefault: 'Protein, glucose, and ketones in urine',
|
|
278
|
+
yAxisLabel: 'Level',
|
|
279
|
+
normalRange: 'Negative/Trace',
|
|
280
|
+
color: 'yellow',
|
|
281
|
+
yMin: 0,
|
|
282
|
+
yMax: 4,
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: 'drugs-fluids',
|
|
286
|
+
titleKey: 'drugsFluids',
|
|
287
|
+
titleDefault: 'Drugs & Fluids',
|
|
288
|
+
descriptionKey: 'drugsFluidsDesc',
|
|
289
|
+
descriptionDefault: 'Medications and fluid administration',
|
|
290
|
+
yAxisLabel: 'ml/hr',
|
|
291
|
+
normalRange: 'As prescribed',
|
|
292
|
+
color: 'magenta',
|
|
293
|
+
yMin: 0,
|
|
294
|
+
yMax: 500,
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: 'progress-events',
|
|
298
|
+
titleKey: 'progressEvents',
|
|
299
|
+
titleDefault: 'Progress & Events',
|
|
300
|
+
descriptionKey: 'progressEventsDesc',
|
|
301
|
+
descriptionDefault: 'Labor milestones and significant events',
|
|
302
|
+
yAxisLabel: 'Progress Stage',
|
|
303
|
+
normalRange: 'Timeline based',
|
|
304
|
+
color: 'gray',
|
|
305
|
+
yMin: 0,
|
|
306
|
+
yMax: 10,
|
|
307
|
+
},
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
export const getTranslatedPartographyGraphs = (t: (key: string, fallback: string) => string) => {
|
|
311
|
+
return PARTOGRAPHY_GRAPH_CONFIGS.map((config) => ({
|
|
312
|
+
id: config.id,
|
|
313
|
+
title: t(config.titleKey, config.titleDefault),
|
|
314
|
+
description: t(config.descriptionKey, config.descriptionDefault),
|
|
315
|
+
yAxisLabel: config.yAxisLabel,
|
|
316
|
+
normalRange: config.normalRange,
|
|
317
|
+
color: config.color,
|
|
318
|
+
yMin: config.yMin,
|
|
319
|
+
yMax: config.yMax,
|
|
320
|
+
}));
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
export const getPartographyTableHeaders = (t: (key: string, fallback: string) => string) => [
|
|
324
|
+
{ key: 'dateTime', header: t('dateAndTime', 'Date and time') },
|
|
325
|
+
{ key: 'value', header: t('value', 'Value') },
|
|
326
|
+
{ key: 'unit', header: t('unit', 'Unit') },
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
export const getColorForGraph = (colorName: string): string => {
|
|
330
|
+
return PARTOGRAPHY_COLOR_MAPPINGS[colorName as keyof typeof PARTOGRAPHY_COLOR_MAPPINGS] || '#525252';
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Concept UUID mappings for form options
|
|
334
|
+
export const FORM_OPTION_CONCEPTS = {
|
|
335
|
+
// Amniotic fluid concepts
|
|
336
|
+
AMNIOTIC_FLUID: {
|
|
337
|
+
MEMBRANE_INTACT: PARTOGRAPHY_CONCEPTS['amniotic-fluid'], // '162653AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
|
|
338
|
+
CLEAR_LIQUOR: '159484AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
339
|
+
MECONIUM_STAINED: '134488AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
340
|
+
ABSENT: '163747AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
341
|
+
BLOOD_STAINED: '1077AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// Moulding concepts
|
|
345
|
+
MOULDING: {
|
|
346
|
+
NONE: '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
347
|
+
SLIGHT: '1362AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
348
|
+
MODERATE: '1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
349
|
+
SEVERE: '1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// Descent of head station concepts
|
|
353
|
+
DESCENT_STATION: {
|
|
354
|
+
ZERO_FIFTHS: '160769AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
355
|
+
ONE_FIFTH: '162135AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
356
|
+
TWO_FIFTHS: '166065AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
357
|
+
THREE_FIFTHS: '166066AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
358
|
+
FOUR_FIFTHS: '166067AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
359
|
+
FIVE_FIFTHS: '163734AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
// Contraction intensity concepts
|
|
363
|
+
CONTRACTION_INTENSITY: {
|
|
364
|
+
MILD: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
|
|
365
|
+
MODERATE: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
|
|
366
|
+
STRONG: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
// Urine analysis level concepts
|
|
370
|
+
URINE_LEVELS: {
|
|
371
|
+
NEGATIVE: '1107AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
372
|
+
TRACE: '1362AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
373
|
+
POSITIVE_PLUS: '1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
374
|
+
POSITIVE_PLUS_PLUS: '1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
// Blood group concept (single concept, different values)
|
|
378
|
+
BLOOD_GROUP: PARTOGRAPHY_CONCEPTS['blood-group'],
|
|
379
|
+
|
|
380
|
+
// Event type concepts
|
|
381
|
+
EVENT_TYPES: {
|
|
382
|
+
MEMBRANE_RUPTURE: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
383
|
+
LABOR_ONSET: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
384
|
+
POSITION_CHANGE: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
385
|
+
MEDICATION_GIVEN: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
386
|
+
COMPLICATION: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
387
|
+
DELIVERY: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
388
|
+
OTHER: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
389
|
+
},
|
|
390
|
+
} as const;
|
|
391
|
+
|
|
392
|
+
// Form option configurations using concepts
|
|
393
|
+
export const AMNIOTIC_FLUID_OPTIONS = [
|
|
394
|
+
{ value: '', text: 'chooseAnOption', conceptUuid: '' },
|
|
395
|
+
{
|
|
396
|
+
value: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.MEMBRANE_INTACT,
|
|
397
|
+
text: 'membraneIntact',
|
|
398
|
+
conceptUuid: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.MEMBRANE_INTACT,
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
value: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.CLEAR_LIQUOR,
|
|
402
|
+
text: 'clearLiquor',
|
|
403
|
+
conceptUuid: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.CLEAR_LIQUOR,
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
value: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.MECONIUM_STAINED,
|
|
407
|
+
text: 'meconiumStained',
|
|
408
|
+
conceptUuid: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.MECONIUM_STAINED,
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
value: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.ABSENT,
|
|
412
|
+
text: 'absent',
|
|
413
|
+
conceptUuid: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.ABSENT,
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
value: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.BLOOD_STAINED,
|
|
417
|
+
text: 'bloodStained',
|
|
418
|
+
conceptUuid: FORM_OPTION_CONCEPTS.AMNIOTIC_FLUID.BLOOD_STAINED,
|
|
419
|
+
},
|
|
420
|
+
] as const;
|
|
421
|
+
|
|
422
|
+
export const MOULDING_OPTIONS = [
|
|
423
|
+
{ value: '', text: 'chooseAnOption', display: '', conceptUuid: '' },
|
|
424
|
+
{
|
|
425
|
+
value: FORM_OPTION_CONCEPTS.MOULDING.NONE,
|
|
426
|
+
text: 'none',
|
|
427
|
+
display: '0',
|
|
428
|
+
conceptUuid: FORM_OPTION_CONCEPTS.MOULDING.NONE,
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
value: FORM_OPTION_CONCEPTS.MOULDING.SLIGHT,
|
|
432
|
+
text: 'slight',
|
|
433
|
+
display: '+',
|
|
434
|
+
conceptUuid: FORM_OPTION_CONCEPTS.MOULDING.SLIGHT,
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
value: FORM_OPTION_CONCEPTS.MOULDING.MODERATE,
|
|
438
|
+
text: 'moderate',
|
|
439
|
+
display: '++',
|
|
440
|
+
conceptUuid: FORM_OPTION_CONCEPTS.MOULDING.MODERATE,
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
value: FORM_OPTION_CONCEPTS.MOULDING.SEVERE,
|
|
444
|
+
text: 'severe',
|
|
445
|
+
display: '+++',
|
|
446
|
+
conceptUuid: FORM_OPTION_CONCEPTS.MOULDING.SEVERE,
|
|
447
|
+
},
|
|
448
|
+
] as const;
|
|
449
|
+
|
|
450
|
+
export const DESCENT_OF_HEAD_OPTIONS = [
|
|
451
|
+
{ value: '', text: 'selectStation', stationValue: 0, conceptUuid: '' },
|
|
452
|
+
{
|
|
453
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.ZERO_FIFTHS,
|
|
454
|
+
text: '0/5',
|
|
455
|
+
stationValue: 0,
|
|
456
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.ZERO_FIFTHS,
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.ONE_FIFTH,
|
|
460
|
+
text: '1/5',
|
|
461
|
+
stationValue: 1,
|
|
462
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.ONE_FIFTH,
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.TWO_FIFTHS,
|
|
466
|
+
text: '2/5',
|
|
467
|
+
stationValue: 2,
|
|
468
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.TWO_FIFTHS,
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.THREE_FIFTHS,
|
|
472
|
+
text: '3/5',
|
|
473
|
+
stationValue: 3,
|
|
474
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.THREE_FIFTHS,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.FOUR_FIFTHS,
|
|
478
|
+
text: '4/5',
|
|
479
|
+
stationValue: 4,
|
|
480
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.FOUR_FIFTHS,
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
value: FORM_OPTION_CONCEPTS.DESCENT_STATION.FIVE_FIFTHS,
|
|
484
|
+
text: '5/5',
|
|
485
|
+
stationValue: 5,
|
|
486
|
+
conceptUuid: FORM_OPTION_CONCEPTS.DESCENT_STATION.FIVE_FIFTHS,
|
|
487
|
+
},
|
|
488
|
+
] as const;
|
|
489
|
+
|
|
490
|
+
export const CONTRACTION_INTENSITY_OPTIONS = [
|
|
491
|
+
{ value: '', text: 'selectIntensity', conceptUuid: '' },
|
|
492
|
+
{ value: 'mild', text: 'mild', conceptUuid: FORM_OPTION_CONCEPTS.CONTRACTION_INTENSITY.MILD },
|
|
493
|
+
{ value: 'moderate', text: 'moderate', conceptUuid: FORM_OPTION_CONCEPTS.CONTRACTION_INTENSITY.MODERATE },
|
|
494
|
+
{ value: 'strong', text: 'strong', conceptUuid: FORM_OPTION_CONCEPTS.CONTRACTION_INTENSITY.STRONG },
|
|
495
|
+
] as const;
|
|
496
|
+
|
|
497
|
+
export const URINE_LEVEL_OPTIONS = [
|
|
498
|
+
{ value: '', text: 'selectLevel', conceptUuid: '' },
|
|
499
|
+
{
|
|
500
|
+
value: FORM_OPTION_CONCEPTS.URINE_LEVELS.NEGATIVE,
|
|
501
|
+
text: 'negative',
|
|
502
|
+
conceptUuid: FORM_OPTION_CONCEPTS.URINE_LEVELS.NEGATIVE,
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
value: FORM_OPTION_CONCEPTS.URINE_LEVELS.TRACE,
|
|
506
|
+
text: 'trace',
|
|
507
|
+
conceptUuid: FORM_OPTION_CONCEPTS.URINE_LEVELS.TRACE,
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
value: FORM_OPTION_CONCEPTS.URINE_LEVELS.POSITIVE_PLUS,
|
|
511
|
+
text: 'positivePlus',
|
|
512
|
+
conceptUuid: FORM_OPTION_CONCEPTS.URINE_LEVELS.POSITIVE_PLUS,
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
value: FORM_OPTION_CONCEPTS.URINE_LEVELS.POSITIVE_PLUS_PLUS,
|
|
516
|
+
text: 'positivePlusPlus',
|
|
517
|
+
conceptUuid: FORM_OPTION_CONCEPTS.URINE_LEVELS.POSITIVE_PLUS_PLUS,
|
|
518
|
+
},
|
|
519
|
+
] as const;
|
|
520
|
+
|
|
521
|
+
export const BLOOD_GROUP_OPTIONS = [
|
|
522
|
+
{ value: '', text: 'selectBG', conceptUuid: '' },
|
|
523
|
+
{ value: 'A+', text: 'A+', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
524
|
+
{ value: 'A-', text: 'A-', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
525
|
+
{ value: 'B+', text: 'B+', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
526
|
+
{ value: 'B-', text: 'B-', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
527
|
+
{ value: 'AB+', text: 'AB+', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
528
|
+
{ value: 'AB-', text: 'AB-', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
529
|
+
{ value: 'O+', text: 'O+', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
530
|
+
{ value: 'O-', text: 'O-', conceptUuid: FORM_OPTION_CONCEPTS.BLOOD_GROUP },
|
|
531
|
+
] as const;
|
|
532
|
+
|
|
533
|
+
export const ADMISSION_OPTIONS = [
|
|
534
|
+
{ value: '', text: 'selectAdmission', conceptUuid: '' },
|
|
535
|
+
{ value: 'normal', text: 'normal', conceptUuid: PARTOGRAPHY_CONCEPTS['date-of-admission'] },
|
|
536
|
+
{ value: 'emergency', text: 'emergency', conceptUuid: PARTOGRAPHY_CONCEPTS['date-of-admission'] },
|
|
537
|
+
{ value: 'elective', text: 'elective', conceptUuid: PARTOGRAPHY_CONCEPTS['date-of-admission'] },
|
|
538
|
+
{ value: 'referral', text: 'referral', conceptUuid: PARTOGRAPHY_CONCEPTS['date-of-admission'] },
|
|
539
|
+
] as const;
|
|
540
|
+
|
|
541
|
+
export const TIME_SLOT_OPTIONS = [
|
|
542
|
+
{ value: '', text: 'selectAM', conceptUuid: '' },
|
|
543
|
+
{ value: 'morning', text: 'morning', conceptUuid: PARTOGRAPHY_CONCEPTS['time-slot'] },
|
|
544
|
+
{ value: 'afternoon', text: 'afternoon', conceptUuid: PARTOGRAPHY_CONCEPTS['time-slot'] },
|
|
545
|
+
{ value: 'evening', text: 'evening', conceptUuid: PARTOGRAPHY_CONCEPTS['time-slot'] },
|
|
546
|
+
{ value: 'night', text: 'night', conceptUuid: PARTOGRAPHY_CONCEPTS['time-slot'] },
|
|
547
|
+
] as const;
|
|
548
|
+
|
|
549
|
+
export const EVENT_TYPE_OPTIONS = [
|
|
550
|
+
{ value: '', text: 'selectEventType', conceptUuid: '' },
|
|
551
|
+
{
|
|
552
|
+
value: 'membrane-rupture',
|
|
553
|
+
text: 'membraneRupture',
|
|
554
|
+
conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.MEMBRANE_RUPTURE,
|
|
555
|
+
},
|
|
556
|
+
{ value: 'labor-onset', text: 'laborOnset', conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.LABOR_ONSET },
|
|
557
|
+
{ value: 'position-change', text: 'positionChange', conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.POSITION_CHANGE },
|
|
558
|
+
{
|
|
559
|
+
value: 'medication-given',
|
|
560
|
+
text: 'medicationGiven',
|
|
561
|
+
conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.MEDICATION_GIVEN,
|
|
562
|
+
},
|
|
563
|
+
{ value: 'complication', text: 'complication', conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.COMPLICATION },
|
|
564
|
+
{ value: 'delivery', text: 'delivery', conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.DELIVERY },
|
|
565
|
+
{ value: 'other', text: 'other', conceptUuid: FORM_OPTION_CONCEPTS.EVENT_TYPES.OTHER },
|
|
566
|
+
] as const;
|
|
567
|
+
|
|
568
|
+
// Mapping functions
|
|
569
|
+
export const getDescentStationMapping = () => {
|
|
570
|
+
const mapping: Record<string, number> = {};
|
|
571
|
+
DESCENT_OF_HEAD_OPTIONS.forEach((option) => {
|
|
572
|
+
if (option.value && option.stationValue !== undefined) {
|
|
573
|
+
mapping[option.value] = option.stationValue;
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
return mapping;
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
// Configurable input validation ranges
|
|
580
|
+
export const VALIDATION_RANGES = {
|
|
581
|
+
FETAL_HEART_RATE: { min: 80, max: 200, normal: { min: 110, max: 160 }, step: 1 },
|
|
582
|
+
CERVICAL_DILATION: { min: 0, max: 10, normal: { min: 0, max: 10 }, step: 0.5 },
|
|
583
|
+
MATERNAL_PULSE: { min: 40, max: 140, normal: { min: 60, max: 100 }, step: 1 },
|
|
584
|
+
SYSTOLIC_BP: { min: 60, max: 250, normal: { min: 90, max: 140 }, step: 1 },
|
|
585
|
+
DIASTOLIC_BP: { min: 30, max: 150, normal: { min: 60, max: 90 }, step: 1 },
|
|
586
|
+
TEMPERATURE: { min: 35, max: 42, normal: { min: 36, max: 37.5 }, step: 0.1 },
|
|
587
|
+
UTERINE_CONTRACTIONS: { min: 0, max: 10, normal: { min: 2, max: 5 }, step: 1 },
|
|
588
|
+
} as const;
|
|
589
|
+
|
|
590
|
+
// Input ranges mapped to graph types
|
|
591
|
+
export const INPUT_RANGES = {
|
|
592
|
+
'fetal-heart-rate': {
|
|
593
|
+
...VALIDATION_RANGES.FETAL_HEART_RATE,
|
|
594
|
+
placeholderKey: 'fetalHeartRatePlaceholder',
|
|
595
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['fetal-heart-rate'],
|
|
596
|
+
},
|
|
597
|
+
'cervical-dilation': {
|
|
598
|
+
...VALIDATION_RANGES.CERVICAL_DILATION,
|
|
599
|
+
placeholderKey: 'cervicalDilationPlaceholder',
|
|
600
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['cervical-dilation'],
|
|
601
|
+
},
|
|
602
|
+
'maternal-pulse': {
|
|
603
|
+
...VALIDATION_RANGES.MATERNAL_PULSE,
|
|
604
|
+
placeholderKey: 'maternalPulsePlaceholder',
|
|
605
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['maternal-pulse'],
|
|
606
|
+
},
|
|
607
|
+
'systolic-bp': {
|
|
608
|
+
...VALIDATION_RANGES.SYSTOLIC_BP,
|
|
609
|
+
placeholderKey: 'systolicBPPlaceholder',
|
|
610
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['systolic-bp'],
|
|
611
|
+
},
|
|
612
|
+
'diastolic-bp': {
|
|
613
|
+
...VALIDATION_RANGES.DIASTOLIC_BP,
|
|
614
|
+
placeholderKey: 'diastolicBPPlaceholder',
|
|
615
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['diastolic-bp'],
|
|
616
|
+
},
|
|
617
|
+
temperature: {
|
|
618
|
+
...VALIDATION_RANGES.TEMPERATURE,
|
|
619
|
+
placeholderKey: 'temperaturePlaceholder',
|
|
620
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS.temperature,
|
|
621
|
+
},
|
|
622
|
+
'uterine-contractions': {
|
|
623
|
+
...VALIDATION_RANGES.UTERINE_CONTRACTIONS,
|
|
624
|
+
placeholderKey: 'contractionFrequencyPlaceholder',
|
|
625
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
|
|
626
|
+
},
|
|
627
|
+
} as const;
|
|
628
|
+
|
|
629
|
+
// Configurable form validation helpers
|
|
630
|
+
export const createRangeValidator = (rangeName: keyof typeof VALIDATION_RANGES) => {
|
|
631
|
+
const range = VALIDATION_RANGES[rangeName];
|
|
632
|
+
return (value: string | number): boolean => {
|
|
633
|
+
const num = typeof value === 'string' ? parseFloat(value) : value;
|
|
634
|
+
return !isNaN(num) && num >= range.min && num <= range.max;
|
|
635
|
+
};
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
export const isValidCervicalDilation = createRangeValidator('CERVICAL_DILATION');
|
|
639
|
+
|
|
640
|
+
export const isValidFetalHeartRate = createRangeValidator('FETAL_HEART_RATE');
|
|
641
|
+
|
|
642
|
+
export const isValidMaternalPulse = createRangeValidator('MATERNAL_PULSE');
|
|
643
|
+
|
|
644
|
+
export const isValidSystolicBP = createRangeValidator('SYSTOLIC_BP');
|
|
645
|
+
|
|
646
|
+
export const isValidDiastolicBP = createRangeValidator('DIASTOLIC_BP');
|
|
647
|
+
|
|
648
|
+
export const isValidTemperature = createRangeValidator('TEMPERATURE');
|
|
649
|
+
|
|
650
|
+
export const isValidUterineContractions = createRangeValidator('UTERINE_CONTRACTIONS');
|
|
651
|
+
|
|
652
|
+
export const isValidBloodPressure = (systolic: string, diastolic: string): boolean => {
|
|
653
|
+
return (
|
|
654
|
+
systolic.trim() !== '' && diastolic.trim() !== '' && isValidSystolicBP(systolic) && isValidDiastolicBP(diastolic)
|
|
655
|
+
);
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
export const isValidUrineAnalysis = (protein: string, glucose: string, ketone: string): boolean => {
|
|
659
|
+
return protein !== '' || glucose !== '' || ketone !== '';
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
export const isValidDrugsFluids = (medication: string, dosage: string): boolean => {
|
|
663
|
+
return medication.trim() !== '' && dosage.trim() !== '';
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
export const isValidProgressEvents = (eventType: string, eventDescription: string): boolean => {
|
|
667
|
+
return eventType !== '' && eventDescription.trim() !== '';
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
export const isValidDescentOfHead = (value: string): boolean => {
|
|
671
|
+
return value.trim() !== '' && DESCENT_OF_HEAD_OPTIONS.some((option) => option.value === value);
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
export const isValidMeasurement = (graphType: string, value: string): boolean => {
|
|
675
|
+
switch (graphType) {
|
|
676
|
+
case 'fetal-heart-rate':
|
|
677
|
+
return isValidFetalHeartRate(value);
|
|
678
|
+
case 'cervical-dilation':
|
|
679
|
+
return isValidCervicalDilation(value);
|
|
680
|
+
case 'maternal-pulse':
|
|
681
|
+
return isValidMaternalPulse(value);
|
|
682
|
+
case 'temperature':
|
|
683
|
+
return isValidTemperature(value);
|
|
684
|
+
case 'uterine-contractions':
|
|
685
|
+
return isValidUterineContractions(value);
|
|
686
|
+
case 'descent-of-head':
|
|
687
|
+
return isValidDescentOfHead(value);
|
|
688
|
+
default:
|
|
689
|
+
return value.trim() !== '';
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
// Measurement label mappings
|
|
694
|
+
export const MEASUREMENT_LABELS = {
|
|
695
|
+
'fetal-heart-rate': { key: 'fetalHeartRate', default: 'Foetal Heart Rate' },
|
|
696
|
+
'cervical-dilation': { key: 'membraneAmnioticFluidMoulding', default: 'Membrane Amniotic Fluid & Moulding' },
|
|
697
|
+
'descent-of-head': { key: 'descentOfHead', default: 'Descent of Head' },
|
|
698
|
+
'uterine-contractions': { key: 'uterineContractions', default: 'Uterine Contractions' },
|
|
699
|
+
'maternal-pulse': { key: 'maternalPulse', default: 'Maternal Pulse' },
|
|
700
|
+
'blood-pressure': { key: 'bloodPressure', default: 'Blood Pressure' },
|
|
701
|
+
temperature: { key: 'temperature', default: 'Temperature' },
|
|
702
|
+
'urine-analysis': { key: 'urineAnalysis', default: 'Urine Analysis' },
|
|
703
|
+
'drugs-fluids': { key: 'drugsFluids', default: 'Drugs & Fluids' },
|
|
704
|
+
'progress-events': { key: 'progressEvents', default: 'Progress & Events' },
|
|
705
|
+
} as const;
|
|
706
|
+
|
|
707
|
+
// Get measurement label function
|
|
708
|
+
// Field label mappings for all form inputs
|
|
709
|
+
export const FIELD_LABELS = {
|
|
710
|
+
// Number input labels
|
|
711
|
+
fetalHeartRate: { key: 'fetalHeartRate', default: 'Fetal Heart Rate (BPM)' },
|
|
712
|
+
cervicalDilation: { key: 'cervicalDilation', default: 'Cervical Dilation (cm)' },
|
|
713
|
+
maternalPulse: { key: 'maternalPulse', default: 'Maternal Pulse (BPM)' },
|
|
714
|
+
systolic: { key: 'systolic', default: 'Systolic (mmHg)' },
|
|
715
|
+
diastolic: { key: 'diastolic', default: 'Diastolic (mmHg)' },
|
|
716
|
+
temperature: { key: 'temperature', default: 'Temperature (°C)' },
|
|
717
|
+
frequency: { key: 'frequency', default: 'Frequency (per 10min)' },
|
|
718
|
+
|
|
719
|
+
// Select field labels
|
|
720
|
+
amnioticFluid: { key: 'amnioticFluid', default: 'Amniotic Fluid' },
|
|
721
|
+
moulding: { key: 'moulding', default: 'Moulding' },
|
|
722
|
+
descentOfHead: { key: 'descentOfHead', default: 'Descent of Head (Station)' },
|
|
723
|
+
intensity: { key: 'intensity', default: 'Intensity' },
|
|
724
|
+
proteinLevel: { key: 'proteinLevel', default: 'Protein Level' },
|
|
725
|
+
glucoseLevel: { key: 'glucoseLevel', default: 'Glucose Level' },
|
|
726
|
+
ketoneLevel: { key: 'ketoneLevel', default: 'Ketone Level' },
|
|
727
|
+
eventType: { key: 'eventType', default: 'Event Type' },
|
|
728
|
+
|
|
729
|
+
// Text input labels
|
|
730
|
+
medication: { key: 'medication', default: 'Medication/Fluid' },
|
|
731
|
+
dosageRate: { key: 'dosageRate', default: 'Dosage/Rate' },
|
|
732
|
+
eventDescription: { key: 'eventDescription', default: 'Event Description' },
|
|
733
|
+
|
|
734
|
+
// Common labels
|
|
735
|
+
admission: { key: 'admission', default: 'Admission' },
|
|
736
|
+
bg: { key: 'bg', default: 'BG' },
|
|
737
|
+
am: { key: 'am', default: 'AM' },
|
|
738
|
+
} as const;
|
|
739
|
+
|
|
740
|
+
// Placeholder mappings for inputs - all translatable
|
|
741
|
+
export const FIELD_PLACEHOLDERS = {
|
|
742
|
+
// Number input placeholders
|
|
743
|
+
fetalHeartRatePlaceholder: { key: 'enterFetalHeartRate', default: 'Enter fetal heart rate (110-160 BPM)' },
|
|
744
|
+
cervicalDilationPlaceholder: { key: 'enterCervicalDilation', default: 'Enter cervical dilation (0-10 cm)' },
|
|
745
|
+
maternalPulsePlaceholder: { key: 'enterMaternalPulse', default: 'Enter maternal pulse (60-100 BPM)' },
|
|
746
|
+
systolicBPPlaceholder: { key: 'enterSystolicBP', default: 'Enter systolic BP (90-140 mmHg)' },
|
|
747
|
+
diastolicBPPlaceholder: { key: 'enterDiastolicBP', default: 'Enter diastolic BP (60-90 mmHg)' },
|
|
748
|
+
temperaturePlaceholder: { key: 'enterTemperature', default: 'Enter temperature (36-37.5°C)' },
|
|
749
|
+
contractionFrequencyPlaceholder: { key: 'enterContractionFrequency', default: 'Enter contractions per 10 minutes' },
|
|
750
|
+
contractionIntensityPlaceholder: { key: 'selectContractionIntensity', default: 'Select contraction intensity' },
|
|
751
|
+
descentOfHeadPlaceholder: { key: 'selectDescentStation', default: 'Select descent station (0/5 - 5/5)' },
|
|
752
|
+
|
|
753
|
+
// Select placeholders
|
|
754
|
+
amnioticFluidPlaceholder: { key: 'selectAmnioticFluid', default: 'Select amniotic fluid status' },
|
|
755
|
+
mouldingPlaceholder: { key: 'selectMoulding', default: 'Select moulding status' },
|
|
756
|
+
proteinLevelPlaceholder: { key: 'selectProteinLevel', default: 'Select protein level' },
|
|
757
|
+
glucoseLevelPlaceholder: { key: 'selectGlucoseLevel', default: 'Select glucose level' },
|
|
758
|
+
ketoneLevelPlaceholder: { key: 'selectKetoneLevel', default: 'Select ketone level' },
|
|
759
|
+
eventTypePlaceholder: { key: 'selectEventType', default: 'Select event type' },
|
|
760
|
+
|
|
761
|
+
// Text input placeholders
|
|
762
|
+
medicationType: { key: 'enterMedicationOrFluidType', default: 'Enter medication or fluid type' },
|
|
763
|
+
dosageRate: { key: 'enterDosageOrFlowRate', default: 'Enter dosage or flow rate' },
|
|
764
|
+
eventDescription: { key: 'describeEventOrMilestone', default: 'Describe the event or milestone' },
|
|
765
|
+
generalMeasurement: { key: 'enterMeasurementValue', default: 'Enter measurement value' },
|
|
766
|
+
} as const;
|
|
767
|
+
|
|
768
|
+
// Get measurement label function
|
|
769
|
+
export const getMeasurementLabel = (
|
|
770
|
+
graphType: string,
|
|
771
|
+
t: (key: string, fallback: string) => string,
|
|
772
|
+
fallbackTitle?: string,
|
|
773
|
+
): string => {
|
|
774
|
+
const labelConfig = MEASUREMENT_LABELS[graphType as keyof typeof MEASUREMENT_LABELS];
|
|
775
|
+
if (labelConfig) {
|
|
776
|
+
return t(labelConfig.key, labelConfig.default);
|
|
777
|
+
}
|
|
778
|
+
return fallbackTitle || graphType;
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// Get field label function
|
|
782
|
+
export const getFieldLabel = (
|
|
783
|
+
fieldKey: keyof typeof FIELD_LABELS,
|
|
784
|
+
t: (key: string, fallback: string) => string,
|
|
785
|
+
): string => {
|
|
786
|
+
const labelConfig = FIELD_LABELS[fieldKey];
|
|
787
|
+
return t(labelConfig.key, labelConfig.default);
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
// Get field placeholder function
|
|
791
|
+
export const getFieldPlaceholder = (
|
|
792
|
+
fieldKey: keyof typeof FIELD_PLACEHOLDERS,
|
|
793
|
+
t: (key: string, fallback: string) => string,
|
|
794
|
+
): string => {
|
|
795
|
+
const placeholderConfig = FIELD_PLACEHOLDERS[fieldKey];
|
|
796
|
+
return t(placeholderConfig.key, placeholderConfig.default);
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
// Get dynamic placeholder for input ranges
|
|
800
|
+
export const getInputRangePlaceholder = (
|
|
801
|
+
graphType: keyof typeof INPUT_RANGES,
|
|
802
|
+
t: (key: string, fallback: string) => string,
|
|
803
|
+
): string => {
|
|
804
|
+
const inputConfig = INPUT_RANGES[graphType];
|
|
805
|
+
if (inputConfig && 'placeholderKey' in inputConfig) {
|
|
806
|
+
return getFieldPlaceholder(inputConfig.placeholderKey as keyof typeof FIELD_PLACEHOLDERS, t);
|
|
807
|
+
}
|
|
808
|
+
return t('enterMeasurementValue', 'Enter measurement value');
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
// Get concept UUID for form option
|
|
812
|
+
export const getConceptUuid = (optionType: string, optionValue: string): string => {
|
|
813
|
+
switch (optionType) {
|
|
814
|
+
case 'amnioticFluid':
|
|
815
|
+
return AMNIOTIC_FLUID_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
816
|
+
case 'moulding':
|
|
817
|
+
return MOULDING_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
818
|
+
case 'descentOfHead':
|
|
819
|
+
return DESCENT_OF_HEAD_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
820
|
+
case 'contractionIntensity':
|
|
821
|
+
return CONTRACTION_INTENSITY_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
822
|
+
case 'urineLevel':
|
|
823
|
+
return URINE_LEVEL_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
824
|
+
case 'bloodGroup':
|
|
825
|
+
return BLOOD_GROUP_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
826
|
+
case 'admission':
|
|
827
|
+
return ADMISSION_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
828
|
+
case 'timeSlot':
|
|
829
|
+
return TIME_SLOT_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
830
|
+
case 'eventType':
|
|
831
|
+
return EVENT_TYPE_OPTIONS.find((opt) => opt.value === optionValue)?.conceptUuid || '';
|
|
832
|
+
default:
|
|
833
|
+
return '';
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// Validate if measurement is within normal range
|
|
838
|
+
export const isWithinNormalRange = (graphType: string, value: number): boolean => {
|
|
839
|
+
const range = Object.values(VALIDATION_RANGES).find((r) => {
|
|
840
|
+
// Match range based on graph type
|
|
841
|
+
switch (graphType) {
|
|
842
|
+
case 'fetal-heart-rate':
|
|
843
|
+
return r === VALIDATION_RANGES.FETAL_HEART_RATE;
|
|
844
|
+
case 'cervical-dilation':
|
|
845
|
+
return r === VALIDATION_RANGES.CERVICAL_DILATION;
|
|
846
|
+
case 'maternal-pulse':
|
|
847
|
+
return r === VALIDATION_RANGES.MATERNAL_PULSE;
|
|
848
|
+
case 'temperature':
|
|
849
|
+
return r === VALIDATION_RANGES.TEMPERATURE;
|
|
850
|
+
case 'uterine-contractions':
|
|
851
|
+
return r === VALIDATION_RANGES.UTERINE_CONTRACTIONS;
|
|
852
|
+
default:
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
if (!range || !range.normal) {
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
return value >= range.normal.min && value <= range.normal.max;
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// Configurable data processing for different graph types
|
|
864
|
+
export interface GraphDataProcessor {
|
|
865
|
+
validate: (formData: any) => boolean;
|
|
866
|
+
getValue: (formData: any) => number;
|
|
867
|
+
getAdditionalData: (formData: any) => Record<string, any>;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export const GRAPH_DATA_PROCESSORS: Record<string, GraphDataProcessor> = {
|
|
871
|
+
'cervical-dilation': {
|
|
872
|
+
validate: (formData) => isValidCervicalDilation(formData.measurementValue),
|
|
873
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
874
|
+
getAdditionalData: (formData) => ({
|
|
875
|
+
amnioticFluid: formData.amnioticFluid,
|
|
876
|
+
moulding: formData.moulding,
|
|
877
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['cervical-dilation'],
|
|
878
|
+
}),
|
|
879
|
+
},
|
|
880
|
+
'blood-pressure': {
|
|
881
|
+
validate: (formData) => isValidBloodPressure(formData.systolic, formData.diastolic),
|
|
882
|
+
getValue: (formData) => parseFloat(formData.systolic) || 0,
|
|
883
|
+
getAdditionalData: (formData) => ({
|
|
884
|
+
diastolic: parseFloat(formData.diastolic) || 0,
|
|
885
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['systolic-bp'],
|
|
886
|
+
diastolicConceptUuid: PARTOGRAPHY_CONCEPTS['diastolic-bp'],
|
|
887
|
+
}),
|
|
888
|
+
},
|
|
889
|
+
'urine-analysis': {
|
|
890
|
+
validate: (formData) => isValidUrineAnalysis(formData.proteinLevel, formData.glucoseLevel, formData.ketoneLevel),
|
|
891
|
+
getValue: () => 1,
|
|
892
|
+
getAdditionalData: (formData) => ({
|
|
893
|
+
proteinLevel: formData.proteinLevel,
|
|
894
|
+
glucoseLevel: formData.glucoseLevel,
|
|
895
|
+
ketoneLevel: formData.ketoneLevel,
|
|
896
|
+
proteinConceptUuid: PARTOGRAPHY_CONCEPTS['protein-level'],
|
|
897
|
+
glucoseConceptUuid: PARTOGRAPHY_CONCEPTS['glucose-level'],
|
|
898
|
+
ketoneConceptUuid: PARTOGRAPHY_CONCEPTS['ketone-level'],
|
|
899
|
+
}),
|
|
900
|
+
},
|
|
901
|
+
'drugs-fluids': {
|
|
902
|
+
validate: (formData) => isValidDrugsFluids(formData.medication, formData.dosage),
|
|
903
|
+
getValue: () => 1,
|
|
904
|
+
getAdditionalData: (formData) => ({
|
|
905
|
+
medication: formData.medication,
|
|
906
|
+
dosage: formData.dosage,
|
|
907
|
+
medicationConceptUuid: PARTOGRAPHY_CONCEPTS.medication,
|
|
908
|
+
dosageConceptUuid: PARTOGRAPHY_CONCEPTS.dosage,
|
|
909
|
+
}),
|
|
910
|
+
},
|
|
911
|
+
'progress-events': {
|
|
912
|
+
validate: (formData) => isValidProgressEvents(formData.eventType, formData.eventDescription),
|
|
913
|
+
getValue: () => 1,
|
|
914
|
+
getAdditionalData: (formData) => ({
|
|
915
|
+
eventType: formData.eventType,
|
|
916
|
+
eventDescription: formData.eventDescription,
|
|
917
|
+
eventTypeConceptUuid: PARTOGRAPHY_CONCEPTS['event-type'],
|
|
918
|
+
eventDescriptionConceptUuid: PARTOGRAPHY_CONCEPTS['event-description'],
|
|
919
|
+
}),
|
|
920
|
+
},
|
|
921
|
+
'uterine-contractions': {
|
|
922
|
+
validate: (formData) => isValidMeasurement('uterine-contractions', formData.measurementValue),
|
|
923
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
924
|
+
getAdditionalData: (formData) => ({
|
|
925
|
+
intensity: formData.eventDescription,
|
|
926
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['uterine-contractions'],
|
|
927
|
+
intensityConceptUuid: PARTOGRAPHY_CONCEPTS['uterine-contraction-duration'],
|
|
928
|
+
}),
|
|
929
|
+
},
|
|
930
|
+
'descent-of-head': {
|
|
931
|
+
validate: (formData) => isValidDescentOfHead(formData.measurementValue),
|
|
932
|
+
getValue: (formData) => {
|
|
933
|
+
const stationMapping = getDescentStationMapping();
|
|
934
|
+
return stationMapping[formData.measurementValue] ?? 0;
|
|
935
|
+
},
|
|
936
|
+
getAdditionalData: (formData) => {
|
|
937
|
+
const stationMapping = getDescentStationMapping();
|
|
938
|
+
return {
|
|
939
|
+
conceptUuid: formData.measurementValue,
|
|
940
|
+
stationValue: stationMapping[formData.measurementValue] ?? 0,
|
|
941
|
+
descentConceptUuid: PARTOGRAPHY_CONCEPTS['descent-of-head'],
|
|
942
|
+
};
|
|
943
|
+
},
|
|
944
|
+
},
|
|
945
|
+
'fetal-heart-rate': {
|
|
946
|
+
validate: (formData) => isValidMeasurement('fetal-heart-rate', formData.measurementValue),
|
|
947
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
948
|
+
getAdditionalData: () => ({
|
|
949
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['fetal-heart-rate'],
|
|
950
|
+
}),
|
|
951
|
+
},
|
|
952
|
+
'maternal-pulse': {
|
|
953
|
+
validate: (formData) => isValidMeasurement('maternal-pulse', formData.measurementValue),
|
|
954
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
955
|
+
getAdditionalData: () => ({
|
|
956
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS['maternal-pulse'],
|
|
957
|
+
}),
|
|
958
|
+
},
|
|
959
|
+
temperature: {
|
|
960
|
+
validate: (formData) => isValidMeasurement('temperature', formData.measurementValue),
|
|
961
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
962
|
+
getAdditionalData: () => ({
|
|
963
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS.temperature,
|
|
964
|
+
}),
|
|
965
|
+
},
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
// Generic processor for unmapped graph types
|
|
969
|
+
export const getDefaultProcessor = (graphType: string): GraphDataProcessor => ({
|
|
970
|
+
validate: (formData) => isValidMeasurement(graphType, formData.measurementValue),
|
|
971
|
+
getValue: (formData) => parseFloat(formData.measurementValue) || 0,
|
|
972
|
+
getAdditionalData: () => ({
|
|
973
|
+
conceptUuid: PARTOGRAPHY_CONCEPTS[graphType as keyof typeof PARTOGRAPHY_CONCEPTS] || '',
|
|
974
|
+
}),
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
// Get processor for a specific graph type
|
|
978
|
+
export const getGraphDataProcessor = (graphType: string): GraphDataProcessor => {
|
|
979
|
+
return GRAPH_DATA_PROCESSORS[graphType] || getDefaultProcessor(graphType);
|
|
980
|
+
};
|