@openmrs/esm-appointments-app 9.2.1-pre.7303 → 9.2.1-pre.7318
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.
- package/.turbo/turbo-build.log +8 -8
- package/dist/1431.js +1 -1
- package/dist/1431.js.map +1 -1
- package/dist/1559.js +1 -1
- package/dist/1559.js.map +1 -1
- package/dist/2265.js +1 -0
- package/dist/2265.js.map +1 -0
- package/dist/{5160.js → 4036.js} +1 -1
- package/dist/{5160.js.map → 4036.js.map} +1 -1
- package/dist/449.js +1 -1
- package/dist/449.js.map +1 -1
- package/dist/4515.js +1 -0
- package/dist/4515.js.map +1 -0
- package/dist/4745.js +1 -1
- package/dist/4745.js.map +1 -1
- package/dist/4889.js +1 -1
- package/dist/4889.js.map +1 -1
- package/dist/525.js +1 -1
- package/dist/525.js.map +1 -1
- package/dist/5666.js +1 -1
- package/dist/5666.js.map +1 -1
- package/dist/5755.js +1 -1
- package/dist/5755.js.map +1 -1
- package/dist/592.js +1 -1
- package/dist/592.js.map +1 -1
- package/dist/6467.js +1 -1
- package/dist/6467.js.map +1 -1
- package/dist/6886.js +1 -1
- package/dist/6886.js.map +1 -1
- package/dist/{7565.js → 7294.js} +1 -1
- package/dist/7294.js.map +1 -0
- package/dist/9712.js +1 -1
- package/dist/9712.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-appointments-app.js +1 -1
- package/dist/openmrs-esm-appointments-app.js.buildmanifest.json +121 -120
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/appointments/common-components/appointments-table.component.tsx +4 -6
- package/src/constants.ts +1 -0
- package/src/form/appointments-form.resource.ts +1 -0
- package/src/form/appointments-form.test.tsx +111 -71
- package/src/form/appointments-form.workspace.tsx +437 -436
- package/src/form/exported-appointments-form.workspace.tsx +24 -0
- package/src/helpers/functions.ts +72 -25
- package/src/index.ts +5 -3
- package/src/metrics/metrics-cards/highest-volume-service.extension.tsx +1 -1
- package/src/metrics/metrics-cards/metrics-card.component.tsx +1 -1
- package/src/metrics/metrics-header.component.tsx +9 -24
- package/src/patient-appointments/patient-appointments-action-menu.component.tsx +2 -6
- package/src/patient-appointments/patient-appointments-detailed-summary.extension.tsx +176 -15
- package/src/patient-appointments/{patient-appointments-base.test.tsx → patient-appointments-detailed-summary.test.tsx} +14 -22
- package/src/patient-appointments/patient-appointments-overview.component.tsx +15 -18
- package/src/routes.json +22 -7
- package/dist/3092.js +0 -1
- package/dist/3092.js.map +0 -1
- package/dist/7026.js +0 -1
- package/dist/7026.js.map +0 -1
- package/dist/7565.js.map +0 -1
- package/src/hooks/patient-appointment-context.ts +0 -18
- package/src/patient-appointments/patient-appointments-base.component.tsx +0 -178
- package/src/patient-search/patient-search.component.tsx +0 -33
- package/src/patient-search/patient-search.scss +0 -24
- /package/src/patient-appointments/{patient-appointments-base.scss → patient-appointments-detailed-summary.scss} +0 -0
|
@@ -18,13 +18,47 @@ import { useProviders } from '../hooks/useProviders';
|
|
|
18
18
|
import type { AppointmentKind, AppointmentStatus } from '../types';
|
|
19
19
|
import AppointmentForm from './appointments-form.workspace';
|
|
20
20
|
|
|
21
|
+
const existingAppointment = {
|
|
22
|
+
uuid: 'appointment-uuid',
|
|
23
|
+
appointmentNumber: 'APT-001',
|
|
24
|
+
startDateTime: '2024-01-04T09:30:00.000Z',
|
|
25
|
+
endDateTime: '2024-01-04T10:00:00.000Z',
|
|
26
|
+
appointmentKind: 'Scheduled' as AppointmentKind.SCHEDULED,
|
|
27
|
+
status: 'Scheduled' as AppointmentStatus.SCHEDULED,
|
|
28
|
+
comments: 'Existing appointment note',
|
|
29
|
+
location: { uuid: 'b1a8b05e-3542-4037-bbd3-998ee9c40574', display: 'Inpatient Ward', name: 'Inpatient Ward' },
|
|
30
|
+
service: {
|
|
31
|
+
uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
|
|
32
|
+
name: 'Outpatient',
|
|
33
|
+
appointmentServiceId: 1,
|
|
34
|
+
creatorName: 'Test Creator',
|
|
35
|
+
description: 'Outpatient service',
|
|
36
|
+
endTime: '17:00',
|
|
37
|
+
initialAppointmentStatus: 'Scheduled' as AppointmentStatus.SCHEDULED,
|
|
38
|
+
maxAppointmentsLimit: null,
|
|
39
|
+
startTime: '08:00',
|
|
40
|
+
},
|
|
41
|
+
patient: { uuid: mockPatient.id, name: 'Test Patient', identifier: '12345', identifiers: [] },
|
|
42
|
+
provider: { uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', display: 'Dr. Cook' },
|
|
43
|
+
providers: [{ uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', response: 'ACCEPTED' }],
|
|
44
|
+
recurring: false,
|
|
45
|
+
voided: false,
|
|
46
|
+
extensions: {},
|
|
47
|
+
teleconsultationLink: null,
|
|
48
|
+
dateAppointmentScheduled: '2024-01-04T00:00:00.000Z',
|
|
49
|
+
};
|
|
50
|
+
|
|
21
51
|
const defaultProps = {
|
|
22
|
-
context: 'creating',
|
|
23
52
|
closeWorkspace: jest.fn(),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
53
|
+
workspaceProps: {
|
|
54
|
+
patientUuid: mockPatient.id,
|
|
55
|
+
},
|
|
56
|
+
windowProps: null,
|
|
57
|
+
groupProps: null,
|
|
58
|
+
workspaceName: 'appointments-form',
|
|
59
|
+
windowName: 'test-window',
|
|
60
|
+
isRootWorkspace: true,
|
|
61
|
+
launchChildWorkspace: jest.fn(),
|
|
28
62
|
};
|
|
29
63
|
|
|
30
64
|
const mockOpenmrsFetch = jest.mocked(openmrsFetch);
|
|
@@ -694,7 +728,7 @@ describe('AppointmentForm', () => {
|
|
|
694
728
|
expect(mockSaveAppointment).not.toHaveBeenCalled();
|
|
695
729
|
});
|
|
696
730
|
|
|
697
|
-
it('should detect patient double-booking conflicts', async () => {
|
|
731
|
+
it('should detect patient double-booking conflicts when creating new appointment', async () => {
|
|
698
732
|
const user = userEvent.setup();
|
|
699
733
|
|
|
700
734
|
mockOpenmrsFetch.mockResolvedValue({ data: mockUseAppointmentServiceData } as unknown as FetchResponse);
|
|
@@ -703,6 +737,7 @@ describe('AppointmentForm', () => {
|
|
|
703
737
|
data: { PATIENT_DOUBLE_BOOKING: true },
|
|
704
738
|
} as FetchResponse);
|
|
705
739
|
|
|
740
|
+
// Render WITHOUT existing appointment (creating mode)
|
|
706
741
|
renderWithSwr(<AppointmentForm {...defaultProps} />);
|
|
707
742
|
|
|
708
743
|
await waitForLoadingToFinish();
|
|
@@ -740,6 +775,7 @@ describe('AppointmentForm', () => {
|
|
|
740
775
|
await user.click(saveButton);
|
|
741
776
|
|
|
742
777
|
expect(mockCheckAppointmentConflict).toHaveBeenCalledTimes(1);
|
|
778
|
+
// Should show double-booking error when creating new appointment
|
|
743
779
|
expect(mockShowSnackbar).toHaveBeenCalledWith({
|
|
744
780
|
isLowContrast: true,
|
|
745
781
|
kind: 'error',
|
|
@@ -747,43 +783,72 @@ describe('AppointmentForm', () => {
|
|
|
747
783
|
});
|
|
748
784
|
expect(mockSaveAppointment).not.toHaveBeenCalled();
|
|
749
785
|
});
|
|
786
|
+
|
|
787
|
+
it('should not show double-booking error when editing same appointment', async () => {
|
|
788
|
+
const user = userEvent.setup();
|
|
789
|
+
|
|
790
|
+
mockOpenmrsFetch.mockResolvedValue({ data: mockUseAppointmentServiceData } as unknown as FetchResponse);
|
|
791
|
+
// Backend should exclude the current appointment from conflict check when UUID is sent
|
|
792
|
+
mockCheckAppointmentConflict.mockResolvedValue({
|
|
793
|
+
status: 204,
|
|
794
|
+
data: {},
|
|
795
|
+
} as FetchResponse);
|
|
796
|
+
mockSaveAppointment.mockResolvedValue({ status: 200, statusText: 'Ok' } as FetchResponse);
|
|
797
|
+
|
|
798
|
+
// Render WITH existing appointment (editing mode)
|
|
799
|
+
renderWithSwr(
|
|
800
|
+
<AppointmentForm
|
|
801
|
+
{...defaultProps}
|
|
802
|
+
workspaceProps={{
|
|
803
|
+
...defaultProps.workspaceProps,
|
|
804
|
+
appointment: existingAppointment,
|
|
805
|
+
}}
|
|
806
|
+
/>,
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
await waitForLoadingToFinish();
|
|
810
|
+
|
|
811
|
+
const appointmentNoteTextarea = screen.getByRole('textbox', { name: /write an additional note/i });
|
|
812
|
+
const saveButton = screen.getByRole('button', { name: /save and close/i });
|
|
813
|
+
|
|
814
|
+
// Make a small change
|
|
815
|
+
await user.clear(appointmentNoteTextarea);
|
|
816
|
+
await user.type(appointmentNoteTextarea, 'Updated note');
|
|
817
|
+
|
|
818
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
819
|
+
await user.click(saveButton);
|
|
820
|
+
|
|
821
|
+
expect(mockCheckAppointmentConflict).toHaveBeenCalledTimes(1);
|
|
822
|
+
// Verify UUID is sent to backend so it can exclude current appointment from conflict check
|
|
823
|
+
expect(mockCheckAppointmentConflict).toHaveBeenCalledWith(
|
|
824
|
+
expect.objectContaining({
|
|
825
|
+
uuid: existingAppointment.uuid,
|
|
826
|
+
}),
|
|
827
|
+
);
|
|
828
|
+
// Should NOT show double-booking error when editing (same appointment)
|
|
829
|
+
expect(mockShowSnackbar).not.toHaveBeenCalledWith(
|
|
830
|
+
expect.objectContaining({
|
|
831
|
+
title: 'Patient already booked for an appointment at this time',
|
|
832
|
+
}),
|
|
833
|
+
);
|
|
834
|
+
// Should proceed with save
|
|
835
|
+
expect(mockSaveAppointment).toHaveBeenCalled();
|
|
836
|
+
});
|
|
750
837
|
});
|
|
751
838
|
|
|
752
839
|
describe('Edit Mode', () => {
|
|
753
840
|
it('should pre-populate form with existing appointment data', async () => {
|
|
754
|
-
const existingAppointment = {
|
|
755
|
-
uuid: 'appointment-uuid',
|
|
756
|
-
appointmentNumber: 'APT-001',
|
|
757
|
-
startDateTime: '2024-01-04T09:30:00.000Z',
|
|
758
|
-
endDateTime: '2024-01-04T10:00:00.000Z',
|
|
759
|
-
appointmentKind: 'Scheduled' as AppointmentKind.SCHEDULED,
|
|
760
|
-
status: 'Scheduled' as AppointmentStatus.SCHEDULED,
|
|
761
|
-
comments: 'Existing appointment note',
|
|
762
|
-
location: { uuid: 'b1a8b05e-3542-4037-bbd3-998ee9c40574', display: 'Inpatient Ward', name: 'Inpatient Ward' },
|
|
763
|
-
service: {
|
|
764
|
-
uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
|
|
765
|
-
name: 'Outpatient',
|
|
766
|
-
appointmentServiceId: 1,
|
|
767
|
-
creatorName: 'Test Creator',
|
|
768
|
-
description: 'Outpatient service',
|
|
769
|
-
endTime: '17:00',
|
|
770
|
-
initialAppointmentStatus: 'Scheduled' as AppointmentStatus.SCHEDULED,
|
|
771
|
-
maxAppointmentsLimit: null,
|
|
772
|
-
startTime: '08:00',
|
|
773
|
-
},
|
|
774
|
-
patient: { uuid: mockPatient.id, name: 'Test Patient', identifier: '12345', identifiers: [] },
|
|
775
|
-
provider: { uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', display: 'Dr. Cook' },
|
|
776
|
-
providers: [{ uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', response: 'ACCEPTED' }],
|
|
777
|
-
recurring: false,
|
|
778
|
-
voided: false,
|
|
779
|
-
extensions: {},
|
|
780
|
-
teleconsultationLink: null,
|
|
781
|
-
dateAppointmentScheduled: '2024-01-04T00:00:00.000Z',
|
|
782
|
-
};
|
|
783
|
-
|
|
784
841
|
mockOpenmrsFetch.mockResolvedValue({ data: mockUseAppointmentServiceData } as unknown as FetchResponse);
|
|
785
842
|
|
|
786
|
-
renderWithSwr(
|
|
843
|
+
renderWithSwr(
|
|
844
|
+
<AppointmentForm
|
|
845
|
+
{...defaultProps}
|
|
846
|
+
workspaceProps={{
|
|
847
|
+
...defaultProps.workspaceProps,
|
|
848
|
+
appointment: existingAppointment,
|
|
849
|
+
}}
|
|
850
|
+
/>,
|
|
851
|
+
);
|
|
787
852
|
|
|
788
853
|
await waitForLoadingToFinish();
|
|
789
854
|
|
|
@@ -795,41 +860,19 @@ describe('AppointmentForm', () => {
|
|
|
795
860
|
|
|
796
861
|
it('should update appointment successfully', async () => {
|
|
797
862
|
const user = userEvent.setup();
|
|
798
|
-
const existingAppointment = {
|
|
799
|
-
uuid: 'appointment-uuid',
|
|
800
|
-
appointmentNumber: 'APT-001',
|
|
801
|
-
startDateTime: '2024-01-04T09:30:00.000Z',
|
|
802
|
-
endDateTime: '2024-01-04T10:00:00.000Z',
|
|
803
|
-
appointmentKind: 'Scheduled' as AppointmentKind.SCHEDULED,
|
|
804
|
-
status: 'Scheduled' as AppointmentStatus.SCHEDULED,
|
|
805
|
-
comments: 'Original note',
|
|
806
|
-
location: { uuid: 'b1a8b05e-3542-4037-bbd3-998ee9c40574', display: 'Inpatient Ward', name: 'Inpatient Ward' },
|
|
807
|
-
service: {
|
|
808
|
-
uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
|
|
809
|
-
name: 'Outpatient',
|
|
810
|
-
appointmentServiceId: 1,
|
|
811
|
-
creatorName: 'Test Creator',
|
|
812
|
-
description: 'Outpatient service',
|
|
813
|
-
endTime: '17:00',
|
|
814
|
-
initialAppointmentStatus: 'Scheduled',
|
|
815
|
-
maxAppointmentsLimit: null,
|
|
816
|
-
startTime: '08:00',
|
|
817
|
-
},
|
|
818
|
-
patient: { uuid: mockPatient.id, name: 'Test Patient', identifier: '12345', identifiers: [] },
|
|
819
|
-
provider: { uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', display: 'Dr. Cook' },
|
|
820
|
-
providers: [{ uuid: 'f9badd80-ab76-11e2-9e96-0800200c9a66', response: 'ACCEPTED' }],
|
|
821
|
-
recurring: false,
|
|
822
|
-
voided: false,
|
|
823
|
-
extensions: {},
|
|
824
|
-
teleconsultationLink: null,
|
|
825
|
-
dateAppointmentScheduled: '2024-01-04T00:00:00.000Z',
|
|
826
|
-
};
|
|
827
863
|
|
|
828
864
|
mockOpenmrsFetch.mockResolvedValue({ data: mockUseAppointmentServiceData } as unknown as FetchResponse);
|
|
829
865
|
mockCheckAppointmentConflict.mockResolvedValue({ status: 204, data: {} } as FetchResponse);
|
|
830
866
|
mockSaveAppointment.mockResolvedValue({ status: 200, statusText: 'Ok' } as FetchResponse);
|
|
831
|
-
|
|
832
|
-
|
|
867
|
+
renderWithSwr(
|
|
868
|
+
<AppointmentForm
|
|
869
|
+
{...defaultProps}
|
|
870
|
+
workspaceProps={{
|
|
871
|
+
...defaultProps.workspaceProps,
|
|
872
|
+
appointment: existingAppointment,
|
|
873
|
+
}}
|
|
874
|
+
/>,
|
|
875
|
+
);
|
|
833
876
|
|
|
834
877
|
await waitForLoadingToFinish();
|
|
835
878
|
|
|
@@ -897,9 +940,6 @@ describe('AppointmentForm', () => {
|
|
|
897
940
|
|
|
898
941
|
// Try to cancel
|
|
899
942
|
await user.click(cancelButton);
|
|
900
|
-
|
|
901
|
-
// Should call promptBeforeClosing if there are unsaved changes
|
|
902
|
-
expect(defaultProps.promptBeforeClosing).toHaveBeenCalled();
|
|
903
943
|
});
|
|
904
944
|
});
|
|
905
945
|
});
|