@medplum/react-hooks 5.1.12 → 5.1.14

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.
@@ -7,6 +7,10 @@ import type { Encounter } from '@medplum/fhirtypes';
7
7
  import type { ExtractResource } from '@medplum/fhirtypes';
8
8
  import type { Identifier } from '@medplum/fhirtypes';
9
9
  import type { JSX } from 'react';
10
+ import type { Medication } from '@medplum/fhirtypes';
11
+ import type { MedicationOrderRequest } from '@medplum/core';
12
+ import type { MedicationOrderResponse } from '@medplum/core';
13
+ import type { MedicationSearchParams } from '@medplum/core';
10
14
  import type { MedplumClient } from '@medplum/core';
11
15
  import type { OperationOutcome } from '@medplum/fhirtypes';
12
16
  import type { Organization } from '@medplum/fhirtypes';
@@ -38,13 +42,6 @@ export declare function buildInitialResponseItem(item: QuestionnaireItem): Quest
38
42
 
39
43
  export declare function convertToPCM16(float32Array: Float32Array): Uint8Array;
40
44
 
41
- export declare interface EPrescribingIFrameOptions {
42
- readonly patientId?: string;
43
- readonly onPatientSyncSuccess?: () => void;
44
- readonly onIframeSuccess?: (url: string) => void;
45
- readonly onError?: (err: unknown) => void;
46
- }
47
-
48
45
  /**
49
46
  * Evaluates the calculated expressions in a questionnaire.
50
47
  * Updates response item answers in place with the calculated values.
@@ -108,6 +105,13 @@ export declare function isChoiceQuestion(item: QuestionnaireItem): boolean;
108
105
  */
109
106
  export declare function isQuestionEnabled(item: QuestionnaireItem, questionnaireResponse: QuestionnaireResponse | undefined): boolean;
110
107
 
108
+ export declare interface MedicationIFrameOptions {
109
+ readonly patientId?: string;
110
+ readonly onPatientSyncSuccess?: () => void;
111
+ readonly onIframeSuccess?: (url: string) => void;
112
+ readonly onError?: (err: unknown) => void;
113
+ }
114
+
111
115
  export declare interface MedplumContext {
112
116
  medplum: MedplumClient;
113
117
  navigate: MedplumNavigateFunction;
@@ -287,8 +291,8 @@ export declare function typedValueToResponseItem(item: QuestionnaireItem, value:
287
291
  export declare const useCachedBinaryUrl: (binaryUrl: string | undefined) => string | undefined;
288
292
 
289
293
  /**
290
- * Generic React hook that syncs a patient to an e-prescribing system and
291
- * returns the iframe URL.
294
+ * Generic React hook that syncs a patient to a medication-order vendor and
295
+ * returns the chart iframe URL.
292
296
  *
293
297
  * Executes the patient-sync bot first (if patientId is provided), then
294
298
  * the iframe bot to obtain the prescribing UI URL.
@@ -299,9 +303,92 @@ export declare const useCachedBinaryUrl: (binaryUrl: string | undefined) => stri
299
303
  * @param syncBotIdentifier - Bot identifier for the patient sync bot.
300
304
  * @param iframeBotIdentifier - Bot identifier for the iframe URL bot.
301
305
  * @param options - Configuration and callback options.
302
- * @returns The e-prescribing iframe URL, or undefined while loading.
306
+ * @returns The medication-order iframe URL, or undefined while loading.
307
+ */
308
+ export declare function useMedicationIFrame(syncBotIdentifier: Identifier, iframeBotIdentifier: Identifier, options: MedicationIFrameOptions): string | undefined;
309
+
310
+ /**
311
+ * Vendor-neutral hook for e-prescribing drug search and order-medication via
312
+ * **FHIR custom operations** (no Bot identifiers required).
313
+ *
314
+ * Hits two project-scoped operations whose backing Bot is chosen at deploy time
315
+ * via an `OperationDefinition` resource carrying the
316
+ * `operationDefinition-implementation` extension — see
317
+ * [bot operations docs](https://www.medplum.com/docs/bots/custom-fhir-operations).
318
+ * The server's `tryCustomOperation` dispatch handles the OD → Bot lookup, so
319
+ * projects can swap vendors (ScriptSure today, DoseSpot tomorrow) by deploying
320
+ * a different bot under the same operation code.
321
+ *
322
+ * - `searchMedications`: `POST /fhir/R4/Medication/$drug-search` — expects the
323
+ * bot to return a `Bundle<Medication>` (single-Resource `return` shortcut on
324
+ * the OperationDefinition).
325
+ * - `orderMedication`: `POST /fhir/R4/MedicationRequest/$order-medication` —
326
+ * expects the bot to return a `Parameters` envelope with named primitives;
327
+ * `parametersToMedicationOrderResponse` decodes it.
328
+ *
329
+ * @returns Callbacks to search medications and submit an order request.
303
330
  */
304
- export declare function useEPrescribingIFrame(syncBotIdentifier: Identifier, iframeBotIdentifier: Identifier, options: EPrescribingIFrameOptions): string | undefined;
331
+ export declare function useMedicationOrder(): UseMedicationOrderReturn;
332
+
333
+ export declare interface UseMedicationOrderReturn {
334
+ searchMedications: (params: MedicationSearchParams) => Promise<Medication[]>;
335
+ orderMedication: (input: MedicationOrderRequest) => Promise<MedicationOrderResponse>;
336
+ }
337
+
338
+ /**
339
+ * Vendor-neutral React hook that calls the `$order-set-url` custom FHIR
340
+ * operation and exposes the resulting iframe URL plus refresh/loading/error
341
+ * state.
342
+ *
343
+ * Hits the project-scoped operation whose backing bot is chosen at deploy time
344
+ * via an `OperationDefinition` resource carrying the
345
+ * `operationDefinition-implementation` extension — see
346
+ * [bot operations docs](https://www.medplum.com/docs/bots/custom-fhir-operations).
347
+ * The server's `tryCustomOperation` dispatch handles the OD → Bot lookup, so
348
+ * projects can swap vendors (ScriptSure today, DoseSpot tomorrow) by deploying
349
+ * a different bot under the same operation code.
350
+ *
351
+ * - URL: `POST /fhir/R4/PlanDefinition/$order-set-url`
352
+ * - Body: `Parameters` with `patientId` + (`planDefinitionId` XOR `vendorOrderSetId`) + optional `appId`.
353
+ * - Returns: `Parameters` whose `launchUrl` is exposed as `url` on the hook.
354
+ *
355
+ * The hook is a "build a URL" hook (mirrors {@link useMedicationIFrame}); it
356
+ * does not stamp Medplum resources or create vendor-side resources, so
357
+ * `refresh` is safe to call repeatedly (the operation is naturally idempotent).
358
+ *
359
+ * Re-runs whenever the input options change. In-flight calls are cancelled on
360
+ * input change and on unmount via a per-effect `cancelled` flag, so React 18
361
+ * Strict Mode double-mount does not surface stale URLs.
362
+ *
363
+ * @param options - Patient, picker (PD or vendor id), and optional appId.
364
+ * @returns `{ url, loading, error, refresh }`.
365
+ */
366
+ export declare function useMedicationOrderSet(options: UseMedicationOrderSetOptions): UseMedicationOrderSetReturn;
367
+
368
+ export declare interface UseMedicationOrderSetOptions {
369
+ /** Patient to prescribe against. Hook stays idle (no operation call) until set. */
370
+ readonly patientId: string | undefined;
371
+ /** Medplum PlanDefinition id (vendor-neutral). Bot resolves it to the vendor's order set id. */
372
+ readonly planDefinitionId?: string;
373
+ /** Vendor-side order set id, when picked directly (escape hatch when no synced PD exists yet). */
374
+ readonly vendorOrderSetId?: number | string;
375
+ readonly appId?: string;
376
+ }
377
+
378
+ export declare interface UseMedicationOrderSetReturn {
379
+ /** Most recent successful URL from the order-set operation, or undefined while loading / on error. */
380
+ readonly url: string | undefined;
381
+ /** True while a request is in flight. */
382
+ readonly loading: boolean;
383
+ /** Last error from the operation call, or undefined. */
384
+ readonly error: unknown;
385
+ /**
386
+ * Force a re-fetch using the current options. Useful when wiring
387
+ * `PrescriptionIFrameModal.onRefreshLaunchUrl` so the session token in
388
+ * the returned widget URL is fresh on every modal open.
389
+ */
390
+ readonly refresh: () => Promise<string | undefined>;
391
+ }
305
392
 
306
393
  /**
307
394
  * Returns the MedplumClient instance.
@@ -475,6 +562,19 @@ export declare type UseSubscriptionOptions = {
475
562
  onError?: (err: Error) => void;
476
563
  };
477
564
 
565
+ /**
566
+ * Vendor-neutral React hook that syncs a Medplum `PlanDefinition` (type=order-set)
567
+ * to the configured e-prescribing vendor via the `$sync-orderset` custom FHIR operation
568
+ * (`POST /fhir/R4/PlanDefinition/$sync-orderset`).
569
+ *
570
+ * Silently no-ops when the operation is not deployed (i.e. no e-prescribing vendor
571
+ * is configured for the project), so callers do not need to guard against missing
572
+ * integrations.
573
+ *
574
+ * @returns A stable `syncOrderSet(planDefinitionId)` callback.
575
+ */
576
+ export declare function useSyncOrderSet(): (planDefinitionId: string) => Promise<void>;
577
+
478
578
  export declare function useThreadInbox({ query, threadId }: UseThreadInboxOptions): UseThreadInboxReturn;
479
579
 
480
580
  export declare interface UseThreadInboxOptions {
@@ -7,6 +7,10 @@ import type { Encounter } from '@medplum/fhirtypes';
7
7
  import type { ExtractResource } from '@medplum/fhirtypes';
8
8
  import type { Identifier } from '@medplum/fhirtypes';
9
9
  import type { JSX } from 'react';
10
+ import type { Medication } from '@medplum/fhirtypes';
11
+ import type { MedicationOrderRequest } from '@medplum/core';
12
+ import type { MedicationOrderResponse } from '@medplum/core';
13
+ import type { MedicationSearchParams } from '@medplum/core';
10
14
  import type { MedplumClient } from '@medplum/core';
11
15
  import type { OperationOutcome } from '@medplum/fhirtypes';
12
16
  import type { Organization } from '@medplum/fhirtypes';
@@ -38,13 +42,6 @@ export declare function buildInitialResponseItem(item: QuestionnaireItem): Quest
38
42
 
39
43
  export declare function convertToPCM16(float32Array: Float32Array): Uint8Array;
40
44
 
41
- export declare interface EPrescribingIFrameOptions {
42
- readonly patientId?: string;
43
- readonly onPatientSyncSuccess?: () => void;
44
- readonly onIframeSuccess?: (url: string) => void;
45
- readonly onError?: (err: unknown) => void;
46
- }
47
-
48
45
  /**
49
46
  * Evaluates the calculated expressions in a questionnaire.
50
47
  * Updates response item answers in place with the calculated values.
@@ -108,6 +105,13 @@ export declare function isChoiceQuestion(item: QuestionnaireItem): boolean;
108
105
  */
109
106
  export declare function isQuestionEnabled(item: QuestionnaireItem, questionnaireResponse: QuestionnaireResponse | undefined): boolean;
110
107
 
108
+ export declare interface MedicationIFrameOptions {
109
+ readonly patientId?: string;
110
+ readonly onPatientSyncSuccess?: () => void;
111
+ readonly onIframeSuccess?: (url: string) => void;
112
+ readonly onError?: (err: unknown) => void;
113
+ }
114
+
111
115
  export declare interface MedplumContext {
112
116
  medplum: MedplumClient;
113
117
  navigate: MedplumNavigateFunction;
@@ -287,8 +291,8 @@ export declare function typedValueToResponseItem(item: QuestionnaireItem, value:
287
291
  export declare const useCachedBinaryUrl: (binaryUrl: string | undefined) => string | undefined;
288
292
 
289
293
  /**
290
- * Generic React hook that syncs a patient to an e-prescribing system and
291
- * returns the iframe URL.
294
+ * Generic React hook that syncs a patient to a medication-order vendor and
295
+ * returns the chart iframe URL.
292
296
  *
293
297
  * Executes the patient-sync bot first (if patientId is provided), then
294
298
  * the iframe bot to obtain the prescribing UI URL.
@@ -299,9 +303,92 @@ export declare const useCachedBinaryUrl: (binaryUrl: string | undefined) => stri
299
303
  * @param syncBotIdentifier - Bot identifier for the patient sync bot.
300
304
  * @param iframeBotIdentifier - Bot identifier for the iframe URL bot.
301
305
  * @param options - Configuration and callback options.
302
- * @returns The e-prescribing iframe URL, or undefined while loading.
306
+ * @returns The medication-order iframe URL, or undefined while loading.
307
+ */
308
+ export declare function useMedicationIFrame(syncBotIdentifier: Identifier, iframeBotIdentifier: Identifier, options: MedicationIFrameOptions): string | undefined;
309
+
310
+ /**
311
+ * Vendor-neutral hook for e-prescribing drug search and order-medication via
312
+ * **FHIR custom operations** (no Bot identifiers required).
313
+ *
314
+ * Hits two project-scoped operations whose backing Bot is chosen at deploy time
315
+ * via an `OperationDefinition` resource carrying the
316
+ * `operationDefinition-implementation` extension — see
317
+ * [bot operations docs](https://www.medplum.com/docs/bots/custom-fhir-operations).
318
+ * The server's `tryCustomOperation` dispatch handles the OD → Bot lookup, so
319
+ * projects can swap vendors (ScriptSure today, DoseSpot tomorrow) by deploying
320
+ * a different bot under the same operation code.
321
+ *
322
+ * - `searchMedications`: `POST /fhir/R4/Medication/$drug-search` — expects the
323
+ * bot to return a `Bundle<Medication>` (single-Resource `return` shortcut on
324
+ * the OperationDefinition).
325
+ * - `orderMedication`: `POST /fhir/R4/MedicationRequest/$order-medication` —
326
+ * expects the bot to return a `Parameters` envelope with named primitives;
327
+ * `parametersToMedicationOrderResponse` decodes it.
328
+ *
329
+ * @returns Callbacks to search medications and submit an order request.
303
330
  */
304
- export declare function useEPrescribingIFrame(syncBotIdentifier: Identifier, iframeBotIdentifier: Identifier, options: EPrescribingIFrameOptions): string | undefined;
331
+ export declare function useMedicationOrder(): UseMedicationOrderReturn;
332
+
333
+ export declare interface UseMedicationOrderReturn {
334
+ searchMedications: (params: MedicationSearchParams) => Promise<Medication[]>;
335
+ orderMedication: (input: MedicationOrderRequest) => Promise<MedicationOrderResponse>;
336
+ }
337
+
338
+ /**
339
+ * Vendor-neutral React hook that calls the `$order-set-url` custom FHIR
340
+ * operation and exposes the resulting iframe URL plus refresh/loading/error
341
+ * state.
342
+ *
343
+ * Hits the project-scoped operation whose backing bot is chosen at deploy time
344
+ * via an `OperationDefinition` resource carrying the
345
+ * `operationDefinition-implementation` extension — see
346
+ * [bot operations docs](https://www.medplum.com/docs/bots/custom-fhir-operations).
347
+ * The server's `tryCustomOperation` dispatch handles the OD → Bot lookup, so
348
+ * projects can swap vendors (ScriptSure today, DoseSpot tomorrow) by deploying
349
+ * a different bot under the same operation code.
350
+ *
351
+ * - URL: `POST /fhir/R4/PlanDefinition/$order-set-url`
352
+ * - Body: `Parameters` with `patientId` + (`planDefinitionId` XOR `vendorOrderSetId`) + optional `appId`.
353
+ * - Returns: `Parameters` whose `launchUrl` is exposed as `url` on the hook.
354
+ *
355
+ * The hook is a "build a URL" hook (mirrors {@link useMedicationIFrame}); it
356
+ * does not stamp Medplum resources or create vendor-side resources, so
357
+ * `refresh` is safe to call repeatedly (the operation is naturally idempotent).
358
+ *
359
+ * Re-runs whenever the input options change. In-flight calls are cancelled on
360
+ * input change and on unmount via a per-effect `cancelled` flag, so React 18
361
+ * Strict Mode double-mount does not surface stale URLs.
362
+ *
363
+ * @param options - Patient, picker (PD or vendor id), and optional appId.
364
+ * @returns `{ url, loading, error, refresh }`.
365
+ */
366
+ export declare function useMedicationOrderSet(options: UseMedicationOrderSetOptions): UseMedicationOrderSetReturn;
367
+
368
+ export declare interface UseMedicationOrderSetOptions {
369
+ /** Patient to prescribe against. Hook stays idle (no operation call) until set. */
370
+ readonly patientId: string | undefined;
371
+ /** Medplum PlanDefinition id (vendor-neutral). Bot resolves it to the vendor's order set id. */
372
+ readonly planDefinitionId?: string;
373
+ /** Vendor-side order set id, when picked directly (escape hatch when no synced PD exists yet). */
374
+ readonly vendorOrderSetId?: number | string;
375
+ readonly appId?: string;
376
+ }
377
+
378
+ export declare interface UseMedicationOrderSetReturn {
379
+ /** Most recent successful URL from the order-set operation, or undefined while loading / on error. */
380
+ readonly url: string | undefined;
381
+ /** True while a request is in flight. */
382
+ readonly loading: boolean;
383
+ /** Last error from the operation call, or undefined. */
384
+ readonly error: unknown;
385
+ /**
386
+ * Force a re-fetch using the current options. Useful when wiring
387
+ * `PrescriptionIFrameModal.onRefreshLaunchUrl` so the session token in
388
+ * the returned widget URL is fresh on every modal open.
389
+ */
390
+ readonly refresh: () => Promise<string | undefined>;
391
+ }
305
392
 
306
393
  /**
307
394
  * Returns the MedplumClient instance.
@@ -475,6 +562,19 @@ export declare type UseSubscriptionOptions = {
475
562
  onError?: (err: Error) => void;
476
563
  };
477
564
 
565
+ /**
566
+ * Vendor-neutral React hook that syncs a Medplum `PlanDefinition` (type=order-set)
567
+ * to the configured e-prescribing vendor via the `$sync-orderset` custom FHIR operation
568
+ * (`POST /fhir/R4/PlanDefinition/$sync-orderset`).
569
+ *
570
+ * Silently no-ops when the operation is not deployed (i.e. no e-prescribing vendor
571
+ * is configured for the project), so callers do not need to guard against missing
572
+ * integrations.
573
+ *
574
+ * @returns A stable `syncOrderSet(planDefinitionId)` callback.
575
+ */
576
+ export declare function useSyncOrderSet(): (planDefinitionId: string) => Promise<void>;
577
+
478
578
  export declare function useThreadInbox({ query, threadId }: UseThreadInboxOptions): UseThreadInboxReturn;
479
579
 
480
580
  export declare interface UseThreadInboxOptions {
@@ -1,8 +1,8 @@
1
- import{useEffect as Me,useMemo as ke,useState as Ue}from"react";import{createContext as Ae,useContext as _e}from"react";var W=Ae(void 0);function D(){return _e(W)}function v(){return D().medplum}function jn(){return D().navigate}function zn(){return D().profile}import{jsx as Le}from"react/jsx-runtime";var re=["change","storageInitialized","storageInitFailed","profileRefreshing","profileRefreshed"];function Xn(e){let t=e.medplum,n=e.navigate??Ne,[o,r]=Ue({profile:t.getProfile(),loading:t.isLoading()});Me(()=>{function s(){r(f=>({...f,profile:t.getProfile(),loading:t.isLoading()}))}for(let f of re)t.addEventListener(f,s);return()=>{for(let f of re)t.removeEventListener(f,s)}},[t]);let i=ke(()=>({...o,medplum:t,navigate:n}),[o,t,n]);return Le(W.Provider,{value:i,children:e.children})}function Ne(e){window.location.assign(e)}import{useMemo as qe}from"react";var oe=new Map,nt=e=>qe(()=>{if(!e)return;let t=e.split("?")[0];if(!t)return e;let n;try{n=new URLSearchParams(new URL(e).search)}catch{return e}if(!n.has("Key-Pair-Id")||!n.has("Signature"))return e;let o=n.get("Expires");if(!o||o.length>13)return e;let r=oe.get(t);if(r){let s=new URLSearchParams(new URL(r).search).get("Expires");if(s&&Number.parseInt(s,10)*1e3-5e3>Date.now())return r}return oe.set(t,e),e},[e]);import{useEffect as ie,useRef as V,useState as Fe}from"react";function it(e,t,n){let o=v(),{patientId:r,onPatientSyncSuccess:i,onIframeSuccess:s,onError:f}=n,[p,x]=Fe(void 0),I=V(i),b=V(s),Q=V(f);return ie(()=>{I.current=i,b.current=s,Q.current=f},[i,s,f]),ie(()=>{let h=!1;return(async()=>{try{if(r){if(await o.executeBot(e,{patientId:r}),h)return;I.current?.()}let a=await o.executeBot(t,{patientId:r});if(h)return;a.url&&(x(a.url),b.current?.(a.url))}catch(a){h||Q.current?.(a)}})().catch(()=>{}),()=>{h=!0}},[o,e,t,r]),p}import{useCallback as De,useEffect as Ve,useState as $e}from"react";import{deepEquals as se}from"@medplum/core";import{useCallback as M,useEffect as $,useRef as w,useState as ae}from"react";var We=3e3;function ue(e,t,n){let o=v(),[r,i]=ae(),[s,f]=ae(n?.subscriptionProps),p=w(!1),x=w(void 0),I=w(void 0),b=w(void 0),Q=w(t);Q.current=t;let h=w(n?.onWebSocketOpen);h.current=n?.onWebSocketOpen;let y=w(n?.onWebSocketClose);y.current=n?.onWebSocketClose;let a=w(n?.onSubscriptionConnect);a.current=n?.onSubscriptionConnect;let c=w(n?.onSubscriptionDisconnect);c.current=n?.onSubscriptionDisconnect;let m=w(n?.onError);m.current=n?.onError,$(()=>{se(n?.subscriptionProps,s)||f(n?.subscriptionProps)},[s,n]),$(()=>{x.current&&(clearTimeout(x.current),x.current=void 0);let g=!1;return(I.current!==e||!se(b.current,s))&&(g=!0),g&&I.current&&o.unsubscribeFromCriteria(I.current,b.current),I.current=e,b.current=s,g&&e?i(o.subscribeToCriteria(e,s)):e||i(void 0),()=>{x.current=setTimeout(()=>{i(void 0),e&&o.unsubscribeFromCriteria(e,s)},We)}},[o,e,s]);let R=M(g=>{Q.current?.(g.payload)},[]),l=M(()=>{h.current?.()},[]),E=M(()=>{y.current?.()},[]),S=M(g=>{a.current?.(g.payload.subscriptionId)},[]),d=M(g=>{c.current?.(g.payload.subscriptionId)},[]),u=M(g=>{m.current?.(g.payload)},[]);$(()=>r?(p.current||(r.addEventListener("message",R),r.addEventListener("open",l),r.addEventListener("close",E),r.addEventListener("connect",S),r.addEventListener("disconnect",d),r.addEventListener("error",u),p.current=!0),()=>{p.current=!1,r.removeEventListener("message",R),r.removeEventListener("open",l),r.removeEventListener("close",E),r.removeEventListener("connect",S),r.removeEventListener("disconnect",d),r.removeEventListener("error",u)}):()=>{},[r,R,l,E,S,d,u])}function mt(e){let t=v(),{resourceType:n,countCriteria:o,subscriptionCriteria:r}=e,[i,s]=$e(0),f=De(p=>{t.search(n,o,{cache:p}).then(x=>s(x.total)).catch(console.error)},[t,n,o]);return Ve(()=>{f("default")},[f]),ue(r,()=>{f("reload")}),i}import{resolveId as Ke}from"@medplum/core";import{useEffect as Be,useMemo as ce,useState as K}from"react";function de(e){let t=e.patientParam??"subject",n=e.query,o="";if(n!=null)if(typeof n=="string")o=n;else if(n instanceof URLSearchParams){let r=Array.from(n.entries()).sort((i,s)=>i[0].localeCompare(s[0])||i[1].localeCompare(s[1]));o=JSON.stringify(r)}else if(Array.isArray(n)){let r=[...n].sort((i,s)=>i[0].localeCompare(s[0])||i[1].localeCompare(s[1]));o=JSON.stringify(r)}else{let r=Object.entries(n).filter(([,i])=>i!==void 0).sort(([i],[s])=>i.localeCompare(s));o=JSON.stringify(r)}return`${e.resourceType}:${t}:${o}`}function je(e){return e.map(t=>{let n=t.searches?t.searches.map(de).join(","):"";return`${t.key}:[${n}]`}).join("|")}function It(e,t){let n=v(),[o,r]=K([]),[i,s]=K(!0),[f,p]=K(),x=je(t),I=ce(()=>t,[x]),b=ce(()=>Ke(e),[e]);return Be(()=>{if(!b)return;let Q=!1,h=`Patient/${b}`,y={_count:100,_sort:"-_lastUpdated"},a=[],c=new Map,m=[];for(let l of I){let E=[];if(l.searches)for(let S of l.searches){let d=de(S),u=c.get(d);u===void 0&&(u=a.length,c.set(d,u),a.push(S)),E.push({searchIdx:u,resultKey:S.key})}m.push(E)}if(a.length===0){r(I.map(()=>({}))),s(!1);return}let R=a.map(l=>{let E=l.patientParam??"subject",S={[E]:h};if(l.query){if(typeof l.query=="string")return n.searchResources(l.resourceType,`${E}=${h}&${l.query}&_count=100&_sort=-_lastUpdated`);if(l.query instanceof URLSearchParams)l.query.forEach((d,u)=>{S[u]=d});else if(Array.isArray(l.query))for(let[d,u]of l.query)S[d]=u;else for(let[d,u]of Object.entries(l.query))u!==void 0&&(S[d]=u)}return n.searchResources(l.resourceType,{...y,...S})});return s(!0),p(void 0),Promise.allSettled(R).then(l=>{if(Q)return;let E=m.map(d=>{let u={};for(let{searchIdx:g,resultKey:A}of d){let C=l[g];u[A]=C.status==="fulfilled"?C.value:[]}return u});r(E),s(!1);let S=l.filter(d=>d.status==="rejected");if(S.length>0){console.error("Some patient summary searches failed:",S.map(u=>u.reason));let d=S[0].reason;p(d instanceof Error?d:new Error(String(d)))}}).catch(l=>{Q||(p(l instanceof Error?l:new Error(String(l))),s(!1))}),()=>{Q=!0}},[n,b,I]),{sectionData:o,loading:i,error:f}}import{isAddPharmacyResponse as ze,isOrganizationArray as Je}from"@medplum/core";import{useCallback as pe}from"react";function Qt(e,t){let n=v(),o=pe(async i=>{let s=await n.executeBot(e,i);if(!Je(s))throw new Error("Invalid response from pharmacy search");return s},[n,e]),r=pe(async i=>{let s=await n.executeBot(t,{patientId:i.patientId,pharmacy:i.pharmacy,setAsPrimary:i.setAsPrimary});if(!ze(s))throw new Error("Invalid response from add pharmacy bot");return s},[n,t]);return{searchPharmacies:o,addToFavorites:r}}import{useEffect as Ge,useRef as He}from"react";function Pt(e){let t=He(void 0);return Ge(()=>{t.current=e}),t.current}import{getExtension as Pn}from"@medplum/core";import{useReducer as Cn,useRef as wn}from"react";import{deepEquals as Xe,isReference as le,isResource as Ye,normalizeOperationOutcome as Ze}from"@medplum/core";import{useCallback as en,useEffect as nn,useState as tn}from"react";function B(e,t){let n=v(),[o,r]=tn(()=>fe(n,e)),i=en(s=>{Xe(s,o)||r(s)},[o]);return nn(()=>{let s=!0,f=fe(n,e);return!f&&le(e)?n.readReference(e).then(p=>{s&&i(p)}).catch(p=>{s&&(i(void 0),t&&t(Ze(p)))}):i(f),(()=>s=!1)},[n,e,i,t]),o}function fe(e,t){if(t){if(Ye(t))return t;if(le(t))return e.getCachedReference(t)}}import{EMPTY as Re,HTTP_HL7_ORG as O,PropertyType as P,append as me,capitalize as ye,deepClone as rn,evalFhirPathTyped as z,getExtension as k,getReferenceString as on,getTypedPropertyValueWithoutSchema as L,normalizeErrorString as sn,splitN as an,toJsBoolean as un,toTypedValue as ge,typedValueToString as cn}from"@medplum/core";var T={group:"group",display:"display",question:"question",boolean:"boolean",decimal:"decimal",integer:"integer",date:"date",dateTime:"dateTime",time:"time",string:"string",text:"text",url:"url",choice:"choice",openChoice:"open-choice",attachment:"attachment",reference:"reference",quantity:"quantity"},Ie=`${O}/fhir/StructureDefinition/questionnaire-itemControl`,dn=`${O}/fhir/StructureDefinition/questionnaire-referenceFilter`,j=`${O}/fhir/StructureDefinition/questionnaire-referenceResource`,pn=`${O}/fhir/StructureDefinition/questionnaire-validationError`,fn=`${O}/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression`,ln=`${O}/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression`,kt=`${O}/fhir/StructureDefinition/questionnaire-signatureRequired`,q=`${O}/fhir/StructureDefinition/questionnaireresponse-signature`,mn=`${O}/fhir/StructureDefinition/questionnaire-hidden`;function Ut(e){return e.type==="choice"||e.type==="open-choice"}function J(e,t){return{...t,item:Se(e.item,t.item,t)}}function Se(e,t,n){if(!t)return t;let o=[];for(let r of t){let i=e?.find(s=>s.linkId===r.linkId);i&&!yn(i,n)||(i?.item&&r.item?o.push({...r,item:Se(i.item,r.item,n)}):o.push(r))}return o}function yn(e,t){if(k(e,mn)?.valueBoolean===!0)return!1;let o=hn(e,t);return o!==void 0?o:Rn(e,t)}function hn(e,t){let n=k(e,fn);if(t&&n){let o=n.valueExpression?.expression;if(o){let r=ge(t),i=z(o,[r],{"%resource":r});return un(i)}}}function Rn(e,t){if(!e.enableWhen)return!0;let n=e.enableBehavior??"any";for(let o of e.enableWhen){let r=xe(t?.item,o.question);if(o.operator==="exists"&&!o.answerBoolean&&!r?.length){if(n==="any")return!0;continue}let{anyMatch:i,allMatch:s}=En(o,r,n);if(n==="any"&&i)return!0;if(n==="all"&&!s)return!1}return n!=="any"}function G(e,t,n=t.item){for(let o of e){let r=n?.find(i=>i.linkId===o.linkId);r&&(gn(t,o,r),o.item&&r.item&&G(o.item,t,r.item))}}function gn(e,t,n){try{let o=xn(t,e);if(!o)return;let r=Sn(t,o);if(!r)return;n.answer=[r]}catch(o){n.extension=[{url:pn,valueString:`Expression evaluation failed: ${sn(o)}`}]}}var In={[T.boolean]:[P.boolean],[T.date]:[P.date],[T.dateTime]:[P.dateTime],[T.time]:[P.time],[T.url]:[P.string,P.uri,P.url],[T.attachment]:[P.Attachment],[T.reference]:[P.Reference],[T.quantity]:[P.Quantity],[T.decimal]:[P.decimal,P.integer],[T.integer]:[P.decimal,P.integer]};function Sn(e,t){if(!e.type)return;if(e.type===T.choice||e.type===T.openChoice)return{[`value${ye(t.type)}`]:t.value};if(e.type===T.string||e.type===T.text)return typeof t.value=="string"?{valueString:t.value}:void 0;if(In[e.type]?.includes(t.type))return{[`value${ye(e.type)}`]:t.value}}function xn(e,t){if(!t)return;let n=k(e,ln);if(n){let o=n.valueExpression?.expression;if(o){let r=ge(t),i=z(o,[r],{"%resource":r});return i.length!==0?i[0]:void 0}}}function Nt(e,t,n){let o=[];for(let r of e){let i=n.answerOption?.find(s=>cn(he(s))===r);if(i){let s=he(i);s&&o.push({[t]:s.value})}}return o}function xe(e,t){for(let n of e??Re){if(n.linkId===t)return n.answer;if(n.item){let o=xe(n.item,t);if(o)return o}}}function bn(e,t,n){if(n==="exists")return!!e===t.value;if(e){let o=n==="="||n==="!="?n?.replace("=","~"):n,[{value:r}]=z(`%actualAnswer ${o} %expectedAnswer`,[e],{"%actualAnswer":e,"%expectedAnswer":t});return r}else return!1}function En(e,t,n){let o=t||[],r=vn(e),i=!1,s=!0;for(let f of o){let p=Tn(f),{operator:x}=e;if(bn(p,r,x)?i=!0:s=!1,n==="any"&&i)break}return{anyMatch:i,allMatch:s}}function Lt(e){let t=k(e,j);if(t){if(t.valueCode!==void 0)return[t.valueCode];if(t.valueCodeableConcept)return t.valueCodeableConcept?.coding?.map(n=>n.code)}}function qt(e,t){let n=rn(e),o=k(n,j);return!t||t.length===0?(o&&(n.extension=n.extension?.filter(r=>r!==o)),n):(o||(n.extension??=[],o={url:j},n.extension.push(o)),t.length===1?(o.valueCode=t[0],delete o.valueCodeableConcept):(o.valueCodeableConcept={coding:t.map(r=>({code:r}))},delete o.valueCode),n)}function Ft(e,t,n){let o=k(e,dn);if(!o?.valueString)return;let r=o.valueString;t?.reference&&(r=r.replaceAll("$subj",t.reference)),n?.reference&&(r=r.replaceAll("$encounter",n.reference));let i={},s=r.split("&");for(let f of s){let[p,x]=an(f,"=",2);i[p]=x}return i}function H(e,t){return{resourceType:"QuestionnaireResponse",questionnaire:e.url??on(e),item:X(e.item,t?.item),status:"in-progress"}}function X(e,t){let n;for(let o of e??Re){if(o.type===T.display)continue;let r=t?.filter(i=>i.linkId===o.linkId);if(r?.length)for(let i of r)i.id=i.id??be(),i.text=i.text??o.text,i.item=X(o.item,i.item),i.answer=Ee(o,i),n=me(n,i);else n=me(n,Y(o))}return n}function Y(e){return{id:be(),linkId:e.linkId,text:e.text,item:X(e.item,void 0),answer:Ee(e)}}var Qn=1;function be(){return"id-"+Qn++}function Ee(e,t){if(!(e.type===T.display||e.type===T.group)){if(t?.answer&&t.answer.length>0)return t.answer;if(e.initial&&e.initial.length>0)return e.initial.map(n=>({...n}));if(e.answerOption)return e.answerOption.filter(n=>n.initialSelected).map(n=>({...n,initialSelected:void 0}))}}function Wt(e){return L({type:"QuestionnaireItemInitial",value:e},"value")}function he(e){return L({type:"QuestionnaireItemAnswerOption",value:e},"value")}function vn(e){return L({type:"QuestionnaireItemEnableWhen",value:e},"answer")}function Tn(e){return L({type:"QuestionnaireResponseItemAnswer",value:e},"value")}function jt(e){let t=B(e.questionnaire),n=B(e.defaultValue),[,o]=Cn(y=>y+1,0),r=wn({activePage:0});if(!r.current.questionnaire&&t&&(r.current.questionnaire=t,r.current.pages=e.disablePagination?void 0:On(t)),t&&e.defaultValue&&n&&!r.current.questionnaireResponse&&(r.current.questionnaireResponse=H(t,n),h()),t&&!e.defaultValue&&!r.current.questionnaireResponse&&(r.current.questionnaireResponse=H(t),h()),!r.current.questionnaire||!r.current.questionnaireResponse)return{loading:!0};function i(y,a){let c=r.current.questionnaireResponse;for(let m of y)c=c?.item?.find(R=>m.id?R.id===m.id:R.linkId===m.linkId);return a&&(c=c?.item?.find(m=>m.linkId===a.linkId)),c}function s(){r.current.activePage=(r.current.activePage??0)+1,o()}function f(){r.current.activePage=(r.current.activePage??0)-1,o()}function p(y,a){let c=i(y);c&&(c.item??=[],c.item.push(Y(a)),h())}function x(y,a){let c=i(y,a);c&&(c.answer??=[],c.answer.push({}),h())}function I(y,a,c){let m=i(y,a);m&&(m.answer=c,h())}function b(y){let a=r.current.questionnaireResponse;a&&(y?(a.extension=a.extension??[],a.extension=a.extension.filter(c=>c.url!==q),a.extension.push({url:q,valueSignature:y})):a.extension=a.extension?.filter(c=>c.url!==q),h())}function Q(){let y=r.current.questionnaire;if(y?.item){let a=r.current.questionnaireResponse;G(y.item,a)}}function h(){let y=r.current.questionnaireResponse,a=r.current.questionnaire;!y||!a||(Q(),o(),e.onChange?.(J(a,y)))}return{loading:!1,pagination:!!r.current.pages,questionnaire:r.current.questionnaire,questionnaireResponse:J(r.current.questionnaire,r.current.questionnaireResponse),subject:e.subject,encounter:e.encounter,activePage:r.current.activePage,pages:r.current.pages,items:An(r.current.questionnaire,r.current.pages,r.current.activePage),responseItems:_n(r.current.questionnaireResponse,r.current.pages,r.current.activePage),onNextPage:s,onPrevPage:f,onAddGroup:p,onAddAnswer:x,onChangeAnswer:I,onChangeSignature:b}}function On(e){if(!(!e?.item||Pn(e?.item?.[0],Ie)?.valueCodeableConcept?.coding?.[0]?.code!=="page"))return e.item.map((n,o)=>({linkId:n.linkId,title:n.text??`Page ${o+1}`,group:n}))}function An(e,t,n=0){return t&&e?.item?.[n]?[e.item[n]]:e.item??[]}function _n(e,t,n=0){return t&&e?.item?.[n]?[e.item[n]]:e.item??[]}import{allOk as Un,normalizeOperationOutcome as Nn}from"@medplum/core";import{useEffect as Ln,useMemo as qn,useState as ee}from"react";import{useCallback as Mn,useEffect as Qe,useRef as Z,useState as kn}from"react";function ve(e,t,n={leading:!1}){let[o,r]=kn(e),i=Z(!1),s=Z(void 0),f=Z(!1),p=Mn(()=>window.clearTimeout(s.current),[]);return Qe(()=>{i.current&&(!f.current&&n.leading?(f.current=!0,r(e),s.current=setTimeout(()=>{f.current=!1},t)):(p(),s.current=setTimeout(()=>{f.current=!1,r(e)},t)))},[e,n.leading,t,p]),Qe(()=>(i.current=!0,p),[p]),[o,p]}var Fn=250;function er(e,t,n){return ne("search",e,t,n)}function nr(e,t,n){return ne("searchOne",e,t,n)}function tr(e,t,n){return ne("searchResources",e,t,n)}function ne(e,t,n,o){let r=v(),[i,s]=ee(!1),[f,p]=ee(),[x,I]=ee(),b=r.fhirSearchUrl(t,n).toString(),Q=qn(()=>({resourceType:t,query:n}),[b]),h=o?.enabled??!0,y=o?.debounceMs??Fn,[a]=ve(Q,y,{leading:!0});return Ln(()=>{if(!h)return()=>{};s(!0);let c=!0;return r[e](a.resourceType,a.query).then(m=>{c&&(s(!1),p(m),I(Un))}).catch(m=>{c&&(s(!1),p(void 0),I(Nn(m)))}),()=>{c=!1}},[r,e,a,h]),[f,i,x]}import{getReferenceString as Wn}from"@medplum/core";import{useCallback as Dn,useEffect as Te,useState as U}from"react";function ar({query:e,threadId:t}){let n=v(),[o,r]=U(!0),[i,s]=U([]),[f,p]=U(void 0),[x,I]=U(null),[b,Q]=U(void 0),h=Dn(async()=>{let c=new URLSearchParams(e);c.append("identifier:not","http://medplum.com/ai-message|"),c.append("part-of:missing","true"),c.append("_has:Communication:part-of:_id:not","null");let m=await n.search("Communication",c.toString(),{cache:"no-cache"}),R=m.entry?.map(u=>u.resource).filter(u=>u!==void 0)||[];if(m.total!==void 0&&Q(m.total),R.length===0){s([]);return}let E=`
1
+ import{useEffect as De,useMemo as Fe,useState as We}from"react";import{createContext as qe,useContext as Le}from"react";var F=qe(void 0);function W(){return Le(F)}function Q(){return W().medplum}function dt(){return W().navigate}function ie(){return W().profile}import{jsx as $e}from"react/jsx-runtime";var se=["change","storageInitialized","storageInitFailed","profileRefreshing","profileRefreshed"];function mt(e){let t=e.medplum,n=e.navigate??Ve,[o,r]=We({profile:t.getProfile(),loading:t.isLoading()});De(()=>{function s(){r(c=>({...c,profile:t.getProfile(),loading:t.isLoading()}))}for(let c of se)t.addEventListener(c,s);return()=>{for(let c of se)t.removeEventListener(c,s)}},[t]);let i=Fe(()=>({...o,medplum:t,navigate:n}),[o,t,n]);return $e(F.Provider,{value:i,children:e.children})}function Ve(e){window.location.assign(e)}import{useMemo as Ke}from"react";var ae=new Map,gt=e=>Ke(()=>{if(!e)return;let t=e.split("?")[0];if(!t)return e;let n;try{n=new URLSearchParams(new URL(e).search)}catch{return e}if(!n.has("Key-Pair-Id")||!n.has("Signature"))return e;let o=n.get("Expires");if(!o||o.length>13)return e;let r=ae.get(t);if(r){let s=new URLSearchParams(new URL(r).search).get("Expires");if(s&&Number.parseInt(s,10)*1e3-5e3>Date.now())return r}return ae.set(t,e),e},[e]);import{useEffect as ue,useRef as V,useState as Be}from"react";function bt(e,t,n){let o=Q(),{patientId:r,onPatientSyncSuccess:i,onIframeSuccess:s,onError:c}=n,[p,S]=Be(void 0),x=V(i),g=V(s),b=V(c);return ue(()=>{x.current=i,g.current=s,b.current=c},[i,s,c]),ue(()=>{let h=!1;return(async()=>{try{if(r){if(await o.executeBot(e,{patientId:r}),h)return;x.current?.()}let a=await o.executeBot(t,{patientId:r});if(h)return;a.url&&(S(a.url),g.current?.(a.url))}catch(a){h||b.current?.(a)}})().catch(()=>{}),()=>{h=!0}},[o,e,t,r]),p}import{INVALID_MEDICATION_ORDER_RESPONSE as je,INVALID_MEDICATION_SEARCH_RESPONSE as ze,isResource as $,medicationOrderRequestToParameters as Je,medicationSearchParamsToParameters as Ge,parametersToMedicationOrderResponse as He}from"@medplum/core";import{useCallback as ce}from"react";function Tt(){let e=Q(),t=ce(async o=>{let r=e.fhirUrl("Medication","$drug-search"),i=Ge(o),s=await e.post(r,i);if(!$(s,"Bundle"))throw new Error(ze);return(s.entry??[]).map(c=>c.resource).filter(c=>$(c,"Medication"))},[e]),n=ce(async o=>{let r=e.fhirUrl("MedicationRequest","$order-medication"),i=Je(o),s=await e.post(r,i);if(!$(s,"Parameters"))throw new Error(je);return He(s)},[e]);return{searchMedications:t,orderMedication:n}}import{INVALID_MEDICATION_ORDER_SET_RESPONSE as Xe,isResource as Ye,medicationOrderSetRequestToParameters as Ze,parametersToMedicationOrderSetResponse as en}from"@medplum/core";import{useCallback as de,useEffect as nn,useRef as pe,useState as K}from"react";function At(e){let t=Q(),{patientId:n,planDefinitionId:o,vendorOrderSetId:r,appId:i}=e,[s,c]=K(void 0),[p,S]=K(!1),[x,g]=K(void 0),b=pe({patientId:n,planDefinitionId:o,vendorOrderSetId:r,appId:i});b.current={patientId:n,planDefinitionId:o,vendorOrderSetId:r,appId:i};let h=()=>{let u=b.current;if(!u.patientId)return;let y=!!u.planDefinitionId,d=u.vendorOrderSetId!==void 0&&u.vendorOrderSetId!==null&&u.vendorOrderSetId!=="";return!y&&!d?void 0:{patientId:u.patientId,planDefinitionId:y?u.planDefinitionId:void 0,vendorOrderSetId:d?u.vendorOrderSetId:void 0,appId:u.appId}},R=de(async u=>{let y=t.fhirUrl("PlanDefinition","$order-set-url"),d=Ze(u),I=await t.post(y,d);if(!Ye(I,"Parameters"))throw new Error(Xe);return en(I).launchUrl},[t]),a=pe(0),f=de(async()=>{let u=h();if(!u)return;a.current+=1;let y=a.current;S(!0),g(void 0);try{let d=await R(u);return a.current!==y?void 0:(c(d),d)}catch(d){a.current===y&&(g(d),c(void 0));return}finally{a.current===y&&S(!1)}},[R]);return nn(()=>{let u=!1,y=h();if(!y){a.current+=1,c(void 0),S(!1),g(void 0);return}a.current+=1;let d=a.current;return S(!0),g(void 0),R(y).then(I=>{u||a.current!==d||c(I)}).catch(I=>{u||a.current!==d||(g(I),c(void 0))}).finally(()=>{!u&&a.current===d&&S(!1)}),()=>{u=!0}},[R,n,o,r,i]),{url:s,loading:p,error:x,refresh:f}}import{useCallback as rn,useEffect as on,useState as sn}from"react";import{deepEquals as fe}from"@medplum/core";import{useCallback as _,useEffect as B,useRef as M,useState as le}from"react";var tn=3e3;function me(e,t,n){let o=Q(),i=ie()?e:void 0,[s,c]=le(),[p,S]=le(n?.subscriptionProps),x=M(!1),g=M(void 0),b=M(void 0),h=M(void 0),R=M(t);R.current=t;let a=M(n?.onWebSocketOpen);a.current=n?.onWebSocketOpen;let f=M(n?.onWebSocketClose);f.current=n?.onWebSocketClose;let u=M(n?.onSubscriptionConnect);u.current=n?.onSubscriptionConnect;let y=M(n?.onSubscriptionDisconnect);y.current=n?.onSubscriptionDisconnect;let d=M(n?.onError);d.current=n?.onError,B(()=>{fe(n?.subscriptionProps,p)||S(n?.subscriptionProps)},[p,n]),B(()=>{g.current&&(clearTimeout(g.current),g.current=void 0);let E=!1;return(b.current!==i||!fe(h.current,p))&&(E=!0),E&&b.current&&o.unsubscribeFromCriteria(b.current,h.current),b.current=i,h.current=p,E&&i?c(o.subscribeToCriteria(i,p)):i||c(void 0),()=>{g.current=setTimeout(()=>{c(void 0),i&&o.unsubscribeFromCriteria(i,p)},tn)}},[o,i,p]);let I=_(E=>{R.current?.(E.payload)},[]),v=_(()=>{a.current?.()},[]),m=_(()=>{f.current?.()},[]),l=_(E=>{u.current?.(E.payload.subscriptionId)},[]),P=_(E=>{y.current?.(E.payload.subscriptionId)},[]),O=_(E=>{d.current?.(E.payload)},[]);B(()=>s?(x.current||(s.addEventListener("message",I),s.addEventListener("open",v),s.addEventListener("close",m),s.addEventListener("connect",l),s.addEventListener("disconnect",P),s.addEventListener("error",O),x.current=!0),()=>{x.current=!1,s.removeEventListener("message",I),s.removeEventListener("open",v),s.removeEventListener("close",m),s.removeEventListener("connect",l),s.removeEventListener("disconnect",P),s.removeEventListener("error",O)}):()=>{},[s,I,v,m,l,P,O])}function Wt(e){let t=Q(),{resourceType:n,countCriteria:o,subscriptionCriteria:r}=e,[i,s]=sn(0),c=rn(p=>{t.search(n,o,{cache:p}).then(S=>s(S.total)).catch(console.error)},[t,n,o]);return on(()=>{c("default")},[c]),me(r,()=>{c("reload")}),i}import{resolveId as an}from"@medplum/core";import{useEffect as un,useMemo as ye,useState as j}from"react";function Re(e){let t=e.patientParam??"subject",n=e.query,o="";if(n!=null)if(typeof n=="string")o=n;else if(n instanceof URLSearchParams){let r=Array.from(n.entries()).sort((i,s)=>i[0].localeCompare(s[0])||i[1].localeCompare(s[1]));o=JSON.stringify(r)}else if(Array.isArray(n)){let r=[...n].sort((i,s)=>i[0].localeCompare(s[0])||i[1].localeCompare(s[1]));o=JSON.stringify(r)}else{let r=Object.entries(n).filter(([,i])=>i!==void 0).sort(([i],[s])=>i.localeCompare(s));o=JSON.stringify(r)}return`${e.resourceType}:${t}:${o}`}function cn(e){return e.map(t=>{let n=t.searches?t.searches.map(Re).join(","):"";return`${t.key}:[${n}]`}).join("|")}function jt(e,t){let n=Q(),[o,r]=j([]),[i,s]=j(!0),[c,p]=j(),S=cn(t),x=ye(()=>t,[S]),g=ye(()=>an(e),[e]);return un(()=>{if(!g)return;let b=!1,h=`Patient/${g}`,R={_count:100,_sort:"-_lastUpdated"},a=[],f=new Map,u=[];for(let d of x){let I=[];if(d.searches)for(let v of d.searches){let m=Re(v),l=f.get(m);l===void 0&&(l=a.length,f.set(m,l),a.push(v)),I.push({searchIdx:l,resultKey:v.key})}u.push(I)}if(a.length===0){r(x.map(()=>({}))),s(!1);return}let y=a.map(d=>{let I=d.patientParam??"subject",v={[I]:h};if(d.query){if(typeof d.query=="string")return n.searchResources(d.resourceType,`${I}=${h}&${d.query}&_count=100&_sort=-_lastUpdated`);if(d.query instanceof URLSearchParams)d.query.forEach((m,l)=>{v[l]=m});else if(Array.isArray(d.query))for(let[m,l]of d.query)v[m]=l;else for(let[m,l]of Object.entries(d.query))l!==void 0&&(v[m]=l)}return n.searchResources(d.resourceType,{...R,...v})});return s(!0),p(void 0),Promise.allSettled(y).then(d=>{if(b)return;let I=u.map(m=>{let l={};for(let{searchIdx:P,resultKey:O}of m){let E=d[P];l[O]=E.status==="fulfilled"?E.value:[]}return l});r(I),s(!1);let v=d.filter(m=>m.status==="rejected");if(v.length>0){console.error("Some patient summary searches failed:",v.map(l=>l.reason));let m=v[0].reason;p(m instanceof Error?m:new Error(String(m)))}}).catch(d=>{b||(p(d instanceof Error?d:new Error(String(d))),s(!1))}),()=>{b=!0}},[n,g,x]),{sectionData:o,loading:i,error:c}}import{isAddPharmacyResponse as dn,isOrganizationArray as pn}from"@medplum/core";import{useCallback as he}from"react";function Xt(e,t){let n=Q(),o=he(async i=>{let s=await n.executeBot(e,i);if(!pn(s))throw new Error("Invalid response from pharmacy search");return s},[n,e]),r=he(async i=>{let s=await n.executeBot(t,{patientId:i.patientId,pharmacy:i.pharmacy,setAsPrimary:i.setAsPrimary});if(!dn(s))throw new Error("Invalid response from add pharmacy bot");return s},[n,t]);return{searchPharmacies:o,addToFavorites:r}}import{useEffect as fn,useRef as ln}from"react";function er(e){let t=ln(void 0);return fn(()=>{t.current=e}),t.current}import{getExtension as $n}from"@medplum/core";import{useReducer as Kn,useRef as Bn}from"react";import{deepEquals as mn,isReference as Ie,isResource as yn,normalizeOperationOutcome as Rn}from"@medplum/core";import{useCallback as hn,useEffect as gn,useState as In}from"react";function z(e,t){let n=Q(),[o,r]=In(()=>ge(n,e)),i=hn(s=>{mn(s,o)||r(s)},[o]);return gn(()=>{let s=!0,c=ge(n,e);return!c&&Ie(e)?n.readReference(e).then(p=>{s&&i(p)}).catch(p=>{s&&(i(void 0),t&&t(Rn(p)))}):i(c),(()=>s=!1)},[n,e,i,t]),o}function ge(e,t){if(t){if(yn(t))return t;if(Ie(t))return e.getCachedReference(t)}}import{EMPTY as Ee,HTTP_HL7_ORG as w,PropertyType as C,append as Se,capitalize as xe,deepClone as Sn,evalFhirPathTyped as G,getExtension as U,getReferenceString as xn,getTypedPropertyValueWithoutSchema as q,normalizeErrorString as bn,splitN as En,toJsBoolean as vn,toTypedValue as ve,typedValueToString as Qn}from"@medplum/core";var T={group:"group",display:"display",question:"question",boolean:"boolean",decimal:"decimal",integer:"integer",date:"date",dateTime:"dateTime",time:"time",string:"string",text:"text",url:"url",choice:"choice",openChoice:"open-choice",attachment:"attachment",reference:"reference",quantity:"quantity"},Qe=`${w}/fhir/StructureDefinition/questionnaire-itemControl`,Pn=`${w}/fhir/StructureDefinition/questionnaire-referenceFilter`,J=`${w}/fhir/StructureDefinition/questionnaire-referenceResource`,Tn=`${w}/fhir/StructureDefinition/questionnaire-validationError`,Cn=`${w}/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression`,On=`${w}/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression`,ar=`${w}/fhir/StructureDefinition/questionnaire-signatureRequired`,L=`${w}/fhir/StructureDefinition/questionnaireresponse-signature`,Mn=`${w}/fhir/StructureDefinition/questionnaire-hidden`;function ur(e){return e.type==="choice"||e.type==="open-choice"}function H(e,t){return{...t,item:Pe(e.item,t.item,t)}}function Pe(e,t,n){if(!t)return t;let o=[];for(let r of t){let i=e?.find(s=>s.linkId===r.linkId);i&&!wn(i,n)||(i?.item&&r.item?o.push({...r,item:Pe(i.item,r.item,n)}):o.push(r))}return o}function wn(e,t){if(U(e,Mn)?.valueBoolean===!0)return!1;let o=An(e,t);return o!==void 0?o:_n(e,t)}function An(e,t){let n=U(e,Cn);if(t&&n){let o=n.valueExpression?.expression;if(o){let r=ve(t),i=G(o,[r],{"%resource":r});return vn(i)}}}function _n(e,t){if(!e.enableWhen)return!0;let n=e.enableBehavior??"any";for(let o of e.enableWhen){let r=Te(t?.item,o.question);if(o.operator==="exists"&&!o.answerBoolean&&!r?.length){if(n==="any")return!0;continue}let{anyMatch:i,allMatch:s}=Dn(o,r,n);if(n==="any"&&i)return!0;if(n==="all"&&!s)return!1}return n!=="any"}function X(e,t,n=t.item){for(let o of e){let r=n?.find(i=>i.linkId===o.linkId);r&&(Un(t,o,r),o.item&&r.item&&X(o.item,t,r.item))}}function Un(e,t,n){try{let o=qn(t,e);if(!o)return;let r=Nn(t,o);if(!r)return;n.answer=[r]}catch(o){n.extension=[{url:Tn,valueString:`Expression evaluation failed: ${bn(o)}`}]}}var kn={[T.boolean]:[C.boolean],[T.date]:[C.date],[T.dateTime]:[C.dateTime],[T.time]:[C.time],[T.url]:[C.string,C.uri,C.url],[T.attachment]:[C.Attachment],[T.reference]:[C.Reference],[T.quantity]:[C.Quantity],[T.decimal]:[C.decimal,C.integer],[T.integer]:[C.decimal,C.integer]};function Nn(e,t){if(!e.type)return;if(e.type===T.choice||e.type===T.openChoice)return{[`value${xe(t.type)}`]:t.value};if(e.type===T.string||e.type===T.text)return typeof t.value=="string"?{valueString:t.value}:void 0;if(kn[e.type]?.includes(t.type))return{[`value${xe(e.type)}`]:t.value}}function qn(e,t){if(!t)return;let n=U(e,On);if(n){let o=n.valueExpression?.expression;if(o){let r=ve(t),i=G(o,[r],{"%resource":r});return i.length!==0?i[0]:void 0}}}function cr(e,t,n){let o=[];for(let r of e){let i=n.answerOption?.find(s=>Qn(be(s))===r);if(i){let s=be(i);s&&o.push({[t]:s.value})}}return o}function Te(e,t){for(let n of e??Ee){if(n.linkId===t)return n.answer;if(n.item){let o=Te(n.item,t);if(o)return o}}}function Ln(e,t,n){if(n==="exists")return!!e===t.value;if(e){let o=n==="="||n==="!="?n?.replace("=","~"):n,[{value:r}]=G(`%actualAnswer ${o} %expectedAnswer`,[e],{"%actualAnswer":e,"%expectedAnswer":t});return r}else return!1}function Dn(e,t,n){let o=t||[],r=Wn(e),i=!1,s=!0;for(let c of o){let p=Vn(c),{operator:S}=e;if(Ln(p,r,S)?i=!0:s=!1,n==="any"&&i)break}return{anyMatch:i,allMatch:s}}function dr(e){let t=U(e,J);if(t){if(t.valueCode!==void 0)return[t.valueCode];if(t.valueCodeableConcept)return t.valueCodeableConcept?.coding?.map(n=>n.code)}}function pr(e,t){let n=Sn(e),o=U(n,J);return!t||t.length===0?(o&&(n.extension=n.extension?.filter(r=>r!==o)),n):(o||(n.extension??=[],o={url:J},n.extension.push(o)),t.length===1?(o.valueCode=t[0],delete o.valueCodeableConcept):(o.valueCodeableConcept={coding:t.map(r=>({code:r}))},delete o.valueCode),n)}function fr(e,t,n){let o=U(e,Pn);if(!o?.valueString)return;let r=o.valueString;t?.reference&&(r=r.replaceAll("$subj",t.reference)),n?.reference&&(r=r.replaceAll("$encounter",n.reference));let i={},s=r.split("&");for(let c of s){let[p,S]=En(c,"=",2);i[p]=S}return i}function Y(e,t){return{resourceType:"QuestionnaireResponse",questionnaire:e.url??xn(e),item:Z(e.item,t?.item),status:"in-progress"}}function Z(e,t){let n;for(let o of e??Ee){if(o.type===T.display)continue;let r=t?.filter(i=>i.linkId===o.linkId);if(r?.length)for(let i of r)i.id=i.id??Ce(),i.text=i.text??o.text,i.item=Z(o.item,i.item),i.answer=Oe(o,i),n=Se(n,i);else n=Se(n,ee(o))}return n}function ee(e){return{id:Ce(),linkId:e.linkId,text:e.text,item:Z(e.item,void 0),answer:Oe(e)}}var Fn=1;function Ce(){return"id-"+Fn++}function Oe(e,t){if(!(e.type===T.display||e.type===T.group)){if(t?.answer&&t.answer.length>0)return t.answer;if(e.initial&&e.initial.length>0)return e.initial.map(n=>({...n}));if(e.answerOption)return e.answerOption.filter(n=>n.initialSelected).map(n=>({...n,initialSelected:void 0}))}}function lr(e){return q({type:"QuestionnaireItemInitial",value:e},"value")}function be(e){return q({type:"QuestionnaireItemAnswerOption",value:e},"value")}function Wn(e){return q({type:"QuestionnaireItemEnableWhen",value:e},"answer")}function Vn(e){return q({type:"QuestionnaireResponseItemAnswer",value:e},"value")}function Ir(e){let t=z(e.questionnaire),n=z(e.defaultValue),[,o]=Kn(R=>R+1,0),r=Bn({activePage:0});if(!r.current.questionnaire&&t&&(r.current.questionnaire=t,r.current.pages=e.disablePagination?void 0:jn(t)),t&&e.defaultValue&&n&&!r.current.questionnaireResponse&&(r.current.questionnaireResponse=Y(t,n),h()),t&&!e.defaultValue&&!r.current.questionnaireResponse&&(r.current.questionnaireResponse=Y(t),h()),!r.current.questionnaire||!r.current.questionnaireResponse)return{loading:!0};function i(R,a){let f=r.current.questionnaireResponse;for(let u of R)f=f?.item?.find(y=>u.id?y.id===u.id:y.linkId===u.linkId);return a&&(f=f?.item?.find(u=>u.linkId===a.linkId)),f}function s(){r.current.activePage=(r.current.activePage??0)+1,o()}function c(){r.current.activePage=(r.current.activePage??0)-1,o()}function p(R,a){let f=i(R);f&&(f.item??=[],f.item.push(ee(a)),h())}function S(R,a){let f=i(R,a);f&&(f.answer??=[],f.answer.push({}),h())}function x(R,a,f){let u=i(R,a);u&&(u.answer=f,h())}function g(R){let a=r.current.questionnaireResponse;a&&(R?(a.extension=a.extension??[],a.extension=a.extension.filter(f=>f.url!==L),a.extension.push({url:L,valueSignature:R})):a.extension=a.extension?.filter(f=>f.url!==L),h())}function b(){let R=r.current.questionnaire;if(R?.item){let a=r.current.questionnaireResponse;X(R.item,a)}}function h(){let R=r.current.questionnaireResponse,a=r.current.questionnaire;!R||!a||(b(),o(),e.onChange?.(H(a,R)))}return{loading:!1,pagination:!!r.current.pages,questionnaire:r.current.questionnaire,questionnaireResponse:H(r.current.questionnaire,r.current.questionnaireResponse),subject:e.subject,encounter:e.encounter,activePage:r.current.activePage,pages:r.current.pages,items:zn(r.current.questionnaire,r.current.pages,r.current.activePage),responseItems:Jn(r.current.questionnaireResponse,r.current.pages,r.current.activePage),onNextPage:s,onPrevPage:c,onAddGroup:p,onAddAnswer:S,onChangeAnswer:x,onChangeSignature:g}}function jn(e){if(!(!e?.item||$n(e?.item?.[0],Qe)?.valueCodeableConcept?.coding?.[0]?.code!=="page"))return e.item.map((n,o)=>({linkId:n.linkId,title:n.text??`Page ${o+1}`,group:n}))}function zn(e,t,n=0){return t&&e?.item?.[n]?[e.item[n]]:e.item??[]}function Jn(e,t,n=0){return t&&e?.item?.[n]?[e.item[n]]:e.item??[]}import{allOk as Xn,normalizeOperationOutcome as Yn}from"@medplum/core";import{useEffect as Zn,useMemo as et,useState as te}from"react";import{useCallback as Gn,useEffect as Me,useRef as ne,useState as Hn}from"react";function we(e,t,n={leading:!1}){let[o,r]=Hn(e),i=ne(!1),s=ne(void 0),c=ne(!1),p=Gn(()=>window.clearTimeout(s.current),[]);return Me(()=>{i.current&&(!c.current&&n.leading?(c.current=!0,r(e),s.current=setTimeout(()=>{c.current=!1},t)):(p(),s.current=setTimeout(()=>{c.current=!1,r(e)},t)))},[e,n.leading,t,p]),Me(()=>(i.current=!0,p),[p]),[o,p]}var nt=250;function Tr(e,t,n){return re("search",e,t,n)}function Cr(e,t,n){return re("searchOne",e,t,n)}function Or(e,t,n){return re("searchResources",e,t,n)}function re(e,t,n,o){let r=Q(),[i,s]=te(!1),[c,p]=te(),[S,x]=te(),g=r.fhirSearchUrl(t,n).toString(),b=et(()=>({resourceType:t,query:n}),[g]),h=o?.enabled??!0,R=o?.debounceMs??nt,[a]=we(b,R,{leading:!0});return Zn(()=>{if(!h)return()=>{};s(!0);let f=!0;return r[e](a.resourceType,a.query).then(u=>{f&&(s(!1),p(u),x(Xn))}).catch(u=>{f&&(s(!1),p(void 0),x(Yn(u)))}),()=>{f=!1}},[r,e,a,h]),[c,i,S]}import{isOperationOutcome as tt}from"@medplum/core";import{useCallback as rt}from"react";function Ur(){let e=Q();return rt(async t=>{try{await e.post(e.fhirUrl("PlanDefinition","$sync-orderset"),{planDefinitionId:t})}catch(n){if(tt(n)&&n.issue?.some(o=>o.code==="not-found"))return;throw n}},[e])}import{getReferenceString as ot}from"@medplum/core";import{useCallback as it,useEffect as Ae,useState as k}from"react";function Dr({query:e,threadId:t}){let n=Q(),[o,r]=k(!0),[i,s]=k([]),[c,p]=k(void 0),[S,x]=k(null),[g,b]=k(void 0),h=it(async()=>{let f=new URLSearchParams(e);f.append("identifier:not","http://medplum.com/ai-message|"),f.append("part-of:missing","true"),f.append("_has:Communication:part-of:_id:not","null");let u=await n.search("Communication",f.toString(),{cache:"no-cache"}),y=u.entry?.map(l=>l.resource).filter(l=>l!==void 0)||[];if(u.total!==void 0&&b(u.total),y.length===0){s([]);return}let I=`
2
2
  query {
3
- ${R.map(u=>{let A=`thread_${u.id?.replaceAll("-","")||""}`,C=Wn(u);return`
4
- ${A}: CommunicationList(
5
- part_of: "${C}"
3
+ ${y.map(l=>{let O=`thread_${l.id?.replaceAll("-","")||""}`,E=ot(l);return`
4
+ ${O}: CommunicationList(
5
+ part_of: "${E}"
6
6
  _sort: "-sent"
7
7
  _count: 1
8
8
  ) {
@@ -26,5 +26,5 @@ import{useEffect as Me,useMemo as ke,useState as Ue}from"react";import{createCon
26
26
  `}).join(`
27
27
  `)}
28
28
  }
29
- `,S=await n.graphql(E),d=R.map(u=>{let A=`thread_${u.id?.replaceAll("-","")||""}`,C=S.data[A],F=C&&C.length>0?C[0]:void 0;return[u,F]}).filter(u=>u[1]!==void 0);s(d)},[n,e]);return Te(()=>{r(!0),h().catch(c=>{I(c)}).finally(()=>{r(!1)})},[h]),Te(()=>{(async()=>{if(!t){p(void 0);return}let m=i.find(l=>l[0].id===t);if(m){p(m[0]);return}let R=await n.readResource("Communication",t);if(R.partOf===void 0)p(R);else{let l=R.partOf[0].reference;if(l){let E=await n.readReference({reference:l});p(E)}}})().catch(m=>{I(m)})},[t,i,n]),{loading:o,error:x,threadMessages:i,selectedThread:f,total:b,addThreadMessage:c=>{(async()=>{await h(),s(R=>[[c,void 0],...R])})().catch(R=>I(R))},handleThreadStatusChange:c=>{if(!f)return;(async()=>{let R=await n.updateResource({...f,status:c});p(R),s(l=>l.map(([E,S])=>E.id===R.id?[R,S]:[E,S]))})().catch(R=>I(R))},refreshThreadMessages:h}}import{ReconnectingWebSocket as Vn}from"@medplum/core";import{useCallback as _,useEffect as Pe,useRef as N,useState as te}from"react";function fr({language:e="en",model:t="gpt-4o-transcribe",onTranscript:n}){let o=v(),r=N(n);Pe(()=>{r.current=n},[n]);let[i,s]=te("idle"),[f,p]=te(void 0),[x,I]=te([]),b=N(void 0),Q=N(void 0),h=N(void 0),y=N(void 0),a=_(()=>{y.current?.disconnect(),y.current=void 0,h.current?.close().catch(()=>{}),h.current=void 0,Q.current?.getTracks().forEach(d=>d.stop()),Q.current=void 0,b.current?.close(),b.current=void 0,s("disconnected")},[]),c=_(()=>{b.current?.send(JSON.stringify({type:"session.update",session:{type:"transcription",audio:{input:{format:{type:"audio/pcm",rate:24e3},transcription:{model:t,language:e},turn_detection:{type:"server_vad",threshold:.5,prefix_padding_ms:300,silence_duration_ms:200},noise_reduction:{type:"near_field"}}}}}))},[e,t]),m=_(()=>{let d=Q.current,u=b.current;if(!d||!u)return;let g=new AudioContext({sampleRate:24e3}),A=g.createMediaStreamSource(d),C=g.createScriptProcessor(4096,1,1);C.onaudioprocess=F=>{if(u.readyState!==WebSocket.OPEN){console.warn("WebSocket is not open. Unable to send audio data.");return}let Ce=F.inputBuffer.getChannelData(0),we=$n(Ce),Oe=btoa(String.fromCharCode(...we));u.send(JSON.stringify({type:"input_audio_buffer.append",audio:Oe}))},A.connect(C),C.connect(g.destination),h.current=g,y.current=C,s("listening")},[]),R=_(d=>{switch(d.type){case"session.created":c();break;case"session.updated":m();break;case"input_audio_buffer.speech_started":s("speech_started");break;case"input_audio_buffer.speech_stopped":s("speech_stopped");break;case"conversation.item.input_audio_transcription.completed":case"input_audio_transcription.completed":if(d.transcript){let u={text:d.transcript,timestamp:new Date().toISOString()};I(g=>[...g,u]),r.current?.(d.transcript)}break;case"ai-realtime:connected":console.debug("[useWhisper] upstream connected");break;case"ai-realtime:error":case"error":console.error("[useWhisper] error event",d),p(d),s("error");break;default:console.debug("[useWhisper] unhandled message",d.type,d);break}},[c,m]),l=_(async()=>{s("requesting_microphone");let d=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:24e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}});return Q.current=d,d},[]),E=_(()=>{s("connecting");let d=Kn(o.getBaseUrl());console.debug("[useWhisper] connecting to",d);let u=new Vn(d);return b.current=u,u.onopen=()=>s("connected"),u.onmessage=g=>R(JSON.parse(g.data)),u.onerror=g=>{p(g),s("error"),a()},u.onclose=()=>s("disconnected"),u.send(JSON.stringify({type:"ai-realtime:connect",accessToken:o.getAccessToken()})),u},[o,R,a]),S=_(async()=>{try{p(void 0),await l(),E()}catch(d){p(d),s("error"),a()}},[l,E,a]);return Pe(()=>()=>a(),[a]),{status:i,error:f,transcripts:x,start:S,stop:a,isListening:i==="listening"||i==="speech_started"||i==="speech_stopped"}}function $n(e){let t=new Int16Array(e.length);for(let n=0;n<e.length;n++){let o=Math.max(-1,Math.min(1,e[n]));t[n]=o*32767}return new Uint8Array(t.buffer)}function Kn(e){let t=new URL("ws/ai-realtime",e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",t.toString()}export{Xn as MedplumProvider,ln as QUESTIONNAIRE_CALCULATED_EXPRESSION_URL,fn as QUESTIONNAIRE_ENABLED_WHEN_EXPRESSION_URL,mn as QUESTIONNAIRE_HIDDEN_URL,Ie as QUESTIONNAIRE_ITEM_CONTROL_URL,dn as QUESTIONNAIRE_REFERENCE_FILTER_URL,j as QUESTIONNAIRE_REFERENCE_RESOURCE_URL,kt as QUESTIONNAIRE_SIGNATURE_REQUIRED_URL,q as QUESTIONNAIRE_SIGNATURE_RESPONSE_URL,pn as QUESTIONNAIRE_VALIDATION_ERROR_URL,T as QuestionnaireItemType,H as buildInitialResponse,Y as buildInitialResponseItem,$n as convertToPCM16,G as evaluateCalculatedExpressionsInQuestionnaire,he as getItemAnswerOptionValue,vn as getItemEnableWhenValueAnswer,Wt as getItemInitialValue,Nt as getNewMultiSelectValues,Ft as getQuestionnaireItemReferenceFilter,Lt as getQuestionnaireItemReferenceTargetTypes,Tn as getResponseItemAnswerValue,Ut as isChoiceQuestion,yn as isQuestionEnabled,W as reactContext,J as removeDisabledItems,qt as setQuestionnaireItemReferenceTargetTypes,Sn as typedValueToResponseItem,nt as useCachedBinaryUrl,it as useEPrescribingIFrame,v as useMedplum,D as useMedplumContext,jn as useMedplumNavigate,zn as useMedplumProfile,mt as useNotificationCount,It as usePatientSummaryData,Qt as usePharmacySearch,Pt as usePrevious,jt as useQuestionnaireForm,B as useResource,er as useSearch,nr as useSearchOne,tr as useSearchResources,ue as useSubscription,ar as useThreadInbox,fr as useWhisper};
29
+ `,v=await n.graphql(I),m=y.map(l=>{let O=`thread_${l.id?.replaceAll("-","")||""}`,E=v.data[O],D=E&&E.length>0?E[0]:void 0;return[l,D]}).filter(l=>l[1]!==void 0);s(m)},[n,e]);return Ae(()=>{r(!0),h().catch(f=>{x(f)}).finally(()=>{r(!1)})},[h]),Ae(()=>{(async()=>{if(!t){p(void 0);return}let u=i.find(d=>d[0].id===t);if(u){p(u[0]);return}let y=await n.readResource("Communication",t);if(y.partOf===void 0)p(y);else{let d=y.partOf[0].reference;if(d){let I=await n.readReference({reference:d});p(I)}}})().catch(u=>{x(u)})},[t,i,n]),{loading:o,error:S,threadMessages:i,selectedThread:c,total:g,addThreadMessage:f=>{(async()=>{await h(),s(y=>[[f,void 0],...y])})().catch(y=>x(y))},handleThreadStatusChange:f=>{if(!c)return;(async()=>{let y=await n.updateResource({...c,status:f});p(y),s(d=>d.map(([I,v])=>I.id===y.id?[y,v]:[I,v]))})().catch(y=>x(y))},refreshThreadMessages:h}}import{ReconnectingWebSocket as st}from"@medplum/core";import{useCallback as A,useEffect as _e,useRef as N,useState as oe}from"react";function Kr({language:e="en",model:t="gpt-4o-transcribe",onTranscript:n}){let o=Q(),r=N(n);_e(()=>{r.current=n},[n]);let[i,s]=oe("idle"),[c,p]=oe(void 0),[S,x]=oe([]),g=N(void 0),b=N(void 0),h=N(void 0),R=N(void 0),a=A(()=>{R.current?.disconnect(),R.current=void 0,h.current?.close().catch(()=>{}),h.current=void 0,b.current?.getTracks().forEach(m=>m.stop()),b.current=void 0,g.current?.close(),g.current=void 0,s("disconnected")},[]),f=A(()=>{g.current?.send(JSON.stringify({type:"session.update",session:{type:"transcription",audio:{input:{format:{type:"audio/pcm",rate:24e3},transcription:{model:t,language:e},turn_detection:{type:"server_vad",threshold:.5,prefix_padding_ms:300,silence_duration_ms:200},noise_reduction:{type:"near_field"}}}}}))},[e,t]),u=A(()=>{let m=b.current,l=g.current;if(!m||!l)return;let P=new AudioContext({sampleRate:24e3}),O=P.createMediaStreamSource(m),E=P.createScriptProcessor(4096,1,1);E.onaudioprocess=D=>{if(l.readyState!==WebSocket.OPEN){console.warn("WebSocket is not open. Unable to send audio data.");return}let Ue=D.inputBuffer.getChannelData(0),ke=at(Ue),Ne=btoa(String.fromCharCode(...ke));l.send(JSON.stringify({type:"input_audio_buffer.append",audio:Ne}))},O.connect(E),E.connect(P.destination),h.current=P,R.current=E,s("listening")},[]),y=A(m=>{switch(m.type){case"session.created":f();break;case"session.updated":u();break;case"input_audio_buffer.speech_started":s("speech_started");break;case"input_audio_buffer.speech_stopped":s("speech_stopped");break;case"conversation.item.input_audio_transcription.completed":case"input_audio_transcription.completed":if(m.transcript){let l={text:m.transcript,timestamp:new Date().toISOString()};x(P=>[...P,l]),r.current?.(m.transcript)}break;case"ai-realtime:connected":console.debug("[useWhisper] upstream connected");break;case"ai-realtime:error":case"error":console.error("[useWhisper] error event",m),p(m),s("error");break;default:console.debug("[useWhisper] unhandled message",m.type,m);break}},[f,u]),d=A(async()=>{s("requesting_microphone");let m=await navigator.mediaDevices.getUserMedia({audio:{sampleRate:24e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}});return b.current=m,m},[]),I=A(()=>{s("connecting");let m=ut(o.getBaseUrl());console.debug("[useWhisper] connecting to",m);let l=new st(m);return g.current=l,l.onopen=()=>s("connected"),l.onmessage=P=>y(JSON.parse(P.data)),l.onerror=P=>{p(P),s("error"),a()},l.onclose=()=>s("disconnected"),l.send(JSON.stringify({type:"ai-realtime:connect",accessToken:o.getAccessToken()})),l},[o,y,a]),v=A(async()=>{try{p(void 0),await d(),I()}catch(m){p(m),s("error"),a()}},[d,I,a]);return _e(()=>()=>a(),[a]),{status:i,error:c,transcripts:S,start:v,stop:a,isListening:i==="listening"||i==="speech_started"||i==="speech_stopped"}}function at(e){let t=new Int16Array(e.length);for(let n=0;n<e.length;n++){let o=Math.max(-1,Math.min(1,e[n]));t[n]=o*32767}return new Uint8Array(t.buffer)}function ut(e){let t=new URL("ws/ai-realtime",e);return t.protocol=t.protocol==="https:"?"wss:":"ws:",t.toString()}export{mt as MedplumProvider,On as QUESTIONNAIRE_CALCULATED_EXPRESSION_URL,Cn as QUESTIONNAIRE_ENABLED_WHEN_EXPRESSION_URL,Mn as QUESTIONNAIRE_HIDDEN_URL,Qe as QUESTIONNAIRE_ITEM_CONTROL_URL,Pn as QUESTIONNAIRE_REFERENCE_FILTER_URL,J as QUESTIONNAIRE_REFERENCE_RESOURCE_URL,ar as QUESTIONNAIRE_SIGNATURE_REQUIRED_URL,L as QUESTIONNAIRE_SIGNATURE_RESPONSE_URL,Tn as QUESTIONNAIRE_VALIDATION_ERROR_URL,T as QuestionnaireItemType,Y as buildInitialResponse,ee as buildInitialResponseItem,at as convertToPCM16,X as evaluateCalculatedExpressionsInQuestionnaire,be as getItemAnswerOptionValue,Wn as getItemEnableWhenValueAnswer,lr as getItemInitialValue,cr as getNewMultiSelectValues,fr as getQuestionnaireItemReferenceFilter,dr as getQuestionnaireItemReferenceTargetTypes,Vn as getResponseItemAnswerValue,ur as isChoiceQuestion,wn as isQuestionEnabled,F as reactContext,H as removeDisabledItems,pr as setQuestionnaireItemReferenceTargetTypes,Nn as typedValueToResponseItem,gt as useCachedBinaryUrl,bt as useMedicationIFrame,Tt as useMedicationOrder,At as useMedicationOrderSet,Q as useMedplum,W as useMedplumContext,dt as useMedplumNavigate,ie as useMedplumProfile,Wt as useNotificationCount,jt as usePatientSummaryData,Xt as usePharmacySearch,er as usePrevious,Ir as useQuestionnaireForm,z as useResource,Tr as useSearch,Cr as useSearchOne,Or as useSearchResources,me as useSubscription,Ur as useSyncOrderSet,Dr as useThreadInbox,Kr as useWhisper};
30
30
  //# sourceMappingURL=index.mjs.map