diff --git a/src/components/encounter/encounter-form-manager.ts b/src/components/encounter/encounter-form-manager.ts index c1fe2ddf..a6db627b 100644 --- a/src/components/encounter/encounter-form-manager.ts +++ b/src/components/encounter/encounter-form-manager.ts @@ -37,6 +37,7 @@ export class EncounterFormManager { const obsForSubmission = []; prepareObs(obsForSubmission, allFields); const ordersForSubmission = prepareOrders(allFields); + const diagnosesForSubmission = prepareDiagnoses(allFields); let encounterForSubmission: OpenmrsEncounter = {}; if (encounterContext.encounter) { @@ -64,6 +65,7 @@ export class EncounterFormManager { } encounterForSubmission.obs = obsForSubmission; encounterForSubmission.orders = ordersForSubmission; + encounterForSubmission.diagnoses = diagnosesForSubmission; } else { encounterForSubmission = { patient: patient.id, @@ -82,6 +84,7 @@ export class EncounterFormManager { }, visit: visit?.uuid, orders: ordersForSubmission, + diagnoses: diagnosesForSubmission, }; } return encounterForSubmission; @@ -158,19 +161,6 @@ export class EncounterFormManager { const ac = new AbortController(); return Promise.all(patientPrograms.map((programPayload) => saveProgramEnrollment(programPayload, ac))); }; - - static saveDiagnosis = (fields: FormField[], encounter: OpenmrsEncounter) => { - const diagnoses = fields?.filter((field) => field.type === 'diagnosis' && hasSubmission(field)); - if (!diagnoses) return []; - const ac = new AbortController(); - return diagnoses.map((diagnosis) => { - const payload = { - ...diagnosis.meta.submission.newValue, - encounter: encounter.uuid, - }; - return savePatientDiagnosis(ac, payload); - }); - }; } // Helpers @@ -247,3 +237,9 @@ function hasSubmittableObs(field: FormField) { } return !field.isHidden && !field.isParentHidden && (type === 'obsGroup' || hasSubmission(field)); } + +function prepareDiagnoses(fields: FormField[]) { + return fields?.filter((field) => field.type === 'diagnosis' && hasSubmission(field)) + .flatMap((field) => [field.meta.submission.newValue, field.meta.submission.voidedValue]) + .filter((o) => o); +} diff --git a/src/components/encounter/encounter-form.component.tsx b/src/components/encounter/encounter-form.component.tsx index e0246474..fc018897 100644 --- a/src/components/encounter/encounter-form.component.tsx +++ b/src/components/encounter/encounter-form.component.tsx @@ -532,22 +532,12 @@ const EncounterForm: React.FC = ({ }); } // handle encounter diagnosis - try { - const saveDiagnoses = await EncounterFormManager.saveDiagnosis(fields, savedEncounter); - if (saveDiagnoses) { - showSnackbar({ - title: t('encounterDiagnosisSaved', 'Encounter diagnosis saved successfully'), - kind: 'success', - isLowContrast: true, - }); - } - } catch (error) { - const errorMessages = extractErrorMessagesFromResponse(error); - return Promise.reject({ - title: t('errorSavingEncounterDiagnosis', 'Error saving encounter diagnosis'), - subtitle: errorMessages.join(', '), - kind: 'error', - isLowContrast: false, + const saveDiagnoses = savedEncounter.diagnoses.map((diagnosis) => diagnosis.uuid); + if (saveDiagnoses) { + showSnackbar({ + title: t('encounterDiagnosisSaved', 'Encounter diagnosis saved successfully'), + kind: 'success', + isLowContrast: true, }); } // handle attachments diff --git a/src/components/repeat/helpers.ts b/src/components/repeat/helpers.ts index 91eab4d8..8e5f7901 100644 --- a/src/components/repeat/helpers.ts +++ b/src/components/repeat/helpers.ts @@ -5,6 +5,7 @@ import { type OpenmrsResource } from '@openmrs/esm-framework'; import { isEmpty } from '../../validators/form-validator'; import { clearSubmission } from '../../utils/common-utils'; import { assignedObsIds } from '../../submission-handlers/obsHandler'; +import { assignedDiagnosisIds } from 'src/submission-handlers/encounterDiagnosisHandler'; export function cloneRepeatField(srcField: FormField, value: OpenmrsResource, idSuffix: number) { const originalGroupMembersIds: string[] = []; @@ -83,6 +84,7 @@ export function hydrateRepeatField( obs.uuid != field.meta.previousValue?.uuid && !assignedObsIds.includes(obs.uuid), ); + // handle orders const unMappedOrders = encounter.orders.filter((order) => { const availableOrderables = field.questionOptions.answers?.map((answer) => answer.concept) || []; return availableOrderables.includes(order.concept?.uuid) && !assignedOrderIds.includes(order.uuid); @@ -96,6 +98,16 @@ export function hydrateRepeatField( return clone; }); } + //handle diagnoses + if (field.type === 'diagnosis') { + return encounter.diagnoses + .filter((diagnosis) => !diagnosis.voided) + .map((diagnosis) => { + const clone = cloneRepeatField(field, diagnosis, counter++); + initialValues[clone.id] = formFieldHandlers[field.type].getInitialValue({ orders: [diagnosis] }, clone, formFields); + return clone; + }); + } // handle obs groups return unMappedGroups.flatMap((group) => { const clone = cloneRepeatField(field, group, counter++); diff --git a/src/components/repeat/repeat.component.tsx b/src/components/repeat/repeat.component.tsx index fb416dce..4992f79b 100644 --- a/src/components/repeat/repeat.component.tsx +++ b/src/components/repeat/repeat.component.tsx @@ -17,6 +17,7 @@ import { ExternalFunctionContext } from '../../external-function-context'; const renderingByTypeMap: Record = { obsGroup: 'group', testOrder: 'select', + diagnosis: 'ui-select-extended', }; const Repeat: React.FC = ({ question, onChange, handler }) => { diff --git a/src/lifecycle.ts b/src/lifecycle.ts index 9621cd2f..b18b06b4 100644 --- a/src/lifecycle.ts +++ b/src/lifecycle.ts @@ -1,4 +1,5 @@ import setupFormEngineLibI18n from './setupI18n'; +import { teardownTestDiagnosisHandler } from './submission-handlers/encounterDiagnosisHandler'; import { teardownObsHandler } from './submission-handlers/obsHandler'; import { teardownTestOrderHandler } from './submission-handlers/testOrderHandler'; @@ -16,4 +17,5 @@ export function init() { export function teardown() { teardownTestOrderHandler(); teardownObsHandler(); + teardownTestDiagnosisHandler(); } diff --git a/src/submission-handlers/encounterDiagnosisHandler.test.ts b/src/submission-handlers/encounterDiagnosisHandler.test.ts new file mode 100644 index 00000000..280e3b2e --- /dev/null +++ b/src/submission-handlers/encounterDiagnosisHandler.test.ts @@ -0,0 +1,57 @@ +import { type FormField } from '../types'; +import { type EncounterContext } from '../form-context'; +import { TestOrderSubmissionHandler } from './testOrderHandler'; +import { EncounterDiagnosisHandler } from './encounterDiagnosisHandler'; + +const encounterContext: EncounterContext = { + patient: { + id: '833db896-c1f0-11eb-8529-0242ac130003', + }, + location: { + uuid: '41e6e516-c1f0-11eb-8529-0242ac130003', + }, + encounter: { + uuid: '873455da-3ec4-453c-b565-7c1fe35426be', + obs: [], + }, + sessionMode: 'enter', + encounterDate: new Date(2020, 11, 29), + setEncounterDate: (value) => {}, + encounterProvider: '2c95f6f5-788e-4e73-9079-5626911231fa', + setEncounterProvider: jest.fn, + setEncounterLocation: jest.fn, + encounterRole: '8cb3a399-d18b-4b62-aefb-5a0f948a3809', + setEncounterRole: jest.fn, +}; + +const encounterDiagnoses: FormField = { + label: 'Test Diagnosis', + id: 'diagnosIS', + type: 'diagnosis', + questionOptions: { + rendering: 'repeating', + rank: 1, + datasource: { + name: 'problem_datasource', + }, + }, +}; + +describe('EncounterDiagnosesSubmissionHandler - handleFieldSubmission', () => { + it('should submit an encounter diagnosis', () => { + const diagnosis = EncounterDiagnosisHandler.handleFieldSubmission( + encounterDiagnoses, + '128125AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + encounterContext, + ); + expect(diagnosis).toEqual({ + patient: '833db896-c1f0-11eb-8529-0242ac130003', + condition: null, + diagnosis: { + coded: '128125AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + }, + certainty: 'CONFIRMED', + rank: 1, + }); + }); +}); diff --git a/src/submission-handlers/encounterDiagnosisHandler.ts b/src/submission-handlers/encounterDiagnosisHandler.ts index 30c26902..61732f59 100644 --- a/src/submission-handlers/encounterDiagnosisHandler.ts +++ b/src/submission-handlers/encounterDiagnosisHandler.ts @@ -1,6 +1,8 @@ import { gracefullySetSubmission } from '../utils/common-utils'; import { type EncounterContext, type FormField, type OpenmrsEncounter, type SubmissionHandler } from '..'; +export let assignedDiagnosisIds: string[] = []; + export const EncounterDiagnosisHandler: SubmissionHandler = { handleFieldSubmission: (field: FormField, value: any, context: EncounterContext) => { const newValue = constructNewDiagnosis(value, field, context.patient.id); @@ -14,13 +16,8 @@ export const EncounterDiagnosisHandler: SubmissionHandler = { context: EncounterContext, ) => { if (encounter?.diagnoses?.length > 0) { - if(field.questionOptions.rank === 1) { - return encounter.diagnoses.find((entry) => entry.voided === false && field.questionOptions.rank === entry.rank)?.diagnosis - ?.coded?.uuid; - } else { - return encounter.diagnoses.find((entry) => entry.voided === false && field.questionOptions.rank !== entry.rank)?.diagnosis - ?.coded?.uuid; - } + assignedDiagnosisIds.push(encounter.diagnoses[0].diagnosis.coded.uuid); + return encounter.diagnoses[0].diagnosis.coded.uuid; } else { return; } @@ -31,7 +28,7 @@ export const EncounterDiagnosisHandler: SubmissionHandler = { }, getPreviousValue: (field: FormField, encounter: OpenmrsEncounter, allFormFields: Array) => { return null; - } + }, }; const constructNewDiagnosis = (value: any, field: FormField, patientUuid: string) => { @@ -47,4 +44,8 @@ const constructNewDiagnosis = (value: any, field: FormField, patientUuid: string certainty: 'CONFIRMED', rank: field.questionOptions.rank, // rank 1 denotes a diagnosis is primary, else secondary }; -}; \ No newline at end of file +}; + +export function teardownTestDiagnosisHandler() { + assignedDiagnosisIds = []; +} diff --git a/src/transformers/default-schema-transformer.ts b/src/transformers/default-schema-transformer.ts index f2060160..2d34707c 100644 --- a/src/transformers/default-schema-transformer.ts +++ b/src/transformers/default-schema-transformer.ts @@ -32,6 +32,9 @@ function handleQuestion(question: FormField, form: FormSchema) { : { hasProgramFields: true }; form.meta = formMeta; } + if (question.type === 'diagnosis') { + handleDiagnosesDataSource(question); + } try { sanitizeQuestion(question); setFieldValidators(question); @@ -221,3 +224,12 @@ function handleQuestionsWithObsComments(sectionQuestions: Array): Arr return augmentedQuestions; } + +function handleDiagnosesDataSource(question: FormField) { + if ('dataSource' in question.questionOptions && question.questionOptions['dataSource'] === 'diagnoses') { + question.questionOptions.datasource = { + name: 'problem_datasource', + }; + delete question.questionOptions['dataSource']; + } +} diff --git a/src/types.ts b/src/types.ts index 87086643..330f9e6c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -496,4 +496,5 @@ export interface Diagnosis { rank: number; display: string; voided: boolean; + uuid: string }