diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js --- a/lib/shared/threads/protocols/dm-thread-protocol.js +++ b/lib/shared/threads/protocols/dm-thread-protocol.js @@ -857,6 +857,10 @@ invariant(false, 'Pin message is not supported for DM threads'); }, + fetchPinnedMessages: async () => { + invariant(false, 'Fetch pinned messages is not supported for DM threads'); + }, + joinThread: async ( input: ProtocolJoinThreadInput, utils: JoinThreadUtils, 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 @@ -112,6 +112,8 @@ DeleteMessageUtils, ProtocolPinMessageInput, PinMessageUtils, + ProtocolFetchPinnedMessagesInput, + FetchPinnedMessagesUtils, } from '../thread-spec.js'; import { threadTypeIsPersonal } from '../thread-specs.js'; @@ -963,6 +965,25 @@ }); }, + fetchPinnedMessages: async ( + input: ProtocolFetchPinnedMessagesInput, + utils: FetchPinnedMessagesUtils, + ) => { + const { threadInfo } = input; + const { fetchMessage } = utils; + + const pinnedMessageIDs = threadInfo.pinnedMessageIDs ?? []; + + const pinnedMessagePromises = pinnedMessageIDs.map(messageID => + fetchMessage(messageID), + ); + + const results = await Promise.all(pinnedMessagePromises); + const pinnedMessages = results.filter(Boolean); + + return { pinnedMessages }; + }, + joinThread: async ( input: ProtocolJoinThreadInput, utils: JoinThreadUtils, diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -120,6 +120,8 @@ ProtocolDeleteMessageInput, PinMessageUtils, ProtocolPinMessageInput, + FetchPinnedMessagesUtils, + ProtocolFetchPinnedMessagesInput, JoinThreadUtils, ProtocolJoinThreadInput, ProtocolChangeThreadMemberRolesInput, @@ -689,6 +691,15 @@ await promise; }, + fetchPinnedMessages: async ( + input: ProtocolFetchPinnedMessagesInput, + utils: FetchPinnedMessagesUtils, + ) => { + return await utils.keyserverFetchPinnedMessages({ + threadID: input.threadInfo.id, + }); + }, + joinThread: async ( input: ProtocolJoinThreadInput, utils: JoinThreadUtils, 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 @@ -53,6 +53,8 @@ FetchMessageInfosPayload, DeleteMessageRequest, DeleteMessageResponse, + FetchPinnedMessagesRequest, + FetchPinnedMessagesResult, RawMessageInfo, MessageInfo, } from '../../types/message-types.js'; @@ -387,6 +389,14 @@ +dispatchActionPromise: DispatchActionPromise, }; +export type ProtocolFetchPinnedMessagesInput = { + +threadInfo: ThreadInfo, +}; +export type FetchPinnedMessagesUtils = { + +keyserverFetchPinnedMessages: FetchPinnedMessagesRequest => Promise, + +fetchMessage: (messageID: string) => Promise, +}; + export type ProtocolJoinThreadInput = { +rawThreadInfo: RawThreadInfo, +viewerID: ?string, @@ -511,6 +521,10 @@ input: ProtocolPinMessageInput, utils: PinMessageUtils, ) => Promise, + +fetchPinnedMessages: ( + input: ProtocolFetchPinnedMessagesInput, + utils: FetchPinnedMessagesUtils, + ) => Promise, +joinThread: ( input: ProtocolJoinThreadInput, utils: JoinThreadUtils, diff --git a/lib/utils/pin-message-utils.js b/lib/utils/pin-message-utils.js --- a/lib/utils/pin-message-utils.js +++ b/lib/utils/pin-message-utils.js @@ -3,9 +3,14 @@ import * as React from 'react'; import { useDispatchActionPromise } from './redux-promise-utils.js'; -import { useToggleMessagePin } from '../hooks/message-hooks.js'; +import { useGetLatestMessageEdit } from '../hooks/latest-message-edit.js'; +import { + useFetchPinnedMessages, + useToggleMessagePin, +} from '../hooks/message-hooks.js'; import { usePinMessage } from '../shared/farcaster/farcaster-api.js'; import { threadSpecs } from '../shared/threads/thread-specs.js'; +import type { FetchPinnedMessagesResult } from '../types/message-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; function usePinMessageAction(): ( @@ -36,4 +41,24 @@ ); } -export { usePinMessageAction }; +function useFetchPinnedMessagesAction(): ( + threadInfo: ThreadInfo, +) => Promise { + const keyserverFetchPinnedMessages = useFetchPinnedMessages(); + const fetchMessage = useGetLatestMessageEdit(); + + return React.useCallback( + async (threadInfo: ThreadInfo) => { + return await threadSpecs[threadInfo.type].protocol().fetchPinnedMessages( + { threadInfo }, + { + keyserverFetchPinnedMessages, + fetchMessage, + }, + ); + }, + [keyserverFetchPinnedMessages, fetchMessage], + ); +} + +export { usePinMessageAction, useFetchPinnedMessagesAction }; diff --git a/native/chat/pinned-messages-screen.react.js b/native/chat/pinned-messages-screen.react.js --- a/native/chat/pinned-messages-screen.react.js +++ b/native/chat/pinned-messages-screen.react.js @@ -5,7 +5,6 @@ import { View } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; -import { useFetchPinnedMessages } from 'lib/hooks/message-hooks.js'; import { type ChatMessageInfoItem, messageListData, @@ -17,6 +16,7 @@ } from 'lib/shared/message-utils.js'; import type { RawMessageInfo } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; +import { useFetchPinnedMessagesAction } from 'lib/utils/pin-message-utils.js'; import { useHeightMeasurer } from './chat-context.js'; import type { ChatNavigationProp } from './chat.react'; @@ -55,15 +55,15 @@ React.useState(); const scrollViewContainerRef = React.useRef>(); - const callFetchPinnedMessages = useFetchPinnedMessages(); + const fetchPinnedMessagesAction = useFetchPinnedMessagesAction(); const userInfos = useSelector(state => state.userStore.userInfos); React.useEffect(() => { void (async () => { - const result = await callFetchPinnedMessages({ threadID }); + const result = await fetchPinnedMessagesAction(threadInfo); setRawMessageResults(result.pinnedMessages); })(); - }, [callFetchPinnedMessages, threadID]); + }, [fetchPinnedMessagesAction, threadInfo]); const translatedMessageResults = React.useMemo(() => { const threadInfos = { [threadID]: threadInfo }; diff --git a/web/modals/chat/pinned-messages-modal.react.js b/web/modals/chat/pinned-messages-modal.react.js --- a/web/modals/chat/pinned-messages-modal.react.js +++ b/web/modals/chat/pinned-messages-modal.react.js @@ -4,7 +4,6 @@ import { fetchPinnedMessageActionTypes } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; -import { useFetchPinnedMessages } from 'lib/hooks/message-hooks.js'; import { type ChatMessageInfoItem, messageListData, @@ -19,6 +18,7 @@ import type { RawMessageInfo } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { pinnedMessageCountText } from 'lib/utils/message-pinning-utils.js'; +import { useFetchPinnedMessagesAction } from 'lib/utils/pin-message-utils.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import css from './pinned-messages-modal.css'; @@ -43,7 +43,7 @@ $ReadOnlyArray, >([]); - const callFetchPinnedMessages = useFetchPinnedMessages(); + const fetchPinnedMessagesAction = useFetchPinnedMessagesAction(); const dispatchActionPromise = useDispatchActionPromise(); const userInfos = useSelector(state => state.userStore.userInfos); @@ -53,11 +53,11 @@ void dispatchActionPromise( fetchPinnedMessageActionTypes, (async () => { - const result = await callFetchPinnedMessages({ threadID }); + const result = await fetchPinnedMessagesAction(threadInfo); setRawMessageResults(result.pinnedMessages); })(), ); - }, [dispatchActionPromise, callFetchPinnedMessages, threadID]); + }, [dispatchActionPromise, fetchPinnedMessagesAction, threadInfo]); const translatedMessageResults = React.useMemo(() => { const threadInfos = { [threadID]: threadInfo };