@kenyaemr/esm-appointments-app 8.1.1-pre.124 → 8.1.2-pre.152

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 (119) hide show
  1. package/.turbo/turbo-build.log +27 -25
  2. package/dist/111.js +2 -0
  3. package/dist/111.js.map +1 -0
  4. package/dist/123.js +2 -0
  5. package/dist/{198.js.LICENSE.txt → 123.js.LICENSE.txt} +0 -6
  6. package/dist/123.js.map +1 -0
  7. package/dist/130.js +1 -1
  8. package/dist/130.js.map +1 -1
  9. package/dist/{385.js → 139.js} +1 -1
  10. package/dist/139.js.map +1 -0
  11. package/dist/228.js +1 -0
  12. package/dist/236.js +1 -0
  13. package/dist/240.js +1 -0
  14. package/dist/261.js +1 -0
  15. package/dist/269.js +1 -1
  16. package/dist/269.js.map +1 -1
  17. package/dist/271.js +1 -1
  18. package/dist/272.js +1 -0
  19. package/dist/319.js +1 -1
  20. package/dist/336.js +1 -0
  21. package/dist/378.js +1 -0
  22. package/dist/443.js +1 -0
  23. package/dist/443.js.map +1 -0
  24. package/dist/460.js +1 -1
  25. package/dist/529.js +1 -1
  26. package/dist/529.js.map +1 -1
  27. package/dist/539.js +1 -0
  28. package/dist/566.js +1 -0
  29. package/dist/574.js +1 -1
  30. package/dist/581.js +1 -1
  31. package/dist/644.js +1 -1
  32. package/dist/652.js +1 -0
  33. package/dist/673.js +1 -0
  34. package/dist/705.js +1 -0
  35. package/dist/711.js +1 -1
  36. package/dist/711.js.map +1 -1
  37. package/dist/727.js +1 -0
  38. package/dist/737.js +1 -0
  39. package/dist/744.js +1 -0
  40. package/dist/757.js +1 -1
  41. package/dist/788.js +1 -1
  42. package/dist/807.js +1 -1
  43. package/dist/833.js +1 -1
  44. package/dist/899.js +1 -0
  45. package/dist/923.js +1 -0
  46. package/dist/923.js.map +1 -0
  47. package/dist/kenyaemr-esm-appointments-app.js +1 -1
  48. package/dist/kenyaemr-esm-appointments-app.js.buildmanifest.json +448 -96
  49. package/dist/kenyaemr-esm-appointments-app.js.map +1 -1
  50. package/dist/main.js +1 -1
  51. package/dist/main.js.map +1 -1
  52. package/dist/routes.json +1 -1
  53. package/package-lock.json +6416 -0
  54. package/package.json +5 -5
  55. package/src/appointments/appointment-tabs.component.tsx +1 -1
  56. package/src/appointments/common-components/appointments-table.component.tsx +0 -1
  57. package/src/appointments/common-components/appointments-table.test.tsx +7 -3
  58. package/src/appointments/common-components/checkin-button.component.tsx +5 -1
  59. package/src/appointments/common-components/end-appointment.modal.tsx +2 -2
  60. package/src/appointments/scheduled/scheduled-appointments.component.tsx +1 -1
  61. package/src/appointments/unscheduled/unscheduled-appointments.component.tsx +6 -6
  62. package/src/appointments/unscheduled/unscheduled-appointments.test.tsx +19 -4
  63. package/src/appointments.component.tsx +7 -7
  64. package/src/appointments.test.tsx +11 -1
  65. package/src/calendar/appointments-calendar-view.component.tsx +2 -2
  66. package/src/calendar/monthly/monthly-workload-view.component.tsx +7 -7
  67. package/src/config-schema.ts +6 -70
  68. package/src/form/appointments-form.component.tsx +84 -73
  69. package/src/form/appointments-form.resource.ts +4 -4
  70. package/src/form/appointments-form.scss +1 -1
  71. package/src/form/appointments-form.test.tsx +142 -110
  72. package/src/patient-appointments/patient-appointments-action-menu.component.tsx +2 -4
  73. package/src/patient-appointments/patient-appointments-base.test.tsx +1 -1
  74. package/src/patient-appointments/patient-appointments-cancel.modal.tsx +6 -1
  75. package/src/patient-appointments/patient-appointments-cancel.scss +29 -0
  76. package/src/patient-appointments/patient-upcoming-appointments-card.component.tsx +64 -8
  77. package/src/routes.json +1 -1
  78. package/src/types/index.ts +1 -1
  79. package/src/workload/monthly-view-workload/monthly-view.component.tsx +8 -6
  80. package/src/workload/monthly-view-workload/monthlyWorkCard.tsx +3 -2
  81. package/src/workload/workload-card.component.tsx +5 -3
  82. package/src/workload/workload.component.tsx +13 -20
  83. package/src/workload/workload.resource.ts +3 -0
  84. package/translations/am.json +4 -2
  85. package/translations/ar.json +24 -22
  86. package/translations/de.json +168 -0
  87. package/translations/en.json +3 -1
  88. package/translations/es.json +58 -56
  89. package/translations/fr.json +4 -2
  90. package/translations/he.json +93 -91
  91. package/translations/hi.json +168 -0
  92. package/translations/hi_IN.json +168 -0
  93. package/translations/id.json +168 -0
  94. package/translations/it.json +168 -0
  95. package/translations/km.json +4 -2
  96. package/translations/ne.json +168 -0
  97. package/translations/pt.json +168 -0
  98. package/translations/pt_BR.json +168 -0
  99. package/translations/qu.json +168 -0
  100. package/translations/si.json +168 -0
  101. package/translations/sw.json +168 -0
  102. package/translations/sw_KE.json +168 -0
  103. package/translations/tr.json +168 -0
  104. package/translations/tr_TR.json +168 -0
  105. package/translations/uk.json +168 -0
  106. package/translations/vi.json +168 -0
  107. package/translations/zh.json +4 -2
  108. package/translations/zh_CN.json +4 -2
  109. package/dist/198.js +0 -2
  110. package/dist/198.js.map +0 -1
  111. package/dist/265.js +0 -1
  112. package/dist/265.js.map +0 -1
  113. package/dist/385.js.map +0 -1
  114. package/dist/440.js +0 -2
  115. package/dist/440.js.map +0 -1
  116. package/dist/501.js +0 -1
  117. package/dist/501.js.map +0 -1
  118. package/src/hooks/useDefaultLocation.ts +0 -14
  119. /package/dist/{440.js.LICENSE.txt → 111.js.LICENSE.txt} +0 -0
@@ -1,6 +1,7 @@
1
1
  import React, { useContext, useEffect, useState } from 'react';
2
- import { useTranslation } from 'react-i18next';
3
2
  import dayjs from 'dayjs';
3
+ import { Controller, useController, useForm } from 'react-hook-form';
4
+ import { useTranslation } from 'react-i18next';
4
5
  import {
5
6
  Button,
6
7
  ButtonSet,
@@ -20,9 +21,7 @@ import {
20
21
  TimePickerSelect,
21
22
  Toggle,
22
23
  } from '@carbon/react';
23
- import { Controller, useController, useForm } from 'react-hook-form';
24
24
  import { zodResolver } from '@hookform/resolvers/zod';
25
- import { z } from 'zod';
26
25
  import {
27
26
  ExtensionSlot,
28
27
  ResponsiveWrapper,
@@ -33,8 +32,11 @@ import {
33
32
  useLocations,
34
33
  usePatient,
35
34
  useSession,
35
+ type DefaultWorkspaceProps,
36
36
  type FetchResponse,
37
37
  } from '@openmrs/esm-framework';
38
+ import { z } from 'zod';
39
+ import { type ConfigObject } from '../config-schema';
38
40
  import {
39
41
  checkAppointmentConflict,
40
42
  saveAppointment,
@@ -42,9 +44,6 @@ import {
42
44
  useAppointmentService,
43
45
  useMutateAppointments,
44
46
  } from './appointments-form.resource';
45
- import { useProviders } from '../hooks/useProviders';
46
- import type { Appointment, AppointmentPayload, RecurringPattern } from '../types';
47
- import { type ConfigObject } from '../config-schema';
48
47
  import {
49
48
  appointmentLocationTagName,
50
49
  dateFormat,
@@ -53,30 +52,30 @@ import {
53
52
  moduleName,
54
53
  weekDays,
55
54
  } from '../constants';
55
+ import { useProviders } from '../hooks/useProviders';
56
+ import type { Appointment, AppointmentPayload, RecurringPattern } from '../types';
56
57
  import SelectedDateContext from '../hooks/selectedDateContext';
57
58
  import Workload from '../workload/workload.component';
58
59
  import styles from './appointments-form.scss';
59
60
 
60
- const time12HourFormatRegexPattern = '^(1[0-2]|0?[1-9]):[0-5][0-9]$';
61
-
62
- function isValidTime(timeStr) {
63
- return timeStr.match(new RegExp(time12HourFormatRegexPattern));
64
- }
65
-
66
61
  interface AppointmentsFormProps {
67
62
  appointment?: Appointment;
68
63
  recurringPattern?: RecurringPattern;
69
64
  patientUuid?: string;
70
65
  context: string;
71
- closeWorkspace: () => void;
72
66
  }
73
67
 
74
- const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
68
+ const time12HourFormatRegexPattern = '^(1[0-2]|0?[1-9]):[0-5][0-9]$';
69
+
70
+ const isValidTime = (timeStr: string) => timeStr.match(new RegExp(time12HourFormatRegexPattern));
71
+
72
+ const AppointmentsForm: React.FC<AppointmentsFormProps & DefaultWorkspaceProps> = ({
75
73
  appointment,
76
74
  recurringPattern,
77
75
  patientUuid,
78
76
  context,
79
77
  closeWorkspace,
78
+ promptBeforeClosing,
80
79
  }) => {
81
80
  const { patient } = usePatient(patientUuid);
82
81
  const { mutateAppointments } = useMutateAppointments();
@@ -97,11 +96,10 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
97
96
 
98
97
  const [isRecurringAppointment, setIsRecurringAppointment] = useState(false);
99
98
  const [isAllDayAppointment, setIsAllDayAppointment] = useState(false);
100
- const [isConflict, setIsConflict] = useState(false);
101
99
  const defaultRecurringPatternType = recurringPattern?.type || 'DAY';
102
100
  const defaultRecurringPatternPeriod = recurringPattern?.period || 1;
103
101
  const defaultRecurringPatternDaysOfWeek = recurringPattern?.daysOfWeek || [];
104
-
102
+ const [isSuccessful, setIsSuccessful] = useState(false);
105
103
  const [isSubmitting, setIsSubmitting] = useState(false);
106
104
 
107
105
  // TODO can we clean this all up to be more consistent between using Date and dayjs?
@@ -127,7 +125,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
127
125
  const defaultDuration =
128
126
  appointment?.startDateTime && appointment?.endDateTime
129
127
  ? dayjs(appointment.endDateTime).diff(dayjs(appointment.startDateTime), 'minutes')
130
- : null;
128
+ : undefined;
131
129
 
132
130
  // t('durationErrorMessage', 'Duration should be greater than zero')
133
131
  const appointmentsFormSchema = z
@@ -156,7 +154,9 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
156
154
  recurringPatternPeriod: z.number(),
157
155
  recurringPatternDaysOfWeek: z.array(z.string()),
158
156
  selectedDaysOfWeekText: z.string().optional(),
159
- startTime: z.string().refine((value) => isValidTime(value)),
157
+ startTime: z.string().refine((value) => isValidTime(value), {
158
+ message: translateFrom(moduleName, 'invalidTime', 'Invalid time'),
159
+ }),
160
160
  timeFormat: z.enum(['AM', 'PM']),
161
161
  appointmentDateTime: z.object({
162
162
  startDate: z.date(),
@@ -219,7 +219,8 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
219
219
  setValue,
220
220
  watch,
221
221
  handleSubmit,
222
- formState: { errors },
222
+ reset,
223
+ formState: { errors, isDirty },
223
224
  } = useForm<AppointmentFormData>({
224
225
  mode: 'all',
225
226
  resolver: zodResolver(appointmentsFormSchema),
@@ -250,7 +251,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
250
251
  },
251
252
  });
252
253
 
253
- useEffect(() => setValue('formIsRecurringAppointment', isRecurringAppointment), [isRecurringAppointment]);
254
+ useEffect(() => setValue('formIsRecurringAppointment', isRecurringAppointment), [isRecurringAppointment, setValue]);
254
255
 
255
256
  // Retrive ref callback for appointmentDateTime (startDate & recurringPatternEndDate)
256
257
  const {
@@ -268,12 +269,22 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
268
269
  endDateRef(endDateElement);
269
270
  }, [startDateRef, endDateRef]);
270
271
 
272
+ useEffect(() => {
273
+ if (isSuccessful) {
274
+ reset();
275
+ promptBeforeClosing(() => false);
276
+ closeWorkspace();
277
+ return;
278
+ }
279
+ promptBeforeClosing(() => isDirty);
280
+ }, [isDirty, promptBeforeClosing, isSuccessful, reset, closeWorkspace]);
281
+
271
282
  const handleWorkloadDateChange = (date: Date) => {
272
283
  const appointmentDate = getValues('appointmentDateTime');
273
284
  setValue('appointmentDateTime', { ...appointmentDate, startDate: date });
274
285
  };
275
286
 
276
- const handleMultiselectChange = (e) => {
287
+ const handleSelectChange = (e) => {
277
288
  setValue(
278
289
  'selectedDaysOfWeekText',
279
290
  (() => {
@@ -338,7 +349,9 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
338
349
  appointmentRequest: appointmentPayload,
339
350
  recurringPattern: constructRecurringPattern(data),
340
351
  };
352
+
341
353
  const abortController = new AbortController();
354
+
342
355
  (isRecurringAppointment
343
356
  ? saveRecurringAppointments(recurringAppointmentPayload, abortController)
344
357
  : saveAppointment(appointmentPayload, abortController)
@@ -346,7 +359,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
346
359
  ({ status }) => {
347
360
  if (status === 200) {
348
361
  setIsSubmitting(false);
349
- closeWorkspace();
362
+ setIsSuccessful(true);
350
363
  mutateAppointments();
351
364
  showSnackbar({
352
365
  isLowContrast: true,
@@ -442,15 +455,13 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
442
455
  };
443
456
  };
444
457
 
445
- const onError = (error) => console.error(error);
446
-
447
458
  if (isLoading)
448
459
  return (
449
460
  <InlineLoading className={styles.loader} description={`${t('loading', 'Loading')} ...`} role="progressbar" />
450
461
  );
451
462
 
452
463
  return (
453
- <Form onSubmit={handleSubmit(handleSaveAppointment, onError)}>
464
+ <Form onSubmit={handleSubmit(handleSaveAppointment)}>
454
465
  <Stack gap={4}>
455
466
  {patient && (
456
467
  <ExtensionSlot
@@ -468,16 +479,16 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
468
479
  <Controller
469
480
  name="location"
470
481
  control={control}
471
- render={({ field: { onChange, value, onBlur, ref }, fieldState }) => (
482
+ render={({ field: { onChange, value, onBlur, ref } }) => (
472
483
  <Select
473
484
  id="location"
485
+ invalid={!!errors?.location}
486
+ invalidText={errors?.location?.message}
474
487
  labelText={t('selectALocation', 'Select a location')}
475
488
  onChange={onChange}
476
489
  onBlur={onBlur}
477
- value={value}
478
490
  ref={ref}
479
- invalid={!!fieldState?.error?.message}
480
- invalidText={fieldState?.error?.message}>
491
+ value={value}>
481
492
  <SelectItem text={t('chooseLocation', 'Choose a location')} value="" />
482
493
  {locations?.length > 0 &&
483
494
  locations.map((location) => (
@@ -496,10 +507,13 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
496
507
  <Controller
497
508
  name="selectedService"
498
509
  control={control}
499
- render={({ field: { onBlur, onChange, value, ref }, fieldState }) => (
510
+ render={({ field: { onBlur, onChange, value, ref } }) => (
500
511
  <Select
501
512
  id="service"
513
+ invalid={!!errors?.selectedService}
514
+ invalidText={errors?.selectedService?.message}
502
515
  labelText={t('selectService', 'Select a service')}
516
+ onBlur={onBlur}
503
517
  onChange={(event) => {
504
518
  if (context === 'creating') {
505
519
  setValue(
@@ -518,11 +532,8 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
518
532
  }
519
533
  onChange(event);
520
534
  }}
521
- onBlur={onBlur}
522
- value={value}
523
535
  ref={ref}
524
- invalid={!!fieldState?.error?.message}
525
- invalidText={fieldState?.error?.message}>
536
+ value={value}>
526
537
  <SelectItem text={t('chooseService', 'Select service')} value="" />
527
538
  {services?.length > 0 &&
528
539
  services.map((service) => (
@@ -541,17 +552,17 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
541
552
  <Controller
542
553
  name="appointmentType"
543
554
  control={control}
544
- render={({ field: { onBlur, onChange, value, ref }, fieldState }) => (
555
+ render={({ field: { onBlur, onChange, value, ref } }) => (
545
556
  <Select
546
557
  disabled={!appointmentTypes?.length}
547
558
  id="appointmentType"
559
+ invalid={!!errors?.appointmentType}
560
+ invalidText={errors?.appointmentType?.message}
548
561
  labelText={t('selectAppointmentType', 'Select the type of appointment')}
562
+ onBlur={onBlur}
549
563
  onChange={onChange}
550
- value={value}
551
564
  ref={ref}
552
- onBlur={onBlur}
553
- invalid={!!fieldState?.error?.message}
554
- invalidText={fieldState?.error?.message}>
565
+ value={value}>
555
566
  <SelectItem text={t('chooseAppointmentType', 'Choose appointment type')} value="" />
556
567
  {appointmentTypes?.length > 0 &&
557
568
  appointmentTypes.map((appointmentType, index) => (
@@ -629,7 +640,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
629
640
  </ResponsiveWrapper>
630
641
 
631
642
  {!isAllDayAppointment && (
632
- <TimeAndDuration isTablet={isTablet} control={control} services={services} watch={watch} t={t} />
643
+ <TimeAndDuration control={control} errors={errors} services={services} watch={watch} t={t} />
633
644
  )}
634
645
 
635
646
  <ResponsiveWrapper>
@@ -681,21 +692,21 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
681
692
  render={({ field: { onChange } }) => (
682
693
  <MultiSelect
683
694
  className={styles.weekSelect}
684
- label={getValues('selectedDaysOfWeekText')}
685
695
  id="daysOfWeek"
696
+ initialSelectedItems={weekDays.filter((i) =>
697
+ getValues('recurringPatternDaysOfWeek').includes(i.id),
698
+ )}
686
699
  items={weekDays}
687
700
  itemToString={(item) => (item ? t(item.labelCode, item.label) : '')}
701
+ label={getValues('selectedDaysOfWeekText')}
702
+ onChange={(e) => {
703
+ onChange(e);
704
+ handleSelectChange(e);
705
+ }}
688
706
  selectionFeedback="top-after-reopen"
689
707
  sortItems={(items) => {
690
708
  return items.sort((a, b) => a.order > b.order);
691
709
  }}
692
- initialSelectedItems={weekDays.filter((i) => {
693
- return getValues('recurringPatternDaysOfWeek').includes(i.id);
694
- })}
695
- onChange={(e) => {
696
- onChange(e);
697
- handleMultiselectChange(e);
698
- }}
699
710
  />
700
711
  )}
701
712
  />
@@ -743,7 +754,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
743
754
  </ResponsiveWrapper>
744
755
 
745
756
  {!isAllDayAppointment && (
746
- <TimeAndDuration isTablet={isTablet} control={control} services={services} watch={watch} t={t} />
757
+ <TimeAndDuration control={control} services={services} watch={watch} t={t} errors={errors} />
747
758
  )}
748
759
  </div>
749
760
  )}
@@ -754,9 +765,9 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
754
765
  <section className={styles.formGroup}>
755
766
  <ResponsiveWrapper>
756
767
  <Workload
757
- selectedService={watch('selectedService')}
758
768
  appointmentDate={watch('appointmentDateTime').startDate}
759
769
  onWorkloadDateChange={handleWorkloadDateChange}
770
+ selectedService={watch('selectedService')}
760
771
  />
761
772
  </ResponsiveWrapper>
762
773
  </section>
@@ -769,11 +780,11 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
769
780
  <Controller
770
781
  name="appointmentStatus"
771
782
  control={control}
772
- render={({ field: { onBlur, onChange, value, ref }, fieldState }) => (
783
+ render={({ field: { onBlur, onChange, value, ref } }) => (
773
784
  <Select
774
785
  id="appointmentStatus"
775
- invalid={!!fieldState?.error?.message}
776
- invalidText={fieldState?.error?.message}
786
+ invalid={!!errors?.appointmentStatus}
787
+ invalidText={errors?.appointmentStatus?.message}
777
788
  labelText={t('selectAppointmentStatus', 'Select status')}
778
789
  onChange={onChange}
779
790
  value={value}
@@ -826,16 +837,16 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
826
837
  <Controller
827
838
  name="dateAppointmentScheduled"
828
839
  control={control}
829
- render={({ field: { onChange, value, ref }, fieldState }) => (
840
+ render={({ field: { onChange, value, ref } }) => (
830
841
  <div style={{ width: '100%' }}>
831
842
  <DatePicker
832
843
  datePickerType="single"
833
844
  dateFormat={datePickerFormat}
834
- value={value}
845
+ invalid={!!errors?.dateAppointmentScheduled}
846
+ invalidText={errors?.dateAppointmentScheduled?.message}
835
847
  maxDate={new Date().toISOString()}
836
848
  onChange={([date]) => onChange(date)}
837
- invalid={!!fieldState?.error?.message}
838
- invalidText={fieldState?.error?.message}>
849
+ value={value}>
839
850
  <DatePickerInput
840
851
  id="dateAppointmentScheduledPickerInput"
841
852
  labelText={t('dateScheduledDetail', 'Date appointment issued')}
@@ -844,7 +855,6 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
844
855
  ref={ref}
845
856
  />
846
857
  </DatePicker>
847
- {fieldState?.error?.message && <div className={styles.errorMessage}>{fieldState.error.message}</div>}
848
858
  </div>
849
859
  )}
850
860
  />
@@ -884,7 +894,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
884
894
  );
885
895
  };
886
896
 
887
- function TimeAndDuration({ isTablet, t, watch, control, services }) {
897
+ function TimeAndDuration({ t, watch, control, services, errors }) {
888
898
  const defaultDuration = services?.find((service) => service.name === watch('selectedService'))?.durationMins || null;
889
899
 
890
900
  return (
@@ -897,12 +907,14 @@ function TimeAndDuration({ isTablet, t, watch, control, services }) {
897
907
  <TimePicker
898
908
  id="time-picker"
899
909
  pattern={time12HourFormatRegexPattern}
900
- invalid={!isValidTime(value)}
901
- invalidText={t('invalidTime', 'Invalid time')}
902
- onChange={(event) => onChange(event.target.value)}
903
- value={value}
910
+ invalid={!!errors?.startTime}
911
+ invalidText={errors?.startTime?.message}
912
+ labelText={t('time', 'Time')}
913
+ onChange={(event) => {
914
+ onChange(event.target.value);
915
+ }}
904
916
  style={{ marginLeft: '0.125rem', flex: 'none' }}
905
- labelText={t('time', 'Time')}>
917
+ value={value}>
906
918
  <Controller
907
919
  name="timeFormat"
908
920
  control={control}
@@ -925,22 +937,21 @@ function TimeAndDuration({ isTablet, t, watch, control, services }) {
925
937
  <Controller
926
938
  name="duration"
927
939
  control={control}
928
- defaultValue={defaultDuration}
929
- render={({ field: { onChange, onBlur, value, ref }, fieldState }) => (
940
+ render={({ field: { onChange, onBlur, value, ref } }) => (
930
941
  <NumberInput
931
- hideSteppers
932
942
  disableWheel
943
+ hideSteppers
933
944
  id="duration"
934
- min={0}
935
- max={1440}
945
+ invalid={!!errors?.duration}
946
+ invalidText={errors?.duration?.message}
936
947
  label={t('durationInMinutes', 'Duration (minutes)')}
937
- invalidText={t('invalidNumber', 'Number is not valid')}
938
- size="md"
948
+ max={1440}
949
+ min={0}
939
950
  onBlur={onBlur}
940
951
  onChange={(event) => onChange(Number(event.target.value))}
941
- value={value}
942
952
  ref={ref}
943
- invalid={fieldState?.error?.message}
953
+ size="md"
954
+ value={value}
944
955
  />
945
956
  )}
946
957
  />
@@ -1,4 +1,6 @@
1
+ import { useCallback } from 'react';
1
2
  import dayjs from 'dayjs';
3
+ import isToday from 'dayjs/plugin/isToday';
2
4
  import useSWR, { useSWRConfig } from 'swr';
3
5
  import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
4
6
  import {
@@ -7,12 +9,10 @@ import {
7
9
  type AppointmentsFetchResponse,
8
10
  type RecurringAppointmentsPayload,
9
11
  } from '../types';
10
- import isToday from 'dayjs/plugin/isToday';
11
- import { useCallback } from 'react';
12
12
  dayjs.extend(isToday);
13
13
 
14
- const appointmentUrlMatcher = '/ws/rest/v1/appointment';
15
- const appointmentsSearchUrl = '/ws/rest/v1/appointments/search';
14
+ const appointmentUrlMatcher = `${restBaseUrl}/appointment`;
15
+ const appointmentsSearchUrl = `${restBaseUrl}/appointments/search`;
16
16
 
17
17
  export function useMutateAppointments() {
18
18
  const { mutate } = useSWRConfig();
@@ -36,7 +36,7 @@ $openmrs-background-grey: #ededed;
36
36
  display: flex;
37
37
  flex-flow: row wrap;
38
38
  gap: layout.$spacing-05;
39
- align-items: center;
39
+ align-items: start;
40
40
  }
41
41
 
42
42
  .dateTimeFields {