diff --git a/.tx/config b/.tx/config
index d3ee9d90f0..cb49faa41c 100644
--- a/.tx/config
+++ b/.tx/config
@@ -37,15 +37,6 @@ replace_edited_strings = false
keep_translations = false
resource_name = esm-patient-allergies-app
-[o:openmrs:p:openmrs-esm-patient-chart:r:esm-patient-appointments-app]
-file_filter = packages/esm-patient-appointments-app/translations/.json
-source_file = packages/esm-patient-appointments-app/translations/en.json
-source_lang = en
-type = KEYVALUEJSON
-replace_edited_strings = false
-keep_translations = false
-resource_name = esm-patient-appointments-app
-
[o:openmrs:p:openmrs-esm-patient-chart:r:esm-patient-attachments-app]
file_filter = packages/esm-patient-attachments-app/translations/.json
source_file = packages/esm-patient-attachments-app/translations/en.json
diff --git a/README.md b/README.md
index ca8f1cbf6d..515679cdd4 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,6 @@
The `openmrs-esm-patient-chart` is a frontend module for the OpenMRS SPA. It contains various microfrontends that constitute widgets in a patient dashboard. These widgets include:
- [Allergies](packages/esm-patient-allergies-app/README.md)
-- [Appointments](packages/esm-patient-appointments-app/README.md)
- [Attachments](packages/esm-patient-attachments-app/README.md)
- [Biometrics](packages/esm-patient-biometrics-app/README.md)
- [Conditions](packages/esm-patient-conditions-app/README.md)
diff --git a/__mocks__/appointments.mock.ts b/__mocks__/appointments.mock.ts
deleted file mode 100644
index 100c175c56..0000000000
--- a/__mocks__/appointments.mock.ts
+++ /dev/null
@@ -1,446 +0,0 @@
-export const mockAppointmentsData = {
- data: [
- {
- uuid: '0d54aa56-0411-47f9-9ce9-23d702965881',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1628598900000,
- endDateTime: 1628599020000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: null,
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '0f445395-74a7-4d8b-a6ae-8f5195cc172e',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1628598900000,
- endDateTime: 1628599020000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: null,
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: 'c5f4fdab-2d48-4412-adf4-ee26a6b0816f',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1628599800000,
- endDateTime: 1628600100000,
- appointmentKind: 'Scheduled',
- status: 'Scheduled',
- comments: null,
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '7cd38a6d-377e-491b-8284-b04cf8b8c6d8',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1630326900000,
- endDateTime: 1630327200000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Walk in appointments',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: 'e10ce4e3-0e91-4b97-bc6c-9b5068e58428',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631278200000,
- endDateTime: 1631278560000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some additional notes',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '8671c6bf-4305-48e4-8d25-bdf227d5f7af',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631367600000,
- endDateTime: 1631368800000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: null,
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: 'cdb0676f-0805-4c3e-bfef-7757a005e892',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631537400000,
- endDateTime: 1631537760000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some additional notes',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '66565d8b-4849-4b7c-966a-554d6073f80c',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: null,
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631605800000,
- endDateTime: 1631606100000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some additional notes',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '45dcc19d-dd14-4a07-95c6-afa264972a34',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: { duration: 15, name: 'Chemotherapy', uuid: '53d58ff1-0c45-4e2e-9bd2-9cc826cb46e1' },
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631623800000,
- endDateTime: 1631624160000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some additional notes',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: 'fa4657ad-db46-487d-8e2e-a3858c906ae6',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: { duration: 15, name: 'Chemotherapy', uuid: '53d58ff1-0c45-4e2e-9bd2-9cc826cb46e1' },
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631712720000,
- endDateTime: 1631713080000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some value',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: '45dcc19d-dd14-4a07-95c6-afa264972a35',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: { duration: 15, name: 'Chemotherapy', uuid: '53d58ff1-0c45-4e2e-9bd2-9cc826cb46e1' },
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631623800000,
- endDateTime: 1631624160000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some additional notes',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- {
- uuid: 'fa4657ad-db46-487d-8e2e-a3858c906ae7',
- appointmentNumber: '0000',
- patient: { identifier: '100GEJ', name: 'John Wilson', uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
- service: {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startTime: '',
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: null,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- },
- serviceType: { duration: 15, name: 'Chemotherapy', uuid: '53d58ff1-0c45-4e2e-9bd2-9cc826cb46e1' },
- provider: null,
- location: { name: 'Isolation Ward', uuid: '2131aff8-2e2a-480a-b7ab-4ac53250262b' },
- startDateTime: 1631712720000,
- endDateTime: 1631713080000,
- appointmentKind: 'WalkIn',
- status: 'Scheduled',
- comments: 'Some value',
- additionalInfo: null,
- providers: [],
- recurring: false,
- },
- ],
-};
-
-export const mockUseAppointmentServiceData = [
- {
- appointmentServiceId: 1,
- name: 'Outpatient',
- description: null,
- speciality: {},
- startDateTime: new Date().toISOString(),
- endTime: '',
- maxAppointmentsLimit: null,
- durationMins: 15,
- location: {},
- uuid: 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90',
- color: '#006400',
- initialAppointmentStatus: 'Scheduled',
- creatorName: null,
- weeklyAvailability: [
- {
- dayOfWeek: 'MONDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: '7c7c53c8-c104-40cc-9926-50fc6fe4c4c1',
- },
- {
- dayOfWeek: 'TUESDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: '7683b94e-6c48-4132-b402-54837a8c0fb2',
- },
- {
- dayOfWeek: 'SUNDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: '00be8427-0037-4984-8875-6a5a2bc57e8e',
- },
- {
- dayOfWeek: 'FRIDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: 'af6b8d5b-be05-4e24-8601-30573f848bec',
- },
- {
- dayOfWeek: 'THURSDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: 'eb35e91b-6909-41fe-9d09-750b83fb3b9c',
- },
- {
- dayOfWeek: 'SATURDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: '7f6347fd-c514-4fd2-ab79-d7fd760bf82f',
- },
- {
- dayOfWeek: 'WEDNESDAY',
- startTime: '07:00:00',
- endTime: '20:00:00',
- maxAppointmentsLimit: null,
- uuid: 'dad83f54-a0a2-4ba9-819b-01e906c89b69',
- },
- ],
- serviceTypes: [{ duration: 15, name: 'Chemotherapy', uuid: '53d58ff1-0c45-4e2e-9bd2-9cc826cb46e1' }],
- },
-];
diff --git a/__mocks__/index.ts b/__mocks__/index.ts
index be3ecee574..e9c23caa57 100644
--- a/__mocks__/index.ts
+++ b/__mocks__/index.ts
@@ -1,5 +1,4 @@
export * from './allergies.mock';
-export * from './appointments.mock';
export * from './chart-widgets-config.mock';
export * from './conditions.mock';
export * from './encounters.mock';
diff --git a/e2e/pages/attachments-page.ts b/e2e/pages/attachments-page.ts
new file mode 100644
index 0000000000..8e40268c95
--- /dev/null
+++ b/e2e/pages/attachments-page.ts
@@ -0,0 +1,9 @@
+import { type Page } from '@playwright/test';
+
+export class AttachmentsPage {
+ constructor(readonly page: Page) {}
+
+ async goTo(uuid: string) {
+ await this.page.goto('/openmrs/spa/patient/' + uuid + '/chart/Attachments');
+ }
+}
diff --git a/e2e/pages/immunizations-page.ts b/e2e/pages/immunizations-page.ts
new file mode 100644
index 0000000000..850debaeb9
--- /dev/null
+++ b/e2e/pages/immunizations-page.ts
@@ -0,0 +1,10 @@
+import { type Page } from '@playwright/test';
+
+export class ImmunizationsPage {
+ constructor(readonly page: Page) {}
+ readonly immunizationsTable = () => this.page.getByRole('table', { name: /immunizations summary/i });
+
+ async goTo(patientUuid: string) {
+ await this.page.goto(`/openmrs/spa/patient/${patientUuid}/chart/Immunizations`);
+ }
+}
diff --git a/e2e/pages/index.ts b/e2e/pages/index.ts
index 45549ac2fa..77104f8ef5 100644
--- a/e2e/pages/index.ts
+++ b/e2e/pages/index.ts
@@ -1,7 +1,9 @@
export * from './allergies-page';
+export * from './attachments-page';
export * from './chart-page';
export * from './conditions-page';
+export * from './immunizations-page';
export * from './medications-page';
export * from './program-page';
-export * from './vitals-and-biometrics-page';
export * from './visits-page';
+export * from './vitals-and-biometrics-page';
diff --git a/e2e/specs/attachments.spec.ts b/e2e/specs/attachments.spec.ts
new file mode 100644
index 0000000000..90885aec8d
--- /dev/null
+++ b/e2e/specs/attachments.spec.ts
@@ -0,0 +1,91 @@
+import { expect } from '@playwright/test';
+import { generateRandomPatient, type Patient, deletePatient } from '../commands';
+import { test } from '../core';
+import { AttachmentsPage } from '../pages';
+
+let patient: Patient;
+
+test.beforeEach(async ({ api }) => {
+ patient = await generateRandomPatient(api);
+});
+
+test('Add and remove an attachment', async ({ page }) => {
+ const attachmentsPage = new AttachmentsPage(page);
+ const filePath = './e2e/support/upload/brainScan.jpeg';
+
+ await test.step('When I go to the Attachments page', async () => {
+ await attachmentsPage.goTo(patient.uuid);
+ });
+
+ await test.step('And I click on the `Record attachments` link', async () => {
+ await page.getByRole('button', { name: /record attachments/i }).click();
+ });
+
+ await test.step('Then I should see the `Add attachment` modal launch in the workspace', async () => {
+ await expect(page.getByText(/add attachment/i)).toBeVisible();
+ });
+
+ await test.step('When I click on the `Upload files` tab', async () => {
+ await page.getByRole('tab', { name: /upload files/i }).click();
+ });
+
+ await test.step('And I choose the attachment file to upload', async () => {
+ await page.on('filechooser', async (fileChooser) => {
+ await fileChooser.setFiles(filePath);
+ });
+ await page.click('.cds--file-browse-btn');
+ });
+
+ await test.step('And I add a description for the image to upload', async () => {
+ await page.getByLabel(/image description/i).clear();
+ await page.getByLabel(/image description/i).fill('This is a brain scan image of the patient');
+ });
+
+ await test.step('And I click on the `Add Attachment` button', async () => {
+ await page.getByRole('button', { name: /add Attachment/i }).click();
+ });
+
+ await test.step('Then I should see a success toast notification', async () => {
+ await expect(page.getByText(/upload complete/i)).toBeVisible();
+ });
+
+ await test.step('When I click on the `Close` button', async () => {
+ await page
+ .locator('button')
+ .filter({ hasText: /^Close$/ })
+ .click();
+ });
+
+ await test.step('Then I should see the file I uploaded displayed in the attachments table', async () => {
+ await expect(page.getByRole('button', { name: /brainScan.jpeg/i })).toBeVisible();
+ });
+
+ await test.step('When I click on the `Table view` tab', async () => {
+ await page.getByLabel(/table view/i).click();
+ });
+
+ await test.step('And I click the overflow menu in the table row of the uploaded file', async () => {
+ await page.getByRole('button', { name: /options/i }).click();
+ });
+
+ await test.step('And I click on the `Delete` button', async () => {
+ await page.getByRole('menuitem', { name: /delete/i }).click();
+ await page.getByRole('button', { name: /delete/i }).click();
+ });
+
+ await test.step('Then I should see a success toast notification', async () => {
+ await expect(page.getByText(/file deleted/i)).toBeVisible();
+ });
+
+ await test.step('And I should not see the deleted attachment in the list', async () => {
+ await expect(page.getByRole('button', { name: /brainScan.jpeg/i })).not.toBeVisible();
+ });
+
+ await test.step('And the attachments table should be empty', async () => {
+ await expect(page.getByText(/There are no attachments to display for this patient/i)).toBeVisible();
+ });
+});
+
+test.afterEach(async ({ api }) => {
+ await deletePatient(api, patient.uuid);
+});
diff --git a/e2e/specs/biometrics.spec.ts b/e2e/specs/biometrics.spec.ts
index a2c9640b10..903b8cf637 100644
--- a/e2e/specs/biometrics.spec.ts
+++ b/e2e/specs/biometrics.spec.ts
@@ -12,25 +12,38 @@ test.beforeEach(async ({ api }) => {
visit = await startVisit(api, patient.uuid);
});
-test('Record biometrics', async ({ page, api }) => {
+test('Record biometrics', async ({ page }) => {
const biometricsPage = new BiometricsAndVitalsPage(page);
await test.step('When I visit the vitals and biometrics page', async () => {
await biometricsPage.goTo(patient.uuid);
});
- await test.step('And I click the `Record biometrics` link to launch the form', async () => {
+ await test.step('And I click on the `Record biometrics` link to launch the form', async () => {
await biometricsPage.page.getByText(/record biometrics/i).click();
});
- await test.step('And then I fill the form', async () => {
+ await test.step('Then I should see the `Record Vitals and Biometrics` form launch in the workspace', async () => {
+ await expect(biometricsPage.page.getByText(/record vitals and biometrics/i)).toBeVisible();
+ });
+
+ await test.step('When I fill `170` as the height', async () => {
await biometricsPage.page.getByRole('spinbutton', { name: /height/i }).fill('170');
+ });
+
+ await test.step('And I fill `65` as the weight', async () => {
await biometricsPage.page.getByRole('spinbutton', { name: /weight/i }).fill('65');
+ });
+
+ await test.step('Then I should see `22.51` as the auto calculated body mass index', async () => {
await expect(biometricsPage.page.getByRole('spinbutton', { name: /bmi/i })).toHaveValue('22.5');
+ });
+
+ await test.step('When I fill `25` as the mid upper arm circumference ', async () => {
await biometricsPage.page.getByRole('spinbutton', { name: /muac/i }).fill('25');
});
- await test.step('And I click the submit button', async () => {
+ await test.step('And I click on the `Save and close` button', async () => {
await biometricsPage.page.getByRole('button', { name: /save and close/i }).click();
});
diff --git a/e2e/specs/clinical-forms.spec.ts b/e2e/specs/clinical-forms.spec.ts
index 0c3342d1d3..ad2c843165 100644
--- a/e2e/specs/clinical-forms.spec.ts
+++ b/e2e/specs/clinical-forms.spec.ts
@@ -43,19 +43,31 @@ test('Fill a clinical form', async ({ page, api }) => {
await expect(chartPage.page.getByRole('cell', { name: /surgical operation/i })).toBeVisible();
});
- await test.step('And if I fill a form', async () => {
+ await test.step('When I click the `Soap note template` link to launch the form', async () => {
await chartPage.page.getByText(/soap note template/i).click();
+ });
- await expect(chartPage.page.getByRole('button', { name: /save and close/i })).toBeVisible();
- await expect(chartPage.page.getByRole('button', { name: /discard/i })).toBeVisible();
+ await test.step('Then I should see the `Soap note template` form launch in the workspace', async () => {
+ await expect(chartPage.page.getByText(/soap note template/i)).toBeVisible();
+ });
+ await test.step('When I fill the `Subjective findings` question', async () => {
await chartPage.page.locator('#SOAPSubjectiveFindingsid').fill(subjectiveFindings);
+ });
+
+ await test.step('And I fill the `Objective findings` question', async () => {
await chartPage.page.locator('#SOAPObjectiveFindingsid').fill(objectiveFindings);
+ });
+
+ await test.step('And I fill the `Assessment` question', async () => {
await chartPage.page.locator('#SOAPAssessmentid').fill(assessment);
+ });
+
+ await test.step('And I fill the `Plan` question', async () => {
await chartPage.page.locator('#SOAPPlanid').fill(plan);
});
- await test.step('And I click the submit button', async () => {
+ await test.step('And I click on the `Save and close` button', async () => {
await chartPage.page.getByRole('button', { name: /save and close/i }).click();
});
diff --git a/e2e/specs/conditions.spec.ts b/e2e/specs/conditions.spec.ts
index 22f1fa3bb8..4fa38171c9 100644
--- a/e2e/specs/conditions.spec.ts
+++ b/e2e/specs/conditions.spec.ts
@@ -9,7 +9,7 @@ test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
});
-test('Record, edit and delete a condition', async ({ page, api }) => {
+test('Record, edit and delete a condition', async ({ page }) => {
const conditionsPage = new ConditionsPage(page);
const headerRow = conditionsPage.conditionsTable().locator('thead > tr');
const dataRow = conditionsPage.conditionsTable().locator('tbody > tr');
@@ -22,14 +22,28 @@ test('Record, edit and delete a condition', async ({ page, api }) => {
await conditionsPage.page.getByText(/record conditions/i).click();
});
- await test.step('And I fill the form', async () => {
+ await test.step('Then I should see the conditions form launch in the workspace', async () => {
+ await expect(conditionsPage.page.getByText(/record a condition/i)).toBeVisible();
+ });
+
+ await test.step('When I search for `Mental status change` in the search box', async () => {
await page.getByPlaceholder(/search conditions/i).fill('mental');
+ });
+
+ await test.step('And I select the condition', async () => {
await page.getByRole('menuitem', { name: 'Mental status change' }).click();
+ });
+
+ await test.step('And I set `10/07/2023` as the onset date', async () => {
await page.getByLabel(/onset date/i).fill('10/07/2023');
await page.getByLabel(/onset date/i).press('Tab');
});
- await test.step('And I save the form', async () => {
+ await test.step('And I set the clinical status to `Active`', async () => {
+ await page.getByText('Active', { exact: true }).check();
+ });
+
+ await test.step('And I click on the `Save & close` button', async () => {
await page.getByRole('button', { name: /save & close/i }).click();
});
@@ -37,7 +51,7 @@ test('Record, edit and delete a condition', async ({ page, api }) => {
await expect(conditionsPage.page.getByText(/condition saved/i)).toBeVisible();
});
- await test.step('And I should see the new condition added to the list', async () => {
+ await test.step('Then I should see the new condition added to the list', async () => {
await expect(headerRow).toContainText(/condition/i);
await expect(headerRow).toContainText(/date of onset/i);
await expect(headerRow).toContainText(/status/i);
@@ -46,20 +60,32 @@ test('Record, edit and delete a condition', async ({ page, api }) => {
await expect(dataRow).toContainText(/active/i);
});
- await test.step('Then if I click on the overflow menu and click the `Edit` button', async () => {
- await expect(conditionsPage.page.getByRole('button', { name: /options/i })).toBeVisible();
- await conditionsPage.page.getByRole('button', { name: /options/i }).click();
- await expect(conditionsPage.page.getByRole('menu', { name: /edit or delete condition/i })).toBeVisible();
+ await test.step('When I click the overflow menu in the table row with the newly created condition', async () => {
+ await conditionsPage.page
+ .getByRole('button', { name: /options/i })
+ .nth(0)
+ .click();
+ });
+
+ await test.step('And I click on the `Edit` button', async () => {
await conditionsPage.page.getByRole('menuitem', { name: /edit/i }).click();
});
- await test.step('And I edit the condition', async () => {
+ await test.step('Then I should see the Conditions form launch in the workspace in edit mode`', async () => {
+ await expect(page.getByRole('cell', { name: /mental status change/i })).toBeVisible();
+ });
+
+ await test.step('When I change the condition status to `Inactive`', async () => {
await page.locator('label').filter({ hasText: 'Inactive' }).click();
- await page.getByLabel(/end date/i).fill('11/07/2023');
- await page.getByLabel(/end date/i).press('Tab');
});
- await test.step('And I save the form', async () => {
+ await test.step('And I change the on onset date to `11/07/2023`', async () => {
+ await page.getByLabel(/onset date/i).clear();
+ await page.getByLabel(/onset date/i).fill('11/07/2023');
+ await page.getByLabel(/onset date/i).press('Tab');
+ });
+
+ await test.step('And I click on the `Save & close` button', async () => {
await page.getByRole('button', { name: /save & close/i }).click();
});
@@ -76,16 +102,15 @@ test('Record, edit and delete a condition', async ({ page, api }) => {
await expect(dataRow).toContainText(/inactive/i);
});
- await test.step('And if I click the overflow menu and then click the `Delete` button', async () => {
- await expect(conditionsPage.page.getByRole('button', { name: /options/i })).toBeVisible();
- await conditionsPage.page.getByRole('button', { name: /options/i }).click();
- await expect(conditionsPage.page.getByRole('menu', { name: /edit or delete condition/i })).toBeVisible();
- await conditionsPage.page.getByRole('menuitem', { name: /delete/i }).click();
-
- await expect(conditionsPage.page.getByRole('heading', { name: /delete condition/i })).toBeVisible();
- await expect(conditionsPage.page.getByText(/are you sure you want to delete this condition/i)).toBeVisible();
- await expect(conditionsPage.page.getByRole('button', { name: /danger delete/i })).toBeVisible();
+ await test.step('When I click the overflow menu in the table row with the updated condition', async () => {
+ await conditionsPage.page
+ .getByRole('button', { name: /options/i })
+ .nth(0)
+ .click();
+ });
+ await test.step('And I click on the `Delete` button', async () => {
+ await conditionsPage.page.getByRole('menuitem', { name: /delete/i }).click();
await page.getByRole('button', { name: /danger delete/i }).click();
});
diff --git a/e2e/specs/drug-orders.spec.ts b/e2e/specs/drug-orders.spec.ts
index f7fd7c76c3..9d19ceb7dc 100644
--- a/e2e/specs/drug-orders.spec.ts
+++ b/e2e/specs/drug-orders.spec.ts
@@ -46,7 +46,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
.click();
});
- await test.step('Then I should be redirected to the drug order form', async () => {
+ await test.step('Then I should see the drug order form launch in the workspace', async () => {
await expect(page.getByText(/order form/i)).toBeVisible();
});
@@ -84,7 +84,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await expect(page.getByText(/new/i)).toBeVisible();
});
- await test.step('When I click on the "Sign and close" button', async () => {
+ await test.step('When I click on the `Sign and close` button', async () => {
await page.getByRole('button', { name: /sign and close/i }).click();
});
@@ -106,7 +106,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await expect(dataRow).toContainText(/indication headache/i);
});
- await test.step('When I click the overflow menu of the created medication', async () => {
+ await test.step('When I click the overflow menu in the table row with the newly created medication', async () => {
await page
.getByRole('button', { name: /options/i })
.nth(0)
@@ -117,7 +117,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await page.getByRole('menuitem', { name: /modify/i }).click();
});
- await test.step('Then I should be redirected to the order form of the created medication`', async () => {
+ await test.step('Then I should see the medication launch in the workspace in edit mode', async () => {
await expect(page.getByText('Aspirin 81mg (81mg)')).toBeVisible();
});
@@ -146,7 +146,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await page.getByLabel(/indication/i).fill('Hypertension');
});
- await test.step('And I click on the "Save Order" button', async () => {
+ await test.step('And I click on the `Save Order` button', async () => {
await page.getByRole('button', { name: /save order/i }).click();
});
@@ -155,7 +155,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await expect(page.getByText(/modify/i)).toBeVisible();
});
- await test.step('When I click on the "Sign and close" button', async () => {
+ await test.step('When I click on the `Sign and close` button', async () => {
await page.getByRole('button', { name: /sign and close/i }).click();
});
@@ -182,7 +182,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await expect(dataRow.nth(0)).toContainText(/indication hypertension/i);
});
- await test.step('When I click the overflow menu of the created medication', async () => {
+ await test.step('When I click the overflow menu in the table row with the updated medication', async () => {
await page
.getByRole('button', { name: /options/i })
.nth(0)
@@ -197,7 +197,7 @@ test('Record, edit and discontinue a drug order', async ({ page }) => {
await expect(page.getByText(/discontinue/i)).toBeVisible();
});
- await test.step('And I save the form', async () => {
+ await test.step('And I click on the `Sign and close` button', async () => {
await page.getByRole('button', { name: /sign and close/i }).click();
});
diff --git a/e2e/specs/immunizations.spec.ts b/e2e/specs/immunizations.spec.ts
new file mode 100644
index 0000000000..ae9fb53b1d
--- /dev/null
+++ b/e2e/specs/immunizations.spec.ts
@@ -0,0 +1,62 @@
+import { expect } from '@playwright/test';
+import { type Visit } from '@openmrs/esm-framework';
+import { generateRandomPatient, type Patient, startVisit, deletePatient } from '../commands';
+import { test } from '../core';
+import { ImmunizationsPage } from '../pages';
+
+let patient: Patient;
+let visit: Visit;
+
+test.beforeEach(async ({ api }) => {
+ patient = await generateRandomPatient(api);
+ visit = await startVisit(api, patient.uuid);
+});
+
+test('Add an immunization', async ({ page }) => {
+ const immunizationsPage = new ImmunizationsPage(page);
+ const headerRow = immunizationsPage.immunizationsTable().locator('thead > tr');
+ const immunizationType = immunizationsPage.immunizationsTable().locator('tbody td:nth-child(2)');
+ const vaccinationDate = immunizationsPage.immunizationsTable().locator('tbody td:nth-child(3)');
+
+ await test.step('When I go to the Immunizations page', async () => {
+ await immunizationsPage.goTo(patient.uuid);
+ });
+
+ await test.step('And I click on the `Record immunizations` link', async () => {
+ await page.getByRole('button', { name: /record immunizations/i }).click();
+ });
+
+ await test.step('Then I should see the Immunization form launch in the workspace', async () => {
+ await expect(page.getByText(/immunization form/i)).toBeVisible();
+ });
+
+ await test.step('When I set `08/03/2024` as the vaccination date', async () => {
+ await page.getByLabel(/vaccination date/i).clear();
+ await page.getByLabel(/vaccination date/i).fill('08/03/2024');
+ await page.getByLabel(/vaccination date/i).press('Tab');
+ });
+
+ await test.step('And I set `Hepatitis B vaccination` as the immunization', async () => {
+ await page.getByRole('combobox', { name: /immunization/i }).click();
+ await page.getByText(/hepatitis b vaccination/i).click();
+ });
+
+ await test.step('And I click on the `Save` button', async () => {
+ await page.getByRole('button', { name: /save/i }).click();
+ });
+
+ await test.step('Then I should see a success toast notification', async () => {
+ await expect(page.getByText(/vaccination saved successfully/i)).toBeVisible();
+ });
+
+ await test.step('And I should see the newly recorded immunization in the list', async () => {
+ await expect(headerRow).toContainText(/vaccine/i);
+ await expect(headerRow).toContainText(/recent vaccination/i);
+ await expect(immunizationType).toContainText(/hepatitis b vaccination/i);
+ await expect(vaccinationDate).toContainText(/mar 8, 2024/i);
+ });
+});
+
+test.afterEach(async ({ api }) => {
+ await deletePatient(api, patient.uuid);
+});
diff --git a/e2e/specs/lab-orders.spec.ts b/e2e/specs/lab-orders.spec.ts
index 7a888d7034..bc95b74332 100644
--- a/e2e/specs/lab-orders.spec.ts
+++ b/e2e/specs/lab-orders.spec.ts
@@ -68,7 +68,7 @@ test('Record, edit and discontinue a lab order', async ({ page }) => {
).toBeVisible();
});
- await test.step('When I launch the overflow menu of the created lab order', async () => {
+ await test.step('When I click the overflow menu in the table row with the newly created lab order', async () => {
await page
.getByRole('button', { name: /options/i })
.nth(0)
@@ -99,7 +99,7 @@ test('Record, edit and discontinue a lab order', async ({ page }) => {
).toBeVisible();
});
- await test.step('When I launch the overflow menu of the created lab order', async () => {
+ await test.step('When I click the overflow menu in the table row with the updated lab order', async () => {
await page
.getByRole('button', { name: /options/i })
.nth(0)
diff --git a/e2e/specs/program-enrollment.spec.ts b/e2e/specs/program-enrollment.spec.ts
index 47938ca227..66404a5efb 100644
--- a/e2e/specs/program-enrollment.spec.ts
+++ b/e2e/specs/program-enrollment.spec.ts
@@ -9,7 +9,7 @@ test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
});
-test('Add and edit a program enrollment', async ({ page, api }) => {
+test('Add and edit a program enrollment', async ({ page }) => {
const programsPage = new ProgramsPage(page);
const headerRow = programsPage.programsTable().locator('thead > tr');
const dataRow = programsPage.programsTable().locator('tbody > tr');
@@ -19,26 +19,39 @@ test('Add and edit a program enrollment', async ({ page, api }) => {
});
await test.step('And I click on the `Record program enrollment` link', async () => {
- await programsPage.page.getByText(/record program enrollment/i).click();
+ await page.getByText(/record program enrollment/i).click();
});
- await test.step('And I record a program enrollment', async () => {
- await programsPage.page.locator('#program').selectOption('64f950e6-1b07-4ac0-8e7e-f3e148f3463f');
- await programsPage.page.locator('#enrollmentDateInput').fill('04/07/2023');
- await programsPage.page.locator('#completionDateInput').fill('05/07/2023');
- await programsPage.page.locator('#completionDateInput').press('Tab');
- await programsPage.page.locator('#location').selectOption('44c3efb0-2583-4c80-a79e-1f756a03c0a1');
+ await test.step('Then I should see the `Record program enrollment` form launch in the workspace', async () => {
+ await expect(page.getByText('Record program enrollment', { exact: true })).toBeVisible();
});
- await test.step('And I click the submit button', async () => {
- await programsPage.page.getByRole('button', { name: /save and close/i }).click();
+ await test.step('When I select the program named `Hiv Care and Treatment`', async () => {
+ await page.locator('#program').selectOption('64f950e6-1b07-4ac0-8e7e-f3e148f3463f');
});
- await test.step('And I should see a success toast notification', async () => {
- await expect(programsPage.page.getByText(/program enrollment saved/i)).toBeVisible();
+ await test.step('And I set `04/07/2023` as the enrollment date', async () => {
+ await page.locator('#enrollmentDateInput').fill('04/07/2023');
});
- await test.step('Then I should see newly recorded program enrollment in the list', async () => {
+ await test.step('And I set `05/07/2023` as the completion date', async () => {
+ await page.locator('#completionDateInput').fill('05/07/2023');
+ await page.locator('#completionDateInput').press('Tab');
+ });
+
+ await test.step('And I select `Outpatient Clinic` as the enrollment location', async () => {
+ await page.locator('#location').selectOption('44c3efb0-2583-4c80-a79e-1f756a03c0a1');
+ });
+
+ await test.step('And I click on the `Save and close` button', async () => {
+ await page.getByRole('button', { name: /save and close/i }).click();
+ });
+
+ await test.step('Then I should see a success toast notification', async () => {
+ await expect(page.getByText(/program enrollment saved/i)).toBeVisible();
+ });
+
+ await test.step('And I should see newly recorded program enrollment in the list', async () => {
await expect(headerRow).toContainText(/active programs/i);
await expect(headerRow).toContainText(/location/i);
await expect(headerRow).toContainText(/date enrolled/i);
@@ -49,31 +62,43 @@ test('Add and edit a program enrollment', async ({ page, api }) => {
await expect(dataRow).toContainText(/outpatient clinic/i);
});
- await test.step('When I click the `Edit` button', async () => {
+ await test.step('When I click on the `Edit` button of the created program', async () => {
await programsPage.editProgramButton().click();
});
- await test.step('And I edit the program enrollment', async () => {
- await programsPage.page.locator('#enrollmentDateInput').clear();
- await programsPage.page.locator('#enrollmentDateInput').fill('03/07/2023');
- await programsPage.page.locator('#completionDateInput').clear();
- await programsPage.page.locator('#completionDateInput').fill('04/07/2023');
- await programsPage.page.locator('#completionDateInput').press('Tab');
- await programsPage.page.locator('#location').selectOption('1ce1b7d4-c865-4178-82b0-5932e51503d6');
+ await test.step('Then I should see the program launch in the workspace in edit mode`', async () => {
+ await expect(page.getByRole('cell', { name: /hiv care and treatment/i })).toBeVisible();
+ });
+
+ await test.step('When I change the enrollment date to `03/07/2023`', async () => {
+ await page.locator('#enrollmentDateInput').clear();
+ await page.locator('#enrollmentDateInput').fill('03/07/2023');
+ });
+
+ await test.step('And I change the completion date to `04/07/2023`', async () => {
+ await page.locator('#completionDateInput').clear();
+ await page.locator('#completionDateInput').fill('04/07/2023');
+ await page.locator('#completionDateInput').press('Tab');
+ });
+
+ await test.step('And I change the enrollment location to `Community Outreach`', async () => {
+ await page.locator('#location').selectOption('1ce1b7d4-c865-4178-82b0-5932e51503d6');
});
- await test.step('And I click the submit button', async () => {
- await programsPage.page.getByRole('button', { name: /save and close/i }).click();
+ await test.step('And I click on the `Save and close` button', async () => {
+ await page.getByRole('button', { name: /save and close/i }).click();
});
- await test.step('And I should see a success toast notification', async () => {
- await expect(programsPage.page.getByText(/program enrollment updated/i)).toBeVisible();
+ await test.step('Then I should see a success toast notification', async () => {
+ await expect(page.getByText(/program enrollment updated/i)).toBeVisible();
});
- await test.step('Then I should see the updated program enrollment in the list', async () => {
+ await test.step('And I should see the updated program enrollment in the list', async () => {
await expect(dataRow).toContainText(/hiv care and treatment/i);
await expect(dataRow).toContainText(/03-Jul-2023/i);
+ await expect(dataRow).not.toContainText(/completed on 05-Jul-2023/i);
await expect(dataRow).toContainText(/completed on 04-Jul-2023/i);
+ await expect(dataRow).not.toContainText(/outpatient clinic/i);
await expect(dataRow).toContainText(/community outreach/i);
});
});
diff --git a/e2e/specs/record-allergy.spec.ts b/e2e/specs/record-allergy.spec.ts
index b10bd6cce4..4198fb64c3 100644
--- a/e2e/specs/record-allergy.spec.ts
+++ b/e2e/specs/record-allergy.spec.ts
@@ -9,7 +9,7 @@ test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
});
-test('Record an allergy', async ({ page, api }) => {
+test('Record an allergy', async ({ page }) => {
const allergiesPage = new PatientAllergiesPage(page);
const headerRow = allergiesPage.allergiesTable().locator('thead > tr');
const dataRow = allergiesPage.allergiesTable().locator('tbody > tr');
@@ -18,19 +18,32 @@ test('Record an allergy', async ({ page, api }) => {
await allergiesPage.goTo(patient.uuid);
});
- await test.step('And I click the `Record allergy intolerance` link to launch the form', async () => {
+ await test.step('And I click on the `Record allergy intolerance` link to launch the form', async () => {
await allergiesPage.page.getByText(/record allergy intolerance/i).click();
});
- await test.step('And I fill the form', async () => {
+ await test.step('Then I should see the record allergy form launch in the workspace', async () => {
+ await expect(page.getByText(/record a new allergy/i)).toBeVisible();
+ });
+
+ await test.step('When I select `ACE inhibitors` as the allergy', async () => {
await allergiesPage.page.getByPlaceholder(/select the allergen/i).click();
await allergiesPage.page.getByText(/ace inhibitors/i).click();
+ });
+
+ await test.step('And I select `Mental status change` as the reaction', async () => {
await allergiesPage.page.getByText(/mental status change/i).click();
+ });
+
+ await test.step('And I select `Mild` as the severity', async () => {
await allergiesPage.page.getByText(/mild/i).click();
+ });
+
+ await test.step('And I write `Test comment` as a comment', async () => {
await allergiesPage.page.locator('#comments').fill('Test comment');
});
- await test.step('And I click the submit button', async () => {
+ await test.step('And I click on the `Save and close` button', async () => {
await allergiesPage.page.getByRole('button', { name: /save and close/i }).click();
});
@@ -44,7 +57,7 @@ test('Record an allergy', async ({ page, api }) => {
await expect(headerRow).toContainText(/reaction/i);
await expect(headerRow).toContainText(/onset date and comments/i);
await expect(dataRow).toContainText(/ace inhibitors/i);
- await expect(dataRow).toContainText(/MILD/i);
+ await expect(dataRow).toContainText(/mild/i);
await expect(dataRow).toContainText(/mental status change/i);
await expect(dataRow).toContainText(/test comment/i);
});
diff --git a/e2e/specs/start-visit.spec.ts b/e2e/specs/visit.spec.ts
similarity index 86%
rename from e2e/specs/start-visit.spec.ts
rename to e2e/specs/visit.spec.ts
index ee09ef68af..fc1d715cbb 100644
--- a/e2e/specs/start-visit.spec.ts
+++ b/e2e/specs/visit.spec.ts
@@ -9,18 +9,18 @@ test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
});
-test('Start a visit', async ({ page, api }) => {
+test('Start and end a visit', async ({ page }) => {
const chartPage = new ChartPage(page);
await test.step('When I visit the chart summary page', async () => {
await chartPage.goTo(patient.uuid);
});
- await test.step('And I click the `Start a visit` button ', async () => {
+ await test.step('And I click on the `Start a visit` button ', async () => {
await chartPage.page.getByRole('button', { name: /start a visit/i }).click();
});
- await test.step('Then I should see the `Start Visit` form in the workspace', async () => {
+ await test.step('Then I should see the `Start Visit` form launch in the workspace', async () => {
await expect(chartPage.page.getByText(/visit start date and time/i)).toBeVisible();
await expect(chartPage.page.getByPlaceholder(/dd\/mm\/yyyy/i)).toBeVisible();
await expect(chartPage.page.getByPlaceholder(/hh\:mm/i)).toBeVisible();
@@ -40,7 +40,7 @@ test('Start a visit', async ({ page, api }) => {
await chartPage.page.getByText(/opd visit/i).click();
});
- await test.step('And I click the `Start Visit` button', async () => {
+ await test.step('And I click on the `Start Visit` button', async () => {
await chartPage.page
.locator('form')
.getByRole('button', { name: /start a visit/i })
@@ -55,7 +55,7 @@ test('Start a visit', async ({ page, api }) => {
await expect(chartPage.page.getByLabel(/active visit/i)).toBeVisible();
});
- await test.step('When I click the `End Visit` button', async () => {
+ await test.step('When I click on the `End Visit` button', async () => {
await chartPage.page.getByRole('button', { name: /end visit/i }).click();
});
@@ -63,7 +63,7 @@ test('Start a visit', async ({ page, api }) => {
await expect(chartPage.page.getByText(/are you sure you want to end this active visit?/i)).toBeVisible();
});
- await test.step('When I click the `End Visit` button to confirm', async () => {
+ await test.step('When I click on the `End Visit` button to confirm', async () => {
await chartPage.page.getByRole('button', { name: 'danger End Visit' }).click();
});
diff --git a/e2e/specs/vitals.spec.ts b/e2e/specs/vitals.spec.ts
index 36e85eaa8f..8a3b572db5 100644
--- a/e2e/specs/vitals.spec.ts
+++ b/e2e/specs/vitals.spec.ts
@@ -12,7 +12,7 @@ test.beforeEach(async ({ api }) => {
visit = await startVisit(api, patient.uuid);
});
-test('Record vital signs', async ({ page, api }) => {
+test('Record vital signs', async ({ page }) => {
const vitalsPage = new BiometricsAndVitalsPage(page);
const headerRow = vitalsPage.vitalsTable().locator('thead > tr');
const dataRow = vitalsPage.vitalsTable().locator('tbody > tr');
@@ -21,21 +21,47 @@ test('Record vital signs', async ({ page, api }) => {
await vitalsPage.goTo(patient.uuid);
});
- await test.step('And I click `Record biometrics` link to launch the form', async () => {
+ await test.step('And I click the `Record biometrics` link to launch the form', async () => {
await vitalsPage.page.getByText(/record vital signs/i).click();
});
- await test.step('And then I fill the form', async () => {
+ await test.step('Then I should see the `Record Vitals and Biometrics` form launch in the workspace', async () => {
+ await expect(vitalsPage.page.getByText(/record vitals and biometrics/i)).toBeVisible();
+ });
+
+ await test.step('When I fill `37` as the temperature', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /temperature/i }).fill('37');
+ });
+
+ await test.step('And I fill `120` as the systolic', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /systolic/i }).fill('120');
+ });
+
+ await test.step('And I fill `100` as the diastolic', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /diastolic/i }).fill('100');
+ });
+
+ await test.step('And I fill `37` as the pulse', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /pulse/i }).fill('65');
+ });
+
+ await test.step('And I fill `37` as the respiration rate', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /respiration rate/i }).fill('16');
+ });
+
+ await test.step('And I fill `37` as the oxygen saturation', async () => {
+ await vitalsPage.page.getByRole('spinbutton', { name: /oxygen saturation/i }).fill('98');
+ });
+
+ await test.step('And I add `37` as the oxygen saturation', async () => {
await vitalsPage.page.getByRole('spinbutton', { name: /oxygen saturation/i }).fill('98');
+ });
+
+ await test.step('And I add additional notes', async () => {
await vitalsPage.page.getByPlaceholder(/type any additional notes here/i).fill('Test notes');
});
- await test.step('And I click the submit button', async () => {
+ await test.step('And I click on the `Save and close` button', async () => {
await vitalsPage.page.getByRole('button', { name: /save and close/i }).click();
});
diff --git a/e2e/support/upload/brainScan.jpeg b/e2e/support/upload/brainScan.jpeg
new file mode 100644
index 0000000000..4a8175c02c
Binary files /dev/null and b/e2e/support/upload/brainScan.jpeg differ
diff --git a/packages/esm-form-entry-app/src/app/form-creation/form-creation.service.ts b/packages/esm-form-entry-app/src/app/form-creation/form-creation.service.ts
index 7a0ecd55bc..78f1e092fa 100644
--- a/packages/esm-form-entry-app/src/app/form-creation/form-creation.service.ts
+++ b/packages/esm-form-entry-app/src/app/form-creation/form-creation.service.ts
@@ -288,6 +288,11 @@ export class FormCreationService {
const question = form.searchNodeByQuestionId(questionId);
question[0]?.control?.setValue(value);
});
+
+ if (encounterDate && preFilledQuestions.hasOwnProperty('encDate') && preFilledQuestions['encDate'] !== null) {
+ encounterDate[0].question.resetValueOnDisable = false;
+ encounterDate[0]?.control?.disable();
+ }
}
}
diff --git a/packages/esm-form-entry-app/src/single-spa-props.ts b/packages/esm-form-entry-app/src/single-spa-props.ts
index 12a6f52627..06ca40fa15 100644
--- a/packages/esm-form-entry-app/src/single-spa-props.ts
+++ b/packages/esm-form-entry-app/src/single-spa-props.ts
@@ -49,7 +49,6 @@ export type SingleSpaProps = AppProps &
VisitProperties &
EncounterProperties &
PatientProperties &
- UIBehavior &
PreFilledQuestions &
ApplicationStatus & {
additionalProps?: any;
diff --git a/packages/esm-patient-appointments-app/README.md b/packages/esm-patient-appointments-app/README.md
deleted file mode 100644
index 5bc1f43118..0000000000
--- a/packages/esm-patient-appointments-app/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# esm-patient-appointments-app
-
-The appointments widget. It provides a tabular overview of the appointments recorded for a patient as well as a form for recording appointments.
-
diff --git a/packages/esm-patient-appointments-app/jest.config.js b/packages/esm-patient-appointments-app/jest.config.js
deleted file mode 100644
index 0352f6214c..0000000000
--- a/packages/esm-patient-appointments-app/jest.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-const rootConfig = require('../../jest.config.js');
-
-module.exports = rootConfig;
diff --git a/packages/esm-patient-appointments-app/package.json b/packages/esm-patient-appointments-app/package.json
deleted file mode 100644
index 8349046cd3..0000000000
--- a/packages/esm-patient-appointments-app/package.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "name": "@openmrs/esm-patient-appointments-app",
- "version": "7.1.0",
- "license": "MPL-2.0",
- "description": "Patient appointments microfrontend for the OpenMRS SPA",
- "browser": "dist/openmrs-esm-patient-appointments-app.js",
- "main": "src/index.ts",
- "source": true,
- "scripts": {
- "start": "openmrs develop",
- "serve": "webpack serve --mode=development",
- "debug": "npm run serve",
- "build": "webpack --mode production --color",
- "analyze": "webpack --mode=production --env analyze=true",
- "lint": "cross-env eslint src --ext tsx,ts --fix --max-warnings=0",
- "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests --color",
- "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
- "coverage": "yarn test --coverage",
- "typescript": "tsc",
- "extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
- },
- "browserslist": [
- "extends browserslist-config-openmrs"
- ],
- "keywords": [
- "openmrs"
- ],
- "homepage": "https://github.com/openmrs/openmrs-esm-patient-chart#readme",
- "publishConfig": {
- "access": "public"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/openmrs/openmrs-esm-patient-chart.git"
- },
- "bugs": {
- "url": "https://github.com/openmrs/openmrs-esm-patient-chart/issues"
- },
- "dependencies": {
- "lodash-es": "^4.17.21"
- },
- "peerDependencies": {
- "@openmrs/esm-framework": "5.x",
- "@openmrs/esm-patient-common-lib": "7.x",
- "dayjs": "1.x",
- "react": "^18.2.0",
- "react-i18next": "11.x",
- "react-router-dom": "6.x",
- "rxjs": "6.x",
- "swr": "2.x"
- },
- "devDependencies": {
- "@openmrs/esm-patient-common-lib": "workspace:*",
- "webpack": "^5.88.2"
- }
-}
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.component.tsx
deleted file mode 100644
index b3b839ae25..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.component.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
-
-import { Layer, OverflowMenu, OverflowMenuItem } from '@carbon/react';
-import { launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
-import { showModal, useLayoutType } from '@openmrs/esm-framework';
-import type { Appointment } from '../types';
-import styles from './appointments-action-menu.scss';
-
-interface appointmentsActionMenuProps {
- appointment: Appointment;
- patientUuid: string;
-}
-
-export const AppointmentsActionMenu = ({ appointment, patientUuid }: appointmentsActionMenuProps) => {
- const { t } = useTranslation();
- const isTablet = useLayoutType() === 'tablet';
-
- const launchEditAppointmentForm = useCallback(
- () =>
- launchPatientWorkspace('appointments-form-workspace', {
- workspaceTitle: t('editAppointment', 'Edit an appointment'),
- appointment,
- context: 'editing',
- }),
- [appointment, t],
- );
-
- const launchCancelAppointmentDialog = () => {
- const dispose = showModal('appointment-cancel-confirmation-dialog', {
- closeCancelModal: () => dispose(),
- appointmentUuid: appointment.uuid,
- patientUuid,
- });
- };
-
- return (
-
-
-
-
-
-
- );
-};
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.scss b/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.scss
deleted file mode 100644
index 2aac4db7c1..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-action-menu.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.layer {
- height: 100%;
-}
-
-.menuItem {
- max-width: none;
-}
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-base.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-base.component.tsx
deleted file mode 100644
index 5f8d62b138..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-base.component.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import React, { useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import dayjs from 'dayjs';
-import { Button, DataTableSkeleton, ContentSwitcher, InlineLoading, Layer, Switch, Tile } from '@carbon/react';
-import { Add } from '@carbon/react/icons';
-import { useLayoutType } from '@openmrs/esm-framework';
-import { CardHeader, EmptyDataIllustration, ErrorState, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
-import { useAppointments } from './appointments.resource';
-import AppointmentsTable from './appointments-table.component';
-import styles from './appointments-base.scss';
-
-interface AppointmentsBaseProps {
- basePath?: string;
- patientUuid: string;
-}
-
-enum AppointmentTypes {
- UPCOMING = 0,
- TODAY = 1,
- PAST = 2,
-}
-
-const AppointmentsBase: React.FC = ({ patientUuid }) => {
- const { t } = useTranslation();
- const headerTitle = t('appointments', 'Appointments');
- const isTablet = useLayoutType() === 'tablet';
-
- const [switchedView, setSwitchedView] = useState(false);
-
- const [contentSwitcherValue, setContentSwitcherValue] = useState(0);
- const startDate = dayjs(new Date().toISOString()).subtract(6, 'month').toISOString();
- const {
- data: appointmentsData,
- isError,
- isLoading,
- isValidating,
- } = useAppointments(patientUuid, startDate, new AbortController());
-
- const launchAppointmentsForm = () => launchPatientWorkspace('appointments-form-workspace');
-
- if (isLoading) return ;
- if (isError) {
- return ;
- }
- if (Object.keys(appointmentsData)?.length) {
- return (
-
-
- {isValidating ? (
-
-
-
- ) : null}
-
-
{
- setContentSwitcherValue(index);
- setSwitchedView(true);
- }}
- >
-
-
-
-
-
|
-
-
-
- {(() => {
- if (contentSwitcherValue === AppointmentTypes.UPCOMING) {
- if (appointmentsData.upcomingAppointments?.length) {
- return (
-
- );
- }
- return (
-
-
-
-
- {t(
- 'noUpcomingAppointmentsForPatient',
- 'There are no upcoming appointments to display for this patient',
- )}
-
-
-
- );
- }
- if (contentSwitcherValue === AppointmentTypes.TODAY) {
- if (appointmentsData.todaysAppointments?.length) {
- return (
-
- );
- }
- return (
-
-
-
-
- {t(
- 'noCurrentAppointments',
- 'There are no appointments scheduled for today to display for this patient',
- )}
-
-
-
- );
- }
-
- if (contentSwitcherValue === AppointmentTypes.PAST) {
- if (appointmentsData.pastAppointments?.length) {
- return (
-
- );
- }
- return (
-
-
-
-
- {t('noPastAppointments', 'There are no past appointments to display for this patient')}
-
-
-
- );
- }
- })()}
-
- );
- }
-};
-
-export default AppointmentsBase;
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-base.scss b/packages/esm-patient-appointments-app/src/appointments/appointments-base.scss
deleted file mode 100644
index 307c3a490c..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-base.scss
+++ /dev/null
@@ -1,83 +0,0 @@
-@use '@carbon/colors';
-@use '@carbon/styles/scss/spacing';
-@use '@carbon/styles/scss/type';
-@import '@openmrs/esm-styleguide/src/vars';
-
-// TO DO Move this styles to style - guide
-// https://github.com/openmrs/openmrs-esm-core/blob/master/packages/framework/esm-styleguide/src/_vars.scss
-$color-blue-30 : #a6c8ff;
-$color-blue-10: #edf5ff;
-
-.widgetCard {
- border: 1px solid $ui-03;
-}
-
-.productiveHeading01 {
- @include type.type-style("heading-compact-01");
-}
-
-.contentSwitcherWrapper {
- display: flex;
- width: fit-content;
- justify-content: flex-end;
- align-items: center;
- width: 60%;
-}
-
-.contentSwitcherWrapper > div > button {
- background-color: $ui-02;
-}
-
-.contentSwitcherWrapper > div button:first-child {
- border-top: 1px solid $color-blue-30;
- border-bottom: 1px solid $color-blue-30;
- border-left: 1px solid $color-blue-30;
- border-right: none;
- border-radius: spacing.$spacing-02 0 0px spacing.$spacing-02;
-}
-
-.contentSwitcherWrapper > div button:last-child {
- border-top: 1px solid $color-blue-30;
- border-bottom: 1px solid $color-blue-30;
- border-right: 1px solid $color-blue-30;
- border-left: none;
- border-radius: 0px spacing.$spacing-02 spacing.$spacing-02 0px;
-}
-
-.contentSwitcherWrapper > div > button[aria-selected=true],
-.contentSwitcherWrapper > div > button[aria-selected=true]:first-child {
- background-color: $color-blue-10;
- color: $color-blue-60-2;
- border-color: $color-blue-60-2;
- border-right: 1px solid $color-blue-60-2;
-}
-
-.contentSwitcherWrapper > div > button[aria-selected=true],
-.contentSwitcherWrapper > div > button[aria-selected=true]:last-child {
- background-color: $color-blue-10;
- color: $color-blue-60-2;
- border-color: $color-blue-60-2;
- border-left: 1px solid $color-blue-60-2;
-}
-
-.contentSwitcherWrapper > div > button[aria-selected=true]:focus {
- box-shadow: none;
-}
-
-.divider {
- width: 1px;
- height: spacing.$spacing-05;
- color: colors.$gray-20;
- margin: 0 spacing.$spacing-05;
-}
-
-.content {
- @include type.type-style("heading-compact-01");
- color: $text-02;
- margin-top: spacing.$spacing-05;
- margin-bottom: spacing.$spacing-03;
-}
-
-.tile {
- text-align: center;
-}
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-base.test.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-base.test.tsx
deleted file mode 100644
index e8aff24abb..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-base.test.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-import React from 'react';
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { openmrsFetch, usePagination } from '@openmrs/esm-framework';
-import { mockAppointmentsData } from '__mocks__';
-import { mockPatient, patientChartBasePath, renderWithSwr, waitForLoadingToFinish } from 'tools';
-import AppointmentsBase from './appointments-base.component';
-
-const testProps = {
- basePath: patientChartBasePath,
- patientUuid: mockPatient.id,
-};
-
-const mockOpenmrsFetch = openmrsFetch as jest.Mock;
-const mockUsePagination = usePagination as jest.Mock;
-
-jest.mock('@openmrs/esm-framework', () => {
- const originalModule = jest.requireActual('@openmrs/esm-framework');
-
- return {
- ...originalModule,
- usePagination: jest.fn().mockImplementation(() => ({
- currentPage: 1,
- goTo: () => {},
- results: [],
- })),
- };
-});
-
-describe('AppointmensOverview', () => {
- it('renders an empty state if appointments data is unavailable', async () => {
- mockOpenmrsFetch.mockReturnValueOnce({ data: [] });
-
- renderAppointments();
-
- await waitForLoadingToFinish();
-
- expect(screen.getByRole('heading', { name: /appointments/i })).toBeInTheDocument();
- expect(screen.getByRole('button', { name: /add/i })).toBeInTheDocument();
- });
-
- it('renders an error state if there was a problem fetching appointments data', async () => {
- const user = userEvent.setup();
-
- const error = {
- message: 'Internal server error',
- response: {
- status: 500,
- statusText: 'Internal server error',
- },
- };
-
- mockOpenmrsFetch.mockRejectedValueOnce(error);
-
- renderAppointments();
-
- await waitForLoadingToFinish();
-
- expect(screen.getByRole('heading', { name: /appointments/i })).toBeInTheDocument();
- expect(
- screen.getByText(
- 'Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.',
- ),
- ).toBeInTheDocument();
- });
-
- it(`renders a tabular overview of the patient's appointment schedule if available`, async () => {
- const user = userEvent.setup();
-
- mockOpenmrsFetch.mockReturnValueOnce(mockAppointmentsData);
- mockUsePagination.mockImplementation(() => ({
- currentPage: 1,
- goTo: () => {},
- results: mockAppointmentsData.data,
- }));
-
- renderAppointments();
-
- await waitForLoadingToFinish();
-
- expect(screen.getByRole('heading', { name: /appointments/i })).toBeInTheDocument();
- expect(screen.getByRole('button', { name: /add/i })).toBeInTheDocument();
-
- const upcomingAppointmentsTab = screen.getByRole('tab', { name: /upcoming/i });
- const pastAppointmentsTab = screen.getByRole('tab', { name: /past/i });
-
- expect(screen.getByRole('tablist')).toContainElement(upcomingAppointmentsTab);
- expect(screen.getByRole('tablist')).toContainElement(pastAppointmentsTab);
- expect(screen.getByTitle(/Empty data illustration/i)).toBeInTheDocument();
- expect(screen.getByText(/There are no upcoming appointments to display for this patient/i)).toBeInTheDocument();
-
- await user.click(pastAppointmentsTab);
- expect(screen.getByRole('table')).toBeInTheDocument();
-
- const expectedColumnHeaders = [/date/, /location/, /service/];
- expectedColumnHeaders.forEach((header) => {
- expect(screen.getByRole('columnheader', { name: new RegExp(header, 'i') })).toBeInTheDocument();
- });
-
- expect(screen.getAllByRole('row').length).toEqual(13);
-
- const previousPageButton = screen.getByRole('button', { name: /previous page/i });
- const nextPageButton = screen.getByRole('button', { name: /next page/i });
-
- expect(previousPageButton).toBeDisabled();
- expect(nextPageButton).not.toBeDisabled();
- });
-});
-
-function renderAppointments() {
- renderWithSwr();
-}
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-cancel-modal.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-cancel-modal.component.tsx
deleted file mode 100644
index 6e99f04967..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-cancel-modal.component.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import React, { useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
-import { showSnackbar } from '@openmrs/esm-framework';
-import { cancelAppointment, useAppointments } from './appointments.resource';
-
-interface CancelAppointmentModalProps {
- closeCancelModal: () => void;
- appointmentUuid: string;
- patientUuid: string;
-}
-
-const CancelAppointmentModal: React.FC = ({
- closeCancelModal,
- appointmentUuid,
- patientUuid,
-}) => {
- const { t } = useTranslation();
- const { mutate } = useAppointments(patientUuid, new Date().toUTCString(), new AbortController());
- const [isSubmitting, setIsSubmitting] = useState(false);
-
- const handleCancel = async () => {
- setIsSubmitting(true);
-
- cancelAppointment('Cancelled', appointmentUuid)
- .then(({ status }) => {
- if (status === 200) {
- mutate();
- closeCancelModal();
- showSnackbar({
- isLowContrast: true,
- kind: 'success',
- subtitle: t('appointmentCancelledSuccessfully', 'Appointment cancelled successfully'),
- title: t('appointmentCancelled', 'Appointment cancelled'),
- });
- }
- })
- .catch((err) => {
- showSnackbar({
- title: t('appointmentCancelError', 'Error cancelling appointment'),
- kind: 'error',
- isLowContrast: true,
- subtitle: err?.message,
- });
- });
- };
-
- return (
-
-
-
- {t('cancelAppointmentModalConfirmationText', 'Are you sure you want to cancel this appointment?')}
-
-
-
-
-
-
- );
-};
-
-export default CancelAppointmentModal;
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-detailed-summary.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-detailed-summary.component.tsx
deleted file mode 100644
index 6734b61f7a..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-detailed-summary.component.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import AppointmentBase from './appointments-base.component';
-
-interface AppointmentsDetailedSummaryProps {
- patientUuid: string;
-}
-
-const AppointmentsDetailedSummary: React.FC = ({ patientUuid }) => {
- return ;
-};
-
-export default AppointmentsDetailedSummary;
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-overview.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-overview.component.tsx
deleted file mode 100644
index 30f7ed768e..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-overview.component.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import AppointmentsBase from './appointments-base.component';
-
-interface AppointmentOverviewProps {
- basePath: string;
- patientUuid: string;
-}
-
-const AppointmentsOverview: React.FC = ({ patientUuid }) => (
-
-);
-
-export default AppointmentsOverview;
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-table.component.tsx b/packages/esm-patient-appointments-app/src/appointments/appointments-table.component.tsx
deleted file mode 100644
index 243de1bb77..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments-table.component.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import React, { useEffect, useMemo } from 'react';
-import classNames from 'classnames';
-import dayjs from 'dayjs';
-const utc = require('dayjs/plugin/utc');
-dayjs.extend(utc);
-import { useTranslation } from 'react-i18next';
-import {
- DataTable,
- type DataTableHeader,
- Table,
- TableCell,
- TableContainer,
- TableBody,
- TableHead,
- TableHeader,
- TableRow,
-} from '@carbon/react';
-import { PatientChartPagination } from '@openmrs/esm-patient-common-lib';
-import { formatDatetime, parseDate, useLayoutType, usePagination } from '@openmrs/esm-framework';
-import { type Appointment } from '../types';
-import { AppointmentsActionMenu } from './appointments-action-menu.component';
-import styles from './appointments-table.scss';
-
-const pageSize = 10;
-
-interface AppointmentTableProps {
- patientAppointments: Array;
- switchedView: boolean;
- setSwitchedView: (value: boolean) => void;
- patientUuid: string;
-}
-
-const AppointmentsTable: React.FC = ({
- patientAppointments,
- patientUuid,
- switchedView,
- setSwitchedView,
-}) => {
- const { t } = useTranslation();
- const { results: paginatedAppointments, currentPage, goTo } = usePagination(patientAppointments, pageSize);
- const isTablet = useLayoutType() === 'tablet';
-
- useEffect(() => {
- if (switchedView && currentPage !== 1) {
- goTo(1);
- }
- }, [switchedView, goTo, currentPage]);
-
- const tableHeaders: Array = useMemo(
- () => [
- { key: 'date', header: t('date', 'Date') },
- { key: 'location', header: t('location', 'Location') },
- { key: 'service', header: t('service', 'Service') },
- { key: 'status', header: t('status', 'Status') },
- { key: 'type', header: t('type', 'Type') },
- { key: 'notes', header: t('notes', 'Notes') },
- ],
- [t],
- );
-
- const tableRows = useMemo(
- () =>
- paginatedAppointments?.map((appointment) => {
- return {
- id: appointment.uuid,
- date: formatDatetime(parseDate(appointment.startDateTime), { mode: 'wide' }),
- location: appointment?.location?.name ? appointment?.location?.name : '——',
- service: appointment.service.name,
- status: appointment.status,
- type: appointment.appointmentKind ? appointment.appointmentKind : '——',
- notes: appointment.comments ? appointment.comments : '——',
- };
- }),
- [paginatedAppointments],
- );
-
- return (
-
-
- {({ rows, headers, getHeaderProps, getTableProps }) => (
-
-
-
-
- {headers.map((header) => (
-
- {header.header?.content ?? header.header}
-
- ))}
-
-
-
-
- {rows.map((row, i) => (
-
- {row.cells.map((cell) => (
- {cell.value?.content ?? cell.value}
- ))}
-
-
-
-
- ))}
-
-
-
- )}
-
-
{
- setSwitchedView(false);
- goTo(page);
- }}
- pageNumber={currentPage}
- pageSize={pageSize}
- />
-
- );
-};
-
-export default AppointmentsTable;
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments-table.scss b/packages/esm-patient-appointments-app/src/appointments/appointments-table.scss
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/packages/esm-patient-appointments-app/src/appointments/appointments.resource.ts b/packages/esm-patient-appointments-app/src/appointments/appointments.resource.ts
deleted file mode 100644
index 79f45c0386..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/appointments.resource.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import dayjs from 'dayjs';
-import useSWR from 'swr';
-import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
-import { type AppointmentsFetchResponse } from '../types';
-import isToday from 'dayjs/plugin/isToday';
-dayjs.extend(isToday);
-
-const appointmentsSearchUrl = `${restBaseUrl}/appointments/search`;
-
-export function useAppointments(patientUuid: string, startDate: string, abortController: AbortController) {
- /*
- SWR isn't meant to make POST requests for data fetching. This is a consequence of the API only exposing this resource via POST.
- This works but likely isn't recommended.
- */
- const fetcher = () =>
- openmrsFetch(appointmentsSearchUrl, {
- method: 'POST',
- signal: abortController.signal,
- headers: {
- 'Content-Type': 'application/json',
- },
- body: {
- patientUuid: patientUuid,
- startDate: startDate,
- },
- });
-
- const { data, error, isLoading, isValidating, mutate } = useSWR(
- appointmentsSearchUrl,
- fetcher,
- );
-
- const appointments = data?.data?.length ? data.data : null;
-
- const pastAppointments = appointments
- ?.sort((a, b) => (b.startDateTime > a.startDateTime ? 1 : -1))
- ?.filter(({ status }) => status !== 'Cancelled')
- ?.filter(({ startDateTime }) =>
- dayjs(new Date(startDateTime).toISOString()).isBefore(new Date().setHours(0, 0, 0, 0)),
- );
-
- const upcomingAppointments = appointments
- ?.sort((a, b) => (a.startDateTime > b.startDateTime ? 1 : -1))
- ?.filter(({ status }) => status !== 'Cancelled')
- ?.filter(({ startDateTime }) => dayjs(new Date(startDateTime).toISOString()).isAfter(new Date()));
-
- const todaysAppointments = appointments
- ?.sort((a, b) => (a.startDateTime > b.startDateTime ? 1 : -1))
- ?.filter(({ status }) => status !== 'Cancelled')
- ?.filter(({ startDateTime }) => dayjs(new Date(startDateTime).toISOString()).isToday());
-
- return {
- data: data ? { pastAppointments, upcomingAppointments, todaysAppointments } : null,
- isError: error,
- isLoading,
- isValidating,
- mutate,
- };
-}
-
-export const cancelAppointment = async (toStatus: string, appointmentUuid: string) => {
- const omrsDateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZZ';
- const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
- const statusChangeTime = dayjs(new Date()).format(omrsDateFormat);
- const url = `${restBaseUrl}/appointments/${appointmentUuid}/status-change`;
- return await openmrsFetch(url, {
- body: { toStatus, onDate: statusChangeTime, timeZone: timeZone },
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- });
-};
diff --git a/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.component.tsx b/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.component.tsx
deleted file mode 100644
index 7b78ee6c84..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.component.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import React, { useEffect, useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import isEmpty from 'lodash-es/isEmpty';
-
-import {
- Checkbox,
- InlineLoading,
- InlineNotification,
- StructuredListHead,
- StructuredListCell,
- StructuredListRow,
- StructuredListBody,
- StructuredListWrapper,
-} from '@carbon/react';
-import { formatDate, parseDate } from '@openmrs/esm-framework';
-import { useAppointments } from './appointments.resource';
-import { ErrorState } from '@openmrs/esm-patient-common-lib';
-
-import styles from './upcoming-appointments-card.scss';
-import dayjs from 'dayjs';
-interface UpcomingAppointmentsProps {
- patientUuid: string;
- setUpcomingAppointment: (value: any) => void;
-}
-
-const UpcomingAppointmentsCard: React.FC = ({ patientUuid, setUpcomingAppointment }) => {
- const { t } = useTranslation();
- const startDate = dayjs(new Date().toISOString()).subtract(6, 'month').toISOString();
- const headerTitle = t('upcomingAppointments', 'Upcoming appointments');
-
- const ac = useMemo(() => new AbortController(), []);
- useEffect(() => () => ac.abort(), [ac]);
- const { data: appointmentsData, isError, isLoading } = useAppointments(patientUuid, startDate, ac);
-
- const todaysAppointments = appointmentsData?.todaysAppointments?.length ? appointmentsData?.todaysAppointments : [];
- const futureAppointments = appointmentsData?.upcomingAppointments?.length
- ? appointmentsData?.upcomingAppointments
- : [];
- const appointments = todaysAppointments.concat(futureAppointments);
- const upcomingAppointment = !isEmpty(appointments)
- ? appointments?.filter(({ dateHonored }) => dateHonored === null)
- : [];
- if (isError) {
- return ;
- }
- if (isLoading) {
-
-
- ;
- }
-
- if (upcomingAppointment?.length) {
- const structuredListBodyRowGenerator = () => {
- return upcomingAppointment.map((appointment, i) => (
-
- {formatDate(parseDate(appointment.startDateTime), { mode: 'wide' })}
- {appointment.service ? appointment.service.name : '——'}
-
- (e.target.checked ? setUpcomingAppointment(appointment) : '')}
- />
-
-
- ));
- };
-
- return (
-
-
-
{headerTitle}
-
- {t('appointmentToFulfill', 'Select appointment(s) to fulfill')}
- {' '}
-
-
-
-
-
- {t('date', 'Date')}
- {t('appointmentType', 'Appointment type')}
- {t('action', 'Action')}
-
-
- {structuredListBodyRowGenerator()}
-
-
- );
- }
- return (
-
- );
-};
-
-export default UpcomingAppointmentsCard;
diff --git a/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.scss b/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.scss
deleted file mode 100644
index b9b3c7bcb8..0000000000
--- a/packages/esm-patient-appointments-app/src/appointments/upcoming-appointments-card.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-@use '@carbon/styles/scss/spacing';
-@use '@carbon/styles/scss/type';
-@import '@openmrs/esm-styleguide/src/vars';
-
-.container {
- margin: spacing.$spacing-05;
-
- & section {
- margin: spacing.$spacing-05 0;
- }
-}
-
-.sectionTitle {
- @include type.type-style("heading-compact-02");
- color: $text-02;
- margin: 0 0 spacing.$spacing-03 0;
-}
-.checkbox {
- &:not(:first-child) {
- margin: 0rem 0rem;
- }
- }
-
- .input {
- margin: 0rem 1rem 1rem;
- }
-
- .headerLabel {
- @include type.type-style('label-01');
- color: $text-02;
- }
-
- .checkboxContainer {
- display: grid;
- grid-template-columns: 1fr 1fr;
- }
-
- .structuredList {
- padding: 0.5rem 0.5rem 0.5rem;
-
- }
-
- .inlineNotification {
- width: 100%;
- max-width: unset;
- padding: '0rem';
- }
diff --git a/packages/esm-patient-appointments-app/src/constants.ts b/packages/esm-patient-appointments-app/src/constants.ts
deleted file mode 100644
index e4243ac16a..0000000000
--- a/packages/esm-patient-appointments-app/src/constants.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const dateFormat = 'DD/MM/YYYY';
diff --git a/packages/esm-patient-appointments-app/src/dashboard.meta.ts b/packages/esm-patient-appointments-app/src/dashboard.meta.ts
deleted file mode 100644
index fcd7822f17..0000000000
--- a/packages/esm-patient-appointments-app/src/dashboard.meta.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export const dashboardMeta = {
- slot: 'patient-chart-appointments-dashboard-slot',
- columns: 1,
- title: 'Appointments',
- path: 'Appointments',
-};
diff --git a/packages/esm-patient-appointments-app/src/declarations.d.ts b/packages/esm-patient-appointments-app/src/declarations.d.ts
deleted file mode 100644
index b2f3aa3b21..0000000000
--- a/packages/esm-patient-appointments-app/src/declarations.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-declare module '*.css';
-declare module '*.scss';
-declare module '*.png';
diff --git a/packages/esm-patient-appointments-app/src/index.ts b/packages/esm-patient-appointments-app/src/index.ts
deleted file mode 100644
index aa147fcbab..0000000000
--- a/packages/esm-patient-appointments-app/src/index.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle, translateFrom } from '@openmrs/esm-framework';
-import { createDashboardLink, registerWorkspace } from '@openmrs/esm-patient-common-lib';
-import { dashboardMeta } from './dashboard.meta';
-import appointmentsOverviewComponent from './appointments/appointments-overview.component';
-import appointmentsDetailedSummaryComponent from './appointments/appointments-detailed-summary.component';
-import upcomingAppointmentsWidgetComponent from './appointments/upcoming-appointments-card.component';
-
-export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
-
-const moduleName = '@openmrs/esm-patient-appointments-app';
-
-const options = {
- featureName: 'patient-appointments',
- moduleName,
-};
-
-export function startupApp() {
- defineConfigSchema(moduleName, {});
-}
-
-export const appointmentsOverview = getSyncLifecycle(appointmentsOverviewComponent, options);
-
-export const appointmentsDetailedSummary = getSyncLifecycle(appointmentsDetailedSummaryComponent, options);
-
-// t('Appointments', 'Appointments')
-export const appointmentsSummaryDashboardLink = getSyncLifecycle(
- createDashboardLink({ ...dashboardMeta, moduleName }),
- options,
-);
-
-export const appointmentsCancelConfirmationDialog = getAsyncLifecycle(
- () => import('./appointments/appointments-cancel-modal.component'),
- options,
-);
-
-export const upcomingAppointmentsWidget = getSyncLifecycle(upcomingAppointmentsWidgetComponent, options);
diff --git a/packages/esm-patient-appointments-app/src/routes.json b/packages/esm-patient-appointments-app/src/routes.json
deleted file mode 100644
index 02f9cce474..0000000000
--- a/packages/esm-patient-appointments-app/src/routes.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "$schema": "https://json.openmrs.org/routes.schema.json",
- "backendDependencies": {
- "webservices.rest": "^2.2.0"
- },
- "extensions": [
- {
- "name": "appointments-overview-widget",
- "component": "appointmentsOverview",
- "order": 8,
- "meta": {
- "columnSpan": 4
- }
- },
- {
- "name": "appointments-details-widget",
- "component": "appointmentsDetailedSummary",
- "slot": "patient-chart-appointments-dashboard-slot",
- "meta": {
- "columnSpan": 1
- }
- },
- {
- "name": "appointments-summary-dashboard",
- "component": "appointmentsSummaryDashboardLink",
- "slot": "patient-chart-dashboard-slot",
- "order": 11,
- "meta": {
- "columns": 1,
- "columnSpan": 1,
- "slot": "patient-chart-appointments-dashboard-slot",
- "title": "Appointments",
- "path": "Appointments"
- }
- },
- {
- "name": "appointment-cancel-confirmation-dialog",
- "component": "appointmentsCancelConfirmationDialog"
- },
- {
- "name": "upcoming-appointment-widget",
- "component": "upcomingAppointmentsWidget",
- "slot": "upcoming-appointment-slot"
- }
- ],
- "pages": []
-}
diff --git a/packages/esm-patient-appointments-app/src/types/index.ts b/packages/esm-patient-appointments-app/src/types/index.ts
deleted file mode 100644
index 13ad9918ee..0000000000
--- a/packages/esm-patient-appointments-app/src/types/index.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import type { OpenmrsResource } from '@openmrs/esm-framework';
-
-export interface AppointmentsFetchResponse {
- data: Array;
-}
-
-export interface Appointment {
- appointmentKind: string;
- appointmentNumber: string;
- comments: string;
- endDateTime: Date | number;
- location: OpenmrsResource;
- patient: fhir.Patient;
- provider: OpenmrsResource;
- providers: Array;
- recurring: boolean;
- service: AppointmentService;
- startDateTime: string;
- status: string;
- dateHonored: Date | number;
- uuid: string;
-}
-
-export interface ServiceTypes {
- duration: number;
- name: string;
- uuid: string;
-}
-
-export interface AppointmentService {
- appointmentServiceId: number;
- color: string;
- creatorName: string;
- description: string;
- durationMins: number;
- endTime: string;
- initialAppointmentStatus: string;
- location: OpenmrsResource;
- maxAppointmentsLimit: number | null;
- name: string;
- speciality: OpenmrsResource;
- startTime: string;
- uuid: string;
- serviceTypes: Array;
-}
diff --git a/packages/esm-patient-appointments-app/translations/am.json b/packages/esm-patient-appointments-app/translations/am.json
deleted file mode 100644
index b2488a10c6..0000000000
--- a/packages/esm-patient-appointments-app/translations/am.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "Action",
- "add": "Add",
- "appointmentCancelError": "Error cancelling appointment",
- "appointmentCancelled": "Appointment cancelled",
- "appointmentCancelledSuccessfully": "Appointment cancelled successfully",
- "appointments": "Appointments",
- "Appointments": "Appointments",
- "appointmentToFulfill": "Select appointment(s) to fulfill",
- "appointmentType": "Appointment type",
- "appointmentType_title": "Appointment Type",
- "cancel": "Cancel",
- "cancelAppointment": "Cancel appointment",
- "cancelAppointmentModalConfirmationText": "Are you sure you want to cancel this appointment?",
- "date": "Date",
- "discard": "Discard",
- "edit": "Edit",
- "editAppointment": "Edit an appointment",
- "location": "Location",
- "noCurrentAppointments": "There are no appointments scheduled for today to display for this patient",
- "noPastAppointments": "There are no past appointments to display for this patient",
- "notes": "Notes",
- "noUpcomingAppointments": "No upcoming appointments found",
- "noUpcomingAppointmentsForPatient": "There are no upcoming appointments to display for this patient",
- "past": "Past",
- "service": "Service",
- "status": "Status",
- "today": "Today",
- "type": "Type",
- "upcoming": "Upcoming",
- "upcomingAppointments": "Upcoming appointments"
-}
diff --git a/packages/esm-patient-appointments-app/translations/ar.json b/packages/esm-patient-appointments-app/translations/ar.json
deleted file mode 100644
index f4cded43a2..0000000000
--- a/packages/esm-patient-appointments-app/translations/ar.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "الإجراء",
- "add": "أضف",
- "appointmentCancelError": "خطأ في إلغاء الموعد",
- "appointmentCancelled": "تم إلغاء الموعد",
- "appointmentCancelledSuccessfully": "تم إلغاء الموعد بنجاح",
- "appointments": "المواعيد",
- "Appointments": "المواعيد",
- "appointmentToFulfill": "حدد الموعد/المواعيد لتنفيذه",
- "appointmentType": "نوع الموعد",
- "appointmentType_title": "نوع الموعد",
- "cancel": "إلغاء",
- "cancelAppointment": "إلغاء الموعد",
- "cancelAppointmentModalConfirmationText": "هل أنت متأكد أنك تريد إلغاء هذا الموعد؟",
- "date": "التاريخ",
- "discard": "تجاهل",
- "edit": "تعديل",
- "editAppointment": "تعديل الموعد",
- "location": "الموقع",
- "noCurrentAppointments": "لا توجد مواعيد مجدولة لهذا المريض اليوم",
- "noPastAppointments": "لا توجد مواعيد سابقة لعرضها لهذا المريض",
- "notes": "الملاحظات",
- "noUpcomingAppointments": "لم يتم العثور على مواعيد قادمة",
- "noUpcomingAppointmentsForPatient": "لا توجد مواعيد قادمة لعرضها لهذا المريض",
- "past": "الماضي",
- "service": "الخدمة",
- "status": "الحالة",
- "today": "اليوم",
- "type": "النوع",
- "upcoming": "القادمة",
- "upcomingAppointments": "المواعيد القادمة"
-}
diff --git a/packages/esm-patient-appointments-app/translations/en.json b/packages/esm-patient-appointments-app/translations/en.json
deleted file mode 100644
index b2488a10c6..0000000000
--- a/packages/esm-patient-appointments-app/translations/en.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "Action",
- "add": "Add",
- "appointmentCancelError": "Error cancelling appointment",
- "appointmentCancelled": "Appointment cancelled",
- "appointmentCancelledSuccessfully": "Appointment cancelled successfully",
- "appointments": "Appointments",
- "Appointments": "Appointments",
- "appointmentToFulfill": "Select appointment(s) to fulfill",
- "appointmentType": "Appointment type",
- "appointmentType_title": "Appointment Type",
- "cancel": "Cancel",
- "cancelAppointment": "Cancel appointment",
- "cancelAppointmentModalConfirmationText": "Are you sure you want to cancel this appointment?",
- "date": "Date",
- "discard": "Discard",
- "edit": "Edit",
- "editAppointment": "Edit an appointment",
- "location": "Location",
- "noCurrentAppointments": "There are no appointments scheduled for today to display for this patient",
- "noPastAppointments": "There are no past appointments to display for this patient",
- "notes": "Notes",
- "noUpcomingAppointments": "No upcoming appointments found",
- "noUpcomingAppointmentsForPatient": "There are no upcoming appointments to display for this patient",
- "past": "Past",
- "service": "Service",
- "status": "Status",
- "today": "Today",
- "type": "Type",
- "upcoming": "Upcoming",
- "upcomingAppointments": "Upcoming appointments"
-}
diff --git a/packages/esm-patient-appointments-app/translations/es.json b/packages/esm-patient-appointments-app/translations/es.json
deleted file mode 100644
index a4e8573f26..0000000000
--- a/packages/esm-patient-appointments-app/translations/es.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "Acción",
- "add": "Añadir",
- "appointmentCancelError": "Error al cancelar la cita",
- "appointmentCancelled": "Cita cancelada",
- "appointmentCancelledSuccessfully": "Cita cancelada con éxito",
- "appointments": "Citas",
- "Appointments": "Citas",
- "appointmentToFulfill": "Seleccionar cita(s) para cumplir",
- "appointmentType": "Tipo de cita",
- "appointmentType_title": "Tipo de cita",
- "cancel": "Cancelar",
- "cancelAppointment": "Cancelar cita",
- "cancelAppointmentModalConfirmationText": "¿Está seguro de que desea cancelar esta cita?",
- "date": "Fecha",
- "discard": "Descartar",
- "edit": "Editar",
- "editAppointment": "Editar una cita",
- "location": "Ubicación",
- "noCurrentAppointments": "No hay citas programadas que mostrar para hoy para este paciente",
- "noPastAppointments": "No hay citas anteriores para mostrar para este paciente",
- "notes": "Apuntes",
- "noUpcomingAppointments": "No hay próximas citas para mostrar para este paciente",
- "noUpcomingAppointmentsForPatient": "No hay próximas citas para mostrar para este paciente",
- "past": "Anterior",
- "service": "Servicio",
- "status": "Estado",
- "today": "Hoy",
- "type": "Tipo",
- "upcoming": "Próximo/a",
- "upcomingAppointments": "Próximas citas"
-}
diff --git a/packages/esm-patient-appointments-app/translations/fr.json b/packages/esm-patient-appointments-app/translations/fr.json
deleted file mode 100644
index 2d2ceda958..0000000000
--- a/packages/esm-patient-appointments-app/translations/fr.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "Action",
- "add": "Ajouter",
- "appointmentCancelError": "Error cancelling appointment",
- "appointmentCancelled": "Appointment cancelled",
- "appointmentCancelledSuccessfully": "Appointment cancelled successfully",
- "appointments": "Rendez-vous",
- "Appointments": "Appointments",
- "appointmentToFulfill": "Select appointment(s) to fulfill",
- "appointmentType": "Type de rendez-vous",
- "appointmentType_title": "Appointment Type",
- "cancel": "Cancel",
- "cancelAppointment": "Cancel appointment",
- "cancelAppointmentModalConfirmationText": "Are you sure you want to cancel this appointment?",
- "date": "Date",
- "discard": "Abandonner",
- "edit": "Edit",
- "editAppointment": "Edit an appointment",
- "location": "Emplacement",
- "noCurrentAppointments": "Il n'y a pas de rendez-vous prévu aujourd'hui à afficher pour ce patient",
- "noPastAppointments": "Il n'y a pas de rendez-vous passé à afficher pour ce patient",
- "notes": "Notes",
- "noUpcomingAppointments": "Il n'y a pas de rendez-vous à venir à afficher pour ce patient",
- "noUpcomingAppointmentsForPatient": "There are no upcoming appointments to display for this patient",
- "past": "Passé",
- "service": "Service",
- "status": "Statut",
- "today": "Aujourd'hui",
- "type": "Type",
- "upcoming": "A venir",
- "upcomingAppointments": "Upcoming appointments"
-}
diff --git a/packages/esm-patient-appointments-app/translations/he.json b/packages/esm-patient-appointments-app/translations/he.json
deleted file mode 100644
index 12c1011f5c..0000000000
--- a/packages/esm-patient-appointments-app/translations/he.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "פעולה",
- "add": "הוסף",
- "appointmentCancelError": "שגיאה בביטול תור",
- "appointmentCancelled": "התור בוטל",
- "appointmentCancelledSuccessfully": "התור בוטל בהצלחה",
- "appointments": "תורים",
- "Appointments": "תורים",
- "appointmentToFulfill": "בחר תור(ים) למילוי",
- "appointmentType": "סוג התור",
- "appointmentType_title": "סוג התור",
- "cancel": "ביטול",
- "cancelAppointment": "ביטול תור",
- "cancelAppointmentModalConfirmationText": "?האם אתה בטוח שברצונך לבטל תור זה",
- "date": "תאריך",
- "discard": "בטל",
- "edit": "ערוך",
- "editAppointment": "ערוך תור",
- "location": "מיקום",
- "noCurrentAppointments": "אין תורים מתוזמנים להצגה עבור מטופל זה ליום הזה",
- "noPastAppointments": "אין תורים עבריים להצגה עבור מטופל זה",
- "notes": "הערות",
- "noUpcomingAppointments": "אין תורים עתידיים להצגה עבור מטופל זה",
- "noUpcomingAppointmentsForPatient": "אין תורים עתידיים להצגה עבור מטופל זה",
- "past": "עבר",
- "service": "שירות",
- "status": "סטטוס",
- "today": "היום",
- "type": "סוג",
- "upcoming": "עתידי",
- "upcomingAppointments": "תורים עתידיים"
-}
diff --git a/packages/esm-patient-appointments-app/translations/km.json b/packages/esm-patient-appointments-app/translations/km.json
deleted file mode 100644
index e7cf0ec160..0000000000
--- a/packages/esm-patient-appointments-app/translations/km.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "សកម្មភាព",
- "add": "បន្ថែម",
- "appointmentCancelError": "មានបញ្ហាបច្ចេកទេសក្នុងការលុបចោលការណាត់ជួប",
- "appointmentCancelled": "ការណាត់ជួបត្រូវបានលុបចោល",
- "appointmentCancelledSuccessfully": "ការណាត់ជួបបានលុបចោលដោយជោគជ័យ",
- "appointments": "ការណាត់ជួប",
- "Appointments": "ការណាត់ជួប",
- "appointmentToFulfill": "ជ្រើសរើសការណាត់ជួបដើម្បីបំពេញ",
- "appointmentType": "ប្រភេទនៃការណាត់ជួប",
- "appointmentType_title": "ប្រភេទនៃការណាត់ជួប",
- "cancel": "បោះបង់",
- "cancelAppointment": "លុបចោលការណាត់ជួប",
- "cancelAppointmentModalConfirmationText": "តើអ្នកពិតជាចង់លុបចោលការណាត់ជួបនេះមែនទេ?",
- "date": "កាលបរិច្ឆេទ",
- "discard": "បោះបង់",
- "edit": "កែសម្រួល",
- "editAppointment": "កែសម្រួលការណាត់ជួប",
- "location": "ទីតាំង",
- "noCurrentAppointments": "មិនមានការណាត់ជួបសម្រាប់ថ្ងៃនេះ ដើម្បីបង្ហាញអ្នកជំងឺនេះទេ",
- "noPastAppointments": "មិនមានការណាត់ជួបពីមុនដើម្បីបង្ហាញសម្រាប់អ្នកជំងឺនេះទេ",
- "notes": "កំណត់ចំណាំ",
- "noUpcomingAppointments": "មិនមានការណាត់ជួបនាពេលខាងមុខដើម្បីបង្ហាញសម្រាប់អ្នកជំងឺនេះទេ",
- "noUpcomingAppointmentsForPatient": "មិនមានការណាត់ជួបនាពេលខាងមុខដើម្បីបង្ហាញសម្រាប់អ្នកជំងឺនេះទេ",
- "past": "អតីតកាល",
- "service": "សេវាកម្ម",
- "status": "ស្ថានភាព",
- "today": "ថ្ងៃនេះ",
- "type": "ប្រភេទ",
- "upcoming": "នាពេលខាងមុខ",
- "upcomingAppointments": "ការណាត់ជួបនាពេលខាងមុខ"
-}
diff --git a/packages/esm-patient-appointments-app/translations/zh.json b/packages/esm-patient-appointments-app/translations/zh.json
deleted file mode 100644
index 1050a3f05e..0000000000
--- a/packages/esm-patient-appointments-app/translations/zh.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "操作",
- "add": "添加",
- "appointmentCancelError": "取消预约时出现错误",
- "appointmentCancelled": "预约已取消",
- "appointmentCancelledSuccessfully": "预约已成功取消",
- "appointments": "预约",
- "Appointments": "预约",
- "appointmentToFulfill": "选择要履行的预约",
- "appointmentType": "预约类型",
- "appointmentType_title": "预约类型",
- "cancel": "取消",
- "cancelAppointment": "取消预约",
- "cancelAppointmentModalConfirmationText": "您确定要取消这个预约吗?",
- "date": "日期",
- "discard": "放弃",
- "edit": "编辑",
- "editAppointment": "编辑一个预约",
- "location": "地点",
- "noCurrentAppointments": "该患者没有安排在今日的预约",
- "noPastAppointments": "该患者没有历史预约",
- "notes": "备注",
- "noUpcomingAppointments": "未找到即将到来的预约",
- "noUpcomingAppointmentsForPatient": "该患者没有即将到来的预约",
- "past": "过往",
- "service": "服务",
- "status": "状态",
- "today": "今日",
- "type": "类型",
- "upcoming": "即将到来",
- "upcomingAppointments": "即将到来的预约"
-}
diff --git a/packages/esm-patient-appointments-app/translations/zh_CN.json b/packages/esm-patient-appointments-app/translations/zh_CN.json
deleted file mode 100644
index 1050a3f05e..0000000000
--- a/packages/esm-patient-appointments-app/translations/zh_CN.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "action": "操作",
- "add": "添加",
- "appointmentCancelError": "取消预约时出现错误",
- "appointmentCancelled": "预约已取消",
- "appointmentCancelledSuccessfully": "预约已成功取消",
- "appointments": "预约",
- "Appointments": "预约",
- "appointmentToFulfill": "选择要履行的预约",
- "appointmentType": "预约类型",
- "appointmentType_title": "预约类型",
- "cancel": "取消",
- "cancelAppointment": "取消预约",
- "cancelAppointmentModalConfirmationText": "您确定要取消这个预约吗?",
- "date": "日期",
- "discard": "放弃",
- "edit": "编辑",
- "editAppointment": "编辑一个预约",
- "location": "地点",
- "noCurrentAppointments": "该患者没有安排在今日的预约",
- "noPastAppointments": "该患者没有历史预约",
- "notes": "备注",
- "noUpcomingAppointments": "未找到即将到来的预约",
- "noUpcomingAppointmentsForPatient": "该患者没有即将到来的预约",
- "past": "过往",
- "service": "服务",
- "status": "状态",
- "today": "今日",
- "type": "类型",
- "upcoming": "即将到来",
- "upcomingAppointments": "即将到来的预约"
-}
diff --git a/packages/esm-patient-appointments-app/tsconfig.json b/packages/esm-patient-appointments-app/tsconfig.json
deleted file mode 100644
index 29fd6726f2..0000000000
--- a/packages/esm-patient-appointments-app/tsconfig.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "extends": "../../tsconfig.json",
- "include": ["src/**/*", "../../tools/setup-tests.ts"],
-}
diff --git a/packages/esm-patient-appointments-app/webpack.config.js b/packages/esm-patient-appointments-app/webpack.config.js
deleted file mode 100644
index 2c74029c85..0000000000
--- a/packages/esm-patient-appointments-app/webpack.config.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = require('openmrs/default-webpack-config');
diff --git a/packages/esm-patient-attachments-app/src/camera-media-uploader/media-uploader.component.tsx b/packages/esm-patient-attachments-app/src/camera-media-uploader/media-uploader.component.tsx
index e5caf6195e..9b5e77f929 100644
--- a/packages/esm-patient-attachments-app/src/camera-media-uploader/media-uploader.component.tsx
+++ b/packages/esm-patient-attachments-app/src/camera-media-uploader/media-uploader.component.tsx
@@ -23,12 +23,25 @@ const MediaUploaderComponent = () => {
if (file.size > maxFileSize * 1024 * 1024) {
setErrorNotification({
title: t('fileSizeLimitExceededText', 'File size limit exceeded'),
- subtitle: `${file.name} ${t('fileSizeLimitExceeded', 'exceeds the size limit of')} ${maxFileSize} MB.`,
+ subtitle: `The file "${file.name}" ${t(
+ 'fileSizeLimitExceeded',
+ 'exceeds the size limit of',
+ )} ${maxFileSize} MB.`,
});
} else if (!isFileExtensionAllowed(file.name, allowedExtensions)) {
+ const lastExtension = allowedExtensions.pop();
+
setErrorNotification({
- title: t('fileExtensionNotAllowedText', 'File extension is not allowed'),
- subtitle: `${file.name} ${t('allowedExtensionsAre', 'Allowed extensions are: ')} ${allowedExtensions}.`,
+ title: t('unsupportedFileType', 'Unsupported file type'),
+ subtitle: t(
+ 'chooseAnAllowedFileType',
+ 'The file "{{fileName}}" cannot be uploaded. Please upload a file with one of the following extensions: {{supportedExtensions}}, or {{ lastExtension }}.',
+ {
+ fileName: file.name,
+ lastExtension: lastExtension,
+ supportedExtensions: allowedExtensions.join(', '),
+ },
+ ),
});
} else {
// Convert MBs to bytes
@@ -56,7 +69,14 @@ const MediaUploaderComponent = () => {
if (!allowedExtensions) {
return true;
}
- const fileExtension = fileName.split('.').pop();
+
+ const match = fileName.match(/\.[^.\s]+$/);
+
+ if (!match) {
+ return false;
+ }
+
+ const fileExtension = match[0].toLowerCase();
return allowedExtensions?.includes(fileExtension.toLowerCase());
};
@@ -81,7 +101,7 @@ const MediaUploaderComponent = () => {
'.' + ext) || ['*']}
+ accept={allowedExtensions?.map((ext) => ext) || ['*']}
labelText={t('fileSizeInstructions', 'Drag and drop files here or click to upload')}
tabIndex={0}
multiple={multipleFiles}
diff --git a/packages/esm-patient-attachments-app/translations/en.json b/packages/esm-patient-attachments-app/translations/en.json
index 199c55a1fd..1266ff6a5c 100644
--- a/packages/esm-patient-attachments-app/translations/en.json
+++ b/packages/esm-patient-attachments-app/translations/en.json
@@ -4,7 +4,6 @@
"addAttachment_title": "Add Attachment",
"addImage": "Add image +",
"addMoreAttachments": "Add more attachments",
- "allowedExtensionsAre": "Allowed extensions are:",
"attachmentCaptionInstruction": "Enter caption",
"attachments": "Attachments",
"Attachments": "Attachments",
@@ -14,6 +13,7 @@
"cameraError": "Camera Error",
"cancel": "Cancel",
"changeImage": "Change image",
+ "chooseAnAllowedFileType": "The file \"{{fileName}}\" cannot be uploaded. Please upload a file with one of the following extensions: {{supportedExtensions}}, or {{ lastExtension }}.",
"closeModal": "Close",
"closePreview": "Close preview",
"dateUploaded": "Date uploaded",
@@ -27,7 +27,6 @@
"fieldRequired": "This field is required",
"file": "File",
"fileDeleted": "File deleted",
- "fileExtensionNotAllowedText": "File extension is not allowed",
"fileName": "File name",
"fileSizeInstructions": "Drag and drop files here or click to upload",
"fileSizeLimitExceeded": "exceeds the size limit of",
diff --git a/packages/esm-patient-chart-app/src/constants.ts b/packages/esm-patient-chart-app/src/constants.ts
index bffc0fb82b..d01f53acb8 100644
--- a/packages/esm-patient-chart-app/src/constants.ts
+++ b/packages/esm-patient-chart-app/src/constants.ts
@@ -5,3 +5,4 @@ export const spaBasePath = `${window.spaBase}${basePath}`;
export const moduleName = '@openmrs/esm-patient-chart-app';
export const patientChartWorkspaceSlot = 'patient-chart-workspace-slot';
export const patientChartWorkspaceHeaderSlot = 'patient-chart-workspace-header-slot';
+export const omrsDateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZZ';
diff --git a/packages/esm-patient-chart-app/src/visit/hooks/useUpcomingAppointments.tsx b/packages/esm-patient-chart-app/src/visit/hooks/useUpcomingAppointments.tsx
index a878cbb253..4c8f8db0d9 100644
--- a/packages/esm-patient-chart-app/src/visit/hooks/useUpcomingAppointments.tsx
+++ b/packages/esm-patient-chart-app/src/visit/hooks/useUpcomingAppointments.tsx
@@ -1,5 +1,6 @@
import dayjs from 'dayjs';
-import { openmrsFetch, restBaseUrl, type OpenmrsResource } from '@openmrs/esm-framework';
+import { openmrsFetch, restBaseUrl, type OpenmrsResource, useAbortController } from '@openmrs/esm-framework';
+import { omrsDateFormat } from '../../constants';
export interface AppointmentPayload {
patientUuid: string;
@@ -17,13 +18,17 @@ export interface AppointmentPayload {
dateHonored?: string;
}
-export function saveAppointment(appointment: AppointmentPayload, abortController: AbortController) {
- return openmrsFetch(`${restBaseUrl}/appointment`, {
+export const updateAppointmentStatus = async (
+ toStatus: string,
+ appointmentUuid: string,
+ abortController: AbortController,
+) => {
+ const statusChangeTime = dayjs().format(omrsDateFormat);
+ const url = `${restBaseUrl}/appointments/${appointmentUuid}/status-change`;
+ return await openmrsFetch(url, {
+ body: { toStatus, onDate: statusChangeTime },
method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
signal: abortController.signal,
- headers: {
- 'Content-Type': 'application/json',
- },
- body: appointment,
});
-}
+};
diff --git a/packages/esm-patient-chart-app/src/visit/visit-form/visit-form.component.tsx b/packages/esm-patient-chart-app/src/visit/visit-form/visit-form.component.tsx
index 9318b04a3d..d698aa241f 100644
--- a/packages/esm-patient-chart-app/src/visit/visit-form/visit-form.component.tsx
+++ b/packages/esm-patient-chart-app/src/visit/visit-form/visit-form.component.tsx
@@ -44,7 +44,7 @@ import {
import { MemoizedRecommendedVisitType } from './recommended-visit-type.component';
import { type ChartConfig } from '../../config-schema';
import { saveQueueEntry } from '../hooks/useServiceQueue';
-import { type AppointmentPayload, saveAppointment } from '../hooks/useUpcomingAppointments';
+import { updateAppointmentStatus } from '../hooks/useUpcomingAppointments';
import { useLocations } from '../hooks/useLocations';
import { useVisitQueueEntry } from '../queue-entry/queue.resource';
import BaseVisitType from './base-visit-type.component';
@@ -375,28 +375,16 @@ const StartVisitForm: React.FC = ({
);
}
if (config.showUpcomingAppointments && upcomingAppointment) {
- const appointmentPayload: AppointmentPayload = {
- appointmentKind: upcomingAppointment?.appointmentKind,
- serviceUuid: upcomingAppointment?.service.uuid,
- startDateTime: upcomingAppointment?.startDateTime,
- endDateTime: upcomingAppointment?.endDateTime,
- locationUuid: visitLocation?.uuid,
- patientUuid: patientUuid,
- uuid: upcomingAppointment?.uuid,
- dateHonored: dayjs(visitStartDate).format(),
- };
- saveAppointment(appointmentPayload, abortController).then(
- ({ status }) => {
- if (status === 201) {
- mutateCurrentVisit();
- mutateVisits();
- showSnackbar({
- isLowContrast: true,
- kind: 'success',
- subtitle: t('appointmentUpdate', 'Upcoming appointment updated successfully'),
- title: t('appointmentEdited', 'Appointment edited'),
- });
- }
+ updateAppointmentStatus('CheckedIn', upcomingAppointment?.uuid, abortController).then(
+ () => {
+ mutateCurrentVisit();
+ mutateVisits();
+ showSnackbar({
+ isLowContrast: true,
+ kind: 'success',
+ subtitle: t('appointmentMarkedChecked', 'Appointment marked as Checked In'),
+ title: t('appointmentCheckedIn', 'Appointment Checked In'),
+ });
},
(error) => {
showSnackbar({
diff --git a/packages/esm-patient-chart-app/translations/en.json b/packages/esm-patient-chart-app/translations/en.json
index b713cdef52..7bde1db556 100644
--- a/packages/esm-patient-chart-app/translations/en.json
+++ b/packages/esm-patient-chart-app/translations/en.json
@@ -5,9 +5,9 @@
"all": "All",
"allEncounters": "All encounters",
"Allergies dashboard": "Allergies dashboard",
- "appointmentEdited": "Appointment edited",
+ "appointmentCheckedIn": "Appointment checked in",
+ "appointmentMarkedChecked": "Appointment marked as Checked In",
"Appointments dashboard": "Appointments dashboard",
- "appointmentUpdate": "Upcoming appointment updated successfully",
"Attachments dashboard": "Attachments dashboard",
"cancel": "Cancel",
"cancelActiveVisitConfirmation": "Are you sure you want to cancel this active visit?",
diff --git a/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.component.tsx b/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.component.tsx
index 4b1bdad552..80ff4e92a8 100644
--- a/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.component.tsx
+++ b/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.component.tsx
@@ -19,9 +19,9 @@ import {
import { Add } from '@carbon/react/icons';
import { formatDate, parseDate, useLayoutType } from '@openmrs/esm-framework';
import { CardHeader, EmptyState, ErrorState, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
-import { useConditions } from './conditions.resource';
import { ConditionsActionMenu } from './conditions-action-menu.component';
import { compare } from './utils';
+import { useConditions } from './conditions.resource';
import styles from './conditions-detailed-summary.scss';
function ConditionsDetailedSummary({ patient }) {
@@ -71,6 +71,7 @@ function ConditionsDetailedSummary({ patient }) {
...condition,
id: condition.id,
condition: condition.display,
+ abatementDateTime: condition.abatementDateTime,
onsetDateTime: {
sortKey: condition.onsetDateTime ?? '',
content: condition.onsetDateTime
@@ -88,7 +89,13 @@ function ConditionsDetailedSummary({ patient }) {
: compare(cellA.sortKey, cellB.sortKey);
};
- const launchConditionsForm = useCallback(() => launchPatientWorkspace('conditions-form-workspace'), []);
+ const launchConditionsForm = useCallback(
+ () =>
+ launchPatientWorkspace('conditions-form-workspace', {
+ formContext: 'creating',
+ }),
+ [],
+ );
const handleConditionStatusChange = ({ selectedItem }) => setFilter(selectedItem);
diff --git a/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.test.tsx b/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.test.tsx
index 125d75ad10..75ed0f1b71 100644
--- a/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.test.tsx
+++ b/packages/esm-patient-conditions-app/src/conditions/conditions-detailed-summary.test.tsx
@@ -92,7 +92,7 @@ it('clicking the Add button or Record Conditions link launches the conditions fo
await user.click(recordConditionsLink);
expect(launchPatientWorkspace).toHaveBeenCalledTimes(1);
- expect(launchPatientWorkspace).toHaveBeenCalledWith('conditions-form-workspace');
+ expect(launchPatientWorkspace).toHaveBeenCalledWith('conditions-form-workspace', { formContext: 'creating' });
});
function renderConditionsDetailedSummary() {
diff --git a/packages/esm-patient-conditions-app/src/conditions/conditions-form.component.tsx b/packages/esm-patient-conditions-app/src/conditions/conditions-form.component.tsx
index 88042796da..5192577943 100644
--- a/packages/esm-patient-conditions-app/src/conditions/conditions-form.component.tsx
+++ b/packages/esm-patient-conditions-app/src/conditions/conditions-form.component.tsx
@@ -15,14 +15,14 @@ interface ConditionFormProps extends DefaultWorkspaceProps {
formContext: 'creating' | 'editing';
}
-const conditionSchema = z.object({
+const schema = z.object({
+ abatementDateTime: z.date().optional().nullable(),
clinicalStatus: z.string(),
- endDate: z.date().optional(),
+ conditionName: z.string({ required_error: 'A condition is required' }),
onsetDateTime: z.date().nullable(),
- search: z.string({ required_error: 'A condition is required' }),
});
-export type ConditionFormData = z.infer;
+export type ConditionSchema = z.infer;
const ConditionsForm: React.FC = ({
closeWorkspace,
@@ -33,52 +33,68 @@ const ConditionsForm: React.FC = ({
promptBeforeClosing,
}) => {
const { t } = useTranslation();
+
const isTablet = useLayoutType() === 'tablet';
const { conditions } = useConditions(patientUuid);
- const matchingCondition = conditions?.find((c) => c?.id === condition?.id);
-
const [isSubmittingForm, setIsSubmittingForm] = useState(false);
const [errorCreating, setErrorCreating] = useState(null);
const [errorUpdating, setErrorUpdating] = useState(null);
+ const matchingCondition = conditions?.find((c) => c?.id === condition?.id);
- const methods = useForm({
+ const methods = useForm({
mode: 'all',
- resolver: zodResolver(conditionSchema),
+ resolver: zodResolver(schema),
defaultValues: {
+ abatementDateTime:
+ formContext == 'editing'
+ ? matchingCondition?.abatementDateTime
+ ? new Date(matchingCondition?.abatementDateTime)
+ : null
+ : null,
+ conditionName: '',
+ clinicalStatus: condition?.cells?.find((cell) => cell?.info?.header === 'clinicalStatus')?.value ?? '',
onsetDateTime:
formContext == 'editing'
? matchingCondition?.onsetDateTime
? new Date(matchingCondition?.onsetDateTime)
: null
: null,
- clinicalStatus: condition?.cells?.find((cell) => cell?.info?.header === 'clinicalStatus')?.value ?? 'Active',
- search: '',
},
});
const {
setError,
- formState: { isDirty, errors },
+ formState: { isDirty },
} = methods;
useEffect(() => {
promptBeforeClosing(() => isDirty);
}, [isDirty]);
- const onSubmit: SubmitHandler = (data) => {
+ const onSubmit: SubmitHandler = (payload) => {
setIsSubmittingForm(true);
- if (formContext === 'creating' && !data.search.trim()) {
- setError('search', {
- type: 'manual',
- message: t('conditionRequired', 'A condition is required'),
- });
+
+ if (formContext === 'creating') {
+ if (!payload.conditionName.trim()) {
+ setError('conditionName', {
+ type: 'manual',
+ message: t('conditionRequired', 'A condition is required'),
+ });
+ }
+ if (!payload.clinicalStatus) {
+ setError('clinicalStatus', {
+ type: 'manual',
+ message: t('clinicalStatusRequired', 'A clinical status is required'),
+ });
+ }
setIsSubmittingForm(false);
- return;
}
+
setIsSubmittingForm(true);
};
- const onError = (error) => {
+ const onError = (e) => {
+ console.error('Error submitting condition: ', e);
setIsSubmittingForm(false);
};
@@ -86,13 +102,13 @@ const ConditionsForm: React.FC = ({