diff --git a/src/api/api.ts b/src/api/api.ts index c55245f4..c853c153 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -1,6 +1,6 @@ import { fhirBaseUrl, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; import { encounterRepresentation } from '../constants'; -import { type OpenmrsForm, type PatientIdentifier, type PatientProgramPayload } from '../types'; +import { type DiagnosisPayload, type OpenmrsForm, type PatientIdentifier, type PatientProgramPayload } from '../types'; import { isUuid } from '../utils/boolean-utils'; export function saveEncounter(abortController: AbortController, payload, encounterUuid?: string) { @@ -173,3 +173,15 @@ export function savePatientIdentifier(patientIdentifier: PatientIdentifier, pati body: JSON.stringify(patientIdentifier), }); } + +export function savePatientDiagnosis(abortController: AbortController, payload: DiagnosisPayload) { + return openmrsFetch(`${restBaseUrl}/patientdiagnoses`, { + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + body: payload, + signal: abortController.signal, + }); +} + diff --git a/src/components/encounter/encounter-form-manager.ts b/src/components/encounter/encounter-form-manager.ts index fa929527..c1fe2ddf 100644 --- a/src/components/encounter/encounter-form-manager.ts +++ b/src/components/encounter/encounter-form-manager.ts @@ -8,7 +8,13 @@ import { type PatientProgramPayload, } from '../../types'; import { type EncounterContext } from '../../form-context'; -import { saveAttachment, saveEncounter, savePatientIdentifier, saveProgramEnrollment } from '../../api/api'; +import { + saveAttachment, + saveEncounter, + savePatientDiagnosis, + savePatientIdentifier, + saveProgramEnrollment, +} from '../../api/api'; import { hasRendering, hasSubmission } from '../../utils/common-utils'; import { voidObs, constructObs } from '../../submission-handlers/obsHandler'; import dayjs from 'dayjs'; @@ -152,6 +158,19 @@ 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 diff --git a/src/components/encounter/encounter-form.component.tsx b/src/components/encounter/encounter-form.component.tsx index 4f39fc77..e0246474 100644 --- a/src/components/encounter/encounter-form.component.tsx +++ b/src/components/encounter/encounter-form.component.tsx @@ -531,6 +531,25 @@ const EncounterForm: React.FC = ({ isLowContrast: true, }); } + // 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, + }); + } // handle attachments try { const attachmentsResponse = await Promise.all( diff --git a/src/constants.ts b/src/constants.ts index 1583fa72..5965ee8c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -5,6 +5,7 @@ export const encounterRepresentation = 'custom:(uuid,encounterDatetime,encounterType:(uuid,name,description),location:(uuid,name),' + 'patient:(uuid,display),encounterProviders:(uuid,provider:(uuid,name),encounterRole:(uuid,name)),' + 'orders:(uuid,display,concept:(uuid,display),voided),' + + 'diagnoses:(uuid,certainty,condition,display,rank,voided,diagnosis:(coded:(uuid,display))),' + 'obs:(uuid,obsDatetime,comment,voided,groupMembers,formFieldNamespace,formFieldPath,concept:(uuid,name:(uuid,name)),value:(uuid,name:(uuid,name),' + 'names:(uuid,conceptNameType,name))))'; export const FormsStore = 'forms-engine-store'; diff --git a/src/registry/inbuilt-components/inbuiltFieldSubmissionHandlers.ts b/src/registry/inbuilt-components/inbuiltFieldSubmissionHandlers.ts index 00229ccd..6e6db543 100644 --- a/src/registry/inbuilt-components/inbuiltFieldSubmissionHandlers.ts +++ b/src/registry/inbuilt-components/inbuiltFieldSubmissionHandlers.ts @@ -11,6 +11,7 @@ import { EncounterRoleHandler } from '../../submission-handlers/encounterRoleHan import { ProgramStateHandler } from '../../submission-handlers/programStateHandler'; import { InlineDateHandler } from '../../submission-handlers/inlineDateHandler'; import { ObsCommentHandler } from '../../submission-handlers/obsCommentHandler'; +import { EncounterDiagnosisHandler } from '../../submission-handlers/encounterDiagnosisHandler'; /** * @internal @@ -76,4 +77,9 @@ export const inbuiltFieldSubmissionHandlers: Array { + const newValue = constructNewDiagnosis(value, field, context.patient.id); + gracefullySetSubmission(field, newValue, null); + return newValue; + }, + getInitialValue: ( + encounter: OpenmrsEncounter, + field: FormField, + allFormFields: Array, + 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; + } + } else { + return; + } + }, + + getDisplayValue: (field: FormField, value: any) => { + return value; + }, + getPreviousValue: (field: FormField, encounter: OpenmrsEncounter, allFormFields: Array) => { + return null; + } +}; + +const constructNewDiagnosis = (value: any, field: FormField, patientUuid: string) => { + if (!value) { + return null; + } + return { + patient: patientUuid, + condition: null, + diagnosis: { + coded: value, + }, + certainty: 'CONFIRMED', + rank: field.questionOptions.rank, // rank 1 denotes a diagnosis is primary, else secondary + }; +}; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 8670b756..87086643 100644 --- a/src/types.ts +++ b/src/types.ts @@ -252,6 +252,7 @@ export interface FormQuestionOptions { showComment?: boolean; comment?: string; shownCommentOptions?: { validators?: Array>; hide?: { hideWhenExpression: string } }; + rank?: number; } export type SessionMode = 'edit' | 'enter' | 'view' | 'embedded-view'; @@ -305,6 +306,7 @@ export interface OpenmrsEncounter { visit?: OpenmrsResource | string; encounterProviders?: Array>; form?: OpenmrsFormResource; + diagnoses?: Array; } export interface OpenmrsObs extends OpenmrsResource { @@ -471,3 +473,27 @@ export interface PatientProgramPayload { endDate?: string; }>; } + +export interface DiagnosisPayload { + encounter: string; + patient: string; + condition: null; + diagnosis: { + coded: string; + }; + certainty: string; + rank: number; +} + +export interface Diagnosis { + patient: string; + diagnosis: { + coded: { + uuid: string; + }; + }; + certainty: string; + rank: number; + display: string; + voided: boolean; +}