diff --git a/app/(app)/index.tsx b/app/(app)/index.tsx index 42fd84e..4629665 100644 --- a/app/(app)/index.tsx +++ b/app/(app)/index.tsx @@ -1,6 +1,6 @@ import { useMedplum } from "@medplum/react-hooks"; import { useRouter } from "expo-router"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useState } from "react"; import { SafeAreaView } from "react-native-safe-area-context"; import { CreateThreadModal } from "@/components/CreateThreadModal"; @@ -20,15 +20,6 @@ export default function Index() { router.replace("/sign-in"); }, [medplum, router]); - // When threads are loaded, fetch their image URLs - useEffect(() => { - if (!isLoadingThreads) { - threads.forEach((thread) => { - thread.loadImageURL({ medplum }); - }); - } - }, [isLoadingThreads, threads, medplum]); - if (isLoadingThreads) { return ( diff --git a/contexts/ChatContext.tsx b/contexts/ChatContext.tsx index b4cdfb9..dc5ea87 100644 --- a/contexts/ChatContext.tsx +++ b/contexts/ChatContext.tsx @@ -219,6 +219,11 @@ export function ChatProvider({ .sort((a, b) => b.threadOrder - a.threadOrder); }, [threads, profile, threadCommMap]); + // Whenever threadsOut changes, load the image URL for each thread + useEffect(() => { + threadsOut.forEach((thread) => thread.loadImageURL({ medplum })); + }, [threadsOut, medplum]); + // Current thread memoized const currentThread = useMemo(() => { if (!currentThreadId || !profile) return null; diff --git a/models/chat.ts b/models/chat.ts index 5eab3cd..08adc97 100644 --- a/models/chat.ts +++ b/models/chat.ts @@ -52,8 +52,8 @@ export class ChatMessage { export class Thread { readonly messages: ChatMessage[]; readonly originalCommunication: Communication; - static imageURLCache = new Map(); - imageURL?: string; + static imageURLMap = new Map(); + static loadImageURLPromiseMap = new Map>(); constructor({ messages, @@ -120,27 +120,30 @@ export class Thread { return this.lastProviderCommunication?.sender?.display; } + get practitionerId(): string | undefined { + return this.lastProviderCommunication?.sender?.reference; + } + + get imageURL(): string | undefined { + return this.practitionerId ? Thread.imageURLMap.get(this.practitionerId) : undefined; + } + async loadImageURL({ medplum }: { medplum: MedplumClient }) { - const practitionerId = this.lastProviderCommunication?.sender?.reference; - if (practitionerId) { - let imageUrl = Thread.imageURLCache.get(practitionerId); - - if (!imageUrl) { - try { - const practitioner = await medplum.readReference( - this.lastProviderCommunication?.sender as Reference, - ); - if (practitioner.photo?.[0]?.url) { - imageUrl = practitioner.photo[0].url; - Thread.imageURLCache.set(practitionerId, imageUrl); - } - } catch { - // Ignore errors from fetching practitioner image - } - } - if (imageUrl) { - this.imageURL = imageUrl; + // Load the image URL for the thread if it hasn't been loaded yet and it isn't already loading + if (!this.practitionerId) return; + if (Thread.imageURLMap.has(this.practitionerId)) return; + if (Thread.loadImageURLPromiseMap.has(this.practitionerId)) return; + + try { + const practitioner = await medplum.readReference( + this.lastProviderCommunication?.sender as Reference, + ); + if (practitioner.photo?.[0]?.url) { + const imageUrl = practitioner.photo[0].url; + Thread.imageURLMap.set(this.practitionerId, imageUrl); } + } catch { + // Ignore errors from fetching practitioner image } } }