@kenyaemr/esm-appointments-app 8.0.1-pre.99 → 8.0.2

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 (104) hide show
  1. package/.turbo/turbo-build.log +25 -26
  2. package/dist/130.js +1 -1
  3. package/dist/130.js.LICENSE.txt +2 -0
  4. package/dist/130.js.map +1 -1
  5. package/dist/171.js +1 -0
  6. package/dist/171.js.map +1 -0
  7. package/dist/198.js +2 -0
  8. package/dist/198.js.map +1 -0
  9. package/dist/2.js +1 -0
  10. package/dist/2.js.map +1 -0
  11. package/dist/269.js +1 -0
  12. package/dist/269.js.map +1 -0
  13. package/dist/271.js +1 -1
  14. package/dist/319.js +1 -1
  15. package/dist/325.js +1 -0
  16. package/dist/325.js.map +1 -0
  17. package/dist/372.js +2 -0
  18. package/dist/372.js.map +1 -0
  19. package/dist/440.js +2 -0
  20. package/dist/440.js.LICENSE.txt +15 -0
  21. package/dist/440.js.map +1 -0
  22. package/dist/460.js +1 -1
  23. package/dist/529.js +1 -1
  24. package/dist/529.js.map +1 -1
  25. package/dist/574.js +1 -1
  26. package/dist/581.js +1 -1
  27. package/dist/644.js +1 -1
  28. package/dist/711.js +1 -0
  29. package/dist/711.js.map +1 -0
  30. package/dist/757.js +1 -1
  31. package/dist/787.js +1 -0
  32. package/dist/787.js.map +1 -0
  33. package/dist/788.js +1 -1
  34. package/dist/807.js +1 -1
  35. package/dist/833.js +1 -1
  36. package/dist/kenyaemr-esm-appointments-app.js +1 -1
  37. package/dist/kenyaemr-esm-appointments-app.js.buildmanifest.json +203 -182
  38. package/dist/kenyaemr-esm-appointments-app.js.map +1 -1
  39. package/dist/main.js +1 -1
  40. package/dist/main.js.map +1 -1
  41. package/dist/routes.json +1 -1
  42. package/package.json +3 -4
  43. package/src/appointments/appointment-tabs.component.tsx +1 -2
  44. package/src/appointments/common-components/appointments-table.component.tsx +2 -2
  45. package/src/appointments/common-components/appointments-table.test.tsx +3 -3
  46. package/src/appointments/common-components/end-appointment.modal.tsx +24 -27
  47. package/src/appointments/common-components/end-appointment.test.tsx +10 -4
  48. package/src/appointments/unscheduled/unscheduled-appointments.component.tsx +2 -2
  49. package/src/appointments/unscheduled/unscheduled-appointments.test.tsx +3 -3
  50. package/src/appointments.component.tsx +1 -1
  51. package/src/appointments.test.tsx +5 -5
  52. package/src/calendar/appointments-calendar-view.component.tsx +1 -1
  53. package/src/calendar/header/calendar-header.component.tsx +7 -5
  54. package/src/calendar/header/calendar-header.scss +12 -0
  55. package/src/calendar/monthly/days-of-week.component.tsx +6 -4
  56. package/src/calendar/monthly/days-of-week.scss +5 -0
  57. package/src/calendar/monthly/monthly-calendar-view.component.tsx +2 -2
  58. package/src/calendar/monthly/monthly-header.component.tsx +49 -0
  59. package/src/calendar/monthly/monthly-view-workload.scss +0 -4
  60. package/src/calendar/monthly/monthly-workload-view-expanded.component.tsx +6 -1
  61. package/src/calendar/monthly/monthly-workload-view.component.tsx +3 -3
  62. package/src/config-schema.ts +6 -0
  63. package/src/constants.ts +1 -1
  64. package/src/form/appointments-form.component.tsx +59 -30
  65. package/src/form/appointments-form.scss +9 -0
  66. package/src/header/appointments-header.component.tsx +38 -55
  67. package/src/header/appointments-header.scss +7 -56
  68. package/src/helpers/excel.ts +31 -15
  69. package/src/hooks/useClinicalMetrics.ts +7 -5
  70. package/src/index.ts +15 -13
  71. package/src/metrics/metrics-header.component.tsx +3 -4
  72. package/src/routes.json +14 -18
  73. package/src/types/index.ts +0 -1
  74. package/translations/am.json +7 -2
  75. package/translations/ar.json +7 -2
  76. package/translations/en.json +8 -3
  77. package/translations/es.json +69 -64
  78. package/translations/fr.json +71 -66
  79. package/translations/he.json +7 -2
  80. package/translations/km.json +7 -2
  81. package/translations/zh.json +7 -2
  82. package/translations/zh_CN.json +7 -2
  83. package/dist/152.js +0 -1
  84. package/dist/152.js.map +0 -1
  85. package/dist/23.js +0 -2
  86. package/dist/23.js.LICENSE.txt +0 -5
  87. package/dist/23.js.map +0 -1
  88. package/dist/255.js +0 -2
  89. package/dist/255.js.map +0 -1
  90. package/dist/303.js +0 -1
  91. package/dist/303.js.map +0 -1
  92. package/dist/646.js +0 -2
  93. package/dist/646.js.map +0 -1
  94. package/dist/729.js +0 -1
  95. package/dist/729.js.map +0 -1
  96. package/dist/85.js +0 -1
  97. package/dist/85.js.map +0 -1
  98. package/dist/89.js +0 -1
  99. package/dist/89.js.map +0 -1
  100. package/src/calendar/monthly/monthly-header.module.tsx +0 -40
  101. package/src/header/appointments-illustration.component.tsx +0 -22
  102. /package/dist/{646.js.LICENSE.txt → 198.js.LICENSE.txt} +0 -0
  103. /package/dist/{255.js.LICENSE.txt → 372.js.LICENSE.txt} +0 -0
  104. /package/src/calendar/monthly/{monthly-header.module.scss → monthly-header.scss} +0 -0
@@ -176,7 +176,34 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
176
176
  },
177
177
  {
178
178
  path: ['appointmentDateTime.recurringPatternEndDate'],
179
- message: 'A recurring appointment should have an end date',
179
+ message: t('recurringAppointmentShouldHaveEndDate', 'A recurring appointment should have an end date'),
180
+ },
181
+ )
182
+ .refine(
183
+ (formValues) => {
184
+ const { appointmentDateTime, dateAppointmentScheduled } = formValues;
185
+
186
+ const startDate = appointmentDateTime?.startDate;
187
+
188
+ if (!startDate || !dateAppointmentScheduled) return true;
189
+
190
+ const normalizeDate = (date: Date) => {
191
+ const normalizedDate = new Date(date);
192
+ normalizedDate.setHours(0, 0, 0, 0);
193
+ return normalizedDate;
194
+ };
195
+
196
+ const startDateObj = normalizeDate(startDate);
197
+ const scheduledDateObj = normalizeDate(dateAppointmentScheduled);
198
+
199
+ return scheduledDateObj <= startDateObj;
200
+ },
201
+ {
202
+ path: ['dateAppointmentScheduled'],
203
+ message: t(
204
+ 'dateAppointmentIssuedCannotBeAfterAppointmentDate',
205
+ 'Date appointment issued cannot be after the appointment date',
206
+ ),
180
207
  },
181
208
  );
182
209
 
@@ -463,33 +490,6 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
463
490
  />
464
491
  </ResponsiveWrapper>
465
492
  </section>
466
- <section className={styles.formGroup}>
467
- <span className={styles.heading}>{t('dateScheduled', 'Date appointment issued')}</span>
468
- <ResponsiveWrapper>
469
- <Controller
470
- name="dateAppointmentScheduled"
471
- control={control}
472
- render={({ field: { onChange, value, ref }, fieldState }) => (
473
- <DatePicker
474
- datePickerType="single"
475
- dateFormat={datePickerFormat}
476
- value={value}
477
- maxDate={new Date()}
478
- onChange={([date]) => onChange(date)}
479
- invalid={!!fieldState?.error?.message}
480
- invalidText={fieldState?.error?.message}>
481
- <DatePickerInput
482
- id="dateAppointmentScheduledPickerInput"
483
- labelText={t('dateScheduledDetail', 'Date appointment issued')}
484
- style={{ width: '100%' }}
485
- placeholder={datePickerPlaceHolder}
486
- ref={ref}
487
- />
488
- </DatePicker>
489
- )}
490
- />
491
- </ResponsiveWrapper>
492
- </section>
493
493
  <section className={styles.formGroup}>
494
494
  <span className={styles.heading}>{t('service', 'Service')}</span>
495
495
  <ResponsiveWrapper>
@@ -535,7 +535,6 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
535
535
  />
536
536
  </ResponsiveWrapper>
537
537
  </section>
538
-
539
538
  <section className={styles.formGroup}>
540
539
  <span className={styles.heading}>{t('appointmentType_title', 'Appointment Type')}</span>
541
540
  <ResponsiveWrapper>
@@ -725,7 +724,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
725
724
  <DatePicker
726
725
  datePickerType="single"
727
726
  dateFormat={datePickerFormat}
728
- value={value.startDate}
727
+ value={value?.startDate}
729
728
  onChange={([date]) => {
730
729
  if (date) {
731
730
  onChange({ ...value, startDate: date });
@@ -821,6 +820,36 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
821
820
  />
822
821
  </ResponsiveWrapper>
823
822
  </section>
823
+ <section className={styles.formGroup}>
824
+ <span className={styles.heading}>{t('dateScheduled', 'Date appointment issued')}</span>
825
+ <ResponsiveWrapper>
826
+ <Controller
827
+ name="dateAppointmentScheduled"
828
+ control={control}
829
+ render={({ field: { onChange, value, ref }, fieldState }) => (
830
+ <div style={{ width: '100%' }}>
831
+ <DatePicker
832
+ datePickerType="single"
833
+ dateFormat={datePickerFormat}
834
+ value={value}
835
+ maxDate={new Date().toISOString()}
836
+ onChange={([date]) => onChange(date)}
837
+ invalid={!!fieldState?.error?.message}
838
+ invalidText={fieldState?.error?.message}>
839
+ <DatePickerInput
840
+ id="dateAppointmentScheduledPickerInput"
841
+ labelText={t('dateScheduledDetail', 'Date appointment issued')}
842
+ style={{ width: '100%' }}
843
+ placeholder={datePickerPlaceHolder}
844
+ ref={ref}
845
+ />
846
+ </DatePicker>
847
+ {fieldState?.error?.message && <div className={styles.errorMessage}>{fieldState.error.message}</div>}
848
+ </div>
849
+ )}
850
+ />
851
+ </ResponsiveWrapper>
852
+ </section>
824
853
 
825
854
  <section className={styles.formGroup}>
826
855
  <span className={styles.heading}>{t('note', 'Note')}</span>
@@ -76,3 +76,12 @@ $openmrs-background-grey: #ededed;
76
76
  max-inline-size: fit-content;
77
77
  padding-top: layout.$spacing-03;
78
78
  }
79
+
80
+ .errorMessage {
81
+ color: red;
82
+ font-size: 0.75rem;
83
+ margin-top: 0.25rem;
84
+ word-wrap: break-word;
85
+ white-space: pre-wrap;
86
+ text-align: left;
87
+ }
@@ -2,13 +2,11 @@ import React, { useContext } from 'react';
2
2
  import dayjs from 'dayjs';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { DatePicker, DatePickerInput, Dropdown } from '@carbon/react';
5
- import { Location } from '@carbon/react/icons';
6
- import { useSession } from '@openmrs/esm-framework';
5
+ import { PageHeader, PageHeaderContent, AppointmentsPictogram } from '@openmrs/esm-framework';
6
+ import { omrsDateFormat } from '../constants';
7
7
  import { useAppointmentServices } from '../hooks/useAppointmentService';
8
- import AppointmentsIllustration from './appointments-illustration.component';
9
- import styles from './appointments-header.scss';
10
8
  import SelectedDateContext from '../hooks/selectedDateContext';
11
- import { omrsDateFormat } from '../constants';
9
+ import styles from './appointments-header.scss';
12
10
 
13
11
  interface AppointmentHeaderProps {
14
12
  title: string;
@@ -18,61 +16,46 @@ interface AppointmentHeaderProps {
18
16
 
19
17
  const AppointmentsHeader: React.FC<AppointmentHeaderProps> = ({ title, appointmentServiceType, onChange }) => {
20
18
  const { t } = useTranslation();
21
- const session = useSession();
22
19
  const { selectedDate, setSelectedDate } = useContext(SelectedDateContext);
23
- const location = session?.sessionLocation?.display;
24
20
  const { serviceTypes } = useAppointmentServices();
25
21
 
26
22
  return (
27
- <div className={styles.header} data-testid="appointments-header">
28
- <div className={styles['left-justified-items']}>
29
- <AppointmentsIllustration />
30
- <div className={styles['page-labels']}>
31
- <p>{t('appointments', 'Appointments')}</p>
32
- <p className={styles['page-name']}>{title}</p>
33
- </div>
34
- </div>
35
- <div className={styles['right-justified-items']}>
36
- <div className={styles['date-and-location']}>
37
- <Location size={16} />
38
- <span className={styles.value}>{location}</span>
39
- <span className={styles.middot}>&middot;</span>
40
- <DatePicker
41
- onChange={([date]) => setSelectedDate(dayjs(date).startOf('day').format(omrsDateFormat))}
42
- value={dayjs(selectedDate).format('DD MMM YYYY')}
43
- dateFormat="d-M-Y"
44
- datePickerType="single">
45
- <DatePickerInput
46
- style={{ cursor: 'pointer', backgroundColor: 'transparent', border: 'none', maxWidth: '10rem' }}
47
- id="appointment-date-picker"
48
- placeholder="DD-MMM-YYYY"
49
- labelText=""
50
- type="text"
51
- />
52
- </DatePicker>
53
- </div>
54
- <div className={styles.dropdownContainer}>
55
- {typeof onChange === 'function' && (
56
- <Dropdown
57
- className={styles.dropdown}
58
- aria-label="Select service type"
59
- id="serviceDropdown"
60
- selectedItem={
61
- serviceTypes.find((service) => service.uuid === appointmentServiceType) || { name: 'All', uuid: '' }
62
- }
63
- items={[{ name: 'All', uuid: '' }, ...serviceTypes]}
64
- itemToString={(item) => (item ? item.name : '')}
65
- label={t('selectServiceType', 'Select service type')}
66
- type="inline"
67
- size="sm"
68
- direction="bottom"
69
- titleText={t('view', 'View')}
70
- onChange={({ selectedItem }) => onChange(selectedItem?.uuid)}
71
- />
72
- )}
73
- </div>
23
+ <PageHeader className={styles.header} data-testid="appointments-header">
24
+ <PageHeaderContent illustration={<AppointmentsPictogram />} title={title} />
25
+ <div className={styles.rightJustifiedItems}>
26
+ <DatePicker
27
+ dateFormat="d-M-Y"
28
+ datePickerType="single"
29
+ onChange={([date]) => setSelectedDate(dayjs(date).startOf('day').format(omrsDateFormat))}
30
+ value={dayjs(selectedDate).format('DD MMM YYYY')}>
31
+ <DatePickerInput
32
+ style={{ cursor: 'pointer', backgroundColor: 'transparent', border: 'none', maxWidth: '10rem' }}
33
+ id="appointment-date-picker"
34
+ labelText=""
35
+ placeholder="DD-MMM-YYYY"
36
+ type="text"
37
+ />
38
+ </DatePicker>
39
+ {typeof onChange === 'function' && (
40
+ <Dropdown
41
+ aria-label={t('selectServiceType', 'Select service type')}
42
+ className={styles.dropdown}
43
+ direction="bottom"
44
+ id="serviceDropdown"
45
+ items={[{ name: 'All', uuid: '' }, ...serviceTypes]}
46
+ itemToString={(item) => (item ? item.name : '')}
47
+ label={t('selectServiceType', 'Select service type')}
48
+ onChange={({ selectedItem }) => onChange(selectedItem?.uuid)}
49
+ selectedItem={
50
+ serviceTypes.find((service) => service.uuid === appointmentServiceType) || { name: 'All', uuid: '' }
51
+ }
52
+ size="sm"
53
+ titleText={t('view', 'View')}
54
+ type="inline"
55
+ />
56
+ )}
74
57
  </div>
75
- </div>
58
+ </PageHeader>
76
59
  );
77
60
  };
78
61
 
@@ -4,71 +4,22 @@
4
4
  @use '@openmrs/esm-styleguide/src/vars' as *;
5
5
 
6
6
  .header {
7
- @include type.type-style('body-compact-02');
8
- color: $text-02;
9
- height: layout.$spacing-12;
10
7
  background-color: $ui-02;
11
- border-bottom: 1px solid $ui-03;
8
+ border: 1px solid $ui-03;
9
+ border-left: 0;
12
10
  display: flex;
13
11
  justify-content: space-between;
14
- }
15
-
16
- .left-justified-items {
17
- display: flex;
18
- flex-direction: row;
19
- align-items: center;
20
- }
21
-
22
- .right-justified-items {
23
- @include type.type-style('body-compact-02');
24
- color: $text-02;
25
- margin: layout.$spacing-03;
26
- }
27
-
28
- .page-name {
29
- @include type.type-style('heading-04');
30
- }
31
-
32
- .page-labels {
33
- margin: layout.$spacing-05 0;
34
-
35
- p:first-of-type {
36
- margin-bottom: layout.$spacing-02;
37
- }
38
- }
39
-
40
- .date-and-location {
41
- display: flex;
42
- justify-content: flex-end;
43
12
  align-items: center;
13
+ padding-right: layout.$spacing-03;
44
14
  }
45
15
 
46
- .dropdownContainer {
16
+ .rightJustifiedItems {
47
17
  display: flex;
48
- align-items: center;
18
+ flex-direction: column;
19
+ align-items: flex-end;
49
20
  justify-content: flex-end;
50
- margin-top: layout.$spacing-02;
51
- }
52
-
53
- .value {
54
- margin-left: layout.$spacing-02;
55
- }
56
-
57
- .middot {
58
21
  margin: 0 layout.$spacing-03;
59
- }
60
-
61
- .view {
62
- @include type.type-style('label-01');
63
- }
64
-
65
- .datePicker {
66
- background-color: transparent;
67
- width: layout.$spacing-13;
68
- border: none;
69
- & > input {
70
- color: colors.$blue-10;
71
- }
22
+ row-gap: layout.$spacing-01;
72
23
  }
73
24
 
74
25
  .dropdown {
@@ -1,21 +1,37 @@
1
- import { formatDate } from '@openmrs/esm-framework';
2
1
  import * as XLSX from 'xlsx';
2
+ import { fetchCurrentPatient, formatDate, getConfig } from '@openmrs/esm-framework';
3
3
  import { type Appointment } from '../types';
4
+ import { type ConfigObject } from '../config-schema';
5
+ import { moduleName } from '../constants';
4
6
 
5
7
  /**
6
- * Downloads the provided appointments as an Excel file.
7
- * @param {Array<Appointment>} appointments - The list of appointments to download.
8
+ * Exports the provided appointments as an Excel spreadsheet.
9
+ * @param {Array<Appointment>} appointments - The list of appointments to export.
8
10
  * @param {string} [fileName] - The name of the downloaded file
9
11
  */
10
- export function downloadAppointmentsAsExcel(appointments: Array<Appointment>, fileName = 'Appointments') {
11
- const appointmentsJSON = appointments?.map((appointment: Appointment) => ({
12
- 'Patient name': appointment.patient.name,
13
- Gender: appointment.patient.gender === 'F' ? 'Female' : 'Male',
14
- Age: appointment.patient.age,
15
- Identifier: appointment.patient.identifier ?? '--',
16
- 'Appointment type': appointment.service?.name,
17
- Date: formatDate(new Date(appointment.startDateTime), { mode: 'wide' }),
18
- }));
12
+ export async function exportAppointmentsToSpreadsheet(appointments: Array<Appointment>, fileName = 'Appointments') {
13
+ const config = await getConfig<ConfigObject>(moduleName);
14
+ const includePhoneNumbers = config.includePhoneNumberInExcelSpreadsheet ?? false;
15
+
16
+ const appointmentsJSON = await Promise.all(
17
+ appointments.map(async (appointment: Appointment) => {
18
+ const patientInfo = await fetchCurrentPatient(appointment.patient.uuid);
19
+ const phoneNumber =
20
+ includePhoneNumbers && patientInfo?.telecom
21
+ ? patientInfo.telecom.map((telecomObj) => telecomObj?.value).join(', ')
22
+ : '';
23
+
24
+ return {
25
+ 'Patient name': appointment.patient.name,
26
+ Gender: appointment.patient.gender === 'F' ? 'Female' : 'Male',
27
+ Age: appointment.patient.age,
28
+ Identifier: appointment.patient.identifier ?? '--',
29
+ 'Appointment type': appointment.service?.name,
30
+ Date: formatDate(new Date(appointment.startDateTime), { mode: 'wide' }),
31
+ ...(includePhoneNumbers ? { 'Telephone number': phoneNumber } : {}),
32
+ };
33
+ }),
34
+ );
19
35
 
20
36
  const worksheet = createWorksheet(appointmentsJSON);
21
37
  const workbook = createWorkbook(worksheet, 'Appointment list');
@@ -23,11 +39,11 @@ export function downloadAppointmentsAsExcel(appointments: Array<Appointment>, fi
23
39
  }
24
40
 
25
41
  /**
26
- Downloads unscheduled appointments as an Excel file.
27
- @param {Array<Object>} unscheduledAppointments - The list of unscheduled appointments to download.
42
+ Exports unscheduled appointments as an Excel spreadsheet.
43
+ @param {Array<Object>} unscheduledAppointments - The list of unscheduled appointments to export.
28
44
  @param {string} fileName - The name of the file to download. Defaults to 'Unscheduled appointments {current date and time}'.
29
45
  */
30
- export function downloadUnscheduledAppointments(
46
+ export function exportUnscheduledAppointmentsToSpreadsheet(
31
47
  unscheduledAppointments: Array<any>,
32
48
  fileName = `Unscheduled appointments ${formatDate(new Date(), { year: true, time: true })}`,
33
49
  ) {
@@ -45,11 +45,13 @@ export function useAllAppointmentsByDate() {
45
45
  openmrsFetch,
46
46
  );
47
47
 
48
- const providersArray = data?.data?.filter(({ providers }) => providers !== null) ?? [];
49
- const providersCount = uniqBy(
50
- providersArray.map(({ providers }) => providers).flat(),
51
- (provider) => provider.uuid,
52
- ).length;
48
+ const providersArray = data?.data?.flatMap(({ providers }) => providers ?? []) ?? [];
49
+
50
+ const validProviders = providersArray.filter((provider) => provider.response === 'ACCEPTED');
51
+
52
+ const uniqueProviders = uniqBy(validProviders, (provider) => provider.uuid);
53
+ const providersCount = uniqueProviders.length;
54
+
53
55
  return {
54
56
  totalProviders: providersCount ? providersCount : 0,
55
57
  isLoading,
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@ import {
7
7
  } from '@openmrs/esm-framework';
8
8
  import { configSchema } from './config-schema';
9
9
  import { createDashboardLink } from './createDashboardLink.component';
10
- import { createDashboardLink as createPatientChartDashboardLink } from '@openmrs/esm-patient-common-lib';
11
10
  import { dashboardMeta, appointmentCalendarDashboardMeta, patientChartDashboardMeta } from './dashboard.meta';
12
11
  import {
13
12
  cancelledAppointmentsPanelConfigSchema,
@@ -22,10 +21,7 @@ import appointmentsDashboardComponent from './appointments.component';
22
21
  import homeAppointmentsComponent from './home/home-appointments.component';
23
22
  import appointmentsListComponent from './appointments/scheduled/appointments-list.component';
24
23
  import earlyAppointmentsComponent from './appointments/scheduled/early-appointments.component';
25
- import patientAppointmentsDetailedSummaryComponent from './patient-appointments/patient-appointments-detailed-summary.component';
26
- import patientAppointmentsOverviewComponent from './patient-appointments/patient-appointments-overview.component';
27
- import patientUpcomingAppointmentsComponent from './patient-appointments/patient-upcoming-appointments-card.component';
28
- import appointementsForm from './form/appointments-form.component';
24
+ import appointmentsFormComponent from './form/appointments-form.component';
29
25
  import patientSearch from './patient-search/patient-search.component';
30
26
  export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
31
27
 
@@ -79,24 +75,30 @@ export const appointmentsList = getSyncLifecycle(appointmentsListComponent, opti
79
75
 
80
76
  export const earlyAppointments = getSyncLifecycle(earlyAppointmentsComponent, options);
81
77
 
82
- export const appointementForm = getSyncLifecycle(appointementsForm, options);
78
+ export const appointmentsForm = getSyncLifecycle(appointmentsFormComponent, options);
83
79
 
84
80
  export const searchPatient = getSyncLifecycle(patientSearch, options);
85
81
 
86
82
  // t('Appointments', 'Appointments')
87
- export const patientAppointmentsSummaryDashboardLink = getSyncLifecycle(
88
- createPatientChartDashboardLink({ ...patientChartDashboardMeta, moduleName }),
83
+ export const patientAppointmentsSummaryDashboardLink = getAsyncLifecycle(async () => {
84
+ const commonLib = await import('@openmrs/esm-patient-common-lib');
85
+ return { default: commonLib.createDashboardLink({ ...patientChartDashboardMeta, moduleName }) };
86
+ }, options);
87
+
88
+ export const patientAppointmentsDetailedSummary = getAsyncLifecycle(
89
+ () => import('./patient-appointments/patient-appointments-detailed-summary.component'),
89
90
  options,
90
91
  );
91
92
 
92
- export const patientAppointmentsDetailedSummary = getSyncLifecycle(
93
- patientAppointmentsDetailedSummaryComponent,
93
+ export const patientAppointmentsOverview = getAsyncLifecycle(
94
+ () => import('./patient-appointments/patient-appointments-overview.component'),
94
95
  options,
95
96
  );
96
97
 
97
- export const patientAppointmentsOverview = getSyncLifecycle(patientAppointmentsOverviewComponent, options);
98
-
99
- export const patientUpcomingAppointmentsWidget = getSyncLifecycle(patientUpcomingAppointmentsComponent, options);
98
+ export const patientUpcomingAppointmentsWidget = getAsyncLifecycle(
99
+ () => import('./patient-appointments/patient-upcoming-appointments-card.component'),
100
+ options,
101
+ );
100
102
 
101
103
  export const patientAppointmentsCancelConfirmationDialog = getAsyncLifecycle(
102
104
  () => import('./patient-appointments/patient-appointments-cancel.modal'),
@@ -1,14 +1,13 @@
1
1
  import React, { useContext } from 'react';
2
2
  import dayjs from 'dayjs';
3
3
  import isToday from 'dayjs/plugin/isToday';
4
- import { launchWorkspace } from '@openmrs/esm-framework';
5
4
  import { useTranslation } from 'react-i18next';
6
5
  import { Calendar, Hospital } from '@carbon/react/icons';
7
6
  import { Button } from '@carbon/react';
8
- import { ExtensionSlot, isDesktop, navigate, useLayoutType } from '@openmrs/esm-framework';
7
+ import { ExtensionSlot, isDesktop, launchWorkspace, navigate, useLayoutType } from '@openmrs/esm-framework';
9
8
  import { spaHomePage } from '../constants';
10
- import styles from './metrics-header.scss';
11
9
  import SelectedDateContext from '../hooks/selectedDateContext';
10
+ import styles from './metrics-header.scss';
12
11
 
13
12
  dayjs.extend(isToday);
14
13
 
@@ -39,7 +38,7 @@ const MetricsHeader: React.FC = () => {
39
38
  onClick={() =>
40
39
  navigate({ to: `${spaHomePage}/appointments/calendar/${dayjs(selectedDate).format('YYYY-MM-DD')}` })
41
40
  }>
42
- {t('appointmentsCalendar', 'Appointments Calendar')}
41
+ {t('appointmentsCalendar', 'Appointments calendar')}
43
42
  </Button>
44
43
  <ExtensionSlot
45
44
  name="patient-search-button-slot"
package/src/routes.json CHANGED
@@ -3,12 +3,6 @@
3
3
  "backendDependencies": {
4
4
  "webservices.rest": "^2.2.0"
5
5
  },
6
- "modals": [
7
- {
8
- "name": "end-appointment-modal",
9
- "component": "endAppointmentModal"
10
- }
11
- ],
12
6
  "extensions": [
13
7
  {
14
8
  "name": "home-appointments",
@@ -36,11 +30,7 @@
36
30
  "slot": "calendar-dashboard-slot",
37
31
  "component": "appointmentsCalendarDashboardLink"
38
32
  },
39
- {
40
- "name": "check-in-appointment-modal",
41
- "slot": "todays-appointment-slot",
42
- "component": "checkInModal"
43
- },
33
+
44
34
  {
45
35
  "name": "todays-appointments-dashboard",
46
36
  "slot": "todays-appointment-slot",
@@ -111,13 +101,9 @@
111
101
  "component": "patientUpcomingAppointmentsWidget",
112
102
  "slot": "upcoming-appointment-slot"
113
103
  },
114
- {
115
- "name": "patient-appointment-cancel-confirmation-dialog",
116
- "component": "patientAppointmentsCancelConfirmationDialog"
117
- },
118
104
  {
119
105
  "name": "edit-appointments-form",
120
- "component": "appointementForm",
106
+ "component": "appointmentsForm",
121
107
  "meta": {
122
108
  "title":{
123
109
  "key":"editAppointment",
@@ -131,7 +117,7 @@
131
117
  },
132
118
  {
133
119
  "name": "create-appointment",
134
- "component": "appointementForm",
120
+ "component": "appointmentsForm",
135
121
  "meta": {
136
122
  "title": {
137
123
  "key":"appointmentForm",
@@ -141,7 +127,7 @@
141
127
  },
142
128
  {
143
129
  "name": "add-appointment",
144
- "component": "appointementForm",
130
+ "component": "appointmentsForm",
145
131
  "meta": {
146
132
  "title": {
147
133
  "key": "createNewAppointment",
@@ -154,5 +140,15 @@
154
140
  "slot": "home-metrics-tiles-slot",
155
141
  "component": "homeAppointmentsTile"
156
142
  }
143
+ ],
144
+ "modals": [
145
+ {
146
+ "name": "end-appointment-modal",
147
+ "component": "endAppointmentModal"
148
+ },
149
+ {
150
+ "name": "patient-appointment-cancel-confirmation-dialog",
151
+ "component": "patientAppointmentsCancelConfirmationDialog"
152
+ }
157
153
  ]
158
154
  }
@@ -27,7 +27,6 @@ export enum AppointmentKind {
27
27
  WALKIN = 'WalkIn',
28
28
  VIRTUAL = 'Virtual',
29
29
  }
30
-
31
30
  // TODO: remove interface elements that aren't actually present on the Appointment object returned from the Appointment API
32
31
  export interface Appointment {
33
32
  appointmentKind: AppointmentKind;
@@ -27,7 +27,7 @@
27
27
  "appointments": "Appointments",
28
28
  "Appointments": "Appointments",
29
29
  "appointments_lower": "appointments",
30
- "appointmentsCalendar": "Appointments Calendar",
30
+ "appointmentsCalendar": "Appointments calendar",
31
31
  "appointmentScheduled": "Appointment scheduled",
32
32
  "appointmentService": "Appointment service",
33
33
  "appointmentServiceCreate": "Appointment service created successfully",
@@ -62,6 +62,7 @@
62
62
  "createNewAppointment": "Create new appointment",
63
63
  "date": "Date",
64
64
  "date&Time": "Date & time",
65
+ "dateAppointmentIssuedCannotBeAfterAppointmentDate": "Date appointment issued cannot be after the appointment date",
65
66
  "dateOfBirth": "Date of birth",
66
67
  "dateScheduled": "Date appointment issued",
67
68
  "dateScheduledDetail": "Date appointment issued",
@@ -89,7 +90,6 @@
89
90
  "filterTable": "Filter table",
90
91
  "gender": "Gender",
91
92
  "highestServiceVolume": "Highest volume service: {{time}}",
92
- "home": "Home",
93
93
  "identifier": "Identifier",
94
94
  "invalidNumber": "Number is not valid",
95
95
  "invalidTime": "Invalid time",
@@ -99,6 +99,8 @@
99
99
  "location": "Location",
100
100
  "medications": "Medications",
101
101
  "missed": "Missed",
102
+ "next": "Next",
103
+ "nextMonth": "Next month",
102
104
  "nextPage": "Next page",
103
105
  "no": "No",
104
106
  "noAppointmentsToDisplay": "No appointments to display",
@@ -119,11 +121,14 @@
119
121
  "patientName": "Patient name",
120
122
  "patients": "Patients",
121
123
  "period": "Period",
124
+ "prev": "Prev",
125
+ "previousMonth": "Previous month",
122
126
  "previousPage": "Previous page",
123
127
  "provider": "Provider",
124
128
  "providers": "Providers",
125
129
  "providersBooked": "Providers booked: {{time}}",
126
130
  "recurringAppointment": "Recurring Appointment",
131
+ "recurringAppointmentShouldHaveEndDate": "A recurring appointment should have an end date",
127
132
  "repeatEvery": "Repeat every",
128
133
  "save": "Save",
129
134
  "saveAndClose": "Save and close",