Skip to main content
Glama
SentFaxesPage.tsx5.85 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ActionIcon, Anchor, Badge, Card, Group, Loader, Stack, Text, Title } from '@mantine/core'; import { showNotification } from '@mantine/notifications'; import { formatDateTime, getDisplayString, normalizeErrorString } from '@medplum/core'; import type { Communication, Organization, Practitioner, Resource } from '@medplum/fhirtypes'; import { Document, useMedplum, useMedplumProfile } from '@medplum/react'; import { IconDownload } from '@tabler/icons-react'; import { useCallback, useEffect, useState } from 'react'; import type { JSX } from 'react'; export function SentFaxesPage(): JSX.Element { const medplum = useMedplum(); const profile = useMedplumProfile(); const [faxes, setFaxes] = useState<Communication[]>([]); const [loading, setLoading] = useState(false); // Load sent faxes where current user is the sender const loadFaxes = useCallback(async () => { if (!profile?.id || profile.resourceType !== 'Practitioner') { return; } setLoading(true); try { const results = await medplum.searchResources('Communication', { medium: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationMode|FAXWRIT', _sort: '-sent', _count: '50', category: 'http://medplum.com/fhir/CodeSystem/fax-direction|outbound', }); setFaxes(results); } catch (err) { showNotification({ color: 'red', title: 'Error', message: normalizeErrorString(err), }); } finally { setLoading(false); } }, [medplum, profile]); useEffect(() => { loadFaxes().catch((err) => { showNotification({ color: 'red', title: 'Error', message: normalizeErrorString(err), }); }); }, [loadFaxes]); const renderContent = (): JSX.Element => { if (loading) { return ( <Stack align="center" mt="xl"> <Loader /> <Text c="dimmed">Loading sent faxes...</Text> </Stack> ); } if (faxes.length === 0) { return ( <Stack align="center" mt="xl"> <Text c="dimmed">No sent faxes found.</Text> </Stack> ); } return ( <Stack gap="md"> {faxes.map((fax) => ( <SentFaxCard key={fax.id} fax={fax} /> ))} </Stack> ); }; return ( <Document> <Group justify="space-between" mb="lg"> <Title order={1}>Sent Faxes</Title> </Group> {renderContent()} </Document> ); } interface SentFaxCardProps { fax: Communication; } function SentFaxCard({ fax }: SentFaxCardProps): JSX.Element { const medplum = useMedplum(); const efaxId = fax.identifier?.find((id) => id.system === 'https://efax.com')?.value; const attachment = fax.payload?.find((p) => p.contentAttachment)?.contentAttachment; const [recipient, setRecipient] = useState<Resource | undefined>(); // Load the recipient resource to get name and fax number useEffect(() => { const recipientRef = fax.recipient?.[0]; if (!recipientRef?.reference) { return; } medplum .readReference(recipientRef) .then(setRecipient) .catch((err) => { console.error('Failed to load recipient:', err); // Set undefined to use fallback display text setRecipient(undefined); }); }, [medplum, fax.recipient]); // Extract name and fax number from recipient const getRecipientInfo = (): { name: string; faxNumber: string | undefined } => { if (!recipient) { return { name: fax.recipient?.[0]?.display || 'Unknown recipient', faxNumber: undefined }; } if (recipient.resourceType === 'Organization') { const org = recipient as Organization; const faxNumber = org.contact?.[0]?.telecom?.find((t) => t.system === 'fax')?.value; return { name: org.name || 'Unknown organization', faxNumber }; } if (recipient.resourceType === 'Practitioner') { const prac = recipient as Practitioner; const faxNumber = prac.telecom?.find((t) => t.system === 'fax')?.value; return { name: getDisplayString(prac), faxNumber }; } return { name: getDisplayString(recipient), faxNumber: undefined }; }; const { name: recipientName, faxNumber: recipientFaxNumber } = getRecipientInfo(); const getStatusColor = (status: string | undefined): string => { switch (status) { case 'completed': return 'green'; case 'in-progress': return 'blue'; case 'preparation': return 'yellow'; case 'stopped': case 'entered-in-error': return 'red'; default: return 'gray'; } }; return ( <Card shadow="sm" padding="lg" radius="md" withBorder> <Group justify="space-between" mb="xs"> <Group> <Text fw={500}>Fax #{efaxId || 'Pending'}</Text> <Badge color={getStatusColor(fax.status)}>{fax.status}</Badge> </Group> {attachment?.url && ( <ActionIcon variant="light" color="blue" component="a" href={attachment.url} target="_blank"> <IconDownload size={18} /> </ActionIcon> )} </Group> <Stack gap="xs"> <Text size="sm" c="dimmed"> To: {recipientName} </Text> {recipientFaxNumber && ( <Text size="sm" c="dimmed"> Fax: {recipientFaxNumber} </Text> )} {fax.sent && ( <Text size="sm" c="dimmed"> Sent: {formatDateTime(fax.sent)} </Text> )} {attachment?.url && ( <Anchor href={attachment.url} target="_blank" size="sm"> {attachment.title || 'View Document'} </Anchor> )} </Stack> </Card> ); }

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