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

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 (64) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/dist/1431.js +1 -1
  3. package/dist/1431.js.map +1 -1
  4. package/dist/1559.js +1 -1
  5. package/dist/1559.js.map +1 -1
  6. package/dist/2265.js +1 -0
  7. package/dist/2265.js.map +1 -0
  8. package/dist/{5160.js → 4036.js} +1 -1
  9. package/dist/{5160.js.map → 4036.js.map} +1 -1
  10. package/dist/449.js +1 -1
  11. package/dist/449.js.map +1 -1
  12. package/dist/4515.js +1 -0
  13. package/dist/4515.js.map +1 -0
  14. package/dist/4745.js +1 -1
  15. package/dist/4745.js.map +1 -1
  16. package/dist/4889.js +1 -1
  17. package/dist/4889.js.map +1 -1
  18. package/dist/525.js +1 -1
  19. package/dist/525.js.map +1 -1
  20. package/dist/5666.js +1 -1
  21. package/dist/5666.js.map +1 -1
  22. package/dist/5755.js +1 -1
  23. package/dist/5755.js.map +1 -1
  24. package/dist/592.js +1 -1
  25. package/dist/592.js.map +1 -1
  26. package/dist/6467.js +1 -1
  27. package/dist/6467.js.map +1 -1
  28. package/dist/6886.js +1 -1
  29. package/dist/6886.js.map +1 -1
  30. package/dist/{7565.js → 7294.js} +1 -1
  31. package/dist/7294.js.map +1 -0
  32. package/dist/9712.js +1 -1
  33. package/dist/9712.js.map +1 -1
  34. package/dist/main.js +1 -1
  35. package/dist/main.js.map +1 -1
  36. package/dist/openmrs-esm-appointments-app.js.buildmanifest.json +121 -120
  37. package/dist/routes.json +1 -1
  38. package/package.json +1 -1
  39. package/src/appointments/common-components/appointments-table.component.tsx +3 -5
  40. package/src/constants.ts +1 -0
  41. package/src/form/appointments-form.resource.ts +1 -0
  42. package/src/form/appointments-form.test.tsx +136 -117
  43. package/src/form/appointments-form.workspace.tsx +43 -50
  44. package/src/form/exported-appointments-form.workspace.tsx +24 -0
  45. package/src/helpers/functions.ts +72 -25
  46. package/src/index.ts +5 -3
  47. package/src/metrics/metrics-cards/highest-volume-service.extension.tsx +1 -1
  48. package/src/metrics/metrics-cards/metrics-card.component.tsx +1 -1
  49. package/src/metrics/metrics-header.component.tsx +9 -24
  50. package/src/patient-appointments/patient-appointments-action-menu.component.tsx +1 -5
  51. package/src/patient-appointments/patient-appointments-detailed-summary.extension.tsx +176 -15
  52. package/src/patient-appointments/{patient-appointments-base.test.tsx → patient-appointments-detailed-summary.test.tsx} +14 -22
  53. package/src/patient-appointments/patient-appointments-overview.component.tsx +15 -18
  54. package/src/routes.json +18 -14
  55. package/dist/3092.js +0 -1
  56. package/dist/3092.js.map +0 -1
  57. package/dist/7026.js +0 -1
  58. package/dist/7026.js.map +0 -1
  59. package/dist/7565.js.map +0 -1
  60. package/src/hooks/patient-appointment-context.ts +0 -18
  61. package/src/patient-appointments/patient-appointments-base.component.tsx +0 -178
  62. package/src/patient-search/patient-search.component.tsx +0 -33
  63. package/src/patient-search/patient-search.scss +0 -24
  64. /package/src/patient-appointments/{patient-appointments-base.scss → patient-appointments-detailed-summary.scss} +0 -0
@@ -34,8 +34,8 @@ import {
34
34
  usePatient,
35
35
  useSession,
36
36
  Workspace2,
37
- type FetchResponse,
38
37
  type Workspace2DefinitionProps,
38
+ type FetchResponse,
39
39
  } from '@openmrs/esm-framework';
40
40
  import { z } from 'zod';
41
41
  import { type ConfigObject } from '../config-schema';
@@ -53,11 +53,10 @@ import { useProviders } from '../hooks/useProviders';
53
53
  import Workload from '../workload/workload.component';
54
54
  import styles from './appointments-form.scss';
55
55
 
56
- export interface AppointmentsFormProps {
56
+ interface AppointmentsFormProps {
57
57
  appointment?: Appointment;
58
58
  recurringPattern?: RecurringPattern;
59
- patientUuid?: string;
60
- context: 'creating' | 'editing';
59
+ patientUuid: string;
61
60
  }
62
61
 
63
62
  const time12HourFormatRegexPattern = '^(1[0-2]|0?[1-9]):[0-5][0-9]$';
@@ -65,8 +64,11 @@ const time12HourFormatRegex = /^(1[0-2]|0?[1-9]):[0-5][0-9]$/;
65
64
 
66
65
  const isValidTime = (timeStr: string) => time12HourFormatRegex.test(timeStr);
67
66
 
67
+ /**
68
+ * Workspace used to create or edit an appointment within the appointments app
69
+ */
68
70
  const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps>> = ({
69
- workspaceProps: { appointment, recurringPattern, patientUuid, context },
71
+ workspaceProps: { appointment, recurringPattern, patientUuid },
70
72
  closeWorkspace,
71
73
  }) => {
72
74
  const { patient } = usePatient(patientUuid);
@@ -262,7 +264,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
262
264
 
263
265
  useEffect(() => setValue('formIsRecurringAppointment', isRecurringAppointment), [isRecurringAppointment, setValue]);
264
266
 
265
- // Retrive ref callback for appointmentDateTime (startDate & recurringPatternEndDate)
267
+ // Retrieve ref callback for appointmentDateTime (startDate & recurringPatternEndDate)
266
268
  const {
267
269
  field: { ref: startDateRef },
268
270
  } = useController({ name: 'appointmentDateTime.startDate', control });
@@ -281,7 +283,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
281
283
  useEffect(() => {
282
284
  if (isSuccessful) {
283
285
  reset();
284
- closeWorkspace({ closeWindow: true, discardUnsavedChanges: true });
286
+ closeWorkspace({ discardUnsavedChanges: true, closeWindow: true });
285
287
  }
286
288
  }, [isSuccessful, reset, closeWorkspace]);
287
289
 
@@ -290,7 +292,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
290
292
  setValue('appointmentDateTime', { ...appointmentDate, startDate: date });
291
293
  };
292
294
 
293
- const handleSelectChange = (e: { selectedItems: Array<{ id: number; label: string }> }) => {
295
+ const handleSelectChange = (e) => {
294
296
  setValue(
295
297
  'selectedDaysOfWeekText',
296
298
  (() => {
@@ -307,8 +309,8 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
307
309
  );
308
310
  setValue(
309
311
  'recurringPatternDaysOfWeek',
310
- e.selectedItems.map((s: { id: number }) => {
311
- return String(s.id);
312
+ e.selectedItems.map((s) => {
313
+ return s.id;
312
314
  }),
313
315
  );
314
316
  };
@@ -326,23 +328,21 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
326
328
  }
327
329
  })();
328
330
 
331
+ const isEditing = Boolean(appointment);
332
+
329
333
  // Same for creating and editing
330
334
  const handleSaveAppointment = async (data: AppointmentFormData) => {
331
335
  setIsSubmitting(true);
332
336
  // Construct appointment payload
333
337
  const appointmentPayload = constructAppointmentPayload(data);
334
338
 
335
- // check if Duplicate Response Occurs
339
+ // Check if a duplicate response occurs
336
340
  const response: FetchResponse = await checkAppointmentConflict(appointmentPayload);
337
341
  let errorMessage = t('appointmentConflict', 'Appointment conflict');
338
342
  if (response?.data?.hasOwnProperty('SERVICE_UNAVAILABLE')) {
339
343
  errorMessage = t('serviceUnavailable', 'Appointment time is outside of service hours');
340
344
  } else if (response?.data?.hasOwnProperty('PATIENT_DOUBLE_BOOKING')) {
341
- if (context !== 'editing') {
342
- errorMessage = t('patientDoubleBooking', 'Patient already booked for an appointment at this time');
343
- } else {
344
- errorMessage = null;
345
- }
345
+ errorMessage = t('patientDoubleBooking', 'Patient already booked for an appointment at this time');
346
346
  }
347
347
 
348
348
  if (response.status === 200 && errorMessage) {
@@ -376,19 +376,17 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
376
376
  isLowContrast: true,
377
377
  kind: 'success',
378
378
  subtitle: t('appointmentNowVisible', 'It is now visible on the Appointments page'),
379
- title:
380
- context === 'editing'
381
- ? t('appointmentEdited', 'Appointment edited')
382
- : t('appointmentScheduled', 'Appointment scheduled'),
379
+ title: isEditing
380
+ ? t('appointmentEdited', 'Appointment edited')
381
+ : t('appointmentScheduled', 'Appointment scheduled'),
383
382
  });
384
383
  }
385
384
  if (status === 204) {
386
385
  setIsSubmitting(false);
387
386
  showSnackbar({
388
- title:
389
- context === 'editing'
390
- ? t('appointmentEditError', 'Error editing appointment')
391
- : t('appointmentFormError', 'Error scheduling appointment'),
387
+ title: isEditing
388
+ ? t('appointmentEditError', 'Error editing appointment')
389
+ : t('appointmentFormError', 'Error scheduling appointment'),
392
390
  kind: 'error',
393
391
  isLowContrast: false,
394
392
  subtitle: t('noContent', 'No Content'),
@@ -398,10 +396,9 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
398
396
  (error) => {
399
397
  setIsSubmitting(false);
400
398
  showSnackbar({
401
- title:
402
- context === 'editing'
403
- ? t('appointmentEditError', 'Error editing appointment')
404
- : t('appointmentFormError', 'Error scheduling appointment'),
399
+ title: isEditing
400
+ ? t('appointmentEditError', 'Error editing appointment')
401
+ : t('appointmentFormError', 'Error scheduling appointment'),
405
402
  kind: 'error',
406
403
  isLowContrast: false,
407
404
  subtitle: error?.message,
@@ -445,7 +442,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
445
442
  providers: [{ uuid: provider }],
446
443
  patientUuid: patientUuid,
447
444
  comments: appointmentNote,
448
- uuid: context === 'editing' ? appointment?.uuid : undefined,
445
+ uuid: isEditing ? appointment.uuid : undefined,
449
446
  dateAppointmentScheduled: dayjs(dateAppointmentScheduled).format(),
450
447
  };
451
448
  };
@@ -469,19 +466,18 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
469
466
  };
470
467
  };
471
468
 
472
- if (isLoading)
469
+ if (isLoading) {
473
470
  return (
474
471
  <InlineLoading className={styles.loader} description={`${t('loading', 'Loading')} ...`} role="progressbar" />
475
472
  );
473
+ }
474
+
475
+ const title = isEditing
476
+ ? t('editAppointment', 'Edit appointment')
477
+ : t('createNewAppointment', 'Create new appointment');
476
478
 
477
479
  return (
478
- <Workspace2
479
- title={
480
- context === 'editing'
481
- ? t('editAppointment', 'Edit appointment')
482
- : t('createNewAppointment', 'Create new appointment')
483
- }
484
- hasUnsavedChanges={isDirty}>
480
+ <Workspace2 title={title} hasUnsavedChanges={isDirty}>
485
481
  <Form onSubmit={handleSubmit(handleSaveAppointment)}>
486
482
  {patient && (
487
483
  <ExtensionSlot
@@ -534,12 +530,12 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
534
530
  labelText={t('selectService', 'Select a service')}
535
531
  onBlur={onBlur}
536
532
  onChange={(event: React.ChangeEvent<HTMLSelectElement>) => {
537
- if (context === 'creating') {
533
+ if (!isEditing) {
538
534
  setValue(
539
535
  'duration',
540
536
  services?.find((service) => service.name === event.target.value)?.durationMins,
541
537
  );
542
- } else if (context === 'editing') {
538
+ } else {
543
539
  const previousServiceDuration = services?.find(
544
540
  (service) => service.name === getValues('selectedService'),
545
541
  )?.durationMins;
@@ -677,7 +673,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
677
673
  invalidText={t('invalidNumber', 'Number is not valid')}
678
674
  value={value}
679
675
  onBlur={onBlur}
680
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
676
+ onChange={(e) => {
681
677
  onChange(Number(e.target.value));
682
678
  }}
683
679
  />
@@ -693,7 +689,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
693
689
  <RadioButtonGroup
694
690
  legendText={t('period', 'Period')}
695
691
  name="radio-button-group"
696
- onChange={(type: string) => onChange(type)}
692
+ onChange={(type) => onChange(type)}
697
693
  valueSelected={value}>
698
694
  <RadioButton labelText={t('day', 'Day')} value="DAY" id="radioDay" />
699
695
  <RadioButton labelText={t('week', 'Week')} value="WEEK" id="radioWeek" />
@@ -716,15 +712,15 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
716
712
  getValues('recurringPatternDaysOfWeek').includes(i.id),
717
713
  )}
718
714
  items={weekDays}
719
- itemToString={(item: any) => (item ? t(item.labelCode, item.label) : '')}
715
+ itemToString={(item) => (item ? t(item.labelCode, item.label) : '')}
720
716
  label={getValues('selectedDaysOfWeekText')}
721
- onChange={(e: any) => {
717
+ onChange={(e) => {
722
718
  onChange(e);
723
719
  handleSelectChange(e);
724
720
  }}
725
721
  selectionFeedback="top-after-reopen"
726
- sortItems={(items: any[]) => {
727
- return items.sort((a: any, b: any) => a.order - b.order);
722
+ sortItems={(items) => {
723
+ return items.sort((a, b) => a.order > b.order);
728
724
  }}
729
725
  />
730
726
  )}
@@ -795,7 +791,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
795
791
  </FormGroup>
796
792
  )}
797
793
 
798
- {context !== 'creating' ? (
794
+ {isEditing ? (
799
795
  <FormGroup className={styles.formGroup} legendText={t('appointmentStatus', 'Appointment Status')}>
800
796
  <ResponsiveWrapper>
801
797
  <Controller
@@ -902,10 +898,7 @@ const AppointmentsForm: React.FC<Workspace2DefinitionProps<AppointmentsFormProps
902
898
  </FormGroup>
903
899
  </Stack>
904
900
  <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
905
- <Button
906
- className={styles.button}
907
- onClick={() => closeWorkspace({ discardUnsavedChanges: false })}
908
- kind="secondary">
901
+ <Button className={styles.button} onClick={closeWorkspace} kind="secondary">
909
902
  {t('discard', 'Discard')}
910
903
  </Button>
911
904
  <Button className={styles.button} disabled={isSubmitting} type="submit">
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { type Workspace2DefinitionProps } from '@openmrs/esm-framework';
3
+ import type { Appointment, RecurringPattern } from '../types';
4
+ import AppointmentsForm from './appointments-form.workspace';
5
+
6
+ interface ExportedAppointmentsFormProps {
7
+ appointment?: Appointment;
8
+ recurringPattern?: RecurringPattern;
9
+ }
10
+
11
+ interface ExportedAppointmentsFormGroupProps {
12
+ patientUuid: string;
13
+ }
14
+
15
+ /**
16
+ * Workspace used to create or edit an appointment in the patient chart (or app with compatible workspaceGroup)
17
+ */
18
+ const ExportedAppointmentsForm: React.FC<
19
+ Workspace2DefinitionProps<ExportedAppointmentsFormProps, {}, ExportedAppointmentsFormGroupProps>
20
+ > = ({ workspaceProps: { appointment, recurringPattern }, groupProps: { patientUuid }, ...rest }) => {
21
+ return <AppointmentsForm workspaceProps={{ appointment, recurringPattern, patientUuid }} groupProps={{}} {...rest} />;
22
+ };
23
+
24
+ export default ExportedAppointmentsForm;
@@ -1,41 +1,65 @@
1
1
  import dayjs, { type Dayjs } from 'dayjs';
2
- import { formatDate, parseDate } from '@openmrs/esm-framework';
3
- import { type AppointmentSummary, type Appointment } from '../types';
4
- import { configSchema } from '../config-schema';
2
+ import { type TFunction } from 'i18next';
3
+ import { launchWorkspace2, type Workspace2DefinitionProps } from '@openmrs/esm-framework';
4
+ import { type AppointmentSummary, type AppointmentCountMap } from '../types';
5
+ import { appointmentsFormWorkspace } from '../constants';
5
6
 
6
- export const getHighestAppointmentServiceLoad = (appointmentSummary: Array<any> = []) => {
7
- const groupedAppointments = appointmentSummary?.map(({ countMap, serviceName }) => ({
7
+ interface FlattenedAppointmentSummary {
8
+ serviceName: string;
9
+ countMap: AppointmentCountMap[];
10
+ }
11
+
12
+ interface ServiceLoadSummary {
13
+ serviceName: string;
14
+ count: number;
15
+ }
16
+
17
+ export const getHighestAppointmentServiceLoad = (
18
+ appointmentSummary: FlattenedAppointmentSummary[] = [],
19
+ ): ServiceLoadSummary | undefined => {
20
+ const groupedAppointments = appointmentSummary.map(({ countMap, serviceName }) => ({
8
21
  serviceName: serviceName,
9
- count: countMap.reduce((cummulator, currentValue) => cummulator + currentValue.allAppointmentsCount, 0),
22
+ count: countMap.reduce((accumulator, currentValue) => accumulator + currentValue.allAppointmentsCount, 0),
10
23
  }));
24
+ if (groupedAppointments.length === 0) {
25
+ return undefined;
26
+ }
11
27
  return groupedAppointments.find((summary) => summary.count === Math.max(...groupedAppointments.map((x) => x.count)));
12
28
  };
13
29
 
14
- export const flattenAppointmentSummary = (appointmentToTransfrom: Array<any>) =>
15
- appointmentToTransfrom.flatMap((el: any) => ({
30
+ export const flattenAppointmentSummary = (
31
+ appointmentToTransform: AppointmentSummary[],
32
+ ): FlattenedAppointmentSummary[] =>
33
+ appointmentToTransform.flatMap((el) => ({
16
34
  serviceName: el.appointmentService.name,
17
- countMap: Object.entries(el.appointmentCountMap).flatMap((el) => el[1]),
35
+ countMap: Object.entries(el.appointmentCountMap).flatMap(([, countMap]) => countMap),
18
36
  }));
19
37
 
20
38
  export const getServiceCountByAppointmentType = (
21
- appointmentSummary: Array<AppointmentSummary>,
22
- appointmentType: string,
23
- ) => {
39
+ appointmentSummary: AppointmentSummary[],
40
+ appointmentType: 'allAppointmentsCount' | 'missedAppointmentsCount',
41
+ ): number => {
24
42
  return appointmentSummary
25
- .map((el) => Object.entries(el.appointmentCountMap).flatMap((el) => el[1][appointmentType]))
43
+ .map((el) =>
44
+ Object.values(el.appointmentCountMap).map((countMap) => {
45
+ const value = countMap[appointmentType];
46
+ if (typeof value === 'number') {
47
+ return value;
48
+ }
49
+ return 0;
50
+ }),
51
+ )
26
52
  .flat(1)
27
53
  .reduce((count, val) => count + val, 0);
28
54
  };
29
55
 
30
- export const formatAMPM = (date) => {
31
- let hours = date.getHours();
32
- let minutes = date.getMinutes();
33
- let ampm = hours >= 12 ? 'PM' : 'AM';
34
- hours = hours % 12;
35
- hours = hours ? hours : 12; // the hour '0' should be '12'
36
- minutes = minutes < 10 ? '0' + minutes : minutes;
37
- const strTime = hours + ':' + minutes + ' ' + ampm;
38
- return strTime;
56
+ export const formatAMPM = (date: Date): string => {
57
+ const hours24 = date.getHours();
58
+ const minutes = date.getMinutes();
59
+ const ampm = hours24 >= 12 ? 'PM' : 'AM';
60
+ const hours12 = hours24 % 12 || 12; // Convert 0 to 12
61
+ const minutesStr = minutes < 10 ? `0${minutes}` : minutes.toString();
62
+ return `${hours12}:${minutesStr} ${ampm}`;
39
63
  };
40
64
 
41
65
  export const isSameMonth = (cellDate: Dayjs, currentDate: Dayjs) => {
@@ -51,7 +75,7 @@ export const monthDays = (currentDate: Dayjs) => {
51
75
  let days: Dayjs[] = [];
52
76
 
53
77
  for (let i = lastMonth.daysInMonth() - monthStart.day() + 1; i <= lastMonth.daysInMonth(); i++) {
54
- days.push(dayjs().month(lastMonth.month()).date(i));
78
+ days.push(lastMonth.date(i));
55
79
  }
56
80
 
57
81
  for (let i = 1; i <= monthDays; i++) {
@@ -61,12 +85,12 @@ export const monthDays = (currentDate: Dayjs) => {
61
85
  const dayLen = days.length > 30 ? 7 : 14;
62
86
 
63
87
  for (let i = 1; i < dayLen - monthEnd.day(); i++) {
64
- days.push(dayjs().month(nextMonth.month()).date(i));
88
+ days.push(nextMonth.date(i));
65
89
  }
66
90
  return days;
67
91
  };
68
92
 
69
- export const getGender = (gender, t) => {
93
+ export const getGender = (gender: string | undefined, t: TFunction<'translation', undefined>): string => {
70
94
  switch (gender) {
71
95
  case 'M':
72
96
  return t('male', 'Male');
@@ -80,3 +104,26 @@ export const getGender = (gender, t) => {
80
104
  return gender;
81
105
  }
82
106
  };
107
+
108
+ export const launchCreateAppointmentForm = (t: TFunction<'translation', undefined>) => {
109
+ launchWorkspace2(
110
+ 'appointments-patient-search-workspace',
111
+ {
112
+ initialQuery: '',
113
+ workspaceTitle: t('createNewAppointment', 'Create new appointment'),
114
+ onPatientSelected(
115
+ patientUuid: string,
116
+ patient: fhir.Patient,
117
+ launchChildWorkspace: Workspace2DefinitionProps['launchChildWorkspace'],
118
+ closeWorkspace: Workspace2DefinitionProps['closeWorkspace'],
119
+ ) {
120
+ launchChildWorkspace(appointmentsFormWorkspace, {
121
+ patientUuid: patient.id,
122
+ });
123
+ },
124
+ },
125
+ {
126
+ startVisitWorkspaceName: 'appointments-patient-search-start-visit-workspace',
127
+ },
128
+ );
129
+ };
package/src/index.ts CHANGED
@@ -92,8 +92,6 @@ export const metricsCardProvidersBooked = getAsyncLifecycle(
92
92
  options,
93
93
  );
94
94
 
95
- export const searchPatient = getAsyncLifecycle(() => import('./patient-search/patient-search.component'), options);
96
-
97
95
  // t('Appointments', 'Appointments')
98
96
  export const patientAppointmentsSummaryDashboardLink = getAsyncLifecycle(async () => {
99
97
  const commonLib = await import('@openmrs/esm-patient-common-lib');
@@ -120,9 +118,13 @@ export const cancelAppointmentModal = getAsyncLifecycle(
120
118
  options,
121
119
  );
122
120
 
123
- // t('createNewAppointment', 'Create new appointment')
124
121
  export const appointmentsFormWorkspace = getAsyncLifecycle(() => import('./form/appointments-form.workspace'), options);
125
122
 
123
+ export const exportedAppointmentsFormWorkspace = getAsyncLifecycle(
124
+ () => import('./form/exported-appointments-form.workspace'),
125
+ options,
126
+ );
127
+
126
128
  export const endAppointmentModal = getAsyncLifecycle(
127
129
  () => import('./appointments/common-components/end-appointment.modal'),
128
130
  options,
@@ -19,7 +19,7 @@ export default function HighestVolumeServiceExtension() {
19
19
  return (
20
20
  <MetricsCard
21
21
  headerLabel={t('highestServiceVolume', 'Highest volume service: {{time}}', { time: formattedStartDate })}
22
- label={highestServiceLoad?.count !== 0 ? t(highestServiceLoad?.serviceName) : t('serviceName', 'Service name')}
22
+ label={highestServiceLoad ? t(highestServiceLoad.serviceName) : t('serviceName', 'Service name')}
23
23
  value={highestServiceLoad?.count ?? '--'}
24
24
  />
25
25
  );
@@ -9,7 +9,7 @@ dayjs.extend(isSameOrBefore);
9
9
 
10
10
  interface MetricsCardProps {
11
11
  label: string;
12
- value: number;
12
+ value: number | string;
13
13
  headerLabel: string;
14
14
  count?: { pendingAppointments: Array<any>; arrivedAppointments: Array<any> };
15
15
  }
@@ -4,10 +4,11 @@ import isToday from 'dayjs/plugin/isToday';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Calendar, Hospital } from '@carbon/react/icons';
6
6
  import { Button } from '@carbon/react';
7
- import { ExtensionSlot, isDesktop, launchWorkspace2, navigate, useLayoutType } from '@openmrs/esm-framework';
7
+ import { isDesktop, navigate, useLayoutType } from '@openmrs/esm-framework';
8
8
  import { spaHomePage } from '../constants';
9
9
  import { useAppointmentsStore } from '../store';
10
10
  import styles from './metrics-header.scss';
11
+ import { launchCreateAppointmentForm } from '../helpers';
11
12
 
12
13
  dayjs.extend(isToday);
13
14
 
@@ -17,16 +18,6 @@ const MetricsHeader: React.FC = () => {
17
18
  const layout = useLayoutType();
18
19
  const responsiveSize = isDesktop(layout) ? 'sm' : 'md';
19
20
 
20
- const launchCreateAppointmentForm = (patientUuid) => {
21
- const props = {
22
- patientUuid: patientUuid,
23
- context: 'creating',
24
- mutate: () => {}, // TODO get this to mutate properly
25
- };
26
-
27
- launchWorkspace2('appointments-form-workspace', { ...props });
28
- };
29
-
30
21
  return (
31
22
  <div className={styles.metricsContainer}>
32
23
  <div className={styles.metricsContent}>
@@ -39,19 +30,13 @@ const MetricsHeader: React.FC = () => {
39
30
  }>
40
31
  {t('appointmentsCalendar', 'Appointments calendar')}
41
32
  </Button>
42
- <ExtensionSlot
43
- name="patient-search-button-slot"
44
- state={{
45
- selectPatientAction: launchCreateAppointmentForm,
46
- buttonText: t('createNewAppointment', 'Create new appointment'),
47
- overlayHeader: t('createNewAppointment', 'Create new appointment'),
48
- buttonProps: {
49
- kind: 'primary',
50
- renderIcon: (props) => <Hospital size={32} {...props} />,
51
- size: responsiveSize,
52
- },
53
- }}
54
- />
33
+ <Button
34
+ kind="primary"
35
+ renderIcon={(props) => <Hospital size={32} {...props} />}
36
+ size={responsiveSize}
37
+ onClick={() => launchCreateAppointmentForm(t)}>
38
+ {t('createNewAppointment', 'Create new appointment')}
39
+ </Button>
55
40
  </div>
56
41
  </div>
57
42
  );
@@ -15,11 +15,7 @@ export const PatientAppointmentsActionMenu = ({ appointment, patientUuid }: appo
15
15
  const isTablet = useLayoutType() === 'tablet';
16
16
 
17
17
  const handleLaunchEditAppointmentForm = () => {
18
- launchWorkspace2('appointments-form-workspace', {
19
- appointment,
20
- context: 'editing',
21
- patientUuid,
22
- });
18
+ launchWorkspace2('appointments-form-workspace', { appointment, patientUuid });
23
19
  };
24
20
 
25
21
  const handleLaunchCancelAppointmentModal = () => {