@medplum/scriptsure-react 5.1.39 → 5.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/cjs/index.d.ts +4 -3
- package/dist/esm/index.d.ts +4 -3
- package/dist/esm/index.mjs.map +2 -2
- package/package.json +8 -8
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts", "../../src/common.ts", "../../src/loadScriptSureQuantityQualifiers.ts", "../../src/pharmacy-search.ts", "../../src/useScriptSureCart.ts", "../../src/useScriptSureIFrame.ts", "../../src/useScriptSureMessageTask.ts", "../../src/useScriptSureOrderMedication.ts", "../../src/useScriptSureOrderSet.ts", "../../src/useScriptSurePharmacySearch.ts", "../../src/useScriptSurePractice.tsx"],
|
|
4
|
-
"sourcesContent": ["// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nexport * from './common';\nexport * from './loadScriptSureQuantityQualifiers';\nexport * from './pharmacy-search';\nexport * from './useScriptSureCart';\nexport * from './useScriptSureIFrame';\nexport * from './useScriptSureMessageTask';\nexport * from './useScriptSureOrderMedication';\nexport * from './useScriptSureOrderSet';\nexport * from './useScriptSurePharmacySearch';\nexport * from './useScriptSurePractice';\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationOrderExtensions } from '@medplum/core';\nimport type { Identifier } from '@medplum/fhirtypes';\n\nexport const MEDPLUM_BOT_SYSTEM = 'https://www.medplum.com/bots';\n\n/**\n * @deprecated Use the vendor-neutral `$drug-search` custom FHIR operation via\n * `useMedicationOrder().searchMedications(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `drug-search` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_DRUG_SEARCH_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-drug-search-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-medication` custom FHIR operation via\n * `useMedicationOrder().orderMedication(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-medication` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_MEDICATION_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-medication-bot',\n};\n\n/** Identifier system for ScriptSure ROUTED_MED_ID on in-memory Medication resources from drug search. */\nexport const SCRIPTSURE_ROUTED_MED_ID_SYSTEM = 'https://scriptsure.com/routed-med-id';\n\n/**\n * Identifier/coding system for the FDB GCN Sequence Number (`GCN_SEQNO`) \u2014 the\n * clinical-formulation key (ingredient+strength+dose-form+route), independent of\n * brand and NDC. Stamped as a `medicationCodeableConcept.coding` on the draft\n * MedicationRequest so the ScriptSure prescription webhook can reconcile a draft\n * to its sent prescription even when the NDC drifts or the pharmacy substitutes a\n * generic (brand and generic share the same GCN). Mirrors the medplum-ee bot\n * constant of the same name.\n */\nexport const SCRIPTSURE_GCN_SEQNO_SYSTEM = 'https://scriptsure.com/gcn-seqno';\n\nexport const SCRIPTSURE_PENDING_ORDER_ID_SYSTEM = 'https://scriptsure.com/pending-order-id';\n\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION = 'https://scriptsure.com/pending-order-status';\n\n/**\n * `SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION` value marking a draft\n * `MedicationRequest` as staged in the patient's ScriptSure MedCart (added by\n * `$checkout-medications`, before the prescriber sends from the MedCart widget).\n * Consumed by the paired `medplum-ee` cart-checkout / cart-manage bots when\n * stamping drafts; the Provider App uses the pure-cart model (all drafts on the\n * Draft tab) rather than filtering on this code today.\n */\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_IN_CART = 'in-cart';\n\nexport const SCRIPTSURE_IFRAME_URL_EXTENSION = 'https://scriptsure.com/iframe-url';\n\n/**\n * Identifier system for the SureScripts `messageId` stamped on a draft\n * `MedicationRequest` by the cart-checkout flow (electronic-queue submit).\n * Consumed by the paired `medplum-ee` `scriptsure-cart-checkout-bot` when\n * stamping queued drafts and by `scriptsure-prescription-webhook-bot` when\n * reconciling the approval webhook back to the originating draft.\n */\nexport const SCRIPTSURE_MESSAGE_ID_SYSTEM = 'https://scriptsure.com/message-id';\n\nexport const SCRIPTSURE_MEDICATION_ORDER_EXTENSIONS: MedicationOrderExtensions = {\n pendingOrderIdSystem: SCRIPTSURE_PENDING_ORDER_ID_SYSTEM,\n pendingOrderStatusUrl: SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION,\n iframeUrlExtension: SCRIPTSURE_IFRAME_URL_EXTENSION,\n messageIdSystem: SCRIPTSURE_MESSAGE_ID_SYSTEM,\n};\n\nexport const SCRIPTSURE_IFRAME_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-iframe-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_SYNC_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-patient-sync-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-set-url` custom FHIR operation via\n * `useScriptSureOrderSet(...)` (thin wrapper around `useMedicationOrderSet`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-set-url` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_SET_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-set-bot',\n};\n\n/** Identifier system for the ScriptSure orderset id stamped on FHIR PlanDefinitions. */\nexport const SCRIPTSURE_ORDERSET_ID_SYSTEM = 'https://spa.scriptsure.com/orderset-id';\n\nexport const SCRIPTSURE_SEARCH_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-search-pharmacy-bot',\n};\n\nexport const SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-add-patient-pharmacy-bot',\n};\n\n/** Bot that launches and reconciles ScriptSure pharmacy-message Tasks. */\nexport const SCRIPTSURE_MESSAGE_TASK_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-message-task-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_ID_SYSTEM = 'https://scriptsure.com/patient-id';\n\n/**\n * Identifier system for the ScriptSure `practiceId` stamped on the Practice-level\n * Medplum `Organization`. Used by the practice/location selector to discover the\n * prescriber's ScriptSure practices and pass the chosen `organizationId` to bots.\n */\nexport const SCRIPTSURE_PRACTICE_ID_SYSTEM = 'https://scriptsure.com/practice-id';\n\n/** Identifier system for the ScriptSure `businessUnitId` on the BU-level Medplum `Organization`. */\nexport const SCRIPTSURE_BUSINESS_UNIT_ID_SYSTEM = 'https://scriptsure.com/business-unit-id';\n\n/** `Organization.type` coding system discriminating ScriptSure entity Organizations (`business-unit` | `practice`). */\nexport const SCRIPTSURE_ORGANIZATION_TYPE_SYSTEM = 'https://scriptsure.com/organization-type';\n\n/** Base URL for ScriptSure-specific extensions on in-memory Medication resources (e.g. `/sig`). */\nexport const SCRIPTSURE_SYSTEM = 'https://scriptsure.com';\n\n/** Pre-built dosing option on a Medication from drug-format lookup (`routedMedId` search). */\nexport const SCRIPTSURE_SIG_EXTENSION = `${SCRIPTSURE_SYSTEM}/sig`;\n\n/** ScriptSure MED_NAME_TYPE_CD on a search-result Medication: `'1'` = brand, `'2'` = generic. */\nexport const SCRIPTSURE_NAME_TYPE_EXTENSION = `${SCRIPTSURE_SYSTEM}/name-type`;\n\n/** ScriptSure GenericName on a search-result Medication (parent generic when the row is a brand). */\nexport const SCRIPTSURE_GENERIC_NAME_EXTENSION = `${SCRIPTSURE_SYSTEM}/generic-name`;\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { MedplumClient } from '@medplum/core';\nimport { isResource, medicationSearchParamsToParameters } from '@medplum/core';\nimport type { Parameters } from '@medplum/fhirtypes';\n\n/**\n * Reads `{ code, label }` rows from a `Parameters` resource produced by the\n * `$drug-quantity-qualifiers` custom operation.\n *\n * The OperationDefinition (see `scriptsure-drug-search-bot` registration in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`) declares a single\n * repeating output parameter named `quantityQualifier`, each entry bearing\n * `part: [{ name: 'code', valueString }, { name: 'label', valueString }]`.\n * The server's `buildOutputParameters` wraps the bot return value into that\n * shape, so the parser only needs to handle this one canonical layout.\n * Entries missing either inner part are skipped defensively.\n *\n * @param params - `Parameters` resource returned by the operation.\n * @returns `{ code, label }` rows for UI selects.\n */\nfunction parametersToQuantityQualifiers(params: Parameters): { code: string; label: string }[] {\n const rows: { code: string; label: string }[] = [];\n for (const p of params.parameter ?? []) {\n if (p.name !== 'quantityQualifier' || !p.part) {\n continue;\n }\n const code = p.part.find((part) => part.name === 'code')?.valueString;\n const label = p.part.find((part) => part.name === 'label')?.valueString;\n if (typeof code === 'string' && typeof label === 'string') {\n rows.push({ code, label });\n }\n }\n return rows;\n}\n\n/**\n * Fetches NCI potency-unit codes for dispense quantity qualifiers via the\n * vendor-neutral `$drug-quantity-qualifiers` custom FHIR operation. Each\n * Medplum project picks the vendor implementation at deploy time by pointing\n * its `OperationDefinition` at the appropriate Bot (ScriptSure's\n * `scriptsure-drug-search-bot` today; see `deploy.ts`).\n *\n * @param medplum - Medplum client (user session).\n * @returns `{ code, label }` rows for UI selects.\n */\nexport async function loadScriptSureQuantityQualifiers(\n medplum: MedplumClient\n): Promise<{ code: string; label: string }[]> {\n const url = medplum.fhirUrl('Medication', '$drug-quantity-qualifiers');\n const body = medicationSearchParamsToParameters({ quantityQualifiers: true });\n const response = await medplum.post(url, body);\n if (!isResource<Parameters>(response, 'Parameters')) {\n return [];\n }\n return parametersToQuantityQualifiers(response);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PharmacySearchParams } from '@medplum/core';\n\n/**\n * SureScripts pharmacy specialty tags accepted by POST /v3/pharmacy/search `specialties`.\n * Must stay aligned with ScriptSure API allowed values.\n */\nexport type ScriptSurePharmacySpecialty =\n | 'Retail'\n | 'MailOrder'\n | 'TwentyFourHourStore'\n | 'SupportsDigitalSignature'\n | 'LongTermCare'\n | 'Specialty'\n | 'FaxPharmacySurescripts';\n\nexport interface ScriptSurePharmacySpecialtyOption {\n readonly value: ScriptSurePharmacySpecialty;\n readonly label: string;\n}\n\n/** Category filters shown in the ScriptSure pharmacy search dialog. */\nexport const SCRIPTSURE_PHARMACY_SPECIALTY_OPTIONS: readonly ScriptSurePharmacySpecialtyOption[] = [\n { value: 'Retail', label: 'Retail' },\n { value: 'MailOrder', label: 'Mail order' },\n { value: 'TwentyFourHourStore', label: '24-hour' },\n { value: 'LongTermCare', label: 'Long-term care' },\n { value: 'Specialty', label: 'Specialty' },\n { value: 'SupportsDigitalSignature', label: 'Digital signature' },\n { value: 'FaxPharmacySurescripts', label: 'Fax (Surescripts)' },\n] as const;\n\n/** Default specialty filter for nearby retail pharmacy pickers. */\nexport const SCRIPTSURE_DEFAULT_PHARMACY_SPECIALTIES: readonly ScriptSurePharmacySpecialty[] = ['Retail'];\n\n/**\n * ScriptSure pharmacy search parameters.\n * Extends the shared dialog fields with SureScripts specialty filters.\n */\nexport interface ScriptSurePharmacySearchParams extends PharmacySearchParams {\n specialties?: ScriptSurePharmacySpecialty[];\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationCartReturn } from '@medplum/react-hooks';\nimport { useMedicationCart } from '@medplum/react-hooks';\n\nexport type UseScriptSureCartReturn = UseMedicationCartReturn;\n\n/**\n * React hook for the ScriptSure **medication cart** lifecycle: add a draft\n * `MedicationRequest` line (`createResource`), check out drafts into the\n * patient's ScriptSure MedCart (`$checkout-medications` \u2192\n * `/widgets/medcart/{patientId}`), and remove/clear cart lines\n * (`$remove-cart-medication` / `$clear-cart`).\n *\n * A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the\n * vendor binding for the custom operations lives entirely on the server, where\n * each Medplum project's `OperationDefinition`s point at the ScriptSure bots via\n * the `operationDefinition-implementation` extension \u2014 see\n * [Custom FHIR Operations](https://www.medplum.com/docs/bots/custom-fhir-operations).\n * (Internal deploy: `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`.)\n *\n * `addToCart` is plain FHIR create (no vendor call); MedCart staging happens at\n * `checkout`. DoseSpot and other iframe-first vendors do not use this surface.\n *\n * Kept as a typed alias for source-compatibility with apps importing\n * `useScriptSureCart` and as a documentation anchor for ScriptSure-specific\n * behavior (patient-must-be-synced precondition; cart items await sign-off in\n * the MedCart widget).\n *\n * @returns The same API as `useMedicationCart` (`addToCart`, `adding`,\n * `checkout`, `removeFromCart`, `clearCart`).\n */\nexport function useScriptSureCart(): UseScriptSureCartReturn {\n return useMedicationCart();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationIFrameOptions } from '@medplum/react-hooks';\nimport { useMedicationIFrame } from '@medplum/react-hooks';\nimport { SCRIPTSURE_IFRAME_BOT, SCRIPTSURE_PATIENT_SYNC_BOT } from './common';\n\nexport type ScriptSureIFrameOptions = MedicationIFrameOptions;\n\n/**\n * React hook that syncs a patient to ScriptSure and returns the iframe URL.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#useMedicationIFrame} hook,\n * pre-configured with ScriptSure bot identifiers.\n *\n * @param options - Configuration and callback options.\n * @returns The ScriptSure iframe URL, or undefined while loading.\n */\nexport function useScriptSureIFrame(options: ScriptSureIFrameOptions): string | undefined {\n return useMedicationIFrame(SCRIPTSURE_PATIENT_SYNC_BOT, SCRIPTSURE_IFRAME_BOT, options);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { isResource } from '@medplum/core';\nimport type { Task } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport { useCallback } from 'react';\nimport { SCRIPTSURE_MESSAGE_TASK_BOT } from './common';\n\nexport type ScriptSureMessageTaskAction = 'launch' | 'reconcile' | 'acknowledge';\n\n/** Request accepted by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskRequest {\n taskId: string;\n action: ScriptSureMessageTaskAction;\n organizationId?: string;\n}\n\n/** Validated response returned by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskResponse {\n task: Task;\n launchUrl?: string;\n vendorStatus?: string;\n}\n\nexport interface ScriptSureMessageTaskParams {\n taskId: string;\n organizationId?: string;\n}\n\nexport interface UseScriptSureMessageTaskReturn {\n launch: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n reconcile: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n acknowledge: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n}\n\nconst INVALID_MESSAGE_TASK_RESPONSE = 'Invalid ScriptSure message-task response';\n\nfunction parseMessageTaskResponse(value: unknown): ScriptSureMessageTaskResponse {\n if (!value || typeof value !== 'object') {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n const response = value as Record<string, unknown>;\n if (\n !isResource<Task>(response.task, 'Task') ||\n (response.launchUrl !== undefined && typeof response.launchUrl !== 'string') ||\n (response.vendorStatus !== undefined && typeof response.vendorStatus !== 'string')\n ) {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n return response as unknown as ScriptSureMessageTaskResponse;\n}\n\n/**\n * Executes the ScriptSure pharmacy-message Task lifecycle bot.\n *\n * The hook intentionally exposes only the three supported actions and validates\n * the untyped Bot response before returning it to the application.\n *\n * @returns Typed launch, reconcile, and acknowledge callbacks.\n */\nexport function useScriptSureMessageTask(): UseScriptSureMessageTaskReturn {\n const medplum = useMedplum();\n\n const execute = useCallback(\n async (\n action: ScriptSureMessageTaskAction,\n params: ScriptSureMessageTaskParams\n ): Promise<ScriptSureMessageTaskResponse> => {\n const request: ScriptSureMessageTaskRequest = { ...params, action };\n return parseMessageTaskResponse(await medplum.executeBot(SCRIPTSURE_MESSAGE_TASK_BOT, request));\n },\n [medplum]\n );\n\n const launch = useCallback((params: ScriptSureMessageTaskParams) => execute('launch', params), [execute]);\n const reconcile = useCallback((params: ScriptSureMessageTaskParams) => execute('reconcile', params), [execute]);\n const acknowledge = useCallback((params: ScriptSureMessageTaskParams) => execute('acknowledge', params), [execute]);\n\n return { launch, reconcile, acknowledge };\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationOrderReturn } from '@medplum/react-hooks';\nimport { useMedicationOrder } from '@medplum/react-hooks';\n\nexport type UseScriptSureOrderMedicationReturn = UseMedicationOrderReturn;\n\n/**\n * React hook for ScriptSure drug search and pending order creation (iframe launch URL).\n *\n * Now a near-empty re-export of `useMedicationOrder` from `@medplum/react-hooks`: the\n * vendor binding lives entirely on the server, where each Medplum project's\n * `OperationDefinition` resources for `$drug-search` and `$order-medication`\n * point at the ScriptSure bots via the\n * `operationDefinition-implementation` extension. See the deploy script in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts` for how those\n * resources are upserted.\n *\n * Kept as a typed alias for backwards source-compatibility with apps importing\n * `useScriptSureOrderMedication` and as a documentation anchor for the\n * ScriptSure-specific behavior (e.g. patient-must-be-synced precondition).\n *\n * @returns The same API as `useMedicationOrder` (search + order callbacks).\n */\nexport function useScriptSureOrderMedication(): UseScriptSureOrderMedicationReturn {\n return useMedicationOrder();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { Organization, Reference } from '@medplum/fhirtypes';\nimport type { UseMedicationOrderSetReturn } from '@medplum/react-hooks';\nimport { useMedicationOrderSet } from '@medplum/react-hooks';\n\nexport interface UseScriptSureOrderSetOptions {\n /** Patient to prescribe against. Hook stays idle (no operation call) until set. */\n readonly patientId: string | undefined;\n /** Medplum PlanDefinition id; bot reverse-looks up the ScriptSure orderset id. */\n readonly planDefinitionId?: string;\n /** ScriptSure orderset id (escape hatch when no synced PD exists yet). */\n readonly scriptSureOrdersetId?: number;\n readonly appId?: string;\n /** Selected practice location for multi-practice deployments. */\n readonly organization?: Reference<Organization>;\n}\n\nexport type UseScriptSureOrderSetReturn = UseMedicationOrderSetReturn;\n\n/**\n * React hook that returns the ScriptSure order-set prescribing widget URL via\n * the vendor-neutral `$order-set-url` FHIR custom operation\n * (`POST /fhir/R4/PlanDefinition/$order-set-url`).\n *\n * Thin wrapper around {@link @medplum/react-hooks#useMedicationOrderSet}: forwards\n * `scriptSureOrdersetId` as the operation's `vendorOrderSetId` parameter,\n * leaves vendor binding to the deployed `OperationDefinition` \u2192\n * `Bot/scriptsure-order-set-bot` link.\n *\n * The operation is naturally idempotent \u2014 re-calls only refresh the session\n * token in the returned URL \u2014 so callers can safely wire `refresh` into\n * `PrescriptionIFrameModal.onRefreshLaunchUrl`.\n *\n * @param options - Patient + order-set picker (PD or ScriptSure id).\n * @returns `{ url, loading, error, refresh }`.\n */\nexport function useScriptSureOrderSet(options: UseScriptSureOrderSetOptions): UseScriptSureOrderSetReturn {\n return useMedicationOrderSet({\n patientId: options.patientId,\n planDefinitionId: options.planDefinitionId,\n vendorOrderSetId: options.scriptSureOrdersetId,\n appId: options.appId,\n organization: options.organization,\n });\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UsePharmacySearchReturn } from '@medplum/react-hooks';\nimport { usePharmacySearch } from '@medplum/react-hooks';\nimport { SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT, SCRIPTSURE_SEARCH_PHARMACY_BOT } from './common';\nimport type { ScriptSurePharmacySearchParams } from './pharmacy-search';\n\nexport type UseScriptSurePharmacySearchReturn = UsePharmacySearchReturn<ScriptSurePharmacySearchParams>;\n\n/**\n * React hook that provides ScriptSure-specific pharmacy search and add-to-favorites functionality.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#usePharmacySearch} hook, pre-configured with\n * ScriptSure bot identifiers and widened so search params carry ScriptSure-only\n * `specialties` filters for POST /v3/pharmacy/search.\n *\n * @returns An object with `searchPharmacies` and `addToFavorites` callbacks.\n */\nexport function useScriptSurePharmacySearch(): UseScriptSurePharmacySearchReturn {\n return usePharmacySearch<ScriptSurePharmacySearchParams>(\n SCRIPTSURE_SEARCH_PHARMACY_BOT,\n SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT\n );\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { getIdentifier, resolveId } from '@medplum/core';\nimport type { Organization, Practitioner, PractitionerRole, Reference } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport type { JSX, ReactNode } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { SCRIPTSURE_PRACTICE_ID_SYSTEM } from './common';\n\nconst STORAGE_KEY = 'medplum.scriptsure.selectedPracticeOrganization';\n\n/** The current ScriptSure practice-location selection for the signed-in prescriber. */\nexport interface ScriptSurePracticeContextValue {\n /**\n * The prescriber's ScriptSure practice `Organization`s \u2014 discovered from their\n * own affiliations (`PractitionerRole.organization` + `ProjectMembership.access`\n * organization parameters), filtered to those carrying a `practice-id` identifier.\n * Never the project-wide list.\n */\n readonly practices: Organization[];\n /** Bare Organization id used by the selector and persisted in localStorage. */\n readonly selectedOrganizationId: string | undefined;\n /** FHIR reference for the selected practice, suitable for operation and hook inputs. */\n readonly selectedOrganization: Reference<Organization> | undefined;\n /** Selects a practice Organization (persisted to localStorage). */\n readonly setSelectedOrganizationId: (id: string | undefined) => void;\n readonly loading: boolean;\n}\n\nconst ScriptSurePracticeContext = createContext<ScriptSurePracticeContextValue>({\n practices: [],\n selectedOrganizationId: undefined,\n selectedOrganization: undefined,\n setSelectedOrganizationId: () => undefined,\n loading: false,\n});\n\nfunction addOrganizationReference(refs: Set<string>, reference: string | undefined): void {\n if (reference?.startsWith('Organization/')) {\n refs.add(reference);\n }\n}\n\nfunction hasPracticeIdentifier(org: Organization): boolean {\n return Boolean(getIdentifier(org, SCRIPTSURE_PRACTICE_ID_SYSTEM));\n}\n\n/**\n * Resolves the signed-in prescriber's `Practitioner.id` from the current profile,\n * whether the profile is a `Practitioner` or a `PractitionerRole`.\n *\n * @param profile - The current Medplum profile resource.\n * @returns The Practitioner id, or undefined when it cannot be resolved.\n */\nfunction resolvePractitionerId(profile: Practitioner | PractitionerRole | undefined): string | undefined {\n if (profile?.resourceType === 'Practitioner') {\n return profile.id;\n }\n if (profile?.resourceType === 'PractitionerRole') {\n return resolveId(profile.practitioner);\n }\n return undefined;\n}\n\n/**\n * Provides the signed-in prescriber's current ScriptSure practice-location\n * selection, discovered from **their own affiliations** \u2014 mirroring the server's\n * multi-practice resolver so the UI never offers a practice the prescriber is not\n * a member of.\n *\n * Discovery: active `PractitionerRole.organization` references for the current\n * `Practitioner` plus any `ProjectMembership.access[].parameter` named\n * `organization`, resolved to `Organization`s and filtered to those carrying a\n * `practice-id` identifier. The sole practice is auto-selected; a previously used\n * selection is restored only when it is still in the affiliation set.\n *\n * @param props - Component props.\n * @param props.children - Child nodes rendered within the provider.\n * @returns The context provider element.\n */\nexport function ScriptSurePracticeProvider(props: { readonly children: ReactNode }): JSX.Element {\n const medplum = useMedplum();\n const [practices, setPractices] = useState<Organization[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedOrganizationId, setSelected] = useState<string | undefined>(\n () => localStorage.getItem(STORAGE_KEY) ?? undefined\n );\n\n useEffect(() => {\n let cancelled = false;\n\n const loadAffiliatedPractices = async (): Promise<Organization[]> => {\n const profile = medplum.getProfile() as Practitioner | PractitionerRole | undefined;\n const practitionerId = resolvePractitionerId(profile);\n const references = new Set<string>();\n\n if (practitionerId) {\n const roles = await medplum.searchResources('PractitionerRole', {\n practitioner: `Practitioner/${practitionerId}`,\n _count: '100',\n });\n for (const role of roles) {\n // `active` is not a standard R4 PractitionerRole search param \u2014 filter in code.\n if (role.active !== false) {\n addOrganizationReference(references, role.organization?.reference);\n }\n }\n }\n\n const membership = medplum.getProjectMembership();\n for (const access of membership?.access ?? []) {\n for (const param of access.parameter ?? []) {\n if (param.name === 'organization') {\n addOrganizationReference(references, param.valueReference?.reference);\n }\n }\n }\n\n const settledOrgs = await Promise.allSettled(\n [...references].map((reference) => medplum.readReference<Organization>({ reference }))\n );\n const seen = new Set<string>();\n const result: Organization[] = [];\n for (const settledOrg of settledOrgs) {\n if (settledOrg.status === 'rejected') {\n continue;\n }\n const org = settledOrg.value;\n if (org.id && !seen.has(org.id) && hasPracticeIdentifier(org)) {\n seen.add(org.id);\n result.push(org);\n }\n }\n return result;\n };\n\n const updateAffiliatedPractices = async (): Promise<void> => {\n setLoading(true);\n try {\n const orgs = await loadAffiliatedPractices();\n if (!cancelled) {\n setPractices(orgs);\n // Default: keep a stored id only if it is still an affiliation; else the sole practice.\n setSelected((current) => {\n if (current && orgs.some((o) => o.id === current)) {\n return current;\n }\n return orgs.length === 1 ? orgs[0].id : undefined;\n });\n }\n } catch {\n if (!cancelled) {\n setPractices([]);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n };\n updateAffiliatedPractices().catch(() => undefined);\n\n return (): void => {\n cancelled = true;\n };\n }, [medplum]);\n\n const setSelectedOrganizationId = useCallback((id: string | undefined): void => {\n setSelected(id);\n if (id) {\n localStorage.setItem(STORAGE_KEY, id);\n } else {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, []);\n\n const selectedOrganization = useMemo<Reference<Organization> | undefined>(\n () => (selectedOrganizationId ? { reference: `Organization/${selectedOrganizationId}` } : undefined),\n [selectedOrganizationId]\n );\n\n const value = useMemo<ScriptSurePracticeContextValue>(\n () => ({ practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading }),\n [practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading]\n );\n\n return <ScriptSurePracticeContext.Provider value={value}>{props.children}</ScriptSurePracticeContext.Provider>;\n}\n\n/**\n * Hook returning the current ScriptSure practice selection + setter.\n *\n * @returns The practice context value.\n */\nexport function useScriptSurePractice(): ScriptSurePracticeContextValue {\n return useContext(ScriptSurePracticeContext);\n}\n"],
|
|
5
|
-
"mappings": "wpBAAA,43ECKO,IAAM,mBAAqB,+BAWrB,2BAAyC,CACpD,OAAQ,mBACR,MAAO,4BACT,EAWa,gCAA8C,CACzD,OAAQ,mBACR,MAAO,iCACT,EAGa,gCAAkC,uCAWlC,4BAA8B,mCAE9B,mCAAqC,0CAErC,0CAA4C,8CAU5C,wCAA0C,UAE1C,gCAAkC,oCASlC,6BAA+B,oCAE/B,uCAAoE,CAC/E,qBAAsB,mCACtB,sBAAuB,0CACvB,mBAAoB,gCACpB,gBAAiB,4BACnB,EAEa,sBAAoC,CAC/C,OAAQ,mBACR,MAAO,uBACT,EAEa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAWa,yBAAuC,CAClD,OAAQ,mBACR,MAAO,0BACT,EAGa,8BAAgC,yCAEhC,+BAA6C,CACxD,OAAQ,mBACR,MAAO,gCACT,EAEa,oCAAkD,CAC7D,OAAQ,mBACR,MAAO,qCACT,EAGa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAEa,6BAA+B,oCAO/B,8BAAgC,qCAGhC,mCAAqC,0CAGrC,oCAAsC,2CAGtC,kBAAoB,yBAGpB,yBAA2B,GAAG,iBAAiB,OAG/C,+BAAiC,GAAG,iBAAiB,aAGrD,kCAAoC,GAAG,iBAAiB,gBCjJrE,gBAA+D,yBAkB/D,SAAS,+BAA+B,OAAuD,CAC7F,IAAM,KAA0C,CAAC,EACjD,QAAW,KAAK,OAAO,WAAa,CAAC,EAAG,CACtC,GAAI,EAAE,OAAS,qBAAuB,CAAC,EAAE,KACvC,SAEF,IAAM,KAAO,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,MAAM,GAAG,YACpD,MAAQ,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,OAAO,GAAG,YACxD,OAAO,MAAS,UAAY,OAAO,OAAU,UAC/C,KAAK,KAAK,CAAE,KAAM,KAAM,CAAC,CAE7B,CACA,OAAO,IACT,CAYA,eAAsB,iCACpB,QAC4C,CAC5C,IAAM,IAAM,QAAQ,QAAQ,aAAc,2BAA2B,EAC/D,QAAO,gDAAmC,CAAE,mBAAoB,EAAK,CAAC,EACtE,SAAW,MAAM,QAAQ,KAAK,IAAK,IAAI,EAC7C,SAAK,wBAAuB,SAAU,YAAY,EAG3C,+BAA+B,QAAQ,EAFrC,CAAC,CAGZ,CCjCO,IAAM,sCAAsF,CACjG,CAAE,MAAO,SAAU,MAAO,QAAS,EACnC,CAAE,MAAO,YAAa,MAAO,YAAa,EAC1C,CAAE,MAAO,sBAAuB,MAAO,SAAU,EACjD,CAAE,MAAO,eAAgB,MAAO,gBAAiB,EACjD,CAAE,MAAO,YAAa,MAAO,WAAY,EACzC,CAAE,MAAO,2BAA4B,MAAO,mBAAoB,EAChE,CAAE,MAAO,yBAA0B,MAAO,mBAAoB,CAChE,EAGa,wCAAkF,CAAC,QAAQ,EC/BxG,uBAAkC,
|
|
4
|
+
"sourcesContent": ["// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nexport * from './common';\nexport * from './loadScriptSureQuantityQualifiers';\nexport * from './pharmacy-search';\nexport * from './useScriptSureCart';\nexport * from './useScriptSureIFrame';\nexport * from './useScriptSureMessageTask';\nexport * from './useScriptSureOrderMedication';\nexport * from './useScriptSureOrderSet';\nexport * from './useScriptSurePharmacySearch';\nexport * from './useScriptSurePractice';\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationOrderExtensions } from '@medplum/core';\nimport type { Identifier } from '@medplum/fhirtypes';\n\nexport const MEDPLUM_BOT_SYSTEM = 'https://www.medplum.com/bots';\n\n/**\n * @deprecated Use the vendor-neutral `$drug-search` custom FHIR operation via\n * `useMedicationOrder().searchMedications(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `drug-search` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_DRUG_SEARCH_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-drug-search-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-medication` custom FHIR operation via\n * `useMedicationOrder().orderMedication(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-medication` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_MEDICATION_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-medication-bot',\n};\n\n/** Identifier system for ScriptSure ROUTED_MED_ID on in-memory Medication resources from drug search. */\nexport const SCRIPTSURE_ROUTED_MED_ID_SYSTEM = 'https://scriptsure.com/routed-med-id';\n\n/**\n * Identifier/coding system for the FDB GCN Sequence Number (`GCN_SEQNO`) \u2014 the\n * clinical-formulation key (ingredient+strength+dose-form+route), independent of\n * brand and NDC. Stamped as a `medicationCodeableConcept.coding` on the draft\n * MedicationRequest so the ScriptSure prescription webhook can reconcile a draft\n * to its sent prescription even when the NDC drifts or the pharmacy substitutes a\n * generic (brand and generic share the same GCN). Mirrors the medplum-ee bot\n * constant of the same name.\n */\nexport const SCRIPTSURE_GCN_SEQNO_SYSTEM = 'https://scriptsure.com/gcn-seqno';\n\nexport const SCRIPTSURE_PENDING_ORDER_ID_SYSTEM = 'https://scriptsure.com/pending-order-id';\n\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION = 'https://scriptsure.com/pending-order-status';\n\n/**\n * `SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION` value marking a draft\n * `MedicationRequest` as staged in the patient's ScriptSure MedCart (added by\n * `$checkout-medications`, before the prescriber sends from the MedCart widget).\n * Consumed by the paired `medplum-ee` cart-checkout / cart-manage bots when\n * stamping drafts; the Provider App uses the pure-cart model (all drafts on the\n * Draft tab) rather than filtering on this code today.\n */\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_IN_CART = 'in-cart';\n\nexport const SCRIPTSURE_IFRAME_URL_EXTENSION = 'https://scriptsure.com/iframe-url';\n\n/**\n * Identifier system for the SureScripts `messageId` stamped on a draft\n * `MedicationRequest` by the cart-checkout flow (electronic-queue submit).\n * Consumed by the paired `medplum-ee` `scriptsure-cart-checkout-bot` when\n * stamping queued drafts and by `scriptsure-prescription-webhook-bot` when\n * reconciling the approval webhook back to the originating draft.\n */\nexport const SCRIPTSURE_MESSAGE_ID_SYSTEM = 'https://scriptsure.com/message-id';\n\nexport const SCRIPTSURE_MEDICATION_ORDER_EXTENSIONS: MedicationOrderExtensions = {\n pendingOrderIdSystem: SCRIPTSURE_PENDING_ORDER_ID_SYSTEM,\n pendingOrderStatusUrl: SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION,\n iframeUrlExtension: SCRIPTSURE_IFRAME_URL_EXTENSION,\n messageIdSystem: SCRIPTSURE_MESSAGE_ID_SYSTEM,\n};\n\nexport const SCRIPTSURE_IFRAME_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-iframe-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_SYNC_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-patient-sync-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-set-url` custom FHIR operation via\n * `useScriptSureOrderSet(...)` (thin wrapper around `useMedicationOrderSet`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-set-url` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_SET_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-set-bot',\n};\n\n/** Identifier system for the ScriptSure orderset id stamped on FHIR PlanDefinitions. */\nexport const SCRIPTSURE_ORDERSET_ID_SYSTEM = 'https://spa.scriptsure.com/orderset-id';\n\nexport const SCRIPTSURE_SEARCH_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-search-pharmacy-bot',\n};\n\nexport const SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-add-patient-pharmacy-bot',\n};\n\n/** Bot that launches and reconciles ScriptSure pharmacy-message Tasks. */\nexport const SCRIPTSURE_MESSAGE_TASK_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-message-task-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_ID_SYSTEM = 'https://scriptsure.com/patient-id';\n\n/**\n * Identifier system for the ScriptSure `practiceId` stamped on the Practice-level\n * Medplum `Organization`. Used by the practice/location selector to discover the\n * prescriber's ScriptSure practices and pass the chosen `organizationId` to bots.\n */\nexport const SCRIPTSURE_PRACTICE_ID_SYSTEM = 'https://scriptsure.com/practice-id';\n\n/** Identifier system for the ScriptSure `businessUnitId` on the BU-level Medplum `Organization`. */\nexport const SCRIPTSURE_BUSINESS_UNIT_ID_SYSTEM = 'https://scriptsure.com/business-unit-id';\n\n/** `Organization.type` coding system discriminating ScriptSure entity Organizations (`business-unit` | `practice`). */\nexport const SCRIPTSURE_ORGANIZATION_TYPE_SYSTEM = 'https://scriptsure.com/organization-type';\n\n/** Base URL for ScriptSure-specific extensions on in-memory Medication resources (e.g. `/sig`). */\nexport const SCRIPTSURE_SYSTEM = 'https://scriptsure.com';\n\n/** Pre-built dosing option on a Medication from drug-format lookup (`routedMedId` search). */\nexport const SCRIPTSURE_SIG_EXTENSION = `${SCRIPTSURE_SYSTEM}/sig`;\n\n/** ScriptSure MED_NAME_TYPE_CD on a search-result Medication: `'1'` = brand, `'2'` = generic. */\nexport const SCRIPTSURE_NAME_TYPE_EXTENSION = `${SCRIPTSURE_SYSTEM}/name-type`;\n\n/** ScriptSure GenericName on a search-result Medication (parent generic when the row is a brand). */\nexport const SCRIPTSURE_GENERIC_NAME_EXTENSION = `${SCRIPTSURE_SYSTEM}/generic-name`;\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { MedplumClient } from '@medplum/core';\nimport { isResource, medicationSearchParamsToParameters } from '@medplum/core';\nimport type { Parameters } from '@medplum/fhirtypes';\n\n/**\n * Reads `{ code, label }` rows from a `Parameters` resource produced by the\n * `$drug-quantity-qualifiers` custom operation.\n *\n * The OperationDefinition (see `scriptsure-drug-search-bot` registration in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`) declares a single\n * repeating output parameter named `quantityQualifier`, each entry bearing\n * `part: [{ name: 'code', valueString }, { name: 'label', valueString }]`.\n * The server's `buildOutputParameters` wraps the bot return value into that\n * shape, so the parser only needs to handle this one canonical layout.\n * Entries missing either inner part are skipped defensively.\n *\n * @param params - `Parameters` resource returned by the operation.\n * @returns `{ code, label }` rows for UI selects.\n */\nfunction parametersToQuantityQualifiers(params: Parameters): { code: string; label: string }[] {\n const rows: { code: string; label: string }[] = [];\n for (const p of params.parameter ?? []) {\n if (p.name !== 'quantityQualifier' || !p.part) {\n continue;\n }\n const code = p.part.find((part) => part.name === 'code')?.valueString;\n const label = p.part.find((part) => part.name === 'label')?.valueString;\n if (typeof code === 'string' && typeof label === 'string') {\n rows.push({ code, label });\n }\n }\n return rows;\n}\n\n/**\n * Fetches NCI potency-unit codes for dispense quantity qualifiers via the\n * vendor-neutral `$drug-quantity-qualifiers` custom FHIR operation. Each\n * Medplum project picks the vendor implementation at deploy time by pointing\n * its `OperationDefinition` at the appropriate Bot (ScriptSure's\n * `scriptsure-drug-search-bot` today; see `deploy.ts`).\n *\n * @param medplum - Medplum client (user session).\n * @returns `{ code, label }` rows for UI selects.\n */\nexport async function loadScriptSureQuantityQualifiers(\n medplum: MedplumClient\n): Promise<{ code: string; label: string }[]> {\n const url = medplum.fhirUrl('Medication', '$drug-quantity-qualifiers');\n const body = medicationSearchParamsToParameters({ quantityQualifiers: true });\n const response = await medplum.post(url, body);\n if (!isResource<Parameters>(response, 'Parameters')) {\n return [];\n }\n return parametersToQuantityQualifiers(response);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PharmacySearchParams } from '@medplum/core';\n\n/**\n * SureScripts pharmacy specialty tags accepted by POST /v3/pharmacy/search `specialties`.\n * Must stay aligned with ScriptSure API allowed values.\n */\nexport type ScriptSurePharmacySpecialty =\n | 'Retail'\n | 'MailOrder'\n | 'TwentyFourHourStore'\n | 'SupportsDigitalSignature'\n | 'LongTermCare'\n | 'Specialty'\n | 'FaxPharmacySurescripts';\n\nexport interface ScriptSurePharmacySpecialtyOption {\n readonly value: ScriptSurePharmacySpecialty;\n readonly label: string;\n}\n\n/** Category filters shown in the ScriptSure pharmacy search dialog. */\nexport const SCRIPTSURE_PHARMACY_SPECIALTY_OPTIONS: readonly ScriptSurePharmacySpecialtyOption[] = [\n { value: 'Retail', label: 'Retail' },\n { value: 'MailOrder', label: 'Mail order' },\n { value: 'TwentyFourHourStore', label: '24-hour' },\n { value: 'LongTermCare', label: 'Long-term care' },\n { value: 'Specialty', label: 'Specialty' },\n { value: 'SupportsDigitalSignature', label: 'Digital signature' },\n { value: 'FaxPharmacySurescripts', label: 'Fax (Surescripts)' },\n] as const;\n\n/** Default specialty filter for nearby retail pharmacy pickers. */\nexport const SCRIPTSURE_DEFAULT_PHARMACY_SPECIALTIES: readonly ScriptSurePharmacySpecialty[] = ['Retail'];\n\n/**\n * ScriptSure pharmacy search parameters.\n * Extends the shared dialog fields with SureScripts specialty filters.\n */\nexport interface ScriptSurePharmacySearchParams extends PharmacySearchParams {\n specialties?: ScriptSurePharmacySpecialty[];\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationCartReturn } from '@medplum/react-hooks';\nimport { useMedicationCart } from '@medplum/react-hooks';\n\nexport type UseScriptSureCartReturn = UseMedicationCartReturn;\n\n/**\n * React hook for the ScriptSure **medication cart** lifecycle: add a draft\n * `MedicationRequest` line (`createResource`), check out drafts into the\n * patient's ScriptSure MedCart (`$checkout-medications` \u2192\n * `/widgets/medcart/{patientId}`), remove/clear cart lines\n * (`$remove-cart-medication` / `$clear-cart`), and read the MedCart as\n * ScriptSure holds it, reconciled against the local drafts (`$get-cart`).\n *\n * A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the\n * vendor binding for the custom operations lives entirely on the server, where\n * each Medplum project's `OperationDefinition`s point at the ScriptSure bots via\n * the `operationDefinition-implementation` extension \u2014 see\n * [Custom FHIR Operations](https://www.medplum.com/docs/bots/custom-fhir-operations).\n * (Internal deploy: `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`.)\n *\n * `addToCart` is plain FHIR create (no vendor call); MedCart staging happens at\n * `checkout`. DoseSpot and other iframe-first vendors do not use this surface.\n *\n * Kept as a typed alias for source-compatibility with apps importing\n * `useScriptSureCart` and as a documentation anchor for ScriptSure-specific\n * behavior (patient-must-be-synced precondition; cart items await sign-off in\n * the MedCart widget).\n *\n * @returns The same API as `useMedicationCart` (`addToCart`, `adding`,\n * `checkout`, `removeFromCart`, `clearCart`, `getCart`).\n */\nexport function useScriptSureCart(): UseScriptSureCartReturn {\n return useMedicationCart();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationIFrameOptions } from '@medplum/react-hooks';\nimport { useMedicationIFrame } from '@medplum/react-hooks';\nimport { SCRIPTSURE_IFRAME_BOT, SCRIPTSURE_PATIENT_SYNC_BOT } from './common';\n\nexport type ScriptSureIFrameOptions = MedicationIFrameOptions;\n\n/**\n * React hook that syncs a patient to ScriptSure and returns the iframe URL.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#useMedicationIFrame} hook,\n * pre-configured with ScriptSure bot identifiers.\n *\n * @param options - Configuration and callback options.\n * @returns The ScriptSure iframe URL, or undefined while loading.\n */\nexport function useScriptSureIFrame(options: ScriptSureIFrameOptions): string | undefined {\n return useMedicationIFrame(SCRIPTSURE_PATIENT_SYNC_BOT, SCRIPTSURE_IFRAME_BOT, options);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { isResource } from '@medplum/core';\nimport type { Task } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport { useCallback } from 'react';\nimport { SCRIPTSURE_MESSAGE_TASK_BOT } from './common';\n\nexport type ScriptSureMessageTaskAction = 'launch' | 'reconcile' | 'acknowledge';\n\n/** Request accepted by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskRequest {\n taskId: string;\n action: ScriptSureMessageTaskAction;\n organizationId?: string;\n}\n\n/** Validated response returned by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskResponse {\n task: Task;\n launchUrl?: string;\n vendorStatus?: string;\n}\n\nexport interface ScriptSureMessageTaskParams {\n taskId: string;\n organizationId?: string;\n}\n\nexport interface UseScriptSureMessageTaskReturn {\n launch: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n reconcile: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n acknowledge: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n}\n\nconst INVALID_MESSAGE_TASK_RESPONSE = 'Invalid ScriptSure message-task response';\n\nfunction parseMessageTaskResponse(value: unknown): ScriptSureMessageTaskResponse {\n if (!value || typeof value !== 'object') {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n const response = value as Record<string, unknown>;\n if (\n !isResource<Task>(response.task, 'Task') ||\n (response.launchUrl !== undefined && typeof response.launchUrl !== 'string') ||\n (response.vendorStatus !== undefined && typeof response.vendorStatus !== 'string')\n ) {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n return response as unknown as ScriptSureMessageTaskResponse;\n}\n\n/**\n * Executes the ScriptSure pharmacy-message Task lifecycle bot.\n *\n * The hook intentionally exposes only the three supported actions and validates\n * the untyped Bot response before returning it to the application.\n *\n * @returns Typed launch, reconcile, and acknowledge callbacks.\n */\nexport function useScriptSureMessageTask(): UseScriptSureMessageTaskReturn {\n const medplum = useMedplum();\n\n const execute = useCallback(\n async (\n action: ScriptSureMessageTaskAction,\n params: ScriptSureMessageTaskParams\n ): Promise<ScriptSureMessageTaskResponse> => {\n const request: ScriptSureMessageTaskRequest = { ...params, action };\n return parseMessageTaskResponse(await medplum.executeBot(SCRIPTSURE_MESSAGE_TASK_BOT, request));\n },\n [medplum]\n );\n\n const launch = useCallback((params: ScriptSureMessageTaskParams) => execute('launch', params), [execute]);\n const reconcile = useCallback((params: ScriptSureMessageTaskParams) => execute('reconcile', params), [execute]);\n const acknowledge = useCallback((params: ScriptSureMessageTaskParams) => execute('acknowledge', params), [execute]);\n\n return { launch, reconcile, acknowledge };\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationOrderReturn } from '@medplum/react-hooks';\nimport { useMedicationOrder } from '@medplum/react-hooks';\n\nexport type UseScriptSureOrderMedicationReturn = UseMedicationOrderReturn;\n\n/**\n * React hook for ScriptSure drug search and pending order creation (iframe launch URL).\n *\n * Now a near-empty re-export of `useMedicationOrder` from `@medplum/react-hooks`: the\n * vendor binding lives entirely on the server, where each Medplum project's\n * `OperationDefinition` resources for `$drug-search` and `$order-medication`\n * point at the ScriptSure bots via the\n * `operationDefinition-implementation` extension. See the deploy script in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts` for how those\n * resources are upserted.\n *\n * Kept as a typed alias for backwards source-compatibility with apps importing\n * `useScriptSureOrderMedication` and as a documentation anchor for the\n * ScriptSure-specific behavior (e.g. patient-must-be-synced precondition).\n *\n * @returns The same API as `useMedicationOrder` (search + order callbacks).\n */\nexport function useScriptSureOrderMedication(): UseScriptSureOrderMedicationReturn {\n return useMedicationOrder();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { Organization, Reference } from '@medplum/fhirtypes';\nimport type { UseMedicationOrderSetReturn } from '@medplum/react-hooks';\nimport { useMedicationOrderSet } from '@medplum/react-hooks';\n\nexport interface UseScriptSureOrderSetOptions {\n /** Patient to prescribe against. Hook stays idle (no operation call) until set. */\n readonly patientId: string | undefined;\n /** Medplum PlanDefinition id; bot reverse-looks up the ScriptSure orderset id. */\n readonly planDefinitionId?: string;\n /** ScriptSure orderset id (escape hatch when no synced PD exists yet). */\n readonly scriptSureOrdersetId?: number;\n readonly appId?: string;\n /** Selected practice location for multi-practice deployments. */\n readonly organization?: Reference<Organization>;\n}\n\nexport type UseScriptSureOrderSetReturn = UseMedicationOrderSetReturn;\n\n/**\n * React hook that returns the ScriptSure order-set prescribing widget URL via\n * the vendor-neutral `$order-set-url` FHIR custom operation\n * (`POST /fhir/R4/PlanDefinition/$order-set-url`).\n *\n * Thin wrapper around {@link @medplum/react-hooks#useMedicationOrderSet}: forwards\n * `scriptSureOrdersetId` as the operation's `vendorOrderSetId` parameter,\n * leaves vendor binding to the deployed `OperationDefinition` \u2192\n * `Bot/scriptsure-order-set-bot` link.\n *\n * The operation is naturally idempotent \u2014 re-calls only refresh the session\n * token in the returned URL \u2014 so callers can safely wire `refresh` into\n * `PrescriptionIFrameModal.onRefreshLaunchUrl`.\n *\n * @param options - Patient + order-set picker (PD or ScriptSure id).\n * @returns `{ url, loading, error, refresh }`.\n */\nexport function useScriptSureOrderSet(options: UseScriptSureOrderSetOptions): UseScriptSureOrderSetReturn {\n return useMedicationOrderSet({\n patientId: options.patientId,\n planDefinitionId: options.planDefinitionId,\n vendorOrderSetId: options.scriptSureOrdersetId,\n appId: options.appId,\n organization: options.organization,\n });\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UsePharmacySearchReturn } from '@medplum/react-hooks';\nimport { usePharmacySearch } from '@medplum/react-hooks';\nimport { SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT, SCRIPTSURE_SEARCH_PHARMACY_BOT } from './common';\nimport type { ScriptSurePharmacySearchParams } from './pharmacy-search';\n\nexport type UseScriptSurePharmacySearchReturn = UsePharmacySearchReturn<ScriptSurePharmacySearchParams>;\n\n/**\n * React hook that provides ScriptSure-specific pharmacy search and add-to-favorites functionality.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#usePharmacySearch} hook, pre-configured with\n * ScriptSure bot identifiers and widened so search params carry ScriptSure-only\n * `specialties` filters for POST /v3/pharmacy/search.\n *\n * @returns An object with `searchPharmacies` and `addToFavorites` callbacks.\n */\nexport function useScriptSurePharmacySearch(): UseScriptSurePharmacySearchReturn {\n return usePharmacySearch<ScriptSurePharmacySearchParams>(\n SCRIPTSURE_SEARCH_PHARMACY_BOT,\n SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT\n );\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { getIdentifier, resolveId } from '@medplum/core';\nimport type { Organization, Practitioner, PractitionerRole, Reference } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport type { JSX, ReactNode } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { SCRIPTSURE_PRACTICE_ID_SYSTEM } from './common';\n\nconst STORAGE_KEY = 'medplum.scriptsure.selectedPracticeOrganization';\n\n/** The current ScriptSure practice-location selection for the signed-in prescriber. */\nexport interface ScriptSurePracticeContextValue {\n /**\n * The prescriber's ScriptSure practice `Organization`s \u2014 discovered from their\n * own affiliations (`PractitionerRole.organization` + `ProjectMembership.access`\n * organization parameters), filtered to those carrying a `practice-id` identifier.\n * Never the project-wide list.\n */\n readonly practices: Organization[];\n /** Bare Organization id used by the selector and persisted in localStorage. */\n readonly selectedOrganizationId: string | undefined;\n /** FHIR reference for the selected practice, suitable for operation and hook inputs. */\n readonly selectedOrganization: Reference<Organization> | undefined;\n /** Selects a practice Organization (persisted to localStorage). */\n readonly setSelectedOrganizationId: (id: string | undefined) => void;\n readonly loading: boolean;\n}\n\nconst ScriptSurePracticeContext = createContext<ScriptSurePracticeContextValue>({\n practices: [],\n selectedOrganizationId: undefined,\n selectedOrganization: undefined,\n setSelectedOrganizationId: () => undefined,\n loading: false,\n});\n\nfunction addOrganizationReference(refs: Set<string>, reference: string | undefined): void {\n if (reference?.startsWith('Organization/')) {\n refs.add(reference);\n }\n}\n\nfunction hasPracticeIdentifier(org: Organization): boolean {\n return Boolean(getIdentifier(org, SCRIPTSURE_PRACTICE_ID_SYSTEM));\n}\n\n/**\n * Resolves the signed-in prescriber's `Practitioner.id` from the current profile,\n * whether the profile is a `Practitioner` or a `PractitionerRole`.\n *\n * @param profile - The current Medplum profile resource.\n * @returns The Practitioner id, or undefined when it cannot be resolved.\n */\nfunction resolvePractitionerId(profile: Practitioner | PractitionerRole | undefined): string | undefined {\n if (profile?.resourceType === 'Practitioner') {\n return profile.id;\n }\n if (profile?.resourceType === 'PractitionerRole') {\n return resolveId(profile.practitioner);\n }\n return undefined;\n}\n\n/**\n * Provides the signed-in prescriber's current ScriptSure practice-location\n * selection, discovered from **their own affiliations** \u2014 mirroring the server's\n * multi-practice resolver so the UI never offers a practice the prescriber is not\n * a member of.\n *\n * Discovery: active `PractitionerRole.organization` references for the current\n * `Practitioner` plus any `ProjectMembership.access[].parameter` named\n * `organization`, resolved to `Organization`s and filtered to those carrying a\n * `practice-id` identifier. The sole practice is auto-selected; a previously used\n * selection is restored only when it is still in the affiliation set.\n *\n * @param props - Component props.\n * @param props.children - Child nodes rendered within the provider.\n * @returns The context provider element.\n */\nexport function ScriptSurePracticeProvider(props: { readonly children: ReactNode }): JSX.Element {\n const medplum = useMedplum();\n const [practices, setPractices] = useState<Organization[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedOrganizationId, setSelected] = useState<string | undefined>(\n () => localStorage.getItem(STORAGE_KEY) ?? undefined\n );\n\n useEffect(() => {\n let cancelled = false;\n\n const loadAffiliatedPractices = async (): Promise<Organization[]> => {\n const profile = medplum.getProfile() as Practitioner | PractitionerRole | undefined;\n const practitionerId = resolvePractitionerId(profile);\n const references = new Set<string>();\n\n if (practitionerId) {\n const roles = await medplum.searchResources('PractitionerRole', {\n practitioner: `Practitioner/${practitionerId}`,\n _count: '100',\n });\n for (const role of roles) {\n // `active` is not a standard R4 PractitionerRole search param \u2014 filter in code.\n if (role.active !== false) {\n addOrganizationReference(references, role.organization?.reference);\n }\n }\n }\n\n const membership = medplum.getProjectMembership();\n for (const access of membership?.access ?? []) {\n for (const param of access.parameter ?? []) {\n if (param.name === 'organization') {\n addOrganizationReference(references, param.valueReference?.reference);\n }\n }\n }\n\n const settledOrgs = await Promise.allSettled(\n [...references].map((reference) => medplum.readReference<Organization>({ reference }))\n );\n const seen = new Set<string>();\n const result: Organization[] = [];\n for (const settledOrg of settledOrgs) {\n if (settledOrg.status === 'rejected') {\n continue;\n }\n const org = settledOrg.value;\n if (org.id && !seen.has(org.id) && hasPracticeIdentifier(org)) {\n seen.add(org.id);\n result.push(org);\n }\n }\n return result;\n };\n\n const updateAffiliatedPractices = async (): Promise<void> => {\n setLoading(true);\n try {\n const orgs = await loadAffiliatedPractices();\n if (!cancelled) {\n setPractices(orgs);\n // Default: keep a stored id only if it is still an affiliation; else the sole practice.\n setSelected((current) => {\n if (current && orgs.some((o) => o.id === current)) {\n return current;\n }\n return orgs.length === 1 ? orgs[0].id : undefined;\n });\n }\n } catch {\n if (!cancelled) {\n setPractices([]);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n };\n updateAffiliatedPractices().catch(() => undefined);\n\n return (): void => {\n cancelled = true;\n };\n }, [medplum]);\n\n const setSelectedOrganizationId = useCallback((id: string | undefined): void => {\n setSelected(id);\n if (id) {\n localStorage.setItem(STORAGE_KEY, id);\n } else {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, []);\n\n const selectedOrganization = useMemo<Reference<Organization> | undefined>(\n () => (selectedOrganizationId ? { reference: `Organization/${selectedOrganizationId}` } : undefined),\n [selectedOrganizationId]\n );\n\n const value = useMemo<ScriptSurePracticeContextValue>(\n () => ({ practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading }),\n [practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading]\n );\n\n return <ScriptSurePracticeContext.Provider value={value}>{props.children}</ScriptSurePracticeContext.Provider>;\n}\n\n/**\n * Hook returning the current ScriptSure practice selection + setter.\n *\n * @returns The practice context value.\n */\nexport function useScriptSurePractice(): ScriptSurePracticeContextValue {\n return useContext(ScriptSurePracticeContext);\n}\n"],
|
|
5
|
+
"mappings": "wpBAAA,43ECKO,IAAM,mBAAqB,+BAWrB,2BAAyC,CACpD,OAAQ,mBACR,MAAO,4BACT,EAWa,gCAA8C,CACzD,OAAQ,mBACR,MAAO,iCACT,EAGa,gCAAkC,uCAWlC,4BAA8B,mCAE9B,mCAAqC,0CAErC,0CAA4C,8CAU5C,wCAA0C,UAE1C,gCAAkC,oCASlC,6BAA+B,oCAE/B,uCAAoE,CAC/E,qBAAsB,mCACtB,sBAAuB,0CACvB,mBAAoB,gCACpB,gBAAiB,4BACnB,EAEa,sBAAoC,CAC/C,OAAQ,mBACR,MAAO,uBACT,EAEa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAWa,yBAAuC,CAClD,OAAQ,mBACR,MAAO,0BACT,EAGa,8BAAgC,yCAEhC,+BAA6C,CACxD,OAAQ,mBACR,MAAO,gCACT,EAEa,oCAAkD,CAC7D,OAAQ,mBACR,MAAO,qCACT,EAGa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAEa,6BAA+B,oCAO/B,8BAAgC,qCAGhC,mCAAqC,0CAGrC,oCAAsC,2CAGtC,kBAAoB,yBAGpB,yBAA2B,GAAG,iBAAiB,OAG/C,+BAAiC,GAAG,iBAAiB,aAGrD,kCAAoC,GAAG,iBAAiB,gBCjJrE,gBAA+D,yBAkB/D,SAAS,+BAA+B,OAAuD,CAC7F,IAAM,KAA0C,CAAC,EACjD,QAAW,KAAK,OAAO,WAAa,CAAC,EAAG,CACtC,GAAI,EAAE,OAAS,qBAAuB,CAAC,EAAE,KACvC,SAEF,IAAM,KAAO,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,MAAM,GAAG,YACpD,MAAQ,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,OAAO,GAAG,YACxD,OAAO,MAAS,UAAY,OAAO,OAAU,UAC/C,KAAK,KAAK,CAAE,KAAM,KAAM,CAAC,CAE7B,CACA,OAAO,IACT,CAYA,eAAsB,iCACpB,QAC4C,CAC5C,IAAM,IAAM,QAAQ,QAAQ,aAAc,2BAA2B,EAC/D,QAAO,gDAAmC,CAAE,mBAAoB,EAAK,CAAC,EACtE,SAAW,MAAM,QAAQ,KAAK,IAAK,IAAI,EAC7C,SAAK,wBAAuB,SAAU,YAAY,EAG3C,+BAA+B,QAAQ,EAFrC,CAAC,CAGZ,CCjCO,IAAM,sCAAsF,CACjG,CAAE,MAAO,SAAU,MAAO,QAAS,EACnC,CAAE,MAAO,YAAa,MAAO,YAAa,EAC1C,CAAE,MAAO,sBAAuB,MAAO,SAAU,EACjD,CAAE,MAAO,eAAgB,MAAO,gBAAiB,EACjD,CAAE,MAAO,YAAa,MAAO,WAAY,EACzC,CAAE,MAAO,2BAA4B,MAAO,mBAAoB,EAChE,CAAE,MAAO,yBAA0B,MAAO,mBAAoB,CAChE,EAGa,wCAAkF,CAAC,QAAQ,EC/BxG,uBAAkC,gCA8B3B,SAAS,mBAA6C,CAC3D,SAAO,sCAAkB,CAC3B,CCjCA,IAAAA,oBAAoC,gCAc7B,SAAS,oBAAoB,QAAsD,CACxF,SAAO,yCAAoB,4BAA6B,sBAAuB,OAAO,CACxF,CCjBA,IAAAC,aAA2B,yBAE3BC,oBAA2B,gCAC3B,aAA4B,iBA8B5B,IAAM,8BAAgC,2CAEtC,SAAS,yBAAyB,MAA+C,CAC/E,GAAI,CAAC,OAAS,OAAO,OAAU,SAC7B,MAAM,IAAI,MAAM,6BAA6B,EAE/C,IAAM,SAAW,MACjB,GACE,IAAC,yBAAiB,SAAS,KAAM,MAAM,GACtC,SAAS,YAAc,QAAa,OAAO,SAAS,WAAc,UAClE,SAAS,eAAiB,QAAa,OAAO,SAAS,cAAiB,SAEzE,MAAM,IAAI,MAAM,6BAA6B,EAE/C,OAAO,QACT,CAUO,SAAS,0BAA2D,CACzE,IAAM,WAAU,gCAAW,EAErB,WAAU,0BACd,MACE,OACA,SAC2C,CAC3C,IAAM,QAAwC,CAAE,GAAG,OAAQ,MAAO,EAClE,OAAO,yBAAyB,MAAM,QAAQ,WAAW,4BAA6B,OAAO,CAAC,CAChG,EACA,CAAC,OAAO,CACV,EAEM,UAAS,0BAAa,QAAwC,QAAQ,SAAU,MAAM,EAAG,CAAC,OAAO,CAAC,EAClG,aAAY,0BAAa,QAAwC,QAAQ,YAAa,MAAM,EAAG,CAAC,OAAO,CAAC,EACxG,eAAc,0BAAa,QAAwC,QAAQ,cAAe,MAAM,EAAG,CAAC,OAAO,CAAC,EAElH,MAAO,CAAE,OAAQ,UAAW,WAAY,CAC1C,CC3EA,IAAAC,oBAAmC,gCAqB5B,SAAS,8BAAmE,CACjF,SAAO,wCAAmB,CAC5B,CCvBA,IAAAC,oBAAsC,gCAiC/B,SAAS,sBAAsB,QAAoE,CACxG,SAAO,2CAAsB,CAC3B,UAAW,QAAQ,UACnB,iBAAkB,QAAQ,iBAC1B,iBAAkB,QAAQ,qBAC1B,MAAO,QAAQ,MACf,aAAc,QAAQ,YACxB,CAAC,CACH,CCzCA,IAAAC,oBAAkC,gCAe3B,SAAS,6BAAiE,CAC/E,SAAO,uCACL,+BACA,mCACF,CACF,CCtBA,IAAAC,aAAyC,yBAEzCC,oBAA2B,gCAE3BC,cAAqF,iBAoL5E,oDAjLH,YAAc,kDAoBd,6BAA4B,6BAA8C,CAC9E,UAAW,CAAC,EACZ,uBAAwB,OACxB,qBAAsB,OACtB,0BAA2B,IAAG,GAC9B,QAAS,EACX,CAAC,EAED,SAAS,yBAAyB,KAAmB,UAAqC,CACpF,WAAW,WAAW,eAAe,GACvC,KAAK,IAAI,SAAS,CAEtB,CAEA,SAAS,sBAAsB,IAA4B,CACzD,MAAO,KAAQ,4BAAc,IAAK,6BAA6B,CACjE,CASA,SAAS,sBAAsB,QAA0E,CACvG,GAAI,SAAS,eAAiB,eAC5B,OAAO,QAAQ,GAEjB,GAAI,SAAS,eAAiB,mBAC5B,SAAO,wBAAU,QAAQ,YAAY,CAGzC,CAkBO,SAAS,2BAA2B,MAAsD,CAC/F,IAAM,WAAU,gCAAW,EACrB,CAAC,UAAW,YAAY,KAAI,wBAAyB,CAAC,CAAC,EACvD,CAAC,QAAS,UAAU,KAAI,wBAAS,EAAI,EACrC,CAAC,uBAAwB,WAAW,KAAI,wBAC5C,IAAM,aAAa,QAAQ,WAAW,GAAK,MAC7C,KAEA,yBAAU,IAAM,CACd,IAAI,UAAY,GAEV,wBAA0B,SAAqC,CACnE,IAAM,QAAU,QAAQ,WAAW,EAC7B,eAAiB,sBAAsB,OAAO,EAC9C,WAAa,IAAI,IAEvB,GAAI,eAAgB,CAClB,IAAM,MAAQ,MAAM,QAAQ,gBAAgB,mBAAoB,CAC9D,aAAc,gBAAgB,cAAc,GAC5C,OAAQ,KACV,CAAC,EACD,QAAW,QAAQ,MAEb,KAAK,SAAW,IAClB,yBAAyB,WAAY,KAAK,cAAc,SAAS,CAGvE,CAEA,IAAM,WAAa,QAAQ,qBAAqB,EAChD,QAAW,UAAU,YAAY,QAAU,CAAC,EAC1C,QAAW,SAAS,OAAO,WAAa,CAAC,EACnC,MAAM,OAAS,gBACjB,yBAAyB,WAAY,MAAM,gBAAgB,SAAS,EAK1E,IAAM,YAAc,MAAM,QAAQ,WAChC,CAAC,GAAG,UAAU,EAAE,IAAK,WAAc,QAAQ,cAA4B,CAAE,SAAU,CAAC,CAAC,CACvF,EACM,KAAO,IAAI,IACX,OAAyB,CAAC,EAChC,QAAW,cAAc,YAAa,CACpC,GAAI,WAAW,SAAW,WACxB,SAEF,IAAM,IAAM,WAAW,MACnB,IAAI,IAAM,CAAC,KAAK,IAAI,IAAI,EAAE,GAAK,sBAAsB,GAAG,IAC1D,KAAK,IAAI,IAAI,EAAE,EACf,OAAO,KAAK,GAAG,EAEnB,CACA,OAAO,MACT,EA0BA,OAxBkC,SAA2B,CAC3D,WAAW,EAAI,EACf,GAAI,CACF,IAAM,KAAO,MAAM,wBAAwB,EACtC,YACH,aAAa,IAAI,EAEjB,YAAa,SACP,SAAW,KAAK,KAAM,GAAM,EAAE,KAAO,OAAO,EACvC,QAEF,KAAK,SAAW,EAAI,KAAK,CAAC,EAAE,GAAK,MACzC,EAEL,MAAQ,CACD,WACH,aAAa,CAAC,CAAC,CAEnB,QAAE,CACK,WACH,WAAW,EAAK,CAEpB,CACF,GAC0B,EAAE,MAAM,IAAG,EAAY,EAE1C,IAAY,CACjB,UAAY,EACd,CACF,EAAG,CAAC,OAAO,CAAC,EAEZ,IAAM,6BAA4B,2BAAa,IAAiC,CAC9E,YAAY,EAAE,EACV,GACF,aAAa,QAAQ,YAAa,EAAE,EAEpC,aAAa,WAAW,WAAW,CAEvC,EAAG,CAAC,CAAC,EAEC,wBAAuB,uBAC3B,IAAO,uBAAyB,CAAE,UAAW,gBAAgB,sBAAsB,EAAG,EAAI,OAC1F,CAAC,sBAAsB,CACzB,EAEM,SAAQ,uBACZ,KAAO,CAAE,UAAW,uBAAwB,qBAAsB,0BAA2B,OAAQ,GACrG,CAAC,UAAW,uBAAwB,qBAAsB,0BAA2B,OAAO,CAC9F,EAEA,SAAO,wBAAC,0BAA0B,SAA1B,CAAmC,MAAe,eAAM,SAAS,CAC3E,CAOO,SAAS,uBAAwD,CACtE,SAAO,0BAAW,yBAAyB,CAC7C",
|
|
6
6
|
"names": ["import_react_hooks", "import_core", "import_react_hooks", "import_react_hooks", "import_react_hooks", "import_react_hooks", "import_core", "import_react_hooks", "import_react"]
|
|
7
7
|
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -235,8 +235,9 @@ export declare function ScriptSurePracticeProvider(props: {
|
|
|
235
235
|
* React hook for the ScriptSure **medication cart** lifecycle: add a draft
|
|
236
236
|
* `MedicationRequest` line (`createResource`), check out drafts into the
|
|
237
237
|
* patient's ScriptSure MedCart (`$checkout-medications` →
|
|
238
|
-
* `/widgets/medcart/{patientId}`),
|
|
239
|
-
* (`$remove-cart-medication` / `$clear-cart`)
|
|
238
|
+
* `/widgets/medcart/{patientId}`), remove/clear cart lines
|
|
239
|
+
* (`$remove-cart-medication` / `$clear-cart`), and read the MedCart as
|
|
240
|
+
* ScriptSure holds it, reconciled against the local drafts (`$get-cart`).
|
|
240
241
|
*
|
|
241
242
|
* A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the
|
|
242
243
|
* vendor binding for the custom operations lives entirely on the server, where
|
|
@@ -254,7 +255,7 @@ export declare function ScriptSurePracticeProvider(props: {
|
|
|
254
255
|
* the MedCart widget).
|
|
255
256
|
*
|
|
256
257
|
* @returns The same API as `useMedicationCart` (`addToCart`, `adding`,
|
|
257
|
-
* `checkout`, `removeFromCart`, `clearCart`).
|
|
258
|
+
* `checkout`, `removeFromCart`, `clearCart`, `getCart`).
|
|
258
259
|
*/
|
|
259
260
|
export declare function useScriptSureCart(): UseScriptSureCartReturn;
|
|
260
261
|
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -235,8 +235,9 @@ export declare function ScriptSurePracticeProvider(props: {
|
|
|
235
235
|
* React hook for the ScriptSure **medication cart** lifecycle: add a draft
|
|
236
236
|
* `MedicationRequest` line (`createResource`), check out drafts into the
|
|
237
237
|
* patient's ScriptSure MedCart (`$checkout-medications` →
|
|
238
|
-
* `/widgets/medcart/{patientId}`),
|
|
239
|
-
* (`$remove-cart-medication` / `$clear-cart`)
|
|
238
|
+
* `/widgets/medcart/{patientId}`), remove/clear cart lines
|
|
239
|
+
* (`$remove-cart-medication` / `$clear-cart`), and read the MedCart as
|
|
240
|
+
* ScriptSure holds it, reconciled against the local drafts (`$get-cart`).
|
|
240
241
|
*
|
|
241
242
|
* A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the
|
|
242
243
|
* vendor binding for the custom operations lives entirely on the server, where
|
|
@@ -254,7 +255,7 @@ export declare function ScriptSurePracticeProvider(props: {
|
|
|
254
255
|
* the MedCart widget).
|
|
255
256
|
*
|
|
256
257
|
* @returns The same API as `useMedicationCart` (`addToCart`, `adding`,
|
|
257
|
-
* `checkout`, `removeFromCart`, `clearCart`).
|
|
258
|
+
* `checkout`, `removeFromCart`, `clearCart`, `getCart`).
|
|
258
259
|
*/
|
|
259
260
|
export declare function useScriptSureCart(): UseScriptSureCartReturn;
|
|
260
261
|
|
package/dist/esm/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/common.ts", "../../src/loadScriptSureQuantityQualifiers.ts", "../../src/pharmacy-search.ts", "../../src/useScriptSureCart.ts", "../../src/useScriptSureIFrame.ts", "../../src/useScriptSureMessageTask.ts", "../../src/useScriptSureOrderMedication.ts", "../../src/useScriptSureOrderSet.ts", "../../src/useScriptSurePharmacySearch.ts", "../../src/useScriptSurePractice.tsx"],
|
|
4
|
-
"sourcesContent": ["// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationOrderExtensions } from '@medplum/core';\nimport type { Identifier } from '@medplum/fhirtypes';\n\nexport const MEDPLUM_BOT_SYSTEM = 'https://www.medplum.com/bots';\n\n/**\n * @deprecated Use the vendor-neutral `$drug-search` custom FHIR operation via\n * `useMedicationOrder().searchMedications(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `drug-search` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_DRUG_SEARCH_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-drug-search-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-medication` custom FHIR operation via\n * `useMedicationOrder().orderMedication(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-medication` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_MEDICATION_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-medication-bot',\n};\n\n/** Identifier system for ScriptSure ROUTED_MED_ID on in-memory Medication resources from drug search. */\nexport const SCRIPTSURE_ROUTED_MED_ID_SYSTEM = 'https://scriptsure.com/routed-med-id';\n\n/**\n * Identifier/coding system for the FDB GCN Sequence Number (`GCN_SEQNO`) \u2014 the\n * clinical-formulation key (ingredient+strength+dose-form+route), independent of\n * brand and NDC. Stamped as a `medicationCodeableConcept.coding` on the draft\n * MedicationRequest so the ScriptSure prescription webhook can reconcile a draft\n * to its sent prescription even when the NDC drifts or the pharmacy substitutes a\n * generic (brand and generic share the same GCN). Mirrors the medplum-ee bot\n * constant of the same name.\n */\nexport const SCRIPTSURE_GCN_SEQNO_SYSTEM = 'https://scriptsure.com/gcn-seqno';\n\nexport const SCRIPTSURE_PENDING_ORDER_ID_SYSTEM = 'https://scriptsure.com/pending-order-id';\n\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION = 'https://scriptsure.com/pending-order-status';\n\n/**\n * `SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION` value marking a draft\n * `MedicationRequest` as staged in the patient's ScriptSure MedCart (added by\n * `$checkout-medications`, before the prescriber sends from the MedCart widget).\n * Consumed by the paired `medplum-ee` cart-checkout / cart-manage bots when\n * stamping drafts; the Provider App uses the pure-cart model (all drafts on the\n * Draft tab) rather than filtering on this code today.\n */\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_IN_CART = 'in-cart';\n\nexport const SCRIPTSURE_IFRAME_URL_EXTENSION = 'https://scriptsure.com/iframe-url';\n\n/**\n * Identifier system for the SureScripts `messageId` stamped on a draft\n * `MedicationRequest` by the cart-checkout flow (electronic-queue submit).\n * Consumed by the paired `medplum-ee` `scriptsure-cart-checkout-bot` when\n * stamping queued drafts and by `scriptsure-prescription-webhook-bot` when\n * reconciling the approval webhook back to the originating draft.\n */\nexport const SCRIPTSURE_MESSAGE_ID_SYSTEM = 'https://scriptsure.com/message-id';\n\nexport const SCRIPTSURE_MEDICATION_ORDER_EXTENSIONS: MedicationOrderExtensions = {\n pendingOrderIdSystem: SCRIPTSURE_PENDING_ORDER_ID_SYSTEM,\n pendingOrderStatusUrl: SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION,\n iframeUrlExtension: SCRIPTSURE_IFRAME_URL_EXTENSION,\n messageIdSystem: SCRIPTSURE_MESSAGE_ID_SYSTEM,\n};\n\nexport const SCRIPTSURE_IFRAME_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-iframe-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_SYNC_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-patient-sync-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-set-url` custom FHIR operation via\n * `useScriptSureOrderSet(...)` (thin wrapper around `useMedicationOrderSet`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-set-url` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_SET_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-set-bot',\n};\n\n/** Identifier system for the ScriptSure orderset id stamped on FHIR PlanDefinitions. */\nexport const SCRIPTSURE_ORDERSET_ID_SYSTEM = 'https://spa.scriptsure.com/orderset-id';\n\nexport const SCRIPTSURE_SEARCH_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-search-pharmacy-bot',\n};\n\nexport const SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-add-patient-pharmacy-bot',\n};\n\n/** Bot that launches and reconciles ScriptSure pharmacy-message Tasks. */\nexport const SCRIPTSURE_MESSAGE_TASK_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-message-task-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_ID_SYSTEM = 'https://scriptsure.com/patient-id';\n\n/**\n * Identifier system for the ScriptSure `practiceId` stamped on the Practice-level\n * Medplum `Organization`. Used by the practice/location selector to discover the\n * prescriber's ScriptSure practices and pass the chosen `organizationId` to bots.\n */\nexport const SCRIPTSURE_PRACTICE_ID_SYSTEM = 'https://scriptsure.com/practice-id';\n\n/** Identifier system for the ScriptSure `businessUnitId` on the BU-level Medplum `Organization`. */\nexport const SCRIPTSURE_BUSINESS_UNIT_ID_SYSTEM = 'https://scriptsure.com/business-unit-id';\n\n/** `Organization.type` coding system discriminating ScriptSure entity Organizations (`business-unit` | `practice`). */\nexport const SCRIPTSURE_ORGANIZATION_TYPE_SYSTEM = 'https://scriptsure.com/organization-type';\n\n/** Base URL for ScriptSure-specific extensions on in-memory Medication resources (e.g. `/sig`). */\nexport const SCRIPTSURE_SYSTEM = 'https://scriptsure.com';\n\n/** Pre-built dosing option on a Medication from drug-format lookup (`routedMedId` search). */\nexport const SCRIPTSURE_SIG_EXTENSION = `${SCRIPTSURE_SYSTEM}/sig`;\n\n/** ScriptSure MED_NAME_TYPE_CD on a search-result Medication: `'1'` = brand, `'2'` = generic. */\nexport const SCRIPTSURE_NAME_TYPE_EXTENSION = `${SCRIPTSURE_SYSTEM}/name-type`;\n\n/** ScriptSure GenericName on a search-result Medication (parent generic when the row is a brand). */\nexport const SCRIPTSURE_GENERIC_NAME_EXTENSION = `${SCRIPTSURE_SYSTEM}/generic-name`;\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { MedplumClient } from '@medplum/core';\nimport { isResource, medicationSearchParamsToParameters } from '@medplum/core';\nimport type { Parameters } from '@medplum/fhirtypes';\n\n/**\n * Reads `{ code, label }` rows from a `Parameters` resource produced by the\n * `$drug-quantity-qualifiers` custom operation.\n *\n * The OperationDefinition (see `scriptsure-drug-search-bot` registration in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`) declares a single\n * repeating output parameter named `quantityQualifier`, each entry bearing\n * `part: [{ name: 'code', valueString }, { name: 'label', valueString }]`.\n * The server's `buildOutputParameters` wraps the bot return value into that\n * shape, so the parser only needs to handle this one canonical layout.\n * Entries missing either inner part are skipped defensively.\n *\n * @param params - `Parameters` resource returned by the operation.\n * @returns `{ code, label }` rows for UI selects.\n */\nfunction parametersToQuantityQualifiers(params: Parameters): { code: string; label: string }[] {\n const rows: { code: string; label: string }[] = [];\n for (const p of params.parameter ?? []) {\n if (p.name !== 'quantityQualifier' || !p.part) {\n continue;\n }\n const code = p.part.find((part) => part.name === 'code')?.valueString;\n const label = p.part.find((part) => part.name === 'label')?.valueString;\n if (typeof code === 'string' && typeof label === 'string') {\n rows.push({ code, label });\n }\n }\n return rows;\n}\n\n/**\n * Fetches NCI potency-unit codes for dispense quantity qualifiers via the\n * vendor-neutral `$drug-quantity-qualifiers` custom FHIR operation. Each\n * Medplum project picks the vendor implementation at deploy time by pointing\n * its `OperationDefinition` at the appropriate Bot (ScriptSure's\n * `scriptsure-drug-search-bot` today; see `deploy.ts`).\n *\n * @param medplum - Medplum client (user session).\n * @returns `{ code, label }` rows for UI selects.\n */\nexport async function loadScriptSureQuantityQualifiers(\n medplum: MedplumClient\n): Promise<{ code: string; label: string }[]> {\n const url = medplum.fhirUrl('Medication', '$drug-quantity-qualifiers');\n const body = medicationSearchParamsToParameters({ quantityQualifiers: true });\n const response = await medplum.post(url, body);\n if (!isResource<Parameters>(response, 'Parameters')) {\n return [];\n }\n return parametersToQuantityQualifiers(response);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PharmacySearchParams } from '@medplum/core';\n\n/**\n * SureScripts pharmacy specialty tags accepted by POST /v3/pharmacy/search `specialties`.\n * Must stay aligned with ScriptSure API allowed values.\n */\nexport type ScriptSurePharmacySpecialty =\n | 'Retail'\n | 'MailOrder'\n | 'TwentyFourHourStore'\n | 'SupportsDigitalSignature'\n | 'LongTermCare'\n | 'Specialty'\n | 'FaxPharmacySurescripts';\n\nexport interface ScriptSurePharmacySpecialtyOption {\n readonly value: ScriptSurePharmacySpecialty;\n readonly label: string;\n}\n\n/** Category filters shown in the ScriptSure pharmacy search dialog. */\nexport const SCRIPTSURE_PHARMACY_SPECIALTY_OPTIONS: readonly ScriptSurePharmacySpecialtyOption[] = [\n { value: 'Retail', label: 'Retail' },\n { value: 'MailOrder', label: 'Mail order' },\n { value: 'TwentyFourHourStore', label: '24-hour' },\n { value: 'LongTermCare', label: 'Long-term care' },\n { value: 'Specialty', label: 'Specialty' },\n { value: 'SupportsDigitalSignature', label: 'Digital signature' },\n { value: 'FaxPharmacySurescripts', label: 'Fax (Surescripts)' },\n] as const;\n\n/** Default specialty filter for nearby retail pharmacy pickers. */\nexport const SCRIPTSURE_DEFAULT_PHARMACY_SPECIALTIES: readonly ScriptSurePharmacySpecialty[] = ['Retail'];\n\n/**\n * ScriptSure pharmacy search parameters.\n * Extends the shared dialog fields with SureScripts specialty filters.\n */\nexport interface ScriptSurePharmacySearchParams extends PharmacySearchParams {\n specialties?: ScriptSurePharmacySpecialty[];\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationCartReturn } from '@medplum/react-hooks';\nimport { useMedicationCart } from '@medplum/react-hooks';\n\nexport type UseScriptSureCartReturn = UseMedicationCartReturn;\n\n/**\n * React hook for the ScriptSure **medication cart** lifecycle: add a draft\n * `MedicationRequest` line (`createResource`), check out drafts into the\n * patient's ScriptSure MedCart (`$checkout-medications` \u2192\n * `/widgets/medcart/{patientId}`), and remove/clear cart lines\n * (`$remove-cart-medication` / `$clear-cart`).\n *\n * A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the\n * vendor binding for the custom operations lives entirely on the server, where\n * each Medplum project's `OperationDefinition`s point at the ScriptSure bots via\n * the `operationDefinition-implementation` extension \u2014 see\n * [Custom FHIR Operations](https://www.medplum.com/docs/bots/custom-fhir-operations).\n * (Internal deploy: `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`.)\n *\n * `addToCart` is plain FHIR create (no vendor call); MedCart staging happens at\n * `checkout`. DoseSpot and other iframe-first vendors do not use this surface.\n *\n * Kept as a typed alias for source-compatibility with apps importing\n * `useScriptSureCart` and as a documentation anchor for ScriptSure-specific\n * behavior (patient-must-be-synced precondition; cart items await sign-off in\n * the MedCart widget).\n *\n * @returns The same API as `useMedicationCart` (`addToCart`, `adding`,\n * `checkout`, `removeFromCart`, `clearCart`).\n */\nexport function useScriptSureCart(): UseScriptSureCartReturn {\n return useMedicationCart();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationIFrameOptions } from '@medplum/react-hooks';\nimport { useMedicationIFrame } from '@medplum/react-hooks';\nimport { SCRIPTSURE_IFRAME_BOT, SCRIPTSURE_PATIENT_SYNC_BOT } from './common';\n\nexport type ScriptSureIFrameOptions = MedicationIFrameOptions;\n\n/**\n * React hook that syncs a patient to ScriptSure and returns the iframe URL.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#useMedicationIFrame} hook,\n * pre-configured with ScriptSure bot identifiers.\n *\n * @param options - Configuration and callback options.\n * @returns The ScriptSure iframe URL, or undefined while loading.\n */\nexport function useScriptSureIFrame(options: ScriptSureIFrameOptions): string | undefined {\n return useMedicationIFrame(SCRIPTSURE_PATIENT_SYNC_BOT, SCRIPTSURE_IFRAME_BOT, options);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { isResource } from '@medplum/core';\nimport type { Task } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport { useCallback } from 'react';\nimport { SCRIPTSURE_MESSAGE_TASK_BOT } from './common';\n\nexport type ScriptSureMessageTaskAction = 'launch' | 'reconcile' | 'acknowledge';\n\n/** Request accepted by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskRequest {\n taskId: string;\n action: ScriptSureMessageTaskAction;\n organizationId?: string;\n}\n\n/** Validated response returned by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskResponse {\n task: Task;\n launchUrl?: string;\n vendorStatus?: string;\n}\n\nexport interface ScriptSureMessageTaskParams {\n taskId: string;\n organizationId?: string;\n}\n\nexport interface UseScriptSureMessageTaskReturn {\n launch: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n reconcile: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n acknowledge: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n}\n\nconst INVALID_MESSAGE_TASK_RESPONSE = 'Invalid ScriptSure message-task response';\n\nfunction parseMessageTaskResponse(value: unknown): ScriptSureMessageTaskResponse {\n if (!value || typeof value !== 'object') {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n const response = value as Record<string, unknown>;\n if (\n !isResource<Task>(response.task, 'Task') ||\n (response.launchUrl !== undefined && typeof response.launchUrl !== 'string') ||\n (response.vendorStatus !== undefined && typeof response.vendorStatus !== 'string')\n ) {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n return response as unknown as ScriptSureMessageTaskResponse;\n}\n\n/**\n * Executes the ScriptSure pharmacy-message Task lifecycle bot.\n *\n * The hook intentionally exposes only the three supported actions and validates\n * the untyped Bot response before returning it to the application.\n *\n * @returns Typed launch, reconcile, and acknowledge callbacks.\n */\nexport function useScriptSureMessageTask(): UseScriptSureMessageTaskReturn {\n const medplum = useMedplum();\n\n const execute = useCallback(\n async (\n action: ScriptSureMessageTaskAction,\n params: ScriptSureMessageTaskParams\n ): Promise<ScriptSureMessageTaskResponse> => {\n const request: ScriptSureMessageTaskRequest = { ...params, action };\n return parseMessageTaskResponse(await medplum.executeBot(SCRIPTSURE_MESSAGE_TASK_BOT, request));\n },\n [medplum]\n );\n\n const launch = useCallback((params: ScriptSureMessageTaskParams) => execute('launch', params), [execute]);\n const reconcile = useCallback((params: ScriptSureMessageTaskParams) => execute('reconcile', params), [execute]);\n const acknowledge = useCallback((params: ScriptSureMessageTaskParams) => execute('acknowledge', params), [execute]);\n\n return { launch, reconcile, acknowledge };\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationOrderReturn } from '@medplum/react-hooks';\nimport { useMedicationOrder } from '@medplum/react-hooks';\n\nexport type UseScriptSureOrderMedicationReturn = UseMedicationOrderReturn;\n\n/**\n * React hook for ScriptSure drug search and pending order creation (iframe launch URL).\n *\n * Now a near-empty re-export of `useMedicationOrder` from `@medplum/react-hooks`: the\n * vendor binding lives entirely on the server, where each Medplum project's\n * `OperationDefinition` resources for `$drug-search` and `$order-medication`\n * point at the ScriptSure bots via the\n * `operationDefinition-implementation` extension. See the deploy script in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts` for how those\n * resources are upserted.\n *\n * Kept as a typed alias for backwards source-compatibility with apps importing\n * `useScriptSureOrderMedication` and as a documentation anchor for the\n * ScriptSure-specific behavior (e.g. patient-must-be-synced precondition).\n *\n * @returns The same API as `useMedicationOrder` (search + order callbacks).\n */\nexport function useScriptSureOrderMedication(): UseScriptSureOrderMedicationReturn {\n return useMedicationOrder();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { Organization, Reference } from '@medplum/fhirtypes';\nimport type { UseMedicationOrderSetReturn } from '@medplum/react-hooks';\nimport { useMedicationOrderSet } from '@medplum/react-hooks';\n\nexport interface UseScriptSureOrderSetOptions {\n /** Patient to prescribe against. Hook stays idle (no operation call) until set. */\n readonly patientId: string | undefined;\n /** Medplum PlanDefinition id; bot reverse-looks up the ScriptSure orderset id. */\n readonly planDefinitionId?: string;\n /** ScriptSure orderset id (escape hatch when no synced PD exists yet). */\n readonly scriptSureOrdersetId?: number;\n readonly appId?: string;\n /** Selected practice location for multi-practice deployments. */\n readonly organization?: Reference<Organization>;\n}\n\nexport type UseScriptSureOrderSetReturn = UseMedicationOrderSetReturn;\n\n/**\n * React hook that returns the ScriptSure order-set prescribing widget URL via\n * the vendor-neutral `$order-set-url` FHIR custom operation\n * (`POST /fhir/R4/PlanDefinition/$order-set-url`).\n *\n * Thin wrapper around {@link @medplum/react-hooks#useMedicationOrderSet}: forwards\n * `scriptSureOrdersetId` as the operation's `vendorOrderSetId` parameter,\n * leaves vendor binding to the deployed `OperationDefinition` \u2192\n * `Bot/scriptsure-order-set-bot` link.\n *\n * The operation is naturally idempotent \u2014 re-calls only refresh the session\n * token in the returned URL \u2014 so callers can safely wire `refresh` into\n * `PrescriptionIFrameModal.onRefreshLaunchUrl`.\n *\n * @param options - Patient + order-set picker (PD or ScriptSure id).\n * @returns `{ url, loading, error, refresh }`.\n */\nexport function useScriptSureOrderSet(options: UseScriptSureOrderSetOptions): UseScriptSureOrderSetReturn {\n return useMedicationOrderSet({\n patientId: options.patientId,\n planDefinitionId: options.planDefinitionId,\n vendorOrderSetId: options.scriptSureOrdersetId,\n appId: options.appId,\n organization: options.organization,\n });\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UsePharmacySearchReturn } from '@medplum/react-hooks';\nimport { usePharmacySearch } from '@medplum/react-hooks';\nimport { SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT, SCRIPTSURE_SEARCH_PHARMACY_BOT } from './common';\nimport type { ScriptSurePharmacySearchParams } from './pharmacy-search';\n\nexport type UseScriptSurePharmacySearchReturn = UsePharmacySearchReturn<ScriptSurePharmacySearchParams>;\n\n/**\n * React hook that provides ScriptSure-specific pharmacy search and add-to-favorites functionality.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#usePharmacySearch} hook, pre-configured with\n * ScriptSure bot identifiers and widened so search params carry ScriptSure-only\n * `specialties` filters for POST /v3/pharmacy/search.\n *\n * @returns An object with `searchPharmacies` and `addToFavorites` callbacks.\n */\nexport function useScriptSurePharmacySearch(): UseScriptSurePharmacySearchReturn {\n return usePharmacySearch<ScriptSurePharmacySearchParams>(\n SCRIPTSURE_SEARCH_PHARMACY_BOT,\n SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT\n );\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { getIdentifier, resolveId } from '@medplum/core';\nimport type { Organization, Practitioner, PractitionerRole, Reference } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport type { JSX, ReactNode } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { SCRIPTSURE_PRACTICE_ID_SYSTEM } from './common';\n\nconst STORAGE_KEY = 'medplum.scriptsure.selectedPracticeOrganization';\n\n/** The current ScriptSure practice-location selection for the signed-in prescriber. */\nexport interface ScriptSurePracticeContextValue {\n /**\n * The prescriber's ScriptSure practice `Organization`s \u2014 discovered from their\n * own affiliations (`PractitionerRole.organization` + `ProjectMembership.access`\n * organization parameters), filtered to those carrying a `practice-id` identifier.\n * Never the project-wide list.\n */\n readonly practices: Organization[];\n /** Bare Organization id used by the selector and persisted in localStorage. */\n readonly selectedOrganizationId: string | undefined;\n /** FHIR reference for the selected practice, suitable for operation and hook inputs. */\n readonly selectedOrganization: Reference<Organization> | undefined;\n /** Selects a practice Organization (persisted to localStorage). */\n readonly setSelectedOrganizationId: (id: string | undefined) => void;\n readonly loading: boolean;\n}\n\nconst ScriptSurePracticeContext = createContext<ScriptSurePracticeContextValue>({\n practices: [],\n selectedOrganizationId: undefined,\n selectedOrganization: undefined,\n setSelectedOrganizationId: () => undefined,\n loading: false,\n});\n\nfunction addOrganizationReference(refs: Set<string>, reference: string | undefined): void {\n if (reference?.startsWith('Organization/')) {\n refs.add(reference);\n }\n}\n\nfunction hasPracticeIdentifier(org: Organization): boolean {\n return Boolean(getIdentifier(org, SCRIPTSURE_PRACTICE_ID_SYSTEM));\n}\n\n/**\n * Resolves the signed-in prescriber's `Practitioner.id` from the current profile,\n * whether the profile is a `Practitioner` or a `PractitionerRole`.\n *\n * @param profile - The current Medplum profile resource.\n * @returns The Practitioner id, or undefined when it cannot be resolved.\n */\nfunction resolvePractitionerId(profile: Practitioner | PractitionerRole | undefined): string | undefined {\n if (profile?.resourceType === 'Practitioner') {\n return profile.id;\n }\n if (profile?.resourceType === 'PractitionerRole') {\n return resolveId(profile.practitioner);\n }\n return undefined;\n}\n\n/**\n * Provides the signed-in prescriber's current ScriptSure practice-location\n * selection, discovered from **their own affiliations** \u2014 mirroring the server's\n * multi-practice resolver so the UI never offers a practice the prescriber is not\n * a member of.\n *\n * Discovery: active `PractitionerRole.organization` references for the current\n * `Practitioner` plus any `ProjectMembership.access[].parameter` named\n * `organization`, resolved to `Organization`s and filtered to those carrying a\n * `practice-id` identifier. The sole practice is auto-selected; a previously used\n * selection is restored only when it is still in the affiliation set.\n *\n * @param props - Component props.\n * @param props.children - Child nodes rendered within the provider.\n * @returns The context provider element.\n */\nexport function ScriptSurePracticeProvider(props: { readonly children: ReactNode }): JSX.Element {\n const medplum = useMedplum();\n const [practices, setPractices] = useState<Organization[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedOrganizationId, setSelected] = useState<string | undefined>(\n () => localStorage.getItem(STORAGE_KEY) ?? undefined\n );\n\n useEffect(() => {\n let cancelled = false;\n\n const loadAffiliatedPractices = async (): Promise<Organization[]> => {\n const profile = medplum.getProfile() as Practitioner | PractitionerRole | undefined;\n const practitionerId = resolvePractitionerId(profile);\n const references = new Set<string>();\n\n if (practitionerId) {\n const roles = await medplum.searchResources('PractitionerRole', {\n practitioner: `Practitioner/${practitionerId}`,\n _count: '100',\n });\n for (const role of roles) {\n // `active` is not a standard R4 PractitionerRole search param \u2014 filter in code.\n if (role.active !== false) {\n addOrganizationReference(references, role.organization?.reference);\n }\n }\n }\n\n const membership = medplum.getProjectMembership();\n for (const access of membership?.access ?? []) {\n for (const param of access.parameter ?? []) {\n if (param.name === 'organization') {\n addOrganizationReference(references, param.valueReference?.reference);\n }\n }\n }\n\n const settledOrgs = await Promise.allSettled(\n [...references].map((reference) => medplum.readReference<Organization>({ reference }))\n );\n const seen = new Set<string>();\n const result: Organization[] = [];\n for (const settledOrg of settledOrgs) {\n if (settledOrg.status === 'rejected') {\n continue;\n }\n const org = settledOrg.value;\n if (org.id && !seen.has(org.id) && hasPracticeIdentifier(org)) {\n seen.add(org.id);\n result.push(org);\n }\n }\n return result;\n };\n\n const updateAffiliatedPractices = async (): Promise<void> => {\n setLoading(true);\n try {\n const orgs = await loadAffiliatedPractices();\n if (!cancelled) {\n setPractices(orgs);\n // Default: keep a stored id only if it is still an affiliation; else the sole practice.\n setSelected((current) => {\n if (current && orgs.some((o) => o.id === current)) {\n return current;\n }\n return orgs.length === 1 ? orgs[0].id : undefined;\n });\n }\n } catch {\n if (!cancelled) {\n setPractices([]);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n };\n updateAffiliatedPractices().catch(() => undefined);\n\n return (): void => {\n cancelled = true;\n };\n }, [medplum]);\n\n const setSelectedOrganizationId = useCallback((id: string | undefined): void => {\n setSelected(id);\n if (id) {\n localStorage.setItem(STORAGE_KEY, id);\n } else {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, []);\n\n const selectedOrganization = useMemo<Reference<Organization> | undefined>(\n () => (selectedOrganizationId ? { reference: `Organization/${selectedOrganizationId}` } : undefined),\n [selectedOrganizationId]\n );\n\n const value = useMemo<ScriptSurePracticeContextValue>(\n () => ({ practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading }),\n [practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading]\n );\n\n return <ScriptSurePracticeContext.Provider value={value}>{props.children}</ScriptSurePracticeContext.Provider>;\n}\n\n/**\n * Hook returning the current ScriptSure practice selection + setter.\n *\n * @returns The practice context value.\n */\nexport function useScriptSurePractice(): ScriptSurePracticeContextValue {\n return useContext(ScriptSurePracticeContext);\n}\n"],
|
|
5
|
-
"mappings": "AAKO,IAAM,mBAAqB,+BAWrB,2BAAyC,CACpD,OAAQ,mBACR,MAAO,4BACT,EAWa,gCAA8C,CACzD,OAAQ,mBACR,MAAO,iCACT,EAGa,gCAAkC,uCAWlC,4BAA8B,mCAE9B,mCAAqC,0CAErC,0CAA4C,8CAU5C,wCAA0C,UAE1C,gCAAkC,oCASlC,6BAA+B,oCAE/B,uCAAoE,CAC/E,qBAAsB,mCACtB,sBAAuB,0CACvB,mBAAoB,gCACpB,gBAAiB,4BACnB,EAEa,sBAAoC,CAC/C,OAAQ,mBACR,MAAO,uBACT,EAEa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAWa,yBAAuC,CAClD,OAAQ,mBACR,MAAO,0BACT,EAGa,8BAAgC,yCAEhC,+BAA6C,CACxD,OAAQ,mBACR,MAAO,gCACT,EAEa,oCAAkD,CAC7D,OAAQ,mBACR,MAAO,qCACT,EAGa,4BAA0C,CACrD,OAAQ,mBACR,MAAO,6BACT,EAEa,6BAA+B,oCAO/B,8BAAgC,qCAGhC,mCAAqC,0CAGrC,oCAAsC,2CAGtC,kBAAoB,yBAGpB,yBAA2B,GAAG,iBAAiB,OAG/C,+BAAiC,GAAG,iBAAiB,aAGrD,kCAAoC,GAAG,iBAAiB,gBCjJrE,OAAS,WAAY,uCAA0C,gBAkB/D,SAAS,+BAA+B,OAAuD,CAC7F,IAAM,KAA0C,CAAC,EACjD,QAAW,KAAK,OAAO,WAAa,CAAC,EAAG,CACtC,GAAI,EAAE,OAAS,qBAAuB,CAAC,EAAE,KACvC,SAEF,IAAM,KAAO,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,MAAM,GAAG,YACpD,MAAQ,EAAE,KAAK,KAAM,MAAS,KAAK,OAAS,OAAO,GAAG,YACxD,OAAO,MAAS,UAAY,OAAO,OAAU,UAC/C,KAAK,KAAK,CAAE,KAAM,KAAM,CAAC,CAE7B,CACA,OAAO,IACT,CAYA,eAAsB,iCACpB,QAC4C,CAC5C,IAAM,IAAM,QAAQ,QAAQ,aAAc,2BAA2B,EAC/D,KAAO,mCAAmC,CAAE,mBAAoB,EAAK,CAAC,EACtE,SAAW,MAAM,QAAQ,KAAK,IAAK,IAAI,EAC7C,OAAK,WAAuB,SAAU,YAAY,EAG3C,+BAA+B,QAAQ,EAFrC,CAAC,CAGZ,CCjCO,IAAM,sCAAsF,CACjG,CAAE,MAAO,SAAU,MAAO,QAAS,EACnC,CAAE,MAAO,YAAa,MAAO,YAAa,EAC1C,CAAE,MAAO,sBAAuB,MAAO,SAAU,EACjD,CAAE,MAAO,eAAgB,MAAO,gBAAiB,EACjD,CAAE,MAAO,YAAa,MAAO,WAAY,EACzC,CAAE,MAAO,2BAA4B,MAAO,mBAAoB,EAChE,CAAE,MAAO,yBAA0B,MAAO,mBAAoB,CAChE,EAGa,wCAAkF,CAAC,QAAQ,EC/BxG,OAAS,sBAAyB,
|
|
4
|
+
"sourcesContent": ["// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationOrderExtensions } from '@medplum/core';\nimport type { Identifier } from '@medplum/fhirtypes';\n\nexport const MEDPLUM_BOT_SYSTEM = 'https://www.medplum.com/bots';\n\n/**\n * @deprecated Use the vendor-neutral `$drug-search` custom FHIR operation via\n * `useMedicationOrder().searchMedications(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `drug-search` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_DRUG_SEARCH_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-drug-search-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-medication` custom FHIR operation via\n * `useMedicationOrder().orderMedication(...)` (see `@medplum/react-hooks`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-medication` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_MEDICATION_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-medication-bot',\n};\n\n/** Identifier system for ScriptSure ROUTED_MED_ID on in-memory Medication resources from drug search. */\nexport const SCRIPTSURE_ROUTED_MED_ID_SYSTEM = 'https://scriptsure.com/routed-med-id';\n\n/**\n * Identifier/coding system for the FDB GCN Sequence Number (`GCN_SEQNO`) \u2014 the\n * clinical-formulation key (ingredient+strength+dose-form+route), independent of\n * brand and NDC. Stamped as a `medicationCodeableConcept.coding` on the draft\n * MedicationRequest so the ScriptSure prescription webhook can reconcile a draft\n * to its sent prescription even when the NDC drifts or the pharmacy substitutes a\n * generic (brand and generic share the same GCN). Mirrors the medplum-ee bot\n * constant of the same name.\n */\nexport const SCRIPTSURE_GCN_SEQNO_SYSTEM = 'https://scriptsure.com/gcn-seqno';\n\nexport const SCRIPTSURE_PENDING_ORDER_ID_SYSTEM = 'https://scriptsure.com/pending-order-id';\n\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION = 'https://scriptsure.com/pending-order-status';\n\n/**\n * `SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION` value marking a draft\n * `MedicationRequest` as staged in the patient's ScriptSure MedCart (added by\n * `$checkout-medications`, before the prescriber sends from the MedCart widget).\n * Consumed by the paired `medplum-ee` cart-checkout / cart-manage bots when\n * stamping drafts; the Provider App uses the pure-cart model (all drafts on the\n * Draft tab) rather than filtering on this code today.\n */\nexport const SCRIPTSURE_PENDING_ORDER_STATUS_IN_CART = 'in-cart';\n\nexport const SCRIPTSURE_IFRAME_URL_EXTENSION = 'https://scriptsure.com/iframe-url';\n\n/**\n * Identifier system for the SureScripts `messageId` stamped on a draft\n * `MedicationRequest` by the cart-checkout flow (electronic-queue submit).\n * Consumed by the paired `medplum-ee` `scriptsure-cart-checkout-bot` when\n * stamping queued drafts and by `scriptsure-prescription-webhook-bot` when\n * reconciling the approval webhook back to the originating draft.\n */\nexport const SCRIPTSURE_MESSAGE_ID_SYSTEM = 'https://scriptsure.com/message-id';\n\nexport const SCRIPTSURE_MEDICATION_ORDER_EXTENSIONS: MedicationOrderExtensions = {\n pendingOrderIdSystem: SCRIPTSURE_PENDING_ORDER_ID_SYSTEM,\n pendingOrderStatusUrl: SCRIPTSURE_PENDING_ORDER_STATUS_EXTENSION,\n iframeUrlExtension: SCRIPTSURE_IFRAME_URL_EXTENSION,\n messageIdSystem: SCRIPTSURE_MESSAGE_ID_SYSTEM,\n};\n\nexport const SCRIPTSURE_IFRAME_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-iframe-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_SYNC_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-patient-sync-bot',\n};\n\n/**\n * @deprecated Use the vendor-neutral `$order-set-url` custom FHIR operation via\n * `useScriptSureOrderSet(...)` (thin wrapper around `useMedicationOrderSet`).\n * The bot identifier is kept exported for one release to preserve source\n * compatibility for any caller still invoking `medplum.executeBot(...)`\n * directly. Project deploys via `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`\n * now register an `OperationDefinition` with code `order-set-url` whose\n * `operationDefinition-implementation` extension points at this bot.\n */\nexport const SCRIPTSURE_ORDER_SET_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-order-set-bot',\n};\n\n/** Identifier system for the ScriptSure orderset id stamped on FHIR PlanDefinitions. */\nexport const SCRIPTSURE_ORDERSET_ID_SYSTEM = 'https://spa.scriptsure.com/orderset-id';\n\nexport const SCRIPTSURE_SEARCH_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-search-pharmacy-bot',\n};\n\nexport const SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-add-patient-pharmacy-bot',\n};\n\n/** Bot that launches and reconciles ScriptSure pharmacy-message Tasks. */\nexport const SCRIPTSURE_MESSAGE_TASK_BOT: Identifier = {\n system: MEDPLUM_BOT_SYSTEM,\n value: 'scriptsure-message-task-bot',\n};\n\nexport const SCRIPTSURE_PATIENT_ID_SYSTEM = 'https://scriptsure.com/patient-id';\n\n/**\n * Identifier system for the ScriptSure `practiceId` stamped on the Practice-level\n * Medplum `Organization`. Used by the practice/location selector to discover the\n * prescriber's ScriptSure practices and pass the chosen `organizationId` to bots.\n */\nexport const SCRIPTSURE_PRACTICE_ID_SYSTEM = 'https://scriptsure.com/practice-id';\n\n/** Identifier system for the ScriptSure `businessUnitId` on the BU-level Medplum `Organization`. */\nexport const SCRIPTSURE_BUSINESS_UNIT_ID_SYSTEM = 'https://scriptsure.com/business-unit-id';\n\n/** `Organization.type` coding system discriminating ScriptSure entity Organizations (`business-unit` | `practice`). */\nexport const SCRIPTSURE_ORGANIZATION_TYPE_SYSTEM = 'https://scriptsure.com/organization-type';\n\n/** Base URL for ScriptSure-specific extensions on in-memory Medication resources (e.g. `/sig`). */\nexport const SCRIPTSURE_SYSTEM = 'https://scriptsure.com';\n\n/** Pre-built dosing option on a Medication from drug-format lookup (`routedMedId` search). */\nexport const SCRIPTSURE_SIG_EXTENSION = `${SCRIPTSURE_SYSTEM}/sig`;\n\n/** ScriptSure MED_NAME_TYPE_CD on a search-result Medication: `'1'` = brand, `'2'` = generic. */\nexport const SCRIPTSURE_NAME_TYPE_EXTENSION = `${SCRIPTSURE_SYSTEM}/name-type`;\n\n/** ScriptSure GenericName on a search-result Medication (parent generic when the row is a brand). */\nexport const SCRIPTSURE_GENERIC_NAME_EXTENSION = `${SCRIPTSURE_SYSTEM}/generic-name`;\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { MedplumClient } from '@medplum/core';\nimport { isResource, medicationSearchParamsToParameters } from '@medplum/core';\nimport type { Parameters } from '@medplum/fhirtypes';\n\n/**\n * Reads `{ code, label }` rows from a `Parameters` resource produced by the\n * `$drug-quantity-qualifiers` custom operation.\n *\n * The OperationDefinition (see `scriptsure-drug-search-bot` registration in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`) declares a single\n * repeating output parameter named `quantityQualifier`, each entry bearing\n * `part: [{ name: 'code', valueString }, { name: 'label', valueString }]`.\n * The server's `buildOutputParameters` wraps the bot return value into that\n * shape, so the parser only needs to handle this one canonical layout.\n * Entries missing either inner part are skipped defensively.\n *\n * @param params - `Parameters` resource returned by the operation.\n * @returns `{ code, label }` rows for UI selects.\n */\nfunction parametersToQuantityQualifiers(params: Parameters): { code: string; label: string }[] {\n const rows: { code: string; label: string }[] = [];\n for (const p of params.parameter ?? []) {\n if (p.name !== 'quantityQualifier' || !p.part) {\n continue;\n }\n const code = p.part.find((part) => part.name === 'code')?.valueString;\n const label = p.part.find((part) => part.name === 'label')?.valueString;\n if (typeof code === 'string' && typeof label === 'string') {\n rows.push({ code, label });\n }\n }\n return rows;\n}\n\n/**\n * Fetches NCI potency-unit codes for dispense quantity qualifiers via the\n * vendor-neutral `$drug-quantity-qualifiers` custom FHIR operation. Each\n * Medplum project picks the vendor implementation at deploy time by pointing\n * its `OperationDefinition` at the appropriate Bot (ScriptSure's\n * `scriptsure-drug-search-bot` today; see `deploy.ts`).\n *\n * @param medplum - Medplum client (user session).\n * @returns `{ code, label }` rows for UI selects.\n */\nexport async function loadScriptSureQuantityQualifiers(\n medplum: MedplumClient\n): Promise<{ code: string; label: string }[]> {\n const url = medplum.fhirUrl('Medication', '$drug-quantity-qualifiers');\n const body = medicationSearchParamsToParameters({ quantityQualifiers: true });\n const response = await medplum.post(url, body);\n if (!isResource<Parameters>(response, 'Parameters')) {\n return [];\n }\n return parametersToQuantityQualifiers(response);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { PharmacySearchParams } from '@medplum/core';\n\n/**\n * SureScripts pharmacy specialty tags accepted by POST /v3/pharmacy/search `specialties`.\n * Must stay aligned with ScriptSure API allowed values.\n */\nexport type ScriptSurePharmacySpecialty =\n | 'Retail'\n | 'MailOrder'\n | 'TwentyFourHourStore'\n | 'SupportsDigitalSignature'\n | 'LongTermCare'\n | 'Specialty'\n | 'FaxPharmacySurescripts';\n\nexport interface ScriptSurePharmacySpecialtyOption {\n readonly value: ScriptSurePharmacySpecialty;\n readonly label: string;\n}\n\n/** Category filters shown in the ScriptSure pharmacy search dialog. */\nexport const SCRIPTSURE_PHARMACY_SPECIALTY_OPTIONS: readonly ScriptSurePharmacySpecialtyOption[] = [\n { value: 'Retail', label: 'Retail' },\n { value: 'MailOrder', label: 'Mail order' },\n { value: 'TwentyFourHourStore', label: '24-hour' },\n { value: 'LongTermCare', label: 'Long-term care' },\n { value: 'Specialty', label: 'Specialty' },\n { value: 'SupportsDigitalSignature', label: 'Digital signature' },\n { value: 'FaxPharmacySurescripts', label: 'Fax (Surescripts)' },\n] as const;\n\n/** Default specialty filter for nearby retail pharmacy pickers. */\nexport const SCRIPTSURE_DEFAULT_PHARMACY_SPECIALTIES: readonly ScriptSurePharmacySpecialty[] = ['Retail'];\n\n/**\n * ScriptSure pharmacy search parameters.\n * Extends the shared dialog fields with SureScripts specialty filters.\n */\nexport interface ScriptSurePharmacySearchParams extends PharmacySearchParams {\n specialties?: ScriptSurePharmacySpecialty[];\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationCartReturn } from '@medplum/react-hooks';\nimport { useMedicationCart } from '@medplum/react-hooks';\n\nexport type UseScriptSureCartReturn = UseMedicationCartReturn;\n\n/**\n * React hook for the ScriptSure **medication cart** lifecycle: add a draft\n * `MedicationRequest` line (`createResource`), check out drafts into the\n * patient's ScriptSure MedCart (`$checkout-medications` \u2192\n * `/widgets/medcart/{patientId}`), remove/clear cart lines\n * (`$remove-cart-medication` / `$clear-cart`), and read the MedCart as\n * ScriptSure holds it, reconciled against the local drafts (`$get-cart`).\n *\n * A near-empty re-export of `useMedicationCart` from `@medplum/react-hooks`: the\n * vendor binding for the custom operations lives entirely on the server, where\n * each Medplum project's `OperationDefinition`s point at the ScriptSure bots via\n * the `operationDefinition-implementation` extension \u2014 see\n * [Custom FHIR Operations](https://www.medplum.com/docs/bots/custom-fhir-operations).\n * (Internal deploy: `medplum-ee/packages/scriptsure/src/scripts/deploy.ts`.)\n *\n * `addToCart` is plain FHIR create (no vendor call); MedCart staging happens at\n * `checkout`. DoseSpot and other iframe-first vendors do not use this surface.\n *\n * Kept as a typed alias for source-compatibility with apps importing\n * `useScriptSureCart` and as a documentation anchor for ScriptSure-specific\n * behavior (patient-must-be-synced precondition; cart items await sign-off in\n * the MedCart widget).\n *\n * @returns The same API as `useMedicationCart` (`addToCart`, `adding`,\n * `checkout`, `removeFromCart`, `clearCart`, `getCart`).\n */\nexport function useScriptSureCart(): UseScriptSureCartReturn {\n return useMedicationCart();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { MedicationIFrameOptions } from '@medplum/react-hooks';\nimport { useMedicationIFrame } from '@medplum/react-hooks';\nimport { SCRIPTSURE_IFRAME_BOT, SCRIPTSURE_PATIENT_SYNC_BOT } from './common';\n\nexport type ScriptSureIFrameOptions = MedicationIFrameOptions;\n\n/**\n * React hook that syncs a patient to ScriptSure and returns the iframe URL.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#useMedicationIFrame} hook,\n * pre-configured with ScriptSure bot identifiers.\n *\n * @param options - Configuration and callback options.\n * @returns The ScriptSure iframe URL, or undefined while loading.\n */\nexport function useScriptSureIFrame(options: ScriptSureIFrameOptions): string | undefined {\n return useMedicationIFrame(SCRIPTSURE_PATIENT_SYNC_BOT, SCRIPTSURE_IFRAME_BOT, options);\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { isResource } from '@medplum/core';\nimport type { Task } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport { useCallback } from 'react';\nimport { SCRIPTSURE_MESSAGE_TASK_BOT } from './common';\n\nexport type ScriptSureMessageTaskAction = 'launch' | 'reconcile' | 'acknowledge';\n\n/** Request accepted by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskRequest {\n taskId: string;\n action: ScriptSureMessageTaskAction;\n organizationId?: string;\n}\n\n/** Validated response returned by the ScriptSure message-task bot. */\nexport interface ScriptSureMessageTaskResponse {\n task: Task;\n launchUrl?: string;\n vendorStatus?: string;\n}\n\nexport interface ScriptSureMessageTaskParams {\n taskId: string;\n organizationId?: string;\n}\n\nexport interface UseScriptSureMessageTaskReturn {\n launch: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n reconcile: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n acknowledge: (params: ScriptSureMessageTaskParams) => Promise<ScriptSureMessageTaskResponse>;\n}\n\nconst INVALID_MESSAGE_TASK_RESPONSE = 'Invalid ScriptSure message-task response';\n\nfunction parseMessageTaskResponse(value: unknown): ScriptSureMessageTaskResponse {\n if (!value || typeof value !== 'object') {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n const response = value as Record<string, unknown>;\n if (\n !isResource<Task>(response.task, 'Task') ||\n (response.launchUrl !== undefined && typeof response.launchUrl !== 'string') ||\n (response.vendorStatus !== undefined && typeof response.vendorStatus !== 'string')\n ) {\n throw new Error(INVALID_MESSAGE_TASK_RESPONSE);\n }\n return response as unknown as ScriptSureMessageTaskResponse;\n}\n\n/**\n * Executes the ScriptSure pharmacy-message Task lifecycle bot.\n *\n * The hook intentionally exposes only the three supported actions and validates\n * the untyped Bot response before returning it to the application.\n *\n * @returns Typed launch, reconcile, and acknowledge callbacks.\n */\nexport function useScriptSureMessageTask(): UseScriptSureMessageTaskReturn {\n const medplum = useMedplum();\n\n const execute = useCallback(\n async (\n action: ScriptSureMessageTaskAction,\n params: ScriptSureMessageTaskParams\n ): Promise<ScriptSureMessageTaskResponse> => {\n const request: ScriptSureMessageTaskRequest = { ...params, action };\n return parseMessageTaskResponse(await medplum.executeBot(SCRIPTSURE_MESSAGE_TASK_BOT, request));\n },\n [medplum]\n );\n\n const launch = useCallback((params: ScriptSureMessageTaskParams) => execute('launch', params), [execute]);\n const reconcile = useCallback((params: ScriptSureMessageTaskParams) => execute('reconcile', params), [execute]);\n const acknowledge = useCallback((params: ScriptSureMessageTaskParams) => execute('acknowledge', params), [execute]);\n\n return { launch, reconcile, acknowledge };\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UseMedicationOrderReturn } from '@medplum/react-hooks';\nimport { useMedicationOrder } from '@medplum/react-hooks';\n\nexport type UseScriptSureOrderMedicationReturn = UseMedicationOrderReturn;\n\n/**\n * React hook for ScriptSure drug search and pending order creation (iframe launch URL).\n *\n * Now a near-empty re-export of `useMedicationOrder` from `@medplum/react-hooks`: the\n * vendor binding lives entirely on the server, where each Medplum project's\n * `OperationDefinition` resources for `$drug-search` and `$order-medication`\n * point at the ScriptSure bots via the\n * `operationDefinition-implementation` extension. See the deploy script in\n * `medplum-ee/packages/scriptsure/src/scripts/deploy.ts` for how those\n * resources are upserted.\n *\n * Kept as a typed alias for backwards source-compatibility with apps importing\n * `useScriptSureOrderMedication` and as a documentation anchor for the\n * ScriptSure-specific behavior (e.g. patient-must-be-synced precondition).\n *\n * @returns The same API as `useMedicationOrder` (search + order callbacks).\n */\nexport function useScriptSureOrderMedication(): UseScriptSureOrderMedicationReturn {\n return useMedicationOrder();\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport type { Organization, Reference } from '@medplum/fhirtypes';\nimport type { UseMedicationOrderSetReturn } from '@medplum/react-hooks';\nimport { useMedicationOrderSet } from '@medplum/react-hooks';\n\nexport interface UseScriptSureOrderSetOptions {\n /** Patient to prescribe against. Hook stays idle (no operation call) until set. */\n readonly patientId: string | undefined;\n /** Medplum PlanDefinition id; bot reverse-looks up the ScriptSure orderset id. */\n readonly planDefinitionId?: string;\n /** ScriptSure orderset id (escape hatch when no synced PD exists yet). */\n readonly scriptSureOrdersetId?: number;\n readonly appId?: string;\n /** Selected practice location for multi-practice deployments. */\n readonly organization?: Reference<Organization>;\n}\n\nexport type UseScriptSureOrderSetReturn = UseMedicationOrderSetReturn;\n\n/**\n * React hook that returns the ScriptSure order-set prescribing widget URL via\n * the vendor-neutral `$order-set-url` FHIR custom operation\n * (`POST /fhir/R4/PlanDefinition/$order-set-url`).\n *\n * Thin wrapper around {@link @medplum/react-hooks#useMedicationOrderSet}: forwards\n * `scriptSureOrdersetId` as the operation's `vendorOrderSetId` parameter,\n * leaves vendor binding to the deployed `OperationDefinition` \u2192\n * `Bot/scriptsure-order-set-bot` link.\n *\n * The operation is naturally idempotent \u2014 re-calls only refresh the session\n * token in the returned URL \u2014 so callers can safely wire `refresh` into\n * `PrescriptionIFrameModal.onRefreshLaunchUrl`.\n *\n * @param options - Patient + order-set picker (PD or ScriptSure id).\n * @returns `{ url, loading, error, refresh }`.\n */\nexport function useScriptSureOrderSet(options: UseScriptSureOrderSetOptions): UseScriptSureOrderSetReturn {\n return useMedicationOrderSet({\n patientId: options.patientId,\n planDefinitionId: options.planDefinitionId,\n vendorOrderSetId: options.scriptSureOrdersetId,\n appId: options.appId,\n organization: options.organization,\n });\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { UsePharmacySearchReturn } from '@medplum/react-hooks';\nimport { usePharmacySearch } from '@medplum/react-hooks';\nimport { SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT, SCRIPTSURE_SEARCH_PHARMACY_BOT } from './common';\nimport type { ScriptSurePharmacySearchParams } from './pharmacy-search';\n\nexport type UseScriptSurePharmacySearchReturn = UsePharmacySearchReturn<ScriptSurePharmacySearchParams>;\n\n/**\n * React hook that provides ScriptSure-specific pharmacy search and add-to-favorites functionality.\n *\n * Thin wrapper around the generic {@link @medplum/react-hooks#usePharmacySearch} hook, pre-configured with\n * ScriptSure bot identifiers and widened so search params carry ScriptSure-only\n * `specialties` filters for POST /v3/pharmacy/search.\n *\n * @returns An object with `searchPharmacies` and `addToFavorites` callbacks.\n */\nexport function useScriptSurePharmacySearch(): UseScriptSurePharmacySearchReturn {\n return usePharmacySearch<ScriptSurePharmacySearchParams>(\n SCRIPTSURE_SEARCH_PHARMACY_BOT,\n SCRIPTSURE_ADD_PATIENT_PHARMACY_BOT\n );\n}\n", "// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors\n// SPDX-License-Identifier: Apache-2.0\nimport { getIdentifier, resolveId } from '@medplum/core';\nimport type { Organization, Practitioner, PractitionerRole, Reference } from '@medplum/fhirtypes';\nimport { useMedplum } from '@medplum/react-hooks';\nimport type { JSX, ReactNode } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';\nimport { SCRIPTSURE_PRACTICE_ID_SYSTEM } from './common';\n\nconst STORAGE_KEY = 'medplum.scriptsure.selectedPracticeOrganization';\n\n/** The current ScriptSure practice-location selection for the signed-in prescriber. */\nexport interface ScriptSurePracticeContextValue {\n /**\n * The prescriber's ScriptSure practice `Organization`s \u2014 discovered from their\n * own affiliations (`PractitionerRole.organization` + `ProjectMembership.access`\n * organization parameters), filtered to those carrying a `practice-id` identifier.\n * Never the project-wide list.\n */\n readonly practices: Organization[];\n /** Bare Organization id used by the selector and persisted in localStorage. */\n readonly selectedOrganizationId: string | undefined;\n /** FHIR reference for the selected practice, suitable for operation and hook inputs. */\n readonly selectedOrganization: Reference<Organization> | undefined;\n /** Selects a practice Organization (persisted to localStorage). */\n readonly setSelectedOrganizationId: (id: string | undefined) => void;\n readonly loading: boolean;\n}\n\nconst ScriptSurePracticeContext = createContext<ScriptSurePracticeContextValue>({\n practices: [],\n selectedOrganizationId: undefined,\n selectedOrganization: undefined,\n setSelectedOrganizationId: () => undefined,\n loading: false,\n});\n\nfunction addOrganizationReference(refs: Set<string>, reference: string | undefined): void {\n if (reference?.startsWith('Organization/')) {\n refs.add(reference);\n }\n}\n\nfunction hasPracticeIdentifier(org: Organization): boolean {\n return Boolean(getIdentifier(org, SCRIPTSURE_PRACTICE_ID_SYSTEM));\n}\n\n/**\n * Resolves the signed-in prescriber's `Practitioner.id` from the current profile,\n * whether the profile is a `Practitioner` or a `PractitionerRole`.\n *\n * @param profile - The current Medplum profile resource.\n * @returns The Practitioner id, or undefined when it cannot be resolved.\n */\nfunction resolvePractitionerId(profile: Practitioner | PractitionerRole | undefined): string | undefined {\n if (profile?.resourceType === 'Practitioner') {\n return profile.id;\n }\n if (profile?.resourceType === 'PractitionerRole') {\n return resolveId(profile.practitioner);\n }\n return undefined;\n}\n\n/**\n * Provides the signed-in prescriber's current ScriptSure practice-location\n * selection, discovered from **their own affiliations** \u2014 mirroring the server's\n * multi-practice resolver so the UI never offers a practice the prescriber is not\n * a member of.\n *\n * Discovery: active `PractitionerRole.organization` references for the current\n * `Practitioner` plus any `ProjectMembership.access[].parameter` named\n * `organization`, resolved to `Organization`s and filtered to those carrying a\n * `practice-id` identifier. The sole practice is auto-selected; a previously used\n * selection is restored only when it is still in the affiliation set.\n *\n * @param props - Component props.\n * @param props.children - Child nodes rendered within the provider.\n * @returns The context provider element.\n */\nexport function ScriptSurePracticeProvider(props: { readonly children: ReactNode }): JSX.Element {\n const medplum = useMedplum();\n const [practices, setPractices] = useState<Organization[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedOrganizationId, setSelected] = useState<string | undefined>(\n () => localStorage.getItem(STORAGE_KEY) ?? undefined\n );\n\n useEffect(() => {\n let cancelled = false;\n\n const loadAffiliatedPractices = async (): Promise<Organization[]> => {\n const profile = medplum.getProfile() as Practitioner | PractitionerRole | undefined;\n const practitionerId = resolvePractitionerId(profile);\n const references = new Set<string>();\n\n if (practitionerId) {\n const roles = await medplum.searchResources('PractitionerRole', {\n practitioner: `Practitioner/${practitionerId}`,\n _count: '100',\n });\n for (const role of roles) {\n // `active` is not a standard R4 PractitionerRole search param \u2014 filter in code.\n if (role.active !== false) {\n addOrganizationReference(references, role.organization?.reference);\n }\n }\n }\n\n const membership = medplum.getProjectMembership();\n for (const access of membership?.access ?? []) {\n for (const param of access.parameter ?? []) {\n if (param.name === 'organization') {\n addOrganizationReference(references, param.valueReference?.reference);\n }\n }\n }\n\n const settledOrgs = await Promise.allSettled(\n [...references].map((reference) => medplum.readReference<Organization>({ reference }))\n );\n const seen = new Set<string>();\n const result: Organization[] = [];\n for (const settledOrg of settledOrgs) {\n if (settledOrg.status === 'rejected') {\n continue;\n }\n const org = settledOrg.value;\n if (org.id && !seen.has(org.id) && hasPracticeIdentifier(org)) {\n seen.add(org.id);\n result.push(org);\n }\n }\n return result;\n };\n\n const updateAffiliatedPractices = async (): Promise<void> => {\n setLoading(true);\n try {\n const orgs = await loadAffiliatedPractices();\n if (!cancelled) {\n setPractices(orgs);\n // Default: keep a stored id only if it is still an affiliation; else the sole practice.\n setSelected((current) => {\n if (current && orgs.some((o) => o.id === current)) {\n return current;\n }\n return orgs.length === 1 ? orgs[0].id : undefined;\n });\n }\n } catch {\n if (!cancelled) {\n setPractices([]);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n };\n updateAffiliatedPractices().catch(() => undefined);\n\n return (): void => {\n cancelled = true;\n };\n }, [medplum]);\n\n const setSelectedOrganizationId = useCallback((id: string | undefined): void => {\n setSelected(id);\n if (id) {\n localStorage.setItem(STORAGE_KEY, id);\n } else {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, []);\n\n const selectedOrganization = useMemo<Reference<Organization> | undefined>(\n () => (selectedOrganizationId ? { reference: `Organization/${selectedOrganizationId}` } : undefined),\n [selectedOrganizationId]\n );\n\n const value = useMemo<ScriptSurePracticeContextValue>(\n () => ({ practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading }),\n [practices, selectedOrganizationId, selectedOrganization, setSelectedOrganizationId, loading]\n );\n\n return <ScriptSurePracticeContext.Provider value={value}>{props.children}</ScriptSurePracticeContext.Provider>;\n}\n\n/**\n * Hook returning the current ScriptSure practice selection + setter.\n *\n * @returns The practice context value.\n */\nexport function useScriptSurePractice(): ScriptSurePracticeContextValue {\n return useContext(ScriptSurePracticeContext);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["isResource", "isResource", "useMedplum", "useCallback", "useMedplum", "useCallback"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medplum/scriptsure-react",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.40",
|
|
4
4
|
"description": "Medplum ScriptSure React SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"medplum",
|
|
@@ -58,10 +58,10 @@
|
|
|
58
58
|
"test:watch": "vitest watch"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@medplum/core": "5.1.
|
|
62
|
-
"@medplum/fhirtypes": "5.1.
|
|
63
|
-
"@medplum/mock": "5.1.
|
|
64
|
-
"@medplum/react-hooks": "5.1.
|
|
61
|
+
"@medplum/core": "5.1.40",
|
|
62
|
+
"@medplum/fhirtypes": "5.1.40",
|
|
63
|
+
"@medplum/mock": "5.1.40",
|
|
64
|
+
"@medplum/react-hooks": "5.1.40",
|
|
65
65
|
"@testing-library/jest-dom": "7.0.1",
|
|
66
66
|
"@testing-library/react": "16.3.3",
|
|
67
67
|
"@types/react": "19.3.0",
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"react-dom": "19.3.0"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@medplum/core": "5.1.
|
|
75
|
-
"@medplum/fhirtypes": "5.1.
|
|
76
|
-
"@medplum/react-hooks": "5.1.
|
|
74
|
+
"@medplum/core": "5.1.40",
|
|
75
|
+
"@medplum/fhirtypes": "5.1.40",
|
|
76
|
+
"@medplum/react-hooks": "5.1.40",
|
|
77
77
|
"react": "^18.0.0 || ^19.0.0"
|
|
78
78
|
},
|
|
79
79
|
"engines": {
|