@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
@@ -1,9 +1,8 @@
1
- import React, { useState, useCallback } from 'react';
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
- import { Button, Modal, Grid, Column, Dropdown, InlineNotification, TextInput, ButtonSkeleton } from '@carbon/react';
5
- import { Add } from '@carbon/react/icons';
6
- import { launchWorkspace } from '@openmrs/esm-framework';
4
+ import { Button, Modal, Grid, Column, Dropdown, TextInput, ButtonSkeleton } from '@carbon/react';
5
+ import { launchWorkspace, useSession, openmrsFetch, showSnackbar } from '@openmrs/esm-framework';
7
6
  import { saveDrugOrderData } from '../partography.resource';
8
7
  import styles from '../partography-data-form.scss';
9
8
  import { ROUTE_OPTIONS, FREQUENCY_OPTIONS } from '../types';
@@ -30,9 +29,27 @@ type DrugsIVFluidsFormProps = {
30
29
 
31
30
  const DrugsIVFluidsForm: React.FC<DrugsIVFluidsFormProps> = ({ isOpen, onClose, onSubmit, onDataSaved, patient }) => {
32
31
  const { t } = useTranslation();
32
+ const session = useSession();
33
33
  const [isSaving, setIsSaving] = useState(false);
34
- const [saveError, setSaveError] = useState<string | null>(null);
35
- const [saveSuccess, setSaveSuccess] = useState(false);
34
+ const [providerUuid, setProviderUuid] = useState<string | undefined>(undefined);
35
+
36
+ useEffect(() => {
37
+ const fetchProviderData = async () => {
38
+ if (session?.user?.person?.uuid && !providerUuid) {
39
+ try {
40
+ const providerResp = await openmrsFetch(`/ws/rest/v1/provider?person=${session.user.person.uuid}&v=default`);
41
+ const providerData = await providerResp.json();
42
+ if (providerData.results && providerData.results.length > 0) {
43
+ setProviderUuid(providerData.results[0].uuid);
44
+ }
45
+ } catch (e) {
46
+ console.warn('Failed to fetch provider data:', e);
47
+ }
48
+ }
49
+ };
50
+
51
+ fetchProviderData();
52
+ }, [session?.user?.person?.uuid, providerUuid]);
36
53
 
37
54
  const {
38
55
  control,
@@ -71,8 +88,6 @@ const DrugsIVFluidsForm: React.FC<DrugsIVFluidsFormProps> = ({ isOpen, onClose,
71
88
 
72
89
  const onSubmitForm = async (data: DrugsIVFluidsFormData) => {
73
90
  clearErrors();
74
- setSaveError(null);
75
- setSaveSuccess(false);
76
91
 
77
92
  if (!data.drugName || data.drugName === '') {
78
93
  setError('drugName', {
@@ -106,67 +121,109 @@ const DrugsIVFluidsForm: React.FC<DrugsIVFluidsFormProps> = ({ isOpen, onClose,
106
121
  return;
107
122
  }
108
123
 
109
- if (patient?.uuid) {
110
- setIsSaving(true);
111
- try {
112
- const result = await saveDrugOrderData(patient.uuid, {
124
+ if (!patient) {
125
+ showSnackbar({
126
+ title: t('validationError', 'Validation Error'),
127
+ subtitle: t('noPatientSelected', 'No patient selected'),
128
+ kind: 'error',
129
+ });
130
+ return;
131
+ }
132
+ if (!patient.uuid) {
133
+ showSnackbar({
134
+ title: t('validationError', 'Validation Error'),
135
+ subtitle: t('patientMissingUuid', 'Patient is missing a UUID'),
136
+ kind: 'error',
137
+ });
138
+ return;
139
+ }
140
+
141
+ setIsSaving(true);
142
+
143
+ const abortController = new AbortController();
144
+
145
+ const timeoutId = setTimeout(() => {
146
+ abortController.abort();
147
+ }, 30000);
148
+ try {
149
+ const locationUuid = session?.sessionLocation?.uuid;
150
+
151
+ const result = await saveDrugOrderData(
152
+ patient.uuid,
153
+ {
113
154
  drugName: data.drugName,
114
155
  dosage: data.dosage,
115
156
  route: data.route,
116
157
  frequency: data.frequency,
117
- });
158
+ },
159
+ locationUuid,
160
+ providerUuid,
161
+ abortController.signal,
162
+ );
118
163
 
119
- if (result.success) {
120
- setSaveSuccess(true);
164
+ clearTimeout(timeoutId);
121
165
 
122
- if (onDataSaved) {
123
- onDataSaved();
124
- }
166
+ if (result.success) {
167
+ // Show success notification
168
+ showSnackbar({
169
+ title: t('drugOrderSaved', 'Drug order saved'),
170
+ subtitle: t('drugOrderSavedSuccessfully', 'Drug order has been saved successfully'),
171
+ kind: 'success',
172
+ isLowContrast: true,
173
+ });
125
174
 
126
- onSubmit({
127
- drugName: data.drugName,
128
- dosage: data.dosage,
129
- route: data.route,
130
- frequency: data.frequency,
131
- });
132
-
133
- reset();
134
-
135
- setTimeout(() => {
136
- setSaveSuccess(false);
137
- onClose();
138
- }, 1500);
139
- } else {
140
- setSaveError(result.message || t('saveError', 'Failed to save data'));
175
+ // Call callbacks
176
+ if (onDataSaved) {
177
+ onDataSaved();
141
178
  }
142
- } catch (error) {
143
- console.error('Save error details:', error);
144
- setSaveError(
145
- error?.message ||
146
- error?.responseBody?.error?.message ||
147
- error?.response?.data?.error?.message ||
148
- t('saveError', 'Failed to save data'),
149
- );
150
- } finally {
151
- setIsSaving(false);
179
+ onSubmit({
180
+ drugName: data.drugName,
181
+ dosage: data.dosage,
182
+ route: data.route,
183
+ frequency: data.frequency,
184
+ });
185
+
186
+ // Reset form and close modal
187
+ reset();
188
+ onClose();
189
+ } else {
190
+ showSnackbar({
191
+ title: t('errorSavingDrugOrder', 'Error saving drug order'),
192
+ subtitle: result.message || t('saveError', 'Failed to save data'),
193
+ kind: 'error',
194
+ });
152
195
  }
153
- } else {
154
- onSubmit({
155
- drugName: data.drugName,
156
- dosage: data.dosage,
157
- route: data.route,
158
- frequency: data.frequency,
196
+ } catch (error) {
197
+ clearTimeout(timeoutId);
198
+
199
+ // Handle request cancellation (timeout or manual abort)
200
+ if (error.name === 'AbortError') {
201
+ showSnackbar({
202
+ title: t('requestCancelled', 'Request cancelled'),
203
+ subtitle: t('saveTimeout', 'Request was cancelled due to timeout. Please try again.'),
204
+ kind: 'warning',
205
+ });
206
+ return;
207
+ }
208
+
209
+ // Handle other errors
210
+ showSnackbar({
211
+ title: t('errorSavingDrugOrder', 'Error saving drug order'),
212
+ subtitle:
213
+ error?.message ||
214
+ error?.responseBody?.error?.message ||
215
+ error?.response?.data?.error?.message ||
216
+ t('saveError', 'Failed to save data'),
217
+ kind: 'error',
159
218
  });
160
- reset();
161
- onClose();
219
+ } finally {
220
+ setIsSaving(false);
162
221
  }
163
222
  };
164
223
 
165
224
  const handleClose = () => {
166
225
  reset();
167
226
  clearErrors();
168
- setSaveError(null);
169
- setSaveSuccess(false);
170
227
  onClose();
171
228
  };
172
229
 
@@ -184,55 +241,8 @@ const DrugsIVFluidsForm: React.FC<DrugsIVFluidsFormProps> = ({ isOpen, onClose,
184
241
  onRequestSubmit={handleSubmit(onSubmitForm)}
185
242
  onSecondarySubmit={handleClose}
186
243
  size="md">
187
- {saveSuccess && (
188
- <InlineNotification
189
- kind="success"
190
- title={t('saveSuccess', 'Data saved successfully')}
191
- subtitle={t('drugOrderDataSaved', 'Drug order data has been saved to OpenMRS')}
192
- hideCloseButton
193
- />
194
- )}
195
-
196
- {saveError && (
197
- <InlineNotification
198
- kind="error"
199
- title={t('saveError', 'Error saving data')}
200
- subtitle={saveError}
201
- onCloseButtonClick={() => setSaveError(null)}
202
- />
203
- )}
204
-
205
244
  <div className={styles.modalContent}>
206
245
  <Grid>
207
- <Column sm={4} md={8} lg={16}>
208
- <div className={styles.workspaceLauncherSection}>
209
- <h4>{t('selectFromDrugList', 'Select from Drug List')}</h4>
210
- <p className={styles.helperText}>
211
- {t(
212
- 'drugOrderDescription',
213
- 'Use the drug order workspace to select from the complete list of available drugs with proper dosing and administration details.',
214
- )}
215
- </p>
216
- <Button
217
- kind="tertiary"
218
- renderIcon={Add}
219
- onClick={handleLaunchDrugOrderWorkspace}
220
- disabled={!patient?.uuid}
221
- className={styles.workspaceLauncherButton}>
222
- {t('addDrugOrder', 'Add drug order')}
223
- </Button>
224
- </div>
225
- </Column>
226
-
227
- <Column sm={4} md={8} lg={16}>
228
- <div className={styles.manualEntrySection}>
229
- <h4>{t('manualEntry', 'Manual Entry')}</h4>
230
- <p className={styles.helperText}>
231
- {t('manualEntryDescription', 'Or enter drug information manually for quick documentation.')}
232
- </p>
233
- </div>
234
- </Column>
235
-
236
246
  <Column sm={4} md={8} lg={16}>
237
247
  <Controller
238
248
  name="drugName"
@@ -57,13 +57,13 @@ const FetalHeartRateForm: React.FC<FetalHeartRateFormProps> = ({
57
57
  });
58
58
  const generateHourOptions = () => {
59
59
  const options = [];
60
- options.push({ value: '0', label: '00' });
61
- options.push({ value: '0.5', label: '30min' });
62
- for (let i = 1; i <= 24; i++) {
63
- options.push({ value: i.toString(), label: `${i}hr` });
64
- if (i < 24) {
65
- options.push({ value: (i + 0.5).toString(), label: `${i}hr 30min` });
66
- }
60
+ // Add 00 hour option first
61
+ options.push({ value: '0', label: '0hr' });
62
+ // Start from 0.5hr, then 1hr, 1.5hr, ... up to 24hr (in 0.5 increments)
63
+ for (let i = 1; i <= 48; i++) {
64
+ const value = (i * 0.5).toString();
65
+ const label = i % 2 === 0 ? `${i / 2}hr` : `${i * 0.5}hr`;
66
+ options.push({ value, label });
67
67
  }
68
68
  return options;
69
69
  };
@@ -69,88 +69,48 @@ const MembraneAmnioticFluidForm: React.FC<MembraneAmnioticFluidFormProps> = ({
69
69
  [],
70
70
  );
71
71
 
72
- const latestUsedTimeSlot = React.useMemo(() => {
72
+ // Calculate the latest used hour from existing entries (similar to fetal heart rate form)
73
+ const latestUsedHour = React.useMemo(() => {
73
74
  if (!existingTimeEntries || existingTimeEntries.length === 0) {
74
75
  return null;
75
76
  }
76
- const sortedTimeSlots = existingTimeEntries
77
- .map((entry) => entry.timeSlot)
78
- .slice()
79
- .sort((a, b) => {
80
- const getMinutes = (time: string) => {
81
- const [hours, minutes] = time.split(':').map(Number);
77
+ // Convert timeSlot values to numeric hours and find the maximum
78
+ const hours = existingTimeEntries.map((entry) => parseFloat(entry.timeSlot || '0')).filter((hour) => !isNaN(hour)); // Filter out invalid values
82
79
 
83
- const adjustedHours = hours <= 5 ? hours + 24 : hours;
84
- return adjustedHours * 60 + minutes;
85
- };
86
- return getMinutes(a) - getMinutes(b);
87
- });
88
- return sortedTimeSlots[sortedTimeSlots.length - 1];
80
+ return hours.length > 0 ? Math.max(...hours) : null;
89
81
  }, [existingTimeEntries]);
90
82
 
91
- const isTimeSlotDisabled = (timeSlot: string) => {
92
- if (!latestUsedTimeSlot) {
93
- return false;
94
- }
95
-
96
- const getMinutes = (time: string) => {
97
- const [hours, minutes] = time.split(':').map(Number);
98
-
99
- const adjustedHours = hours <= 5 ? hours + 24 : hours;
100
- return adjustedHours * 60 + minutes;
101
- };
102
-
103
- return getMinutes(timeSlot) <= getMinutes(latestUsedTimeSlot);
104
- };
83
+ // Generate time slot options with disabled state (similar to fetal heart rate form)
84
+ const timeSlotOptionsWithDisabled = React.useMemo(() => {
85
+ return timeSlotOptions.map((option) => {
86
+ const hourValue = parseFloat(option.value);
87
+ const isDisabled = latestUsedHour !== null && hourValue <= latestUsedHour;
105
88
 
106
- const amnioticFluidOptions = useMemo(
107
- () => [
108
- {
109
- value: 'Membrane intact',
110
- label: t('membraneIntact', 'Membrane intact'),
111
- concept: AMNIOTIC_MEMBRANE_INTACT_CONCEPT,
112
- },
113
- { value: 'Clear liquor', label: t('clearLiquor', 'Clear liquor'), concept: AMNIOTIC_CLEAR_LIQUOR_CONCEPT },
114
- {
115
- value: 'Meconium Stained',
116
- label: t('meconiumStained', 'Meconium Stained'),
117
- concept: AMNIOTIC_MECONIUM_STAINED_CONCEPT,
118
- },
119
- { value: 'Absent', label: t('absent', 'Absent'), concept: AMNIOTIC_ABSENT_CONCEPT },
120
- {
121
- value: 'Blood Stained',
122
- label: t('bloodStained', 'Blood Stained'),
123
- concept: AMNIOTIC_BLOOD_STAINED_CONCEPT,
124
- },
125
- ],
126
- [t],
127
- );
128
-
129
- const mouldingOptions = useMemo(
130
- () => [
131
- { value: '0', label: '0', concept: MOULDING_NONE_CONCEPT },
132
- { value: '+', label: '+', concept: MOULDING_SLIGHT_CONCEPT },
133
- { value: '++', label: '++', concept: MOULDING_MODERATE_CONCEPT },
134
- { value: '+++', label: '+++', concept: MOULDING_SEVERE_CONCEPT },
135
- ],
136
- [],
137
- );
89
+ return {
90
+ ...option,
91
+ disabled: isDisabled,
92
+ };
93
+ });
94
+ }, [timeSlotOptions, latestUsedHour]);
138
95
 
139
96
  const handleFormSubmit = (data: MembraneAmnioticFluidFormData) => {
140
97
  clearErrors();
141
98
 
142
99
  let hasErrors = false;
143
100
 
101
+ // Validate time slot selection
144
102
  if (!data.timeSlot || data.timeSlot.trim() === '') {
145
103
  setError('timeSlot', { type: 'manual', message: t('timeSlotRequired', 'Please select a time slot') });
146
104
  hasErrors = true;
147
105
  }
148
106
 
107
+ // Validate exact time
149
108
  if (!data.exactTime || data.exactTime.trim() === '') {
150
109
  setError('exactTime', { type: 'manual', message: t('exactTimeRequired', 'Exact time is required') });
151
110
  hasErrors = true;
152
111
  }
153
112
 
113
+ // Validate amniotic fluid selection
154
114
  if (!data.amnioticFluid || data.amnioticFluid.trim() === '') {
155
115
  setError('amnioticFluid', {
156
116
  type: 'manual',
@@ -159,6 +119,7 @@ const MembraneAmnioticFluidForm: React.FC<MembraneAmnioticFluidFormProps> = ({
159
119
  hasErrors = true;
160
120
  }
161
121
 
122
+ // Validate moulding selection
162
123
  if (!data.moulding || data.moulding.trim() === '') {
163
124
  setError('moulding', {
164
125
  type: 'manual',
@@ -172,10 +133,16 @@ const MembraneAmnioticFluidForm: React.FC<MembraneAmnioticFluidFormProps> = ({
172
133
  return;
173
134
  }
174
135
 
175
- if (isTimeSlotDisabled(data.timeSlot)) {
136
+ // Progressive validation - prevent selecting hours before the latest entered hour
137
+ const selectedHour = parseFloat(data.timeSlot);
138
+
139
+ if (latestUsedHour !== null && selectedHour <= latestUsedHour) {
176
140
  setError('timeSlot', {
177
141
  type: 'manual',
178
- message: t('timeSlotDisabled', 'Selected time slot is not available. Please select a later time.'),
142
+ message: t(
143
+ 'timeSlotDisabled',
144
+ `Cannot select ${data.timeSlot}hr. Please select a time after ${latestUsedHour}hr.`,
145
+ ),
179
146
  });
180
147
  alert(t('timeSlotValidationError', 'Please select a valid time slot that comes after the previous entry.'));
181
148
  return;
@@ -191,6 +158,39 @@ const MembraneAmnioticFluidForm: React.FC<MembraneAmnioticFluidFormProps> = ({
191
158
  reset();
192
159
  };
193
160
 
161
+ const amnioticFluidOptions = useMemo(
162
+ () => [
163
+ {
164
+ value: 'Membrane intact',
165
+ label: t('membraneIntact', 'Membrane intact'),
166
+ concept: AMNIOTIC_MEMBRANE_INTACT_CONCEPT,
167
+ },
168
+ { value: 'Clear liquor', label: t('clearLiquor', 'Clear liquor'), concept: AMNIOTIC_CLEAR_LIQUOR_CONCEPT },
169
+ {
170
+ value: 'Meconium Stained',
171
+ label: t('meconiumStained', 'Meconium Stained'),
172
+ concept: AMNIOTIC_MECONIUM_STAINED_CONCEPT,
173
+ },
174
+ { value: 'Absent', label: t('absent', 'Absent'), concept: AMNIOTIC_ABSENT_CONCEPT },
175
+ {
176
+ value: 'Blood Stained',
177
+ label: t('bloodStained', 'Blood Stained'),
178
+ concept: AMNIOTIC_BLOOD_STAINED_CONCEPT,
179
+ },
180
+ ],
181
+ [t],
182
+ );
183
+
184
+ const mouldingOptions = useMemo(
185
+ () => [
186
+ { value: '0', label: '0', concept: MOULDING_NONE_CONCEPT },
187
+ { value: '+', label: '+', concept: MOULDING_SLIGHT_CONCEPT },
188
+ { value: '++', label: '++', concept: MOULDING_MODERATE_CONCEPT },
189
+ { value: '+++', label: '+++', concept: MOULDING_SEVERE_CONCEPT },
190
+ ],
191
+ [],
192
+ );
193
+
194
194
  const handleClose = () => {
195
195
  reset();
196
196
  clearErrors();
@@ -223,25 +223,22 @@ const MembraneAmnioticFluidForm: React.FC<MembraneAmnioticFluidFormProps> = ({
223
223
  invalid={!!fieldState.error}
224
224
  invalidText={fieldState.error?.message}
225
225
  helperText={
226
- latestUsedTimeSlot
227
- ? t('timeSlotInfo', `Select a time after ${latestUsedTimeSlot}`)
226
+ latestUsedHour !== null
227
+ ? t('timeSlotInfo', `Select a time after ${latestUsedHour}hr`)
228
228
  : t('timeSlotInfoInitial', 'Select a time slot')
229
229
  }
230
230
  value={field.value}
231
231
  onChange={(e) => field.onChange(e.target.value)}>
232
232
  <SelectItem value="" text={t('chooseAnOption', 'Choose an option')} />
233
- {timeSlotOptions.map((option) => {
234
- const isDisabled = isTimeSlotDisabled(option.value);
235
- return (
236
- <SelectItem
237
- key={option.value}
238
- value={option.value}
239
- text={option.label}
240
- disabled={isDisabled}
241
- className={isDisabled ? styles.disabledOption : undefined}
242
- />
243
- );
244
- })}
233
+ {timeSlotOptionsWithDisabled.map((option) => (
234
+ <SelectItem
235
+ key={option.value}
236
+ value={option.value}
237
+ text={option.label}
238
+ disabled={option.disabled}
239
+ className={option.disabled ? styles.disabledOption : undefined}
240
+ />
241
+ ))}
245
242
  </Select>
246
243
  )}
247
244
  />
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
- import { Button, Modal, Grid, Column, NumberInput, Dropdown } from '@carbon/react';
4
+ import { Button, Modal, Grid, Column, NumberInput, Select, SelectItem } from '@carbon/react';
5
5
  import TimePickerDropdown from './time-picker-dropdown.component';
6
6
  import styles from '../partography-data-form.scss';
7
7
 
@@ -45,11 +45,6 @@ const OxytocinForm: React.FC<OxytocinFormProps> = ({
45
45
 
46
46
  const watchOxytocinUsed = watch('oxytocinUsed');
47
47
 
48
- const oxytocinOptions = [
49
- { id: 'yes', text: t('yes', 'Yes') },
50
- { id: 'no', text: t('no', 'No') },
51
- ];
52
-
53
48
  const onSubmitForm = async (data: OxytocinFormData) => {
54
49
  if (!data.time || data.time === '') {
55
50
  setError('time', {
@@ -148,17 +143,17 @@ const OxytocinForm: React.FC<OxytocinFormProps> = ({
148
143
  required: 'Oxytocin usage selection is required',
149
144
  }}
150
145
  render={({ field, fieldState }) => (
151
- <Dropdown
152
- id="oxytocin-usage-dropdown"
153
- titleText={t('oxytocin', 'Oxytocin')}
154
- label="Select if oxytocin is used"
155
- items={oxytocinOptions}
156
- itemToString={(item) => (item ? item.text : '')}
157
- selectedItem={field.value ? oxytocinOptions.find((opt) => opt.id === field.value) : null}
158
- onChange={({ selectedItem }) => field.onChange(selectedItem?.id || '')}
146
+ <Select
147
+ id="oxytocin-usage-select"
148
+ labelText={t('oxytocin', 'Oxytocin')}
149
+ value={field.value}
150
+ onChange={(e) => field.onChange(e.target.value)}
159
151
  invalid={!!fieldState.error}
160
- invalidText={fieldState.error?.message}
161
- />
152
+ invalidText={fieldState.error?.message}>
153
+ <SelectItem value="" text={t('selectIfOxytocinIsUsed', 'Select if oxytocin is used')} />
154
+ <SelectItem value="yes" text={t('yes', 'Yes')} />
155
+ <SelectItem value="no" text={t('no', 'No')} />
156
+ </Select>
162
157
  )}
163
158
  />
164
159
  </Column>
@@ -185,14 +180,14 @@ const OxytocinForm: React.FC<OxytocinFormProps> = ({
185
180
  <NumberInput
186
181
  id="drops-per-minute-input"
187
182
  label={t('dropsPerMinute', 'Drops per minute')}
188
- placeholder="Enter drops per minute"
189
- value={field.value || ''}
190
- onChange={(e, { value }) => field.onChange(String(value))}
191
183
  min={0}
192
184
  max={60}
193
185
  step={1}
186
+ value={field.value || ''}
187
+ onChange={(e, { value }) => field.onChange(String(value))}
194
188
  invalid={!!fieldState.error}
195
189
  invalidText={fieldState.error?.message}
190
+ allowEmpty
196
191
  />
197
192
  )}
198
193
  />