diff --git a/lib/shared/farcaster/farcaster-hooks.js b/lib/shared/farcaster/farcaster-hooks.js --- a/lib/shared/farcaster/farcaster-hooks.js +++ b/lib/shared/farcaster/farcaster-hooks.js @@ -35,6 +35,53 @@ return results; } +function useFetchConversation(): ( + conversationID: string, +) => Promise { + const fetchFarcasterConversation = useFetchFarcasterConversation(); + const dispatch = useDispatch(); + + return React.useCallback( + async (conversationID: string): Promise => { + try { + const conversationResult = await fetchFarcasterConversation({ + conversationId: conversationID, + }); + + if (!conversationResult) { + return null; + } + + const farcasterConversation = conversationResult.result.conversation; + const thread = createFarcasterRawThreadInfo(farcasterConversation); + const update = { + type: updateTypes.JOIN_THREAD, + id: uuid.v4(), + time: thread.creationTime, + threadInfo: thread, + rawMessageInfos: [], + truncationStatus: messageTruncationStatus.UNCHANGED, + rawEntryInfos: [], + }; + + dispatch({ + type: processFarcasterOpsActionType, + payload: { + rawMessageInfos: [], + updateInfos: [update], + }, + }); + + return farcasterConversation; + } catch (e) { + console.error(`Failed fetching conversation ${conversationID}:`, e); + return null; + } + }, + [fetchFarcasterConversation, dispatch], + ); +} + function useFarcasterConversationsSync(): (limit: number) => Promise { const [fullInbox, setFullInbox] = React.useState(false); const [conversations, setConversations] = React.useState< @@ -43,11 +90,11 @@ const [messagesNumberLimit, setMessagesNumberLimit] = React.useState(20); const fetchFarcasterInbox = useFetchFarcasterInbox(); - const fetchFarcasterConversation = useFetchFarcasterConversation(); const fetchFarcasterMessages = useFetchFarcasterMessages(); const sendFarcasterTextMessage = useSendFarcasterTextMessage(); const dispatch = useDispatch(); const utils = useSendDMOperationUtils(); + const fetchConversationCallback = useFetchConversation(); const fetchInboxes: (cursor: ?string) => Promise = React.useCallback( async (cursor: ?string) => { @@ -90,49 +137,10 @@ void (async () => { const farcasterConversations: Array = []; - const fetchConversation = async ( - conversationId: string, - ): Promise => { - try { - const conversationResult = await fetchFarcasterConversation({ - conversationId, - }); - - if (!conversationResult) { - return null; - } - - const farcasterConversation = conversationResult.result.conversation; - const thread = createFarcasterRawThreadInfo(farcasterConversation); - const update = { - type: updateTypes.JOIN_THREAD, - id: uuid.v4(), - time: thread.creationTime, - threadInfo: thread, - rawMessageInfos: [], - truncationStatus: messageTruncationStatus.UNCHANGED, - rawEntryInfos: [], - }; - - dispatch({ - type: processFarcasterOpsActionType, - payload: { - rawMessageInfos: [], - updateInfos: [update], - }, - }); - - return farcasterConversation; - } catch (e) { - console.error(`Failed fetching conversation ${conversationId}:`, e); - return null; - } - }; - const conversationResults = await processInBatches( conversations, 20, - fetchConversation, + fetchConversationCallback, ); farcasterConversations.push(...conversationResults.filter(Boolean)); @@ -210,7 +218,7 @@ }, [ conversations, dispatch, - fetchFarcasterConversation, + fetchConversationCallback, fetchFarcasterMessages, fullInbox, inProgress, @@ -230,4 +238,4 @@ ); } -export { useFarcasterConversationsSync }; +export { useFarcasterConversationsSync, useFetchConversation }; diff --git a/lib/shared/threads/protocols/farcaster-thread-protocol.js b/lib/shared/threads/protocols/farcaster-thread-protocol.js --- a/lib/shared/threads/protocols/farcaster-thread-protocol.js +++ b/lib/shared/threads/protocols/farcaster-thread-protocol.js @@ -45,6 +45,8 @@ ProtocolSendTextMessageInput, SendTextMessageUtils, ThreadProtocol, + OnOpenThreadUtils, + ProtocolOnOpenThreadInput, } from '../thread-spec.js'; const farcasterThreadProtocol: ThreadProtocol = { @@ -238,6 +240,14 @@ throw new Error('joinThread method is not yet implemented'); }, + onOpenThread: ( + input: ProtocolOnOpenThreadInput, + utils: OnOpenThreadUtils, + ) => { + const conversationID = conversationIDFromFarcasterThreadID(input.threadID); + void utils.farcasterFetchConversation(conversationID); + }, + threadIDMatchesProtocol: (threadID: string): boolean => { return farcasterThreadIDRegExp.test(threadID); }, diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -291,6 +291,13 @@ +calendarQuery: () => CalendarQuery, }; +export type ProtocolOnOpenThreadInput = { + +threadID: string, +}; +export type OnOpenThreadUtils = { + +farcasterFetchConversation: (conversationID: string) => Promise, +}; + export type ThreadProtocol< RawThreadMemberType: | MemberInfoSansPermissions @@ -382,6 +389,10 @@ input: ProtocolJoinThreadInput, utils: JoinThreadUtils, ) => Promise, + +onOpenThread?: ( + input: ProtocolOnOpenThreadInput, + utils: OnOpenThreadUtils, + ) => mixed, +threadIDMatchesProtocol: string => boolean, +allowsDeletingSidebarSource: boolean, +presentationDetails: { diff --git a/native/chat/message-list-container.react.js b/native/chat/message-list-container.react.js --- a/native/chat/message-list-container.react.js +++ b/native/chat/message-list-container.react.js @@ -10,6 +10,7 @@ import { useUsersSupportThickThreads } from 'lib/hooks/user-identities-hooks.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js'; +import { useFetchConversation } from 'lib/shared/farcaster/farcaster-hooks.js'; import { usePotentialMemberItems, useSearchUsers, @@ -456,6 +457,20 @@ colors.panelBackgroundLabel, ]); + const prevActiveThreadID = React.useRef(threadInfo.id); + const farcasterFetchConversation = useFetchConversation(); + React.useEffect(() => { + if (prevActiveThreadID !== threadInfo.id) { + threadSpecs[threadInfo.type] + .protocol() + .onOpenThread?.( + { threadID: threadInfo.id }, + { farcasterFetchConversation }, + ); + prevActiveThreadID.current = threadInfo.id; + } + }, [farcasterFetchConversation, threadInfo.id, threadInfo.type]); + return ( {pinnedCountBanner} diff --git a/web/chat/chat-message-list-container.react.js b/web/chat/chat-message-list-container.react.js --- a/web/chat/chat-message-list-container.react.js +++ b/web/chat/chat-message-list-container.react.js @@ -6,7 +6,9 @@ import { useDrop } from 'react-dnd'; import { NativeTypes } from 'react-dnd-html5-backend'; +import { useFetchConversation } from 'lib/shared/farcaster/farcaster-hooks.js'; import { threadIsPending } from 'lib/shared/thread-utils.js'; +import { threadSpecs } from 'lib/shared/threads/thread-specs.js'; import { useWatchThread } from 'lib/shared/watch-thread-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; @@ -143,6 +145,20 @@ ); }, [inputState, isChatCreation, selectedUserInfos, threadInfo]); + const prevActiveThreadID = React.useRef(activeChatThreadID); + const farcasterFetchConversation = useFetchConversation(); + React.useEffect(() => { + if (prevActiveThreadID !== activeChatThreadID && activeChatThreadID) { + threadSpecs[threadInfo.type] + .protocol() + .onOpenThread?.( + { threadID: activeChatThreadID }, + { farcasterFetchConversation }, + ); + prevActiveThreadID.current = activeChatThreadID; + } + }, [farcasterFetchConversation, activeChatThreadID, threadInfo.type]); + return connectDropTarget(
{content}