Skip to main content
Glama
DoseSpotFavoritesPage.tsx6.17 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import React, { useEffect, useState } from 'react'; import { Container, Title, Paper, Button, Modal, Group, Box, TextInput, Stack, Divider, Group as MantineGroup, } from '@mantine/core'; import { showNotification } from '@mantine/notifications'; import { DOSESPOT_CLINIC_FAVORITE_ID_SYSTEM, useDoseSpotClinicFormulary } from '@medplum/dosespot-react'; import type { CodeableConcept, MedicationKnowledge } from '@medplum/fhirtypes'; import { IconPlus } from '@tabler/icons-react'; import { formatSearchQuery, isCodeableConcept, normalizeErrorString } from '@medplum/core'; import { AsyncAutocomplete, useMedplum } from '@medplum/react'; import { FavoriteMedicationsTable } from './FavoriteMedicationsTable'; import { showErrorNotification } from '../../utils/notifications'; import { v4 as uuidv4 } from 'uuid'; /** * This is a demo component for how you could display your favorite Medications * from DoseSpot. * * @returns A React component that displays the favorite medications and allows you to add new favorites. */ export function DoseSpotFavoritesPage(): React.JSX.Element { const [modalOpened, setModalOpened] = useState(false); const [loading, setLoading] = useState(false); const [loadingFavorites, setLoadingFavorites] = useState(true); const [clinicFavoriteMedications, setClinicFavoriteMedications] = useState<MedicationKnowledge[] | undefined>(); const { state, saveFavoriteMedication, searchMedications, setSelectedMedicationDirections, setSelectedMedication, clear, } = useDoseSpotClinicFormulary(); const medplum = useMedplum(); // Load favorite MedicationKnowledge resources that have a DoseSpot favorite id system useEffect(() => { const loadFavorites = async (): Promise<void> => { try { setLoadingFavorites(true); const searchRequest = { resourceType: 'MedicationKnowledge' as const, filters: [ { code: 'code', operator: 'eq' as const, value: `${DOSESPOT_CLINIC_FAVORITE_ID_SYSTEM}|`, }, ], }; const queryString = formatSearchQuery(searchRequest); const result = await medplum.search('MedicationKnowledge', queryString); setClinicFavoriteMedications(result.entry?.map((e) => e.resource as MedicationKnowledge) || []); } catch (err) { showErrorNotification(err); } finally { setLoadingFavorites(false); } }; loadFavorites().catch(showErrorNotification); }, [medplum]); const handleAddFavoriteMedication = async (): Promise<void> => { try { setLoading(true); const created = await saveFavoriteMedication(); // Optimistically update local favorites list setClinicFavoriteMedications((prev) => [created, ...(prev || [])]); setModalOpened(false); showNotification({ title: 'Medication added to favorites', message: 'The medication has been added to your favorites', color: 'green', }); } catch (error) { showErrorNotification({ title: 'Error adding medication to favorites', message: normalizeErrorString(error as Error), color: 'red', }); } finally { clear(); setLoading(false); } }; const toOption = (medication: CodeableConcept): { value: string; label: string; resource: CodeableConcept } => ({ value: uuidv4(), label: medication.text || 'Unknown Medication', resource: medication, }); return ( <Container size="xl" py="xl"> <Paper mb="lg" p="md" withBorder shadow="sm"> <Group justify="space-between" mb="md"> <Title order={2}>DoseSpot Medication Favorites</Title> <Button leftSection={<IconPlus size={16} />} onClick={() => setModalOpened(true)}> Add Favorite Medication </Button> </Group> {/* Example of a table to display favorite medications (MedicationKnowledge resources) */} <FavoriteMedicationsTable clinicFavoriteMedications={clinicFavoriteMedications} loadingFavorites={loadingFavorites} /> </Paper> <Modal opened={modalOpened} onClose={() => { setModalOpened(false); clear(); }} title="Medication" size="lg" withCloseButton > <Box> <AsyncAutocomplete<CodeableConcept> placeholder="Search medications..." loadOptions={searchMedications} toOption={toOption} onChange={(medications) => { if (medications.length > 0) { setSelectedMedication(medications[0] as CodeableConcept); } else { setSelectedMedication(undefined); } }} minInputLength={3} //DoseSpot requires at least 3 characters to search clearable maxValues={1} // Only allow single selection /> {/* After selecting a medication, show the medication info with followup input items */} {state.selectedMedication && isCodeableConcept(state.selectedMedication) && ( <Stack gap="md" mt="lg"> <Divider /> {/* Prescription Form */} <TextInput label="Directions" placeholder="e.g., Take 1 tablet by mouth daily" value={state.directions} onChange={(e) => setSelectedMedicationDirections(e.target.value)} required /> </Stack> )} {/* Action Buttons */} <MantineGroup justify="flex-end" gap="md" mt="md"> <Button onClick={() => handleAddFavoriteMedication()} disabled={!state.directions || !state.selectedMedication || loading} loading={loading} > Add Favorite </Button> </MantineGroup> </Box> </Modal> </Container> ); }

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