Skip to main content
Glama
CreateEncounter.tsx5.31 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { Button, Modal } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { showNotification } from '@mantine/notifications'; import { createReference, normalizeErrorString, parseReference } from '@medplum/core'; import type { PatchOperation } from '@medplum/core'; import type { Communication, Encounter, Group, Patient, Period, Practitioner, Reference, Resource, } from '@medplum/fhirtypes'; import { ResourceForm, useMedplum, useMedplumProfile } from '@medplum/react'; import { IconCircleCheck, IconCircleOff } from '@tabler/icons-react'; import { useEffect, useState } from 'react'; import type { JSX } from 'react'; import { useNavigate } from 'react-router'; import { getAttenders } from '../../utils'; interface CreateEncounterProps { readonly communication: Communication; readonly onChange: (communication: Communication) => void; } export function CreateEncounter(props: CreateEncounterProps): JSX.Element { const medplum = useMedplum(); const navigate = useNavigate(); const profile = useMedplumProfile() as Practitioner; const [opened, handlers] = useDisclosure(false); const [period, setPeriod] = useState<Period>(); async function onEncounterSubmit(resource: Resource): Promise<void> { const encounterData = resource as Encounter; encounterData.period = period; try { // Create the encounter and update the communication to be linked to it. For more details see https://www.medplum.com/docs/communications/async-encounters const encounter = await medplum.createResource(encounterData); linkEncounterToCommunication(encounter, props.communication).catch(console.error); showNotification({ icon: <IconCircleCheck />, title: 'Success', message: 'Encounter created.', }); handlers.close(); navigate(`/Encounter/${encounter.id}`)?.catch(console.error); } catch (err) { showNotification({ icon: <IconCircleOff />, title: 'Error', message: normalizeErrorString(err), }); } } // A function that links a Communication to an Encounter using the Communication.encounter field. For more details see https://www.medplum.com/docs/communications/async-encounters async function linkEncounterToCommunication(encounter: Encounter, communication: Communication): Promise<void> { const communicationId = communication.id as string; const encounterReference = createReference(encounter); const ops: PatchOperation[] = [ // Test to prevent race conditions { op: 'test', path: '/meta/versionId', value: communication.meta?.versionId }, // Patch the encounter field of the communication { op: 'add', path: '/encounter', value: encounterReference }, ]; try { // Update the communication const result = await medplum.patchResource('Communication', communicationId, ops); props.onChange(result); } catch (err) { console.error(err); } } useEffect(() => { // When creating an encounter, the period should be from the time the first message in the thread was sent until the last message was sent const getEncounterPeriod = async (thread: Communication): Promise<Period> => { const messages = await medplum.searchResources('Communication', { 'part-of': `Communication/${thread.id}`, _sort: 'sent', }); const period: Period = { start: messages[0].sent, end: messages[messages.length - 1].sent, }; return period; }; getEncounterPeriod(props.communication).then(setPeriod).catch(console.error); }, [medplum, props.communication]); const attenders = getAttenders(props.communication.recipient, profile, false); const subject = getEncounterSubject(props.communication); // A default encounter to pre-fill the form with const defaultEncounter: Encounter = { resourceType: 'Encounter', status: 'in-progress', class: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'VR', display: 'virtual', }, subject: subject, participant: attenders, period: period, }; return ( <div> <Button fullWidth onClick={handlers.toggle}> Create Encounter </Button> <Modal opened={opened} onClose={handlers.close} title="Create a linked Encounter" size="lg"> <ResourceForm defaultValue={defaultEncounter} onSubmit={onEncounterSubmit} /> </Modal> </div> ); } function getEncounterSubject(thread: Communication): Reference<Patient | Group> | undefined { // If the thread has a subject, this will be the Encounter subject if (thread.subject) { return thread.subject; } if (!thread.recipient || thread.recipient.length === 0) { return undefined; } // Filter for only the recipients that are patients const patients = thread.recipient.filter( (recipient) => parseReference(recipient)[0] === 'Patient' ) as Reference<Patient>[]; // If there are none, or more than one do not return a subject if (patients.length !== 1) { return undefined; } // Return a the patient if there is only one return patients[0]; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server