@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2788 → 5.4.2-pre.2797

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/dist/127.js +1 -1
  3. package/dist/40.js +1 -1
  4. package/dist/{189.js → 791.js} +1 -1
  5. package/dist/791.js.map +1 -0
  6. package/dist/916.js +1 -1
  7. package/dist/kenyaemr-esm-patient-clinical-view-app.js +3 -3
  8. package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +36 -36
  9. package/dist/main.js +3 -3
  10. package/dist/main.js.map +1 -1
  11. package/dist/routes.json +1 -1
  12. package/package.json +1 -1
  13. package/src/config-schema.ts +8 -2
  14. package/src/maternal-and-child-health/partography/forms/cervical-contractions-form.component.tsx +63 -28
  15. package/src/maternal-and-child-health/partography/forms/cervix-form.component.tsx +52 -108
  16. package/src/maternal-and-child-health/partography/forms/drugs-iv-fluids-form.component.tsx +110 -100
  17. package/src/maternal-and-child-health/partography/forms/fetal-heart-rate-form.component.tsx +7 -7
  18. package/src/maternal-and-child-health/partography/forms/membrane-amniotic-fluid-form.component.tsx +72 -75
  19. package/src/maternal-and-child-health/partography/forms/oxytocin-form.component.tsx +14 -19
  20. package/src/maternal-and-child-health/partography/forms/pulse-bp-form.component.tsx +34 -28
  21. package/src/maternal-and-child-health/partography/forms/temperature-form.component.tsx +10 -9
  22. package/src/maternal-and-child-health/partography/forms/time-picker-dropdown.component.tsx +10 -10
  23. package/src/maternal-and-child-health/partography/forms/urine-test-form.component.tsx +7 -6
  24. package/src/maternal-and-child-health/partography/graphs/cervical-contractions-graph.component.tsx +51 -61
  25. package/src/maternal-and-child-health/partography/graphs/drugs-iv-fluids-graph-wrapper.component.tsx +0 -6
  26. package/src/maternal-and-child-health/partography/graphs/drugs-iv-fluids-graph.component.tsx +3 -3
  27. package/src/maternal-and-child-health/partography/graphs/fetal-heart-rate-graph.component.tsx +53 -30
  28. package/src/maternal-and-child-health/partography/graphs/membrane-amniotic-fluid-graph.component.tsx +25 -3
  29. package/src/maternal-and-child-health/partography/graphs/oxytocin-graph-wrapper.component.tsx +102 -97
  30. package/src/maternal-and-child-health/partography/graphs/oxytocin-graph.component.tsx +21 -22
  31. package/src/maternal-and-child-health/partography/graphs/pulse-bp-graph.component.tsx +21 -24
  32. package/src/maternal-and-child-health/partography/graphs/temperature-graph.component.tsx +23 -26
  33. package/src/maternal-and-child-health/partography/graphs/urine-test-graph.component.tsx +1 -1
  34. package/src/maternal-and-child-health/partography/partograph.component.tsx +323 -171
  35. package/src/maternal-and-child-health/partography/partography-data-form.scss +23 -0
  36. package/src/maternal-and-child-health/partography/partography.resource.ts +70 -56
  37. package/src/maternal-and-child-health/partography/partography.scss +65 -6
  38. package/src/maternal-and-child-health/partography/resources/fetal-heart-rate.resource.ts +5 -10
  39. package/src/maternal-and-child-health/partography/resources/oxytocin.resource.ts +5 -3
  40. package/src/maternal-and-child-health/partography/types/index.ts +40 -37
  41. package/translations/am.json +1 -1
  42. package/translations/en.json +1 -1
  43. package/translations/sw.json +1 -1
  44. package/dist/189.js.map +0 -1
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"wrapComponent","route":"case-management"}],"extensions":[{"name":"hiv-care-and-treatment-dashboard-link","component":"hivCareAndTreatmentLink","slot":"patient-chart-dashboard-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","path":"hiv-care-and-treatment-dashboard","layoutMode":"anchored"}},{"name":"hiv-care-and-treatment-dashboard","slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","component":"hivCareAndTreatment","order":0,"online":true,"offline":false},{"name":"relationship-dashboard-link","component":"relationshipsLink","order":24,"online":true,"offline":false,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-relationship-slot","path":"relationships","layoutMode":"anchored"}},{"name":"relationship-dashboard","slot":"patient-chart-relationship-slot","component":"relationships","order":0,"online":true,"offline":false},{"name":"clinical-encounter-dashboard-link","component":"clinicalEncounterLink","order":25,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-clinical-encounter-slot","path":"clinical-encounter","layoutMode":"anchored"}},{"name":"clinical-encounter-dashboard","slot":"patient-chart-clinical-encounter-slot","component":"clinicalEncounter","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-dashboard-link","component":"maternalAndChildHealthDashboardLink","order":26,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-maternal-and-child-health-slot","path":"maternal-and-child-health","layoutMode":"anchored"}},{"name":"maternal-and-child-health-dashboard","slot":"patient-chart-maternal-and-child-health-slot","component":"maternalAndChildHealthDashboard","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-partograph","slot":"maternal-and-child-health-partograph-slot","component":"partograph","order":0,"online":true,"offline":false},{"name":"contact-list-dashboard-link","component":"contactListLink","order":27,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-contact-list-slot","path":"contact-list","layoutMode":"anchored"}},{"name":"contact-list-dashboard","slot":"patient-chart-contact-list-slot","component":"contactList","order":0,"online":true,"offline":false},{"component":"caseManagementDashboardLink","name":"case-management-dashboard-link","meta":{"name":"case-management","title":"Case Management","slot":"case-management-dashboard-slot","path":"/case-management"}},{"name":"wrap-component-view","slot":"case-management-dashboard-slot","component":"wrapComponent","order":2,"online":true,"offline":false},{"name":"case-encounter-link","component":"caseEncounterDashboardLink","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-case-encounter-slot","path":"case-management-encounters","layoutMode":"anchored"}},{"name":"case-encounter-table","slot":"patient-chart-case-encounter-slot","component":"caseEncounterTable","order":0,"online":true,"offline":false},{"component":"peerCalendarDashboardLink","name":"peer-calendar-dashboard-link","meta":{"name":"peer-calendar","title":"Peer Calendar","slot":"peer-calendar-dashboard-slot","path":"peer-management"}},{"name":"peer-calendar","slot":"peer-calendar-dashboard-slot","component":"peerCalendar","order":0,"online":true,"offline":false},{"name":"special-clinics-dashboard-link","component":"specialClinicsDashboardLink","order":15,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-special-clinics-slot","path":"special-clinics","layoutMode":"anchored"}},{"name":"special-clinics-dashboard","slot":"patient-chart-special-clinics-slot","component":"specialClinicsDashboard","order":0,"online":true,"offline":false},{"name":"patient-complaints","slot":"ewf-patient-summary-slot","component":"patientComplaints","order":0,"online":true,"offline":false}],"modals":[{"name":"birth-date-calculator","component":"birthDateCalculator"},{"name":"relationship-delete-confirm-dialog","component":"relationshipDeleteConfirmialog"},{"name":"end-relationship-dialog","component":"endRelationshipModal"}],"workspaces":[{"name":"contact-list-form","component":"contactListForm","title":"Contact List Form","type":"form"},{"name":"case-management-form","component":"caseManagementForm","title":"Case Management Form","type":"form"},{"name":"add-patient-case-form","component":"addPatientCaseForm","title":"Add patient case Form","type":"form"},{"name":"family-relationship-form","component":"familyRelationshipForm","title":"Family Relationship Form","type":"form"},{"name":"peers-form","component":"peersForm","title":"Add New Peer","type":"form"},{"name":"kenyaemr-cusom-form-entry-workspace","component":"peerCalendarFormEntry","title":"KVP Peer Educator Outreach Calendar","type":"form","width":"extra-wide","canMaximize":true,"canHide":true},{"name":"contact-list-update-form","component":"contactListUpdateForm","title":"Contact List Update Form","type":"form"},{"name":"other-relationship-form","component":"otherRelationshipsForm","title":"Other Relationships Form","type":"form"},{"name":"end-relationship-form","component":"endRelationshipWorkspace","title":"Discontinue relationship form","type":"form"}],"version":"5.4.2-pre.2788"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"wrapComponent","route":"case-management"}],"extensions":[{"name":"hiv-care-and-treatment-dashboard-link","component":"hivCareAndTreatmentLink","slot":"patient-chart-dashboard-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","path":"hiv-care-and-treatment-dashboard","layoutMode":"anchored"}},{"name":"hiv-care-and-treatment-dashboard","slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","component":"hivCareAndTreatment","order":0,"online":true,"offline":false},{"name":"relationship-dashboard-link","component":"relationshipsLink","order":24,"online":true,"offline":false,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-relationship-slot","path":"relationships","layoutMode":"anchored"}},{"name":"relationship-dashboard","slot":"patient-chart-relationship-slot","component":"relationships","order":0,"online":true,"offline":false},{"name":"clinical-encounter-dashboard-link","component":"clinicalEncounterLink","order":25,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-clinical-encounter-slot","path":"clinical-encounter","layoutMode":"anchored"}},{"name":"clinical-encounter-dashboard","slot":"patient-chart-clinical-encounter-slot","component":"clinicalEncounter","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-dashboard-link","component":"maternalAndChildHealthDashboardLink","order":26,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-maternal-and-child-health-slot","path":"maternal-and-child-health","layoutMode":"anchored"}},{"name":"maternal-and-child-health-dashboard","slot":"patient-chart-maternal-and-child-health-slot","component":"maternalAndChildHealthDashboard","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-partograph","slot":"maternal-and-child-health-partograph-slot","component":"partograph","order":0,"online":true,"offline":false},{"name":"contact-list-dashboard-link","component":"contactListLink","order":27,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-contact-list-slot","path":"contact-list","layoutMode":"anchored"}},{"name":"contact-list-dashboard","slot":"patient-chart-contact-list-slot","component":"contactList","order":0,"online":true,"offline":false},{"component":"caseManagementDashboardLink","name":"case-management-dashboard-link","meta":{"name":"case-management","title":"Case Management","slot":"case-management-dashboard-slot","path":"/case-management"}},{"name":"wrap-component-view","slot":"case-management-dashboard-slot","component":"wrapComponent","order":2,"online":true,"offline":false},{"name":"case-encounter-link","component":"caseEncounterDashboardLink","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-case-encounter-slot","path":"case-management-encounters","layoutMode":"anchored"}},{"name":"case-encounter-table","slot":"patient-chart-case-encounter-slot","component":"caseEncounterTable","order":0,"online":true,"offline":false},{"component":"peerCalendarDashboardLink","name":"peer-calendar-dashboard-link","meta":{"name":"peer-calendar","title":"Peer Calendar","slot":"peer-calendar-dashboard-slot","path":"peer-management"}},{"name":"peer-calendar","slot":"peer-calendar-dashboard-slot","component":"peerCalendar","order":0,"online":true,"offline":false},{"name":"special-clinics-dashboard-link","component":"specialClinicsDashboardLink","order":15,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-special-clinics-slot","path":"special-clinics","layoutMode":"anchored"}},{"name":"special-clinics-dashboard","slot":"patient-chart-special-clinics-slot","component":"specialClinicsDashboard","order":0,"online":true,"offline":false},{"name":"patient-complaints","slot":"ewf-patient-summary-slot","component":"patientComplaints","order":0,"online":true,"offline":false}],"modals":[{"name":"birth-date-calculator","component":"birthDateCalculator"},{"name":"relationship-delete-confirm-dialog","component":"relationshipDeleteConfirmialog"},{"name":"end-relationship-dialog","component":"endRelationshipModal"}],"workspaces":[{"name":"contact-list-form","component":"contactListForm","title":"Contact List Form","type":"form"},{"name":"case-management-form","component":"caseManagementForm","title":"Case Management Form","type":"form"},{"name":"add-patient-case-form","component":"addPatientCaseForm","title":"Add patient case Form","type":"form"},{"name":"family-relationship-form","component":"familyRelationshipForm","title":"Family Relationship Form","type":"form"},{"name":"peers-form","component":"peersForm","title":"Add New Peer","type":"form"},{"name":"kenyaemr-cusom-form-entry-workspace","component":"peerCalendarFormEntry","title":"KVP Peer Educator Outreach Calendar","type":"form","width":"extra-wide","canMaximize":true,"canHide":true},{"name":"contact-list-update-form","component":"contactListUpdateForm","title":"Contact List Update Form","type":"form"},{"name":"other-relationship-form","component":"otherRelationshipsForm","title":"Other Relationships Form","type":"form"},{"name":"end-relationship-form","component":"endRelationshipWorkspace","title":"Discontinue relationship form","type":"form"}],"version":"5.4.2-pre.2797"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-patient-clinical-view-app",
3
- "version": "5.4.2-pre.2788",
3
+ "version": "5.4.2-pre.2797",
4
4
  "description": "Patient clinical view microfrontend for the OpenMRS SPA",
5
5
  "keywords": [
6
6
  "openmrs"
@@ -2,6 +2,7 @@ export const FETAL_HEART_RATE_GRAPH_UUIDS = {
2
2
  fetalHeartRate: 'FETAL_HEART_RATE_CONCEPT',
3
3
  fetalHeartRateHour: 'FETAL_HEART_RATE_HOUR_CONCEPT',
4
4
  fetalHeartRateTime: 'FETAL_HEART_RATE_TIME_CONCEPT',
5
+ fetalHeartRateNew: 'FETAL_HEART_RATE_NEW_CONCEPT',
5
6
  };
6
7
  import { Type } from '@openmrs/esm-framework';
7
8
  import _default from 'react-hook-form/dist/logic/appendErrors';
@@ -447,7 +448,7 @@ export const AMNIOTIC_ABSENT_CONCEPT = '163747AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
447
448
  export const AMNIOTIC_BLOOD_STAINED_CONCEPT = '1077AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
448
449
  export const AMNIOTIC_MEMBRANE_INTACT_CONCEPT = 'd1787a76-7310-4223-a645-9fd410d418c1';
449
450
 
450
- // Cervical Contractions Graph
451
+ //Contractions Graph
451
452
  export const UTERINE_CONTRACTIONS_CONCEPT = '163750AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
452
453
  export const CONTRACTION_LEVEL_MILD_CONCEPT = '1498AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
453
454
  export const CONTRACTION_LEVEL_MODERATE_CONCEPT = '1499AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
@@ -456,12 +457,15 @@ export const UTERINE_CONTRACTION_FREQUENCY_CONCEPT = '166529AAAAAAAAAAAAAAAAAAAA
456
457
  export const UTERINE_CONTRACTION_DURATION_CONCEPT = '159368AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
457
458
 
458
459
  // Oxytocin Graph
460
+
461
+ export const OXYTOCIN_TIME_CONCEPT = 'bb3724c9-fbcc-49c5-9702-6cde0be325ca';
462
+ export const OXYTOCIN_DROPS_PER_MINUTE_CONCEPT = '1d109b10-7b30-4bfa-8a7c-6ecb73357fc2';
459
463
  export const OXYTOCIN_DOSE_CONCEPT = '81369AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
460
464
  export const ROUTE_CONCEPT = '8878f9c0-a1ce-47ec-a88f-69ef0f6576ba';
461
465
  export const FREQUENCY_CONCEPT = 'fd9f82fd-f327-4502-ac8e-5d9144dbd504';
462
466
 
463
467
  // Drugs IV Fluids Graph
464
- export const MEDICATION_CONCEPT = '1282AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
468
+ export const MEDICATION_CONCEPT = 'c3082af8-f935-40c5-aa5b-74c684e81aea';
465
469
  export const IV_FLUIDS_CONCEPT = '161911AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
466
470
  export const DOSAGE_CONCEPT = 'b71ddb80-2d7f-4bde-a44b-236e62d4c1b6';
467
471
  export const DRUG_DOSE_CONCEPT = '162384AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
@@ -478,6 +482,8 @@ export const GLUCOSE_LEVEL_CONCEPT = '887AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
478
482
  export const KETONE_LEVEL_CONCEPT = '165438AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
479
483
  export const URINE_VOLUME_CONCEPT = '159660AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
480
484
  export const URINE_CHARACTERISTICS_CONCEPT = '56AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
485
+ export const TIME_RESULTS_RETURNED = '67c3d4c6-465e-4c12-9b7f-d8587ca90603';
486
+ export const TIME_SAMPLE_COLLECTED = 'c554f157-2e16-4585-af29-c48f5e765ce0';
481
487
 
482
488
  // Cervix / Cervical Monitoring During Labor
483
489
  export const CERVIX_CONCEPT = '162261AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
4
  import { contractionLevelOptions as baseContractionLevelOptions } from '../types';
5
- import { Modal, Dropdown } from '@carbon/react';
5
+ import { Modal, Select, SelectItem } from '@carbon/react';
6
6
  import styles from '../partography.scss';
7
7
 
8
8
  type CervicalContractionsFormData = {
@@ -56,6 +56,8 @@ const CervicalContractionsForm: React.FC<CervicalContractionsFormProps> = ({
56
56
  const handleFormSubmit = async (data: CervicalContractionsFormData) => {
57
57
  clearErrors();
58
58
  let hasErrors = false;
59
+
60
+ // Validate contraction level
59
61
  if (!data.contractionLevel || data.contractionLevel.trim() === '') {
60
62
  setError('contractionLevel', {
61
63
  type: 'manual',
@@ -63,15 +65,58 @@ const CervicalContractionsForm: React.FC<CervicalContractionsFormProps> = ({
63
65
  });
64
66
  hasErrors = true;
65
67
  }
68
+
69
+ // Validate contraction count
66
70
  if (!data.contractionCount || data.contractionCount.trim() === '') {
67
71
  setError('contractionCount', {
68
72
  type: 'manual',
69
73
  message: t('contractionCountRequired', 'Please select number of contractions'),
70
74
  });
71
75
  hasErrors = true;
76
+ } else {
77
+ const countValue = parseInt(data.contractionCount);
78
+ if (isNaN(countValue) || countValue < 1 || countValue > 5) {
79
+ setError('contractionCount', {
80
+ type: 'manual',
81
+ message: t('contractionCountRange', 'Contraction count must be between 1 and 5'),
82
+ });
83
+ hasErrors = true;
84
+ }
72
85
  }
86
+
87
+ // Clinical validation warnings
88
+ if (!hasErrors) {
89
+ const countValue = parseInt(data.contractionCount);
90
+
91
+ // Warning for high contraction frequency
92
+ if (countValue >= 5) {
93
+ const proceedWithHighFrequency = window.confirm(
94
+ t(
95
+ 'highContractionWarning',
96
+ 'High contraction frequency (5 per 10 minutes) detected. This may indicate hyperstimulation. Do you want to proceed?',
97
+ ),
98
+ );
99
+ if (!proceedWithHighFrequency) {
100
+ return;
101
+ }
102
+ }
103
+
104
+ // Warning for strong contractions with high frequency
105
+ if (data.contractionLevel === 'strong' && countValue >= 4) {
106
+ const proceedWithIntensePattern = window.confirm(
107
+ t(
108
+ 'intenseContractionWarning',
109
+ 'Strong contractions with high frequency detected. This requires close monitoring. Do you want to proceed?',
110
+ ),
111
+ );
112
+ if (!proceedWithIntensePattern) {
113
+ return;
114
+ }
115
+ }
116
+ }
117
+
73
118
  if (hasErrors) {
74
- alert(t('formValidationError', 'Please select both contraction level and count before submitting.'));
119
+ alert(t('formValidationError', 'Please correct the validation errors before submitting.'));
75
120
  return;
76
121
  }
77
122
  const currentTime = new Date().toLocaleTimeString('en-GB', {
@@ -111,7 +156,7 @@ const CervicalContractionsForm: React.FC<CervicalContractionsFormProps> = ({
111
156
  preventCloseOnClickOutside={isSaving}>
112
157
  <div className={styles.contractionsFormContainer} style={{ maxWidth: 600, margin: 0, padding: '0 8px' }}>
113
158
  <h3 className={styles.sectionTitle} style={{ marginBottom: 0 }}>
114
- {t('cervicalContractionsData', 'Cervical Contractions')}
159
+ {t('cervicalContractionsData', 'Contractions')}
115
160
  </h3>
116
161
 
117
162
  <Controller
@@ -162,31 +207,21 @@ const CervicalContractionsForm: React.FC<CervicalContractionsFormProps> = ({
162
207
  rules={{ required: t('contractionCountRequired', 'Please select number of contractions') }}
163
208
  render={({ field, fieldState }) => (
164
209
  <>
165
- <Dropdown
166
- id="contraction-count-dropdown"
167
- titleText=""
168
- label={t('chooseCount', 'Choose count')}
169
- items={[
170
- { id: '1', text: t('oneContraction', '1 contraction') },
171
- { id: '2', text: t('twoContractions', '2 contractions') },
172
- { id: '3', text: t('threeContractions', '3 contractions') },
173
- { id: '4', text: t('fourContractions', '4 contractions') },
174
- { id: '5', text: t('fiveContractions', '5 contractions') },
175
- ]}
176
- itemToString={(item) => (item ? item.text : '')}
177
- selectedItem={
178
- field.value
179
- ? {
180
- id: field.value,
181
- text: `${field.value} contraction${field.value === '1' ? '' : 's'}`,
182
- }
183
- : null
184
- }
185
- onChange={({ selectedItem }) => field.onChange(selectedItem?.id || '')}
186
- className={styles.contractionCountDropdown}
187
- style={{ minWidth: 280, borderRadius: 24, background: '#eee', fontWeight: 600 }}
188
- />
189
- {fieldState.error && <div className={styles.errorMessage}>{fieldState.error.message}</div>}
210
+ <Select
211
+ id="contraction-count-select"
212
+ value={field.value}
213
+ onChange={(e) => field.onChange(e.target.value)}
214
+ invalid={!!fieldState.error}
215
+ invalidText={fieldState.error?.message}
216
+ style={{ minWidth: 280 }}
217
+ helperText={t('contractionCountHelper', 'Normal range: 2-4 contractions per 10 minutes')}>
218
+ <SelectItem value="" text={t('chooseAnOption', 'Choose an option')} />
219
+ <SelectItem value="1" text={t('oneContraction', '1 contraction')} />
220
+ <SelectItem value="2" text={t('twoContractions', '2 contractions')} />
221
+ <SelectItem value="3" text={t('threeContractions', '3 contractions')} />
222
+ <SelectItem value="4" text={t('fourContractions', '4 contractions')} />
223
+ <SelectItem value="5" text={t('fiveContractions', '5 contractions (High - Monitor closely)')} />
224
+ </Select>
190
225
  </>
191
226
  )}
192
227
  />
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from 'react';
1
+ import React, { useMemo, useEffect, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
4
  import { Button, Modal, Grid, Column, NumberInput, Select, SelectItem } from '@carbon/react';
@@ -40,7 +40,14 @@ const CervixForm: React.FC<CervixFormProps> = ({
40
40
  }) => {
41
41
  const { t } = useTranslation();
42
42
 
43
- const { control, handleSubmit, reset, setError, clearErrors } = useForm<CervixFormData>({
43
+ const {
44
+ control,
45
+ handleSubmit,
46
+ reset,
47
+ setError,
48
+ clearErrors,
49
+ formState: { errors },
50
+ } = useForm<CervixFormData>({
44
51
  defaultValues: {
45
52
  hour: '',
46
53
  time: '',
@@ -86,37 +93,39 @@ const CervixForm: React.FC<CervixFormProps> = ({
86
93
  });
87
94
  }, [usedHours]);
88
95
 
96
+ // Clear any errors when form opens
97
+ useEffect(() => {
98
+ if (isOpen) {
99
+ reset({
100
+ hour: '',
101
+ time: '',
102
+ cervicalDilation: '',
103
+ descent: '',
104
+ });
105
+ clearErrors();
106
+ }
107
+ }, [isOpen, clearErrors, reset]);
89
108
  const onSubmitForm = async (data: CervixFormData) => {
109
+ clearErrors();
110
+
111
+ // Basic validation
90
112
  if (!data.hour || data.hour === '') {
91
- setError('hour', {
92
- type: 'manual',
93
- message: 'Hour selection is required',
94
- });
113
+ setError('hour', { type: 'manual', message: 'Hour selection is required' });
95
114
  return;
96
115
  }
97
116
 
98
117
  if (!data.time || data.time === '') {
99
- setError('time', {
100
- type: 'manual',
101
- message: 'Time selection is required',
102
- });
103
- console.warn('[CervixForm] Attempted to submit with empty time value:', data);
118
+ setError('time', { type: 'manual', message: 'Time selection is required' });
104
119
  return;
105
120
  }
106
121
 
107
122
  if (!data.cervicalDilation || data.cervicalDilation === '') {
108
- setError('cervicalDilation', {
109
- type: 'manual',
110
- message: 'Cervical dilation is required',
111
- });
123
+ setError('cervicalDilation', { type: 'manual', message: 'Cervical dilation is required' });
112
124
  return;
113
125
  }
114
126
 
115
127
  if (!data.descent || data.descent === '') {
116
- setError('descent', {
117
- type: 'manual',
118
- message: 'Descent of head is required',
119
- });
128
+ setError('descent', { type: 'manual', message: 'Descent of head is required' });
120
129
  return;
121
130
  }
122
131
 
@@ -125,26 +134,17 @@ const CervixForm: React.FC<CervixFormProps> = ({
125
134
  const descentOfHead = parseInt(data.descent);
126
135
 
127
136
  if (isNaN(hourValue)) {
128
- setError('hour', {
129
- type: 'manual',
130
- message: 'Invalid hour value',
131
- });
137
+ setError('hour', { type: 'manual', message: 'Invalid hour value' });
132
138
  return;
133
139
  }
134
140
 
135
141
  if (isNaN(cervicalDilation)) {
136
- setError('cervicalDilation', {
137
- type: 'manual',
138
- message: 'Invalid cervical dilation value',
139
- });
142
+ setError('cervicalDilation', { type: 'manual', message: 'Invalid cervical dilation value' });
140
143
  return;
141
144
  }
142
145
 
143
146
  if (isNaN(descentOfHead)) {
144
- setError('descent', {
145
- type: 'manual',
146
- message: 'Invalid descent of head value',
147
- });
147
+ setError('descent', { type: 'manual', message: 'Invalid descent of head value' });
148
148
  return;
149
149
  }
150
150
 
@@ -157,33 +157,21 @@ const CervixForm: React.FC<CervixFormProps> = ({
157
157
  }
158
158
 
159
159
  if (cervicalDilation > 10) {
160
- setError('cervicalDilation', {
161
- type: 'manual',
162
- message: 'Cervical dilation cannot exceed 10cm',
163
- });
160
+ setError('cervicalDilation', { type: 'manual', message: 'Cervical dilation cannot exceed 10cm' });
164
161
  return;
165
162
  }
166
163
 
167
164
  if (descentOfHead < 1) {
168
- setError('descent', {
169
- type: 'manual',
170
- message: 'Descent of head cannot be less than 1 (most descended)',
171
- });
165
+ setError('descent', { type: 'manual', message: 'Descent of head cannot be less than 1 (most descended)' });
172
166
  return;
173
167
  }
168
+
174
169
  if (descentOfHead > 5) {
175
- setError('descent', {
176
- type: 'manual',
177
- message: 'Descent of head cannot exceed 5',
178
- });
170
+ setError('descent', { type: 'manual', message: 'Descent of head cannot exceed 5' });
179
171
  return;
180
172
  }
181
173
 
182
- clearErrors();
183
- if (!data.time || data.time.trim() === '') {
184
- alert('Time cannot be empty. Please select a valid time.');
185
- return;
186
- }
174
+ // All validation passed, submit the form
187
175
  onSubmit({
188
176
  hour: hourValue,
189
177
  time: data.time,
@@ -197,6 +185,7 @@ const CervixForm: React.FC<CervixFormProps> = ({
197
185
 
198
186
  const handleClose = () => {
199
187
  reset();
188
+ clearErrors();
200
189
  onClose();
201
190
  };
202
191
 
@@ -225,9 +214,6 @@ const CervixForm: React.FC<CervixFormProps> = ({
225
214
  <Controller
226
215
  name="hour"
227
216
  control={control}
228
- rules={{
229
- required: 'Hour selection is required',
230
- }}
231
217
  render={({ field, fieldState }) => (
232
218
  <Select
233
219
  id="hour-select"
@@ -248,9 +234,6 @@ const CervixForm: React.FC<CervixFormProps> = ({
248
234
  <Controller
249
235
  name="time"
250
236
  control={control}
251
- rules={{
252
- required: 'Time selection is required',
253
- }}
254
237
  render={({ field, fieldState }) => (
255
238
  <TimePickerDropdown
256
239
  id="time-input"
@@ -269,40 +252,20 @@ const CervixForm: React.FC<CervixFormProps> = ({
269
252
  <Controller
270
253
  name="cervicalDilation"
271
254
  control={control}
272
- rules={{
273
- required: 'Cervical dilation is required',
274
- validate: {
275
- isNumber: (value) => !isNaN(parseFloat(value)) || 'Must be a valid number',
276
- minValue: (value) => {
277
- const numValue = parseFloat(value);
278
- return (
279
- numValue >= validationLimits.cervicalDilationMin ||
280
- `Cannot be less than previous measurement (${validationLimits.cervicalDilationMin}cm)`
281
- );
282
- },
283
- maxValue: (value) => {
284
- const numValue = parseFloat(value);
285
- return numValue <= 10 || 'Cannot exceed 10cm';
286
- },
287
- },
288
- }}
289
255
  render={({ field, fieldState }) => (
290
256
  <>
291
257
  <NumberInput
292
258
  id="cervical-dilation-input"
293
259
  label="Cervical Dilation (cm) *"
294
260
  placeholder="Enter dilation (min: 4cm, max: 10cm)"
295
- value={field.value || ''}
296
- onChange={(e, { value }) => {
297
- // Only allow whole numbers
298
- const intValue = String(value).replace(/[^\d]/g, '');
299
- field.onChange(intValue);
300
- }}
301
261
  min={4}
302
262
  max={10}
303
263
  step={1}
264
+ value={field.value || ''}
265
+ onChange={(e, { value }) => field.onChange(String(value))}
304
266
  invalid={!!fieldState.error}
305
267
  invalidText={fieldState.error?.message}
268
+ allowEmpty
306
269
  />
307
270
  {existingCervixData.length > 0 && (
308
271
  <div className={styles.validationHint}>
@@ -313,46 +276,27 @@ const CervixForm: React.FC<CervixFormProps> = ({
313
276
  )}
314
277
  />
315
278
  </Column>
316
-
317
279
  <Column sm={4} md={8} lg={16}>
318
- <Controller
319
- name="descent"
320
- control={control}
321
- rules={{
322
- required: 'Descent of head is required',
323
- validate: {
324
- isNumber: (value) => !isNaN(parseInt(value)) || 'Must be a valid number',
325
- minValue: (value) => {
326
- const numValue = parseInt(value);
327
- return numValue >= 1 || 'Descent of head cannot be less than 1 (most descended)';
328
- },
329
- maxValue: (value) => {
330
- const numValue = parseInt(value);
331
- return numValue <= 5 || 'Descent of head cannot exceed 5';
332
- },
333
- },
334
- }}
335
- render={({ field, fieldState }) => (
336
- <>
280
+ <div className={styles.formField}>
281
+ <Controller
282
+ name="descent"
283
+ control={control}
284
+ render={({ field, fieldState }) => (
337
285
  <NumberInput
338
286
  id="descent-input"
339
287
  label="Descent of Head *"
340
- placeholder={
341
- existingCervixData.length === 0
342
- ? `Default: 5 (high position), can decrement to lower values`
343
- : `Enter descent (1=most descended, 5=high position)`
344
- }
345
- value={field.value || ''}
346
- onChange={(e, { value }) => field.onChange(String(value))}
347
- min={1}
288
+ min={0}
348
289
  max={5}
349
290
  step={1}
291
+ value={field.value || ''}
292
+ onChange={(e, { value }) => field.onChange(String(value))}
350
293
  invalid={!!fieldState.error}
351
294
  invalidText={fieldState.error?.message}
295
+ allowEmpty
352
296
  />
353
- </>
354
- )}
355
- />
297
+ )}
298
+ />
299
+ </div>
356
300
  </Column>
357
301
  </Grid>
358
302
  </div>