Skip to content

Commit

Permalink
Introduce generic program enrollment
Browse files Browse the repository at this point in the history
  • Loading branch information
kajambiya committed Dec 12, 2023
1 parent cfe5cca commit c018794
Show file tree
Hide file tree
Showing 11 changed files with 453 additions and 37 deletions.
116 changes: 116 additions & 0 deletions __mocks__/forms/ohri-forms/post-submission-test-form.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"name": "TB Case Enrollment Form",
"published": true,
"retired": false,
"pages": [
{
"label": "TB Enrollment",
"sections": [
{
"label": "TB Program",
"isExpanded": "true",
"questions": [
{
"label": "TB Program to enrol",
"type": "obs",
"required": false,
"id": "tbProgramType",
"questionOptions": {
"rendering": "radio",
"concept": "163775AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"conceptMappings": [],
"answers": [
{
"concept": "160541AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"label": "Drug-susceptible (DS) TB Program"
},
{
"concept": "160052AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"label": "Drug Resistant (DR) TB program"
}
]
},
"validators": []
},
{
"label": "Date enrolled in tuberculosis (TB) care",
"type": "obs",
"required": true,
"id": "tbRegDate",
"questionOptions": {
"rendering": "date",
"concept": "161552AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"conceptMappings": [
{
"relationship": "SAME-AS",
"type": "CIEL",
"value": "161552"
},
{
"relationship": "NARROWER-THAN",
"type": "SNOMED CT",
"value": "413946009"
}
],
"answers": []
},
"validators": []
},
{
"label": "DS TB Treatment Number",
"type": "obs",
"required": false,
"id": "dsServiceID",
"questionOptions": {
"rendering": "number",
"concept": "161654AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"conceptMappings": [
{
"relationship": "SAME-AS",
"type": "CIEL",
"value": "161654"
}
],
"answers": []
},
"validators": []
}
]
}
]
}
],
"availableIntents": [
{
"intent": "*",
"display": "TB Case Enrollment Form"
}
],
"processor": "EncounterFormProcessor",
"encounterType": "9a199b59-b185-485b-b9b3-a9754e65ae57",
"postSubmissionActions": [
{
"actionId": "ProgramEnrollmentSubmissionAction",
"enabled":"tbProgramType === '160541AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'",
"config": {
"enrollmentDate": "tbRegDate",
"programUuid": "58005eb2-4560-4ada-b7bb-67a5cffa0a27",
"completionDate": "outcomeTBRx"
}
},
{
"actionId": "ProgramEnrollmentSubmissionAction",
"enabled":"tbProgramType === '160052AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'",
"config": {
"enrollmentDate": "utbRegDate",
"programUuid": "00f37871-0578-4ebc-af1d-e4b3ce75310d",
"completionDate": "outcomeTBRx"
}
}
],
"encounter": "TB Program Enrolment",
"referencedForms": [],
"uuid": "9ad909d2-64a9-437d-9a40-301d50cae1f6",
"description": "This form enrols a client to the respective TB Program",
"version": "1.0"
}
44 changes: 44 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { encounterRepresentation } from '../constants';
import { OpenmrsForm } from './types';
import { isUuid } from '../utils/boolean-utils';

const BASE_WS_API_URL = '/ws/rest/v1/';

export function saveEncounter(abortController: AbortController, payload, encounterUuid?: string) {
const url = !!encounterUuid ? `/ws/rest/v1/encounter/${encounterUuid}?v=full` : `/ws/rest/v1/encounter?v=full`;

Expand Down Expand Up @@ -152,3 +154,45 @@ function dataURItoFile(dataURI: string) {
const blob = new Blob([buffer], { type: mimeString });
return blob;
}

//Program Enrollment
export function getPatientEnrolledPrograms(patientUuid: string) {
return openmrsFetch(
`${BASE_WS_API_URL}programenrollment?patient=${patientUuid}&v=custom:(uuid,display,program,dateEnrolled,dateCompleted,location:(uuid,display))`,
).then(({ data }) => {
if (data) {
return data;
}
return null;
});
}

export function createProgramEnrollment(payload, abortController) {
if (!payload) {
return null;
}
const { program, patient, dateEnrolled, dateCompleted, location } = payload;
return openmrsObservableFetch(`${BASE_WS_API_URL}programenrollment`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: { program, patient, dateEnrolled, dateCompleted, location },
signal: abortController.signal,
});
}

export function updateProgramEnrollment(programEnrollmentUuid: string, payload, abortController) {
if (!payload && !payload.program) {
return null;
}
const { program, dateEnrolled, dateCompleted, location } = payload;
return openmrsObservableFetch(`${BASE_WS_API_URL}programenrollment/${programEnrollmentUuid}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: { dateEnrolled, dateCompleted, location },
signal: abortController.signal,
});
}
1 change: 1 addition & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export interface PostSubmissionAction {
sessionMode: SessionMode;
},
config?: Record<string, any>,
enabled?: string,
): void;
}

Expand Down
12 changes: 7 additions & 5 deletions src/hooks/usePostSubmissionAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import { useEffect, useState } from 'react';
import { PostSubmissionAction } from '../api/types';
import { getRegisteredPostSubmissionAction } from '../registry/registry';

export function usePostSubmissionAction(actionRefs: Array<{ actionId: string; config?: Record<string, any> }>) {
export function usePostSubmissionAction(
actionRefs: Array<{ actionId: string; enabled?: string; config?: Record<string, any> }>,
) {
const [actions, setActions] = useState<
Array<{ postAction: PostSubmissionAction; config: Record<string, any>; actionId: string }>
Array<{ postAction: PostSubmissionAction; config: Record<string, any>; actionId: string; enabled?: string }>
>([]);
useEffect(() => {
const actionArray = [];
if (actionRefs?.length) {
actionRefs.map(ref => {
actionRefs.map((ref) => {
const actionId = typeof ref === 'string' ? ref : ref.actionId;
getRegisteredPostSubmissionAction(actionId)?.then(action =>
actionArray.push({ postAction: action, config: ref.config, actionId: actionId }),
getRegisteredPostSubmissionAction(actionId)?.then((action) =>
actionArray.push({ postAction: action, config: ref.config, actionId: actionId, enabled: ref.enabled }),
);
});
}
Expand Down
69 changes: 68 additions & 1 deletion src/ohri-form.component.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import { mockSessionDataResponse } from '../__mocks__/session.mock';
import demoHtsOpenmrsForm from '../__mocks__/forms/omrs-forms/demo_hts-form.json';
import demoHtsOhriForm from '../__mocks__/forms/ohri-forms/demo_hts-form.json';
import obsGroup_test_form from '../__mocks__/forms/ohri-forms/obs-group-test_form.json';
import postSubmission_test_form from '../__mocks__/forms/ohri-forms/post-submission-test-form.json';
import { getRegisteredPostSubmissionAction } from './registry/registry';
import { isPostSubmissionEnabled } from './utils/program-enrolment-helper';

import {
assertFormHasAllFields,
Expand All @@ -47,6 +50,7 @@ import {
findTextOrDateInput,
} from './utils/test-utils';
import { mockVisit } from '../__mocks__/visit.mock';
import { PostSubmissionAction } from './api/types';

//////////////////////////////////////////
////// Base setup
Expand Down Expand Up @@ -94,6 +98,10 @@ jest.mock('../src/api/api', () => {
saveEncounter: jest.fn(),
};
});
// Mock getRegisteredPostSubmissionAction
jest.mock('./registry/registry', () => ({
getRegisteredPostSubmissionAction: jest.fn(),
}));

describe('OHRI Forms:', () => {
afterEach(() => {
Expand Down Expand Up @@ -207,6 +215,65 @@ describe('OHRI Forms:', () => {
expect(encounter.obs.length).toEqual(3);
expect(encounter.obs.find((obs) => obs.formFieldPath === 'ohri-forms-hivEnrolmentDate')).toBeUndefined();
});
fit('should evaluate post submission enabled flag expression', () => {
const encounters = [
{
uuid: '47cfe95b-357a-48f8-aa70-63eb5ae51916',
obs: [
{
formFieldPath: 'ohri-forms-tbProgramType',
value: {
display: 'Tuberculosis treatment program',
uuid: '160541AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
},
},
{
formFieldPath: 'ohri-forms-tbRegDate',
value: '2023-12-05T00:00:00.000+0000',
},
],
},
];

const expression1 = "tbProgramType === '160541AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'";
const expression2 = "tbProgramType === '160052AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'";
let enabled = isPostSubmissionEnabled(expression1, encounters);
expect(enabled).toEqual(true);
enabled = isPostSubmissionEnabled(expression2, encounters);
expect(enabled).toEqual(false);
});
it('Should test post submission actions', async () => {
const mockPostSubmissionAction = {
postAction: {
applyAction: jest.fn(),
},
config: {},
actionId: 'ProgramEnrollmentSubmissionAction',
enabled: 'some_expression',
};

// Set up mocks
getRegisteredPostSubmissionAction.mockResolvedValue(mockPostSubmissionAction);
// Render the form
await act(async () => renderForm(null, postSubmission_test_form));
const drugSensitiveProgramField = await findRadioGroupMember(screen, 'Drug-susceptible (DS) TB Program');
const enrolmentDateField = await findTextOrDateInput(screen, 'Date enrolled in tuberculosis (TB) care');
const treatmentNumber = await findNumberInput(screen, 'DS TB Treatment Number');

// Simulate user interaction
fireEvent.click(drugSensitiveProgramField);
fireEvent.blur(enrolmentDateField, { target: { value: '2023-12-12T00:00:00.000Z' } });
fireEvent.blur(treatmentNumber, { target: { value: '11200' } });

// Simulate a successful form submission
await act(async () => {
fireEvent.submit(screen.getByText(/save/i));
});

//Assertions
// Verify that getRegisteredPostSubmissionAction was called
expect(getRegisteredPostSubmissionAction).toHaveBeenCalledWith('ProgramEnrollmentSubmissionAction');
});
});

describe('Filter Answer Options', () => {
Expand Down Expand Up @@ -484,7 +551,7 @@ describe('OHRI Forms:', () => {
await act(async () => expect(birthDateFields.length).toBe(2));
});

fit('Should test deletion of a group', async () => {
it('Should test deletion of a group', async () => {
//Setup
await act(async () => renderForm(null, obsGroup_test_form));
let femaleRadios = await findAllRadioGroupMembers(screen, 'Female');
Expand Down
23 changes: 14 additions & 9 deletions src/ohri-form.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import LoadingIcon from './components/loaders/loading.component';
import OHRIFormSidebar from './components/sidebar/ohri-form-sidebar.component';
import WarningModal from './components/warning-modal.component';
import styles from './ohri-form.component.scss';
import { isPostSubmissionEnabled } from './utils/program-enrolment-helper';

interface OHRIFormProps {
patientUUID: string;
Expand Down Expand Up @@ -200,7 +201,7 @@ const OHRIForm: React.FC<OHRIFormProps> = ({
// Post Submission Actions
if (postSubmissionHandlers) {
await Promise.all(
postSubmissionHandlers.map(async ({ postAction, config, actionId }) => {
postSubmissionHandlers.map(async ({ postAction, config, actionId, enabled }) => {
try {
const encounterData = [];
if (results) {
Expand All @@ -210,14 +211,18 @@ const OHRIForm: React.FC<OHRIFormProps> = ({
}
});
if (encounterData.length) {
await postAction.applyAction(
{
patient,
sessionMode,
encounters: encounterData,
},
config,
);
//pass enabled here
const isActionEnabled = enabled ? isPostSubmissionEnabled(enabled, encounterData) : true;
if (isActionEnabled) {
await postAction.applyAction(
{
patient,
sessionMode,
encounters: encounterData,
},
config,
);
}
} else {
throw new Error('No encounter data to process post submission action');
}
Expand Down
Loading

0 comments on commit c018794

Please sign in to comment.