@openmrs/esm-appointments-app 9.2.1-pre.7296 → 9.2.1-pre.7303

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.
@@ -33,9 +33,8 @@ import {
33
33
  useLocations,
34
34
  usePatient,
35
35
  useSession,
36
- Workspace2,
36
+ type DefaultWorkspaceProps,
37
37
  type FetchResponse,
38
- type Workspace2DefinitionProps,
39
38
  } from '@openmrs/esm-framework';
40
39
  import { z } from 'zod';
41
40
  import { type ConfigObject } from '../config-schema';
@@ -53,21 +52,24 @@ import { useProviders } from '../hooks/useProviders';
53
52
  import Workload from '../workload/workload.component';
54
53
  import styles from './appointments-form.scss';
55
54
 
56
- export interface AppointmentsFormProps {
55
+ interface AppointmentsFormProps {
57
56
  appointment?: Appointment;
58
57
  recurringPattern?: RecurringPattern;
59
58
  patientUuid?: string;
60
- context: 'creating' | 'editing';
59
+ context: string;
61
60
  }
62
61
 
63
62
  const time12HourFormatRegexPattern = '^(1[0-2]|0?[1-9]):[0-5][0-9]$';
64
- const time12HourFormatRegex = /^(1[0-2]|0?[1-9]):[0-5][0-9]$/;
65
63
 
66
- const isValidTime = (timeStr: string) => time12HourFormatRegex.test(timeStr);
64
+ const isValidTime = (timeStr: string) => timeStr.match(new RegExp(time12HourFormatRegexPattern));
67
65
 
68
- const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps>> = ({
69
- workspaceProps: { appointment, recurringPattern, patientUuid, context },
66
+ const AppointmentsForm: React.FC<AppointmentsFormProps & DefaultWorkspaceProps> = ({
67
+ appointment,
68
+ recurringPattern,
69
+ patientUuid,
70
+ context,
70
71
  closeWorkspace,
72
+ promptBeforeClosing,
71
73
  }) => {
72
74
  const { patient } = usePatient(patientUuid);
73
75
  const { mutateAppointments } = useMutateAppointments();
@@ -281,16 +283,19 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
281
283
  useEffect(() => {
282
284
  if (isSuccessful) {
283
285
  reset();
284
- closeWorkspace({ closeWindow: true, discardUnsavedChanges: true });
286
+ promptBeforeClosing(() => false);
287
+ closeWorkspace();
288
+ return;
285
289
  }
286
- }, [isSuccessful, reset, closeWorkspace]);
290
+ promptBeforeClosing(() => isDirty);
291
+ }, [isDirty, promptBeforeClosing, isSuccessful, reset, closeWorkspace]);
287
292
 
288
293
  const handleWorkloadDateChange = (date: Date) => {
289
294
  const appointmentDate = getValues('appointmentDateTime');
290
295
  setValue('appointmentDateTime', { ...appointmentDate, startDate: date });
291
296
  };
292
297
 
293
- const handleSelectChange = (e: { selectedItems: Array<{ id: number; label: string }> }) => {
298
+ const handleSelectChange = (e) => {
294
299
  setValue(
295
300
  'selectedDaysOfWeekText',
296
301
  (() => {
@@ -307,8 +312,8 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
307
312
  );
308
313
  setValue(
309
314
  'recurringPatternDaysOfWeek',
310
- e.selectedItems.map((s: { id: number }) => {
311
- return String(s.id);
315
+ e.selectedItems.map((s) => {
316
+ return s.id;
312
317
  }),
313
318
  );
314
319
  };
@@ -445,7 +450,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
445
450
  providers: [{ uuid: provider }],
446
451
  patientUuid: patientUuid,
447
452
  comments: appointmentNote,
448
- uuid: context === 'editing' ? appointment?.uuid : undefined,
453
+ uuid: context === 'editing' ? appointment.uuid : undefined,
449
454
  dateAppointmentScheduled: dayjs(dateAppointmentScheduled).format(),
450
455
  };
451
456
  };
@@ -475,375 +480,340 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
475
480
  );
476
481
 
477
482
  return (
478
- <Workspace2
479
- title={
480
- context === 'editing'
481
- ? t('editAppointment', 'Edit appointment')
482
- : t('createNewAppointment', 'Create new appointment')
483
- }
484
- hasUnsavedChanges={isDirty}>
485
- <Form onSubmit={handleSubmit(handleSaveAppointment)}>
486
- {patient && (
487
- <ExtensionSlot
488
- name="patient-header-slot"
489
- state={{
490
- patient,
491
- patientUuid: patientUuid,
492
- hideActionsOverflow: true,
493
- }}
494
- />
495
- )}
496
- <Stack className={styles.formWrapper} gap={6}>
497
- <FormGroup className={styles.formGroup} legendText={t('location', 'Location')}>
498
- <ResponsiveWrapper>
499
- <Controller
500
- name="location"
501
- control={control}
502
- render={({ field: { onChange, value, onBlur, ref } }) => (
503
- <Select
504
- id="location"
505
- invalid={!!errors?.location}
506
- invalidText={errors?.location?.message}
507
- labelText={t('selectALocation', 'Select a location')}
508
- onChange={onChange}
509
- onBlur={onBlur}
510
- ref={ref}
511
- value={value}>
512
- <SelectItem text={t('chooseLocation', 'Choose a location')} value="" />
513
- {locations?.length > 0 &&
514
- locations.map((location) => (
515
- <SelectItem key={location.uuid} text={location.display} value={location.uuid}>
516
- {location.display}
517
- </SelectItem>
518
- ))}
519
- </Select>
520
- )}
521
- />
522
- </ResponsiveWrapper>
523
- </FormGroup>
524
- <FormGroup className={styles.formGroup} legendText={t('service', 'Service')}>
525
- <ResponsiveWrapper>
526
- <Controller
527
- name="selectedService"
528
- control={control}
529
- render={({ field: { onBlur, onChange, value, ref } }) => (
530
- <Select
531
- id="service"
532
- invalid={!!errors?.selectedService}
533
- invalidText={errors?.selectedService?.message}
534
- labelText={t('selectService', 'Select a service')}
535
- onBlur={onBlur}
536
- onChange={(event: React.ChangeEvent<HTMLSelectElement>) => {
537
- if (context === 'creating') {
538
- setValue(
539
- 'duration',
540
- services?.find((service) => service.name === event.target.value)?.durationMins,
541
- );
542
- } else if (context === 'editing') {
543
- const previousServiceDuration = services?.find(
544
- (service) => service.name === getValues('selectedService'),
545
- )?.durationMins;
546
- const selectedServiceDuration = services?.find(
547
- (service) => service.name === event.target.value,
548
- )?.durationMins;
549
- if (selectedServiceDuration && previousServiceDuration === getValues('duration')) {
550
- setValue('duration', selectedServiceDuration);
551
- }
483
+ <Form onSubmit={handleSubmit(handleSaveAppointment)}>
484
+ {patient && (
485
+ <ExtensionSlot
486
+ name="patient-header-slot"
487
+ state={{
488
+ patient,
489
+ patientUuid: patientUuid,
490
+ hideActionsOverflow: true,
491
+ }}
492
+ />
493
+ )}
494
+ <Stack className={styles.formWrapper} gap={6}>
495
+ <FormGroup className={styles.formGroup} legendText={t('location', 'Location')}>
496
+ <ResponsiveWrapper>
497
+ <Controller
498
+ name="location"
499
+ control={control}
500
+ render={({ field: { onChange, value, onBlur, ref } }) => (
501
+ <Select
502
+ id="location"
503
+ invalid={!!errors?.location}
504
+ invalidText={errors?.location?.message}
505
+ labelText={t('selectALocation', 'Select a location')}
506
+ onChange={onChange}
507
+ onBlur={onBlur}
508
+ ref={ref}
509
+ value={value}>
510
+ <SelectItem text={t('chooseLocation', 'Choose a location')} value="" />
511
+ {locations?.length > 0 &&
512
+ locations.map((location) => (
513
+ <SelectItem key={location.uuid} text={location.display} value={location.uuid}>
514
+ {location.display}
515
+ </SelectItem>
516
+ ))}
517
+ </Select>
518
+ )}
519
+ />
520
+ </ResponsiveWrapper>
521
+ </FormGroup>
522
+ <FormGroup className={styles.formGroup} legendText={t('service', 'Service')}>
523
+ <ResponsiveWrapper>
524
+ <Controller
525
+ name="selectedService"
526
+ control={control}
527
+ render={({ field: { onBlur, onChange, value, ref } }) => (
528
+ <Select
529
+ id="service"
530
+ invalid={!!errors?.selectedService}
531
+ invalidText={errors?.selectedService?.message}
532
+ labelText={t('selectService', 'Select a service')}
533
+ onBlur={onBlur}
534
+ onChange={(event) => {
535
+ if (context === 'creating') {
536
+ setValue(
537
+ 'duration',
538
+ services?.find((service) => service.name === event.target.value)?.durationMins,
539
+ );
540
+ } else if (context === 'editing') {
541
+ const previousServiceDuration = services?.find(
542
+ (service) => service.name === getValues('selectedService'),
543
+ )?.durationMins;
544
+ const selectedServiceDuration = services?.find(
545
+ (service) => service.name === event.target.value,
546
+ )?.durationMins;
547
+ if (selectedServiceDuration && previousServiceDuration === getValues('duration')) {
548
+ setValue('duration', selectedServiceDuration);
552
549
  }
553
- onChange(event);
554
- }}
555
- ref={ref}
556
- value={value}>
557
- <SelectItem text={t('chooseService', 'Select service')} value="" />
558
- {services?.length > 0 &&
559
- services.map((service) => (
560
- <SelectItem key={service.uuid} text={service.name} value={service.name}>
561
- {service.name}
562
- </SelectItem>
563
- ))}
564
- </Select>
565
- )}
566
- />
567
- </ResponsiveWrapper>
568
- </FormGroup>
569
- <FormGroup className={styles.formGroup} legendText={t('appointmentType_title', 'Appointment Type')}>
570
- <ResponsiveWrapper>
571
- <Controller
572
- name="appointmentType"
573
- control={control}
574
- render={({ field: { onBlur, onChange, value, ref } }) => (
575
- <Select
576
- disabled={!appointmentTypes?.length}
577
- id="appointmentType"
578
- invalid={!!errors?.appointmentType}
579
- invalidText={errors?.appointmentType?.message}
580
- labelText={t('selectAppointmentType', 'Select the type of appointment')}
581
- onBlur={onBlur}
582
- onChange={onChange}
583
- ref={ref}
584
- value={value}>
585
- <SelectItem text={t('chooseAppointmentType', 'Choose appointment type')} value="" />
586
- {appointmentTypes?.length > 0 &&
587
- appointmentTypes.map((appointmentType, index) => (
588
- <SelectItem key={index} text={appointmentType} value={appointmentType}>
589
- {appointmentType}
590
- </SelectItem>
591
- ))}
592
- </Select>
550
+ }
551
+ onChange(event);
552
+ }}
553
+ ref={ref}
554
+ value={value}>
555
+ <SelectItem text={t('chooseService', 'Select service')} value="" />
556
+ {services?.length > 0 &&
557
+ services.map((service) => (
558
+ <SelectItem key={service.uuid} text={service.name} value={service.name}>
559
+ {service.name}
560
+ </SelectItem>
561
+ ))}
562
+ </Select>
563
+ )}
564
+ />
565
+ </ResponsiveWrapper>
566
+ </FormGroup>
567
+ <FormGroup className={styles.formGroup} legendText={t('appointmentType_title', 'Appointment Type')}>
568
+ <ResponsiveWrapper>
569
+ <Controller
570
+ name="appointmentType"
571
+ control={control}
572
+ render={({ field: { onBlur, onChange, value, ref } }) => (
573
+ <Select
574
+ disabled={!appointmentTypes?.length}
575
+ id="appointmentType"
576
+ invalid={!!errors?.appointmentType}
577
+ invalidText={errors?.appointmentType?.message}
578
+ labelText={t('selectAppointmentType', 'Select the type of appointment')}
579
+ onBlur={onBlur}
580
+ onChange={onChange}
581
+ ref={ref}
582
+ value={value}>
583
+ <SelectItem text={t('chooseAppointmentType', 'Choose appointment type')} value="" />
584
+ {appointmentTypes?.length > 0 &&
585
+ appointmentTypes.map((appointmentType, index) => (
586
+ <SelectItem key={index} text={appointmentType} value={appointmentType}>
587
+ {appointmentType}
588
+ </SelectItem>
589
+ ))}
590
+ </Select>
591
+ )}
592
+ />
593
+ </ResponsiveWrapper>
594
+ </FormGroup>
595
+
596
+ <FormGroup className={styles.formGroup} legendText={t('recurringAppointment', 'Recurring Appointment')}>
597
+ <div>
598
+ <Toggle
599
+ id="recurringToggle"
600
+ labelB={t('yes', 'Yes')}
601
+ labelA={t('no', 'No')}
602
+ labelText={t('isRecurringAppointment', 'Is this a recurring appointment?')}
603
+ onClick={() => setIsRecurringAppointment(!isRecurringAppointment)}
604
+ />
605
+ </div>
606
+ </FormGroup>
607
+
608
+ <FormGroup className={styles.formGroup} legendText={t('dateTime', 'Date & Time')}>
609
+ <div className={styles.dateTimeFields}>
610
+ {isRecurringAppointment && (
611
+ <div className={styles.inputContainer}>
612
+ {allowAllDayAppointments && (
613
+ <Controller
614
+ name="isAllDayAppointment"
615
+ control={control}
616
+ render={({ field: { value, onChange } }) => (
617
+ <Toggle
618
+ id="allDayToggle"
619
+ labelA={t('no', 'No')}
620
+ labelB={t('yes', 'Yes')}
621
+ labelText={t('allDay', 'All day')}
622
+ toggled={value}
623
+ onToggle={onChange}
624
+ />
625
+ )}
626
+ />
593
627
  )}
594
- />
595
- </ResponsiveWrapper>
596
- </FormGroup>
597
-
598
- <FormGroup className={styles.formGroup} legendText={t('recurringAppointment', 'Recurring Appointment')}>
599
- <div>
600
- <Toggle
601
- id="recurringToggle"
602
- labelB={t('yes', 'Yes')}
603
- labelA={t('no', 'No')}
604
- labelText={t('isRecurringAppointment', 'Is this a recurring appointment?')}
605
- onClick={() => setIsRecurringAppointment(!isRecurringAppointment)}
606
- />
607
- </div>
608
- </FormGroup>
628
+ <ResponsiveWrapper>
629
+ <Controller
630
+ name="appointmentDateTime"
631
+ control={control}
632
+ render={({ field: { onChange, value }, fieldState }) => (
633
+ <OpenmrsDateRangePicker
634
+ value={
635
+ value.startDate && value.recurringPatternEndDate
636
+ ? [value.startDate, value.recurringPatternEndDate]
637
+ : null
638
+ }
639
+ onChange={(dateRange) => {
640
+ const [startDate, endDate] = dateRange;
641
+ onChange({
642
+ ...value,
643
+ startDate,
644
+ startDateText: startDate ? dayjs(startDate).format(dateFormat) : '',
645
+ recurringPatternEndDate: endDate,
646
+ recurringPatternEndDateText: endDate ? dayjs(endDate).format(dateFormat) : '',
647
+ });
648
+ }}
649
+ startName="start"
650
+ endName="end"
651
+ id="appointmentRecurringDateRangePicker"
652
+ data-testid="appointmentRecurringDateRangePicker"
653
+ labelText={t('dateRange', 'Set date range')}
654
+ invalid={!!fieldState?.error?.message}
655
+ invalidText={fieldState?.error?.message}
656
+ isRequired
657
+ />
658
+ )}
659
+ />
660
+ </ResponsiveWrapper>
661
+
662
+ {!watch('isAllDayAppointment') && <TimeAndDuration t={t} control={control} errors={errors} />}
663
+
664
+ <ResponsiveWrapper>
665
+ <Controller
666
+ name="recurringPatternPeriod"
667
+ control={control}
668
+ render={({ field: { onBlur, onChange, value } }) => (
669
+ <NumberInput
670
+ hideSteppers
671
+ id="repeatNumber"
672
+ min={1}
673
+ max={356}
674
+ label={t('repeatEvery', 'Repeat every')}
675
+ invalidText={t('invalidNumber', 'Number is not valid')}
676
+ value={value}
677
+ onBlur={onBlur}
678
+ onChange={(e) => {
679
+ onChange(Number(e.target.value));
680
+ }}
681
+ />
682
+ )}
683
+ />
684
+ </ResponsiveWrapper>
685
+
686
+ <ResponsiveWrapper>
687
+ <Controller
688
+ name="recurringPatternType"
689
+ control={control}
690
+ render={({ field: { onChange, value } }) => (
691
+ <RadioButtonGroup
692
+ legendText={t('period', 'Period')}
693
+ name="radio-button-group"
694
+ onChange={(type) => onChange(type)}
695
+ valueSelected={value}>
696
+ <RadioButton labelText={t('day', 'Day')} value="DAY" id="radioDay" />
697
+ <RadioButton labelText={t('week', 'Week')} value="WEEK" id="radioWeek" />
698
+ </RadioButtonGroup>
699
+ )}
700
+ />
701
+ </ResponsiveWrapper>
609
702
 
610
- <FormGroup className={styles.formGroup} legendText={t('dateTime', 'Date & Time')}>
611
- <div className={styles.dateTimeFields}>
612
- {isRecurringAppointment && (
613
- <div className={styles.inputContainer}>
614
- {allowAllDayAppointments && (
703
+ {watch('recurringPatternType') === 'WEEK' && (
704
+ <div>
615
705
  <Controller
616
- name="isAllDayAppointment"
706
+ name="selectedDaysOfWeekText"
617
707
  control={control}
618
- render={({ field: { value, onChange } }) => (
619
- <Toggle
620
- id="allDayToggle"
621
- labelA={t('no', 'No')}
622
- labelB={t('yes', 'Yes')}
623
- labelText={t('allDay', 'All day')}
624
- toggled={value}
625
- onToggle={onChange}
626
- />
627
- )}
628
- />
629
- )}
630
- <ResponsiveWrapper>
631
- <Controller
632
- name="appointmentDateTime"
633
- control={control}
634
- render={({ field: { onChange, value }, fieldState }) => (
635
- <OpenmrsDateRangePicker
636
- value={
637
- value.startDate && value.recurringPatternEndDate
638
- ? [value.startDate, value.recurringPatternEndDate]
639
- : null
640
- }
641
- onChange={(dateRange) => {
642
- const [startDate, endDate] = dateRange;
643
- onChange({
644
- ...value,
645
- startDate,
646
- startDateText: startDate ? dayjs(startDate).format(dateFormat) : '',
647
- recurringPatternEndDate: endDate,
648
- recurringPatternEndDateText: endDate ? dayjs(endDate).format(dateFormat) : '',
649
- });
708
+ defaultValue={defaultSelectedDaysOfWeekText}
709
+ render={({ field: { onChange } }) => (
710
+ <MultiSelect
711
+ className={styles.weekSelect}
712
+ id="daysOfWeek"
713
+ initialSelectedItems={weekDays.filter((i) =>
714
+ getValues('recurringPatternDaysOfWeek').includes(i.id),
715
+ )}
716
+ items={weekDays}
717
+ itemToString={(item) => (item ? t(item.labelCode, item.label) : '')}
718
+ label={getValues('selectedDaysOfWeekText')}
719
+ onChange={(e) => {
720
+ onChange(e);
721
+ handleSelectChange(e);
650
722
  }}
651
- startName="start"
652
- endName="end"
653
- id="appointmentRecurringDateRangePicker"
654
- data-testid="appointmentRecurringDateRangePicker"
655
- labelText={t('dateRange', 'Set date range')}
656
- invalid={!!fieldState?.error?.message}
657
- invalidText={fieldState?.error?.message}
658
- isRequired
659
- />
660
- )}
661
- />
662
- </ResponsiveWrapper>
663
-
664
- {!watch('isAllDayAppointment') && <TimeAndDuration t={t} control={control} errors={errors} />}
665
-
666
- <ResponsiveWrapper>
667
- <Controller
668
- name="recurringPatternPeriod"
669
- control={control}
670
- render={({ field: { onBlur, onChange, value } }) => (
671
- <NumberInput
672
- hideSteppers
673
- id="repeatNumber"
674
- min={1}
675
- max={356}
676
- label={t('repeatEvery', 'Repeat every')}
677
- invalidText={t('invalidNumber', 'Number is not valid')}
678
- value={value}
679
- onBlur={onBlur}
680
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
681
- onChange(Number(e.target.value));
723
+ selectionFeedback="top-after-reopen"
724
+ sortItems={(items) => {
725
+ return items.sort((a, b) => a.order > b.order);
682
726
  }}
683
727
  />
684
728
  )}
685
729
  />
686
- </ResponsiveWrapper>
687
-
688
- <ResponsiveWrapper>
689
- <Controller
690
- name="recurringPatternType"
691
- control={control}
692
- render={({ field: { onChange, value } }) => (
693
- <RadioButtonGroup
694
- legendText={t('period', 'Period')}
695
- name="radio-button-group"
696
- onChange={(type: string) => onChange(type)}
697
- valueSelected={value}>
698
- <RadioButton labelText={t('day', 'Day')} value="DAY" id="radioDay" />
699
- <RadioButton labelText={t('week', 'Week')} value="WEEK" id="radioWeek" />
700
- </RadioButtonGroup>
701
- )}
702
- />
703
- </ResponsiveWrapper>
704
-
705
- {watch('recurringPatternType') === 'WEEK' && (
706
- <div>
707
- <Controller
708
- name="selectedDaysOfWeekText"
709
- control={control}
710
- defaultValue={defaultSelectedDaysOfWeekText}
711
- render={({ field: { onChange } }) => (
712
- <MultiSelect
713
- className={styles.weekSelect}
714
- id="daysOfWeek"
715
- initialSelectedItems={weekDays.filter((i) =>
716
- getValues('recurringPatternDaysOfWeek').includes(i.id),
717
- )}
718
- items={weekDays}
719
- itemToString={(item: any) => (item ? t(item.labelCode, item.label) : '')}
720
- label={getValues('selectedDaysOfWeekText')}
721
- onChange={(e: any) => {
722
- onChange(e);
723
- handleSelectChange(e);
724
- }}
725
- selectionFeedback="top-after-reopen"
726
- sortItems={(items: any[]) => {
727
- return items.sort((a: any, b: any) => a.order - b.order);
728
- }}
729
- />
730
- )}
730
+ </div>
731
+ )}
732
+ </div>
733
+ )}
734
+
735
+ {!isRecurringAppointment && (
736
+ <div className={styles.inputContainer}>
737
+ {allowAllDayAppointments && (
738
+ <Controller
739
+ name="isAllDayAppointment"
740
+ control={control}
741
+ render={({ field: { value, onChange } }) => (
742
+ <Toggle
743
+ id="allDayToggle"
744
+ labelA={t('no', 'No')}
745
+ labelB={t('yes', 'Yes')}
746
+ labelText={t('allDay', 'All day')}
747
+ toggled={value}
748
+ onToggle={onChange}
731
749
  />
732
- </div>
733
- )}
734
- </div>
735
- )}
750
+ )}
751
+ />
752
+ )}
753
+ <ResponsiveWrapper>
754
+ <Controller
755
+ name="appointmentDateTime"
756
+ control={control}
757
+ render={({ field, fieldState }) => (
758
+ <OpenmrsDatePicker
759
+ data-testid="datePickerInput"
760
+ id="datePickerInput"
761
+ invalid={!!fieldState?.error?.message}
762
+ invalidText={fieldState?.error?.message}
763
+ labelText={t('date', 'Date')}
764
+ onBlur={field.onBlur}
765
+ onChange={(date) => {
766
+ field.onChange({
767
+ ...field.value,
768
+ startDate: date,
769
+ });
770
+ }}
771
+ style={{ width: '100%' }}
772
+ value={field.value.startDate}
773
+ />
774
+ )}
775
+ />
776
+ </ResponsiveWrapper>
736
777
 
737
- {!isRecurringAppointment && (
738
- <div className={styles.inputContainer}>
739
- {allowAllDayAppointments && (
740
- <Controller
741
- name="isAllDayAppointment"
742
- control={control}
743
- render={({ field: { value, onChange } }) => (
744
- <Toggle
745
- id="allDayToggle"
746
- labelA={t('no', 'No')}
747
- labelB={t('yes', 'Yes')}
748
- labelText={t('allDay', 'All day')}
749
- toggled={value}
750
- onToggle={onChange}
751
- />
752
- )}
753
- />
754
- )}
755
- <ResponsiveWrapper>
756
- <Controller
757
- name="appointmentDateTime"
758
- control={control}
759
- render={({ field, fieldState }) => (
760
- <OpenmrsDatePicker
761
- data-testid="datePickerInput"
762
- id="datePickerInput"
763
- invalid={!!fieldState?.error?.message}
764
- invalidText={fieldState?.error?.message}
765
- labelText={t('date', 'Date')}
766
- onBlur={field.onBlur}
767
- onChange={(date) => {
768
- field.onChange({
769
- ...field.value,
770
- startDate: date,
771
- });
772
- }}
773
- style={{ width: '100%' }}
774
- value={field.value.startDate}
775
- />
776
- )}
777
- />
778
- </ResponsiveWrapper>
778
+ {!watch('isAllDayAppointment') && <TimeAndDuration t={t} control={control} errors={errors} />}
779
+ </div>
780
+ )}
781
+ </div>
782
+ </FormGroup>
779
783
 
780
- {!watch('isAllDayAppointment') && <TimeAndDuration t={t} control={control} errors={errors} />}
781
- </div>
782
- )}
783
- </div>
784
+ {getValues('selectedService') && (
785
+ <FormGroup className={styles.formGroup} legendText="">
786
+ <ResponsiveWrapper>
787
+ <Workload
788
+ appointmentDate={watch('appointmentDateTime').startDate}
789
+ onWorkloadDateChange={handleWorkloadDateChange}
790
+ selectedService={watch('selectedService')}
791
+ />
792
+ </ResponsiveWrapper>
784
793
  </FormGroup>
794
+ )}
785
795
 
786
- {getValues('selectedService') && (
787
- <FormGroup className={styles.formGroup} legendText="">
788
- <ResponsiveWrapper>
789
- <Workload
790
- appointmentDate={watch('appointmentDateTime').startDate}
791
- onWorkloadDateChange={handleWorkloadDateChange}
792
- selectedService={watch('selectedService')}
793
- />
794
- </ResponsiveWrapper>
795
- </FormGroup>
796
- )}
797
-
798
- {context !== 'creating' ? (
799
- <FormGroup className={styles.formGroup} legendText={t('appointmentStatus', 'Appointment Status')}>
800
- <ResponsiveWrapper>
801
- <Controller
802
- name="appointmentStatus"
803
- control={control}
804
- render={({ field: { onBlur, onChange, value, ref } }) => (
805
- <Select
806
- id="appointmentStatus"
807
- invalid={!!errors?.appointmentStatus}
808
- invalidText={errors?.appointmentStatus?.message}
809
- labelText={t('selectAppointmentStatus', 'Select status')}
810
- onBlur={onBlur}
811
- onChange={onChange}
812
- ref={ref}
813
- value={value}>
814
- <SelectItem text={t('selectAppointmentStatus', 'Select status')} value="" />
815
- {appointmentStatuses?.length > 0 &&
816
- appointmentStatuses.map((appointmentStatus, index) => (
817
- <SelectItem key={index} text={appointmentStatus} value={appointmentStatus}>
818
- {appointmentStatus}
819
- </SelectItem>
820
- ))}
821
- </Select>
822
- )}
823
- />
824
- </ResponsiveWrapper>
825
- </FormGroup>
826
- ) : null}
827
-
828
- <FormGroup className={styles.formGroup} legendText={t('provider', 'Provider')}>
796
+ {context !== 'creating' ? (
797
+ <FormGroup className={styles.formGroup} legendText={t('appointmentStatus', 'Appointment Status')}>
829
798
  <ResponsiveWrapper>
830
799
  <Controller
831
- name="provider"
800
+ name="appointmentStatus"
832
801
  control={control}
833
- render={({ field: { onChange, value, onBlur, ref } }) => (
802
+ render={({ field: { onBlur, onChange, value, ref } }) => (
834
803
  <Select
835
- id="provider"
836
- invalidText="Required"
837
- labelText={t('selectProvider', 'Select a provider')}
838
- onChange={onChange}
804
+ id="appointmentStatus"
805
+ invalid={!!errors?.appointmentStatus}
806
+ invalidText={errors?.appointmentStatus?.message}
807
+ labelText={t('selectAppointmentStatus', 'Select status')}
839
808
  onBlur={onBlur}
809
+ onChange={onChange}
840
810
  ref={ref}
841
811
  value={value}>
842
- <SelectItem text={t('chooseProvider', 'Choose a provider')} value="" />
843
- {providers?.providers?.length > 0 &&
844
- providers?.providers?.map((provider) => (
845
- <SelectItem key={provider.uuid} text={provider.display} value={provider.uuid}>
846
- {provider.display}
812
+ <SelectItem text={t('selectAppointmentStatus', 'Select status')} value="" />
813
+ {appointmentStatuses?.length > 0 &&
814
+ appointmentStatuses.map((appointmentStatus, index) => (
815
+ <SelectItem key={index} text={appointmentStatus} value={appointmentStatus}>
816
+ {appointmentStatus}
847
817
  </SelectItem>
848
818
  ))}
849
819
  </Select>
@@ -851,69 +821,93 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
851
821
  />
852
822
  </ResponsiveWrapper>
853
823
  </FormGroup>
854
-
855
- <FormGroup
856
- className={styles.formGroup}
857
- legendText={t('dateAppointmentScheduled', 'Date appointment scheduled')}>
858
- <ResponsiveWrapper>
859
- <Controller
860
- name="dateAppointmentScheduled"
861
- control={control}
862
- render={({ field, fieldState }) => (
863
- <div style={{ width: '100%' }}>
864
- <OpenmrsDatePicker
865
- data-testid="dateAppointmentScheduledPickerInput"
866
- id="dateAppointmentScheduledPickerInput"
867
- invalid={!!fieldState?.error?.message}
868
- invalidText={fieldState?.error?.message}
869
- labelText={t('dateAppointmentIssued', 'Date appointment issued')}
870
- maxDate={new Date()}
871
- onBlur={field.onBlur}
872
- onChange={field.onChange}
873
- style={{ width: '100%' }}
874
- value={field.value}
875
- />
876
- </div>
877
- )}
878
- />
879
- </ResponsiveWrapper>
880
- </FormGroup>
881
-
882
- <FormGroup className={styles.formGroup} legendText={t('note', 'Note')}>
883
- <ResponsiveWrapper>
884
- <Controller
885
- name="appointmentNote"
886
- control={control}
887
- render={({ field: { onChange, onBlur, value, ref } }) => (
888
- <TextArea
889
- enableCounter
890
- id="appointmentNote"
891
- value={value}
892
- labelText={t('appointmentNoteLabel', 'Write an additional note')}
893
- placeholder={t('appointmentNotePlaceholder', 'Write any additional points here')}
894
- maxCount={255}
895
- onChange={onChange}
896
- onBlur={onBlur}
897
- ref={ref}
824
+ ) : null}
825
+
826
+ <FormGroup className={styles.formGroup} legendText={t('provider', 'Provider')}>
827
+ <ResponsiveWrapper>
828
+ <Controller
829
+ name="provider"
830
+ control={control}
831
+ render={({ field: { onChange, value, onBlur, ref } }) => (
832
+ <Select
833
+ id="provider"
834
+ invalidText="Required"
835
+ labelText={t('selectProvider', 'Select a provider')}
836
+ onChange={onChange}
837
+ onBlur={onBlur}
838
+ ref={ref}
839
+ value={value}>
840
+ <SelectItem text={t('chooseProvider', 'Choose a provider')} value="" />
841
+ {providers?.providers?.length > 0 &&
842
+ providers?.providers?.map((provider) => (
843
+ <SelectItem key={provider.uuid} text={provider.display} value={provider.uuid}>
844
+ {provider.display}
845
+ </SelectItem>
846
+ ))}
847
+ </Select>
848
+ )}
849
+ />
850
+ </ResponsiveWrapper>
851
+ </FormGroup>
852
+
853
+ <FormGroup
854
+ className={styles.formGroup}
855
+ legendText={t('dateAppointmentScheduled', 'Date appointment scheduled')}>
856
+ <ResponsiveWrapper>
857
+ <Controller
858
+ name="dateAppointmentScheduled"
859
+ control={control}
860
+ render={({ field, fieldState }) => (
861
+ <div style={{ width: '100%' }}>
862
+ <OpenmrsDatePicker
863
+ data-testid="dateAppointmentScheduledPickerInput"
864
+ id="dateAppointmentScheduledPickerInput"
865
+ invalid={!!fieldState?.error?.message}
866
+ invalidText={fieldState?.error?.message}
867
+ labelText={t('dateAppointmentIssued', 'Date appointment issued')}
868
+ maxDate={new Date()}
869
+ onBlur={field.onBlur}
870
+ onChange={field.onChange}
871
+ style={{ width: '100%' }}
872
+ value={field.value}
898
873
  />
899
- )}
900
- />
901
- </ResponsiveWrapper>
902
- </FormGroup>
903
- </Stack>
904
- <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
905
- <Button
906
- className={styles.button}
907
- onClick={() => closeWorkspace({ discardUnsavedChanges: false })}
908
- kind="secondary">
909
- {t('discard', 'Discard')}
910
- </Button>
911
- <Button className={styles.button} disabled={isSubmitting} type="submit">
912
- {t('saveAndClose', 'Save and close')}
913
- </Button>
914
- </ButtonSet>
915
- </Form>
916
- </Workspace2>
874
+ </div>
875
+ )}
876
+ />
877
+ </ResponsiveWrapper>
878
+ </FormGroup>
879
+
880
+ <FormGroup className={styles.formGroup} legendText={t('note', 'Note')}>
881
+ <ResponsiveWrapper>
882
+ <Controller
883
+ name="appointmentNote"
884
+ control={control}
885
+ render={({ field: { onChange, onBlur, value, ref } }) => (
886
+ <TextArea
887
+ enableCounter
888
+ id="appointmentNote"
889
+ value={value}
890
+ labelText={t('appointmentNoteLabel', 'Write an additional note')}
891
+ placeholder={t('appointmentNotePlaceholder', 'Write any additional points here')}
892
+ maxCount={255}
893
+ onChange={onChange}
894
+ onBlur={onBlur}
895
+ ref={ref}
896
+ />
897
+ )}
898
+ />
899
+ </ResponsiveWrapper>
900
+ </FormGroup>
901
+ </Stack>
902
+ <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
903
+ <Button className={styles.button} onClick={closeWorkspace} kind="secondary">
904
+ {t('discard', 'Discard')}
905
+ </Button>
906
+ <Button className={styles.button} disabled={isSubmitting} type="submit">
907
+ {t('saveAndClose', 'Save and close')}
908
+ </Button>
909
+ </ButtonSet>
910
+ </Form>
917
911
  );
918
912
  };
919
913
 
@@ -943,7 +937,7 @@ function TimeAndDuration({ t, control, errors }: TimeAndDurationProps) {
943
937
  invalid={!!errors?.startTime}
944
938
  invalidText={errors?.startTime?.message}
945
939
  labelText={t('time', 'Time')}
946
- onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
940
+ onChange={(event) => {
947
941
  onChange(event.target.value);
948
942
  }}
949
943
  style={{ marginLeft: '0.125rem', flex: 'none' }}
@@ -954,9 +948,7 @@ function TimeAndDuration({ t, control, errors }: TimeAndDurationProps) {
954
948
  render={({ field: { value, onChange } }) => (
955
949
  <TimePickerSelect
956
950
  id="time-picker-select-1"
957
- onChange={(event: React.ChangeEvent<HTMLSelectElement>) =>
958
- onChange(event.target.value as 'AM' | 'PM')
959
- }
951
+ onChange={(event) => onChange(event.target.value as 'AM' | 'PM')}
960
952
  value={value}
961
953
  aria-label={t('time', 'Time')}>
962
954
  <SelectItem value="AM" text="AM" />