diff --git a/lib/actions/message-actions.js b/lib/actions/message-actions.js --- a/lib/actions/message-actions.js +++ b/lib/actions/message-actions.js @@ -15,29 +15,43 @@ SearchMessagesResponse, } from '../types/message-types.js'; import type { MediaMessageServerDBContent } from '../types/messages/media.js'; +import type { CallServerEndpointResultInfo } from '../utils/call-server-endpoint.js'; +import { useKeyserverCall } from '../utils/keyserver-call.js'; import type { - CallServerEndpoint, - CallServerEndpointResultInfo, -} from '../utils/call-server-endpoint.js'; + CallKeyserverEndpoint, + KeyserverCall, +} from '../utils/keyserver-call.js'; +import { + targetMessageKeyserverIDExtractor, + threadIDKeyserverIDExtractor, +} from '../utils/keyserver-id-extractors.js'; const fetchMessagesBeforeCursorActionTypes = Object.freeze({ started: 'FETCH_MESSAGES_BEFORE_CURSOR_STARTED', success: 'FETCH_MESSAGES_BEFORE_CURSOR_SUCCESS', failed: 'FETCH_MESSAGES_BEFORE_CURSOR_FAILED', }); -const fetchMessagesBeforeCursor = +export type FetchMessagesBeforeCursorInput = { + +threadID: string, + +beforeMessageID: string, +}; +const fetchMessagesBeforeCursorActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): (( - threadID: string, - beforeMessageID: string, + input: FetchMessagesBeforeCursorInput, ) => Promise) => - async (threadID, beforeMessageID) => { - const response = await callServerEndpoint('fetch_messages', { - cursors: { - [threadID]: beforeMessageID, + async input => { + const { threadID, beforeMessageID } = input; + const response = await callServerEndpoint( + 'fetch_messages', + { + cursors: { + [threadID]: beforeMessageID, + }, }, - }); + input, + ); return { threadID, rawMessageInfos: response.rawMessageInfos, @@ -45,21 +59,49 @@ }; }; +const fetchMessagesBeforeCursor: KeyserverCall< + FetchMessagesBeforeCursorInput, + FetchMessageInfosPayload, +> = { + actionFunc: fetchMessagesBeforeCursorActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, +}; + +function useFetchMessagesBeforeCursor(): ( + input: FetchMessagesBeforeCursorInput, +) => Promise { + return useKeyserverCall(fetchMessagesBeforeCursor); +} + +export type FetchMostRecentMessagesInput = { + +threadID: string, +}; + const fetchMostRecentMessagesActionTypes = Object.freeze({ started: 'FETCH_MOST_RECENT_MESSAGES_STARTED', success: 'FETCH_MOST_RECENT_MESSAGES_SUCCESS', failed: 'FETCH_MOST_RECENT_MESSAGES_FAILED', }); -const fetchMostRecentMessages = +const fetchMostRecentMessagesActionFunc = ( - callServerEndpoint: CallServerEndpoint, - ): ((threadID: string) => Promise) => - async threadID => { - const response = await callServerEndpoint('fetch_messages', { - cursors: { - [threadID]: null, + callServerEndpoint: CallKeyserverEndpoint, + ): (( + input: FetchMostRecentMessagesInput, + ) => Promise) => + async input => { + const { threadID } = input; + const response = await callServerEndpoint( + 'fetch_messages', + { + cursors: { + [threadID]: null, + }, }, - }); + input, + ); return { threadID, rawMessageInfos: response.rawMessageInfos, @@ -67,55 +109,110 @@ }; }; +const fetchMostRecentMessages: KeyserverCall< + FetchMostRecentMessagesInput, + FetchMessageInfosPayload, +> = { + actionFunc: fetchMostRecentMessagesActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, +}; + +function useFetchMostRecentMessages(): ( + input: FetchMostRecentMessagesInput, +) => Promise { + return useKeyserverCall(fetchMostRecentMessages); +} + const fetchSingleMostRecentMessagesFromThreadsActionTypes = Object.freeze({ started: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_STARTED', success: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_SUCCESS', failed: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_FAILED', }); -const fetchSingleMostRecentMessagesFromThreads = +const fetchSingleMostRecentMessagesFromThreadsActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint<$ReadOnlyArray>, ): ((threadIDs: $ReadOnlyArray) => Promise) => async threadIDs => { const cursors = Object.fromEntries( threadIDs.map(threadID => [threadID, null]), ); - const response = await callServerEndpoint('fetch_messages', { - cursors, - numberPerThread: 1, - }); + const responses = await callServerEndpoint( + 'fetch_messages', + { + cursors, + numberPerThread: 1, + }, + threadIDs, + ); + let rawMessageInfos = []; + let truncationStatuses = {}; + for (const response of responses) { + rawMessageInfos = rawMessageInfos.concat(response.rawMessageInfos); + truncationStatuses = { + ...truncationStatuses, + ...response.truncationStatuses, + }; + } + return { - rawMessageInfos: response.rawMessageInfos, - truncationStatuses: response.truncationStatuses, + rawMessageInfos, + truncationStatuses, }; }; +const fetchSingleMostRecentMessagesFromThreads: KeyserverCall< + $ReadOnlyArray, + SimpleMessagesPayload, +> = { + actionFunc: fetchSingleMostRecentMessagesFromThreadsActionFunc, + config: { + keyserverSelection: 'fanout', + }, +}; + +function useFetchSingleMostRecentMessagesFromThreads(): ( + threadIDs: $ReadOnlyArray, +) => Promise { + return useKeyserverCall(fetchSingleMostRecentMessagesFromThreads); +} + +export type SendTextMessageInput = { + threadID: string, + localID: string, + text: string, + sidebarCreation?: boolean, +}; + const sendTextMessageActionTypes = Object.freeze({ started: 'SEND_TEXT_MESSAGE_STARTED', success: 'SEND_TEXT_MESSAGE_SUCCESS', failed: 'SEND_TEXT_MESSAGE_FAILED', }); -const sendTextMessage = +const sendTextMessageActionFunc = ( - callServerEndpoint: CallServerEndpoint, - ): (( - threadID: string, - localID: string, - text: string, - sidebarCreation?: boolean, - ) => Promise) => - async (threadID, localID, text, sidebarCreation) => { + callServerEndpoint: CallKeyserverEndpoint, + ): ((input: SendTextMessageInput) => Promise) => + async input => { let resultInfo; const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; + const { threadID, localID, text, sidebarCreation } = input; let payload = { threadID, localID, text }; if (sidebarCreation) { payload = { ...payload, sidebarCreation }; } - const response = await callServerEndpoint('create_text_message', payload, { - getResultInfo, - }); + const response = await callServerEndpoint( + 'create_text_message', + payload, + input, + { + getResultInfo, + }, + ); const resultInterface = resultInfo?.interface; invariant( resultInterface, @@ -128,27 +225,45 @@ }; }; +const sendTextMessage: KeyserverCall = + { + actionFunc: sendTextMessageActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, + }; + +function useSendTextMessage(): ( + request: SendTextMessageInput, +) => Promise { + return useKeyserverCall(sendTextMessage); +} + const createLocalMessageActionType = 'CREATE_LOCAL_MESSAGE'; +export type SendMultimediaMessageInput = { + +threadID: string, + +localID: string, + +mediaMessageContents: $ReadOnlyArray, + +sidebarCreation?: boolean, +}; + const sendMultimediaMessageActionTypes = Object.freeze({ started: 'SEND_MULTIMEDIA_MESSAGE_STARTED', success: 'SEND_MULTIMEDIA_MESSAGE_SUCCESS', failed: 'SEND_MULTIMEDIA_MESSAGE_FAILED', }); -const sendMultimediaMessage = +const sendMultimediaMessageActionFunc = ( - callServerEndpoint: CallServerEndpoint, - ): (( - threadID: string, - localID: string, - mediaMessageContents: $ReadOnlyArray, - sidebarCreation?: boolean, - ) => Promise) => - async (threadID, localID, mediaMessageContents, sidebarCreation) => { + callServerEndpoint: CallKeyserverEndpoint, + ): ((input: SendMultimediaMessageInput) => Promise) => + async input => { let resultInfo; const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; + const { threadID, localID, mediaMessageContents, sidebarCreation } = input; let payload = { threadID, localID, mediaMessageContents }; if (sidebarCreation) { payload = { ...payload, sidebarCreation }; @@ -156,6 +271,7 @@ const response = await callServerEndpoint( 'create_multimedia_message', payload, + input, { getResultInfo }, ); const resultInterface = resultInfo?.interface; @@ -170,20 +286,42 @@ }; }; -const legacySendMultimediaMessage = +const sendMultimediaMessage: KeyserverCall< + SendMultimediaMessageInput, + SendMessageResult, +> = { + actionFunc: sendMultimediaMessageActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, +}; + +function useSendMultimediaMessage(): ( + input: SendMultimediaMessageInput, +) => Promise { + return useKeyserverCall(sendMultimediaMessage); +} + +export type LegacySendMultimediaMessageInput = { + +threadID: string, + +localID: string, + +mediaIDs: $ReadOnlyArray, + +sidebarCreation?: boolean, +}; + +const legacySendMultimediaMessageActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): (( - threadID: string, - localID: string, - mediaIDs: $ReadOnlyArray, - sidebarCreation?: boolean, + input: LegacySendMultimediaMessageInput, ) => Promise) => - async (threadID, localID, mediaIDs, sidebarCreation) => { + async input => { let resultInfo; const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; + const { threadID, localID, mediaIDs, sidebarCreation } = input; let payload = { threadID, localID, mediaIDs }; if (sidebarCreation) { payload = { ...payload, sidebarCreation }; @@ -191,6 +329,7 @@ const response = await callServerEndpoint( 'create_multimedia_message', payload, + input, { getResultInfo }, ); const resultInterface = resultInfo?.interface; @@ -205,14 +344,31 @@ }; }; +const legacySendMultimediaMessage: KeyserverCall< + LegacySendMultimediaMessageInput, + SendMessageResult, +> = { + actionFunc: legacySendMultimediaMessageActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, +}; + +function useLegacySendMultimediaMessage(): ( + input: LegacySendMultimediaMessageInput, +) => Promise { + return useKeyserverCall(legacySendMultimediaMessage); +} + const sendReactionMessageActionTypes = Object.freeze({ started: 'SEND_REACTION_MESSAGE_STARTED', success: 'SEND_REACTION_MESSAGE_SUCCESS', failed: 'SEND_REACTION_MESSAGE_FAILED', }); -const sendReactionMessage = +const sendReactionMessageActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): ((request: SendReactionMessageRequest) => Promise) => async request => { let resultInfo; @@ -229,6 +385,7 @@ reaction: request.reaction, action: request.action, }, + request, { getResultInfo }, ); @@ -245,25 +402,63 @@ }; }; +const sendReactionMessage: KeyserverCall< + SendReactionMessageRequest, + SendMessageResult, +> = { + actionFunc: sendReactionMessageActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: threadIDKeyserverIDExtractor, + }, +}; + +function useSendReactionMessage(): ( + request: SendReactionMessageRequest, +) => Promise { + return useKeyserverCall(sendReactionMessage); +} + const sendEditMessageActionTypes = Object.freeze({ started: 'SEND_EDIT_MESSAGE_STARTED', success: 'SEND_EDIT_MESSAGE_SUCCESS', failed: 'SEND_EDIT_MESSAGE_FAILED', }); -const sendEditMessage = +const sendEditMessageActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): ((request: SendEditMessageRequest) => Promise) => async request => { - const response = await callServerEndpoint('edit_message', { - targetMessageID: request.targetMessageID, - text: request.text, - }); + const response = await callServerEndpoint( + 'edit_message', + { + targetMessageID: request.targetMessageID, + text: request.text, + }, + request, + ); return { newMessageInfos: response.newMessageInfos, }; }; +const sendEditMessage: KeyserverCall< + SendEditMessageRequest, + SendEditMessageResult, +> = { + actionFunc: sendEditMessageActionFunc, + config: { + keyserverSelection: 'specific', + keyserverIDExtractor: targetMessageKeyserverIDExtractor, + }, +}; + +function useSendEditMessage(): ( + request: SendEditMessageRequest, +) => Promise { + return useKeyserverCall(sendEditMessage); +} + const saveMessagesActionType = 'SAVE_MESSAGES'; const processMessagesActionType = 'PROCESS_MESSAGES'; const messageStorePruneActionType = 'MESSAGE_STORE_PRUNE'; @@ -273,57 +468,107 @@ success: 'FETCH_PINNED_MESSAGES_SUCCESS', failed: 'FETCH_PINNED_MESSAGES_FAILED', }); -const fetchPinnedMessages = +const fetchPinnedMessagesActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): (( request: FetchPinnedMessagesRequest, ) => Promise) => async request => { - const response = await callServerEndpoint('fetch_pinned_messages', request); - return { pinnedMessages: response.pinnedMessages }; + const responses = await callServerEndpoint( + 'fetch_pinned_messages', + request, + request, + ); + let pinnedMessages = []; + for (const response of responses) { + pinnedMessages = pinnedMessages.concat(response.pinnedMessages); + } + return { pinnedMessages }; }; +const fetchPinnedMessages: KeyserverCall< + FetchPinnedMessagesRequest, + FetchPinnedMessagesResult, +> = { + actionFunc: fetchPinnedMessagesActionFunc, + config: { keyserverSelection: 'fanout' }, +}; + +function useFetchPinnedMessages(): ( + request: FetchPinnedMessagesRequest, +) => Promise { + return useKeyserverCall(fetchPinnedMessages); +} + const searchMessagesActionTypes = Object.freeze({ started: 'SEARCH_MESSAGES_STARTED', success: 'SEARCH_MESSAGES_SUCCESS', failed: 'SEARCH_MESSAGES_FAILED', }); -const searchMessages = +const searchMessagesActionFunc = ( - callServerEndpoint: CallServerEndpoint, + callServerEndpoint: CallKeyserverEndpoint, ): ((request: SearchMessagesRequest) => Promise) => async request => { - const response = await callServerEndpoint('search_messages', request); + const responses = await callServerEndpoint( + 'search_messages', + request, + request, + ); + + let messages = []; + let endReached = true; + for (const response of responses) { + messages = messages.concat(response.messages); + if (!response.endReached) { + endReached = false; + } + } + return { - messages: response.messages, - endReached: response.endReached, + messages, + endReached, }; }; +const searchMessages: KeyserverCall< + SearchMessagesRequest, + SearchMessagesResponse, +> = { + actionFunc: searchMessagesActionFunc, + config: { keyserverSelection: 'fanout' }, +}; + +function useSearchMessages(): ( + request: SearchMessagesRequest, +) => Promise { + return useKeyserverCall(searchMessages); +} + export { fetchMessagesBeforeCursorActionTypes, - fetchMessagesBeforeCursor, + useFetchMessagesBeforeCursor, fetchMostRecentMessagesActionTypes, - fetchMostRecentMessages, + useFetchMostRecentMessages, fetchSingleMostRecentMessagesFromThreadsActionTypes, - fetchSingleMostRecentMessagesFromThreads, + useFetchSingleMostRecentMessagesFromThreads, sendTextMessageActionTypes, - sendTextMessage, + useSendTextMessage, createLocalMessageActionType, sendMultimediaMessageActionTypes, - sendMultimediaMessage, - legacySendMultimediaMessage, + useSendMultimediaMessage, + useLegacySendMultimediaMessage, searchMessagesActionTypes, - searchMessages, + useSearchMessages, sendReactionMessageActionTypes, - sendReactionMessage, + useSendReactionMessage, saveMessagesActionType, processMessagesActionType, messageStorePruneActionType, sendEditMessageActionTypes, - sendEditMessage, - fetchPinnedMessages, + useSendEditMessage, + useFetchPinnedMessages, fetchPinnedMessageActionTypes, }; diff --git a/lib/hooks/child-threads.js b/lib/hooks/child-threads.js --- a/lib/hooks/child-threads.js +++ b/lib/hooks/child-threads.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { - fetchSingleMostRecentMessagesFromThreads, + useFetchSingleMostRecentMessagesFromThreads, fetchSingleMostRecentMessagesFromThreadsActionTypes, } from '../actions/message-actions.js'; import { @@ -15,10 +15,7 @@ import { threadInChatList } from '../shared/thread-utils.js'; import threadWatcher from '../shared/thread-watcher.js'; import type { ThreadInfo } from '../types/thread-types.js'; -import { - useDispatchActionPromise, - useServerCall, -} from '../utils/action-utils.js'; +import { useDispatchActionPromise } from '../utils/action-utils.js'; import { useSelector } from '../utils/redux-utils.js'; type ThreadFilter = { @@ -96,9 +93,8 @@ [filteredSubchannelsChatList], ); const dispatchActionPromise = useDispatchActionPromise(); - const fetchSingleMostRecentMessages = useServerCall( - fetchSingleMostRecentMessagesFromThreads, - ); + const fetchSingleMostRecentMessages = + useFetchSingleMostRecentMessagesFromThreads(); React.useEffect(() => { if (!threadIDsWithNoMessages.size) { diff --git a/lib/shared/edit-messages-utils.js b/lib/shared/edit-messages-utils.js --- a/lib/shared/edit-messages-utils.js +++ b/lib/shared/edit-messages-utils.js @@ -5,7 +5,7 @@ import { threadIsPending, threadHasPermission } from './thread-utils.js'; import { sendEditMessageActionTypes, - sendEditMessage, + useSendEditMessage, } from '../actions/message-actions.js'; import type { SendEditMessageResult, @@ -16,17 +16,14 @@ import { messageTypes } from '../types/message-types-enum.js'; import { threadPermissions } from '../types/thread-permission-types.js'; import { type ThreadInfo } from '../types/thread-types.js'; -import { - useDispatchActionPromise, - useServerCall, -} from '../utils/action-utils.js'; +import { useDispatchActionPromise } from '../utils/action-utils.js'; import { useSelector } from '../utils/redux-utils.js'; function useEditMessage(): ( messageID: string, newText: string, ) => Promise { - const callEditMessage = useServerCall(sendEditMessage); + const callEditMessage = useSendEditMessage(); const dispatchActionPromise = useDispatchActionPromise(); return React.useCallback( diff --git a/lib/shared/search-utils.js b/lib/shared/search-utils.js --- a/lib/shared/search-utils.js +++ b/lib/shared/search-utils.js @@ -10,7 +10,7 @@ getContainingThreadID, } from './thread-utils.js'; import { - searchMessages, + useSearchMessages as useSearchMessagesAction, searchMessagesActionTypes, } from '../actions/message-actions.js'; import { @@ -240,7 +240,7 @@ queryID: number, cursor?: string, ) => void { - const callSearchMessages = useServerCall(searchMessages); + const callSearchMessages = useSearchMessagesAction(); const dispatchActionPromise = useDispatchActionPromise(); return React.useCallback( diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -14,7 +14,7 @@ import threadWatcher from './thread-watcher.js'; import { fetchMostRecentMessagesActionTypes, - fetchMostRecentMessages, + useFetchMostRecentMessages, } from '../actions/message-actions.js'; import { changeThreadMemberRolesActionTypes, @@ -1101,7 +1101,7 @@ function useWatchThread(threadInfo: ?ThreadInfo) { const dispatchActionPromise = useDispatchActionPromise(); - const callFetchMostRecentMessages = useServerCall(fetchMostRecentMessages); + const callFetchMostRecentMessages = useFetchMostRecentMessages(); const threadID = threadInfo?.id; const threadNotInChatList = !threadInChatList(threadInfo); @@ -1110,7 +1110,7 @@ threadWatcher.watchID(threadID); dispatchActionPromise( fetchMostRecentMessagesActionTypes, - callFetchMostRecentMessages(threadID), + callFetchMostRecentMessages({ threadID }), ); } return () => { diff --git a/lib/utils/keyserver-id-extractors.js b/lib/utils/keyserver-id-extractors.js new file mode 100644 --- /dev/null +++ b/lib/utils/keyserver-id-extractors.js @@ -0,0 +1,25 @@ +// @flow + +import invariant from 'invariant'; + +import { extractKeyserverIDFromID } from './action-utils.js'; + +function threadIDKeyserverIDExtractor(input: { + +threadID: string, + ... +}): string { + const id = extractKeyserverIDFromID(input.threadID); + invariant(id, 'keyserver data missing from request'); + return id; +} + +function targetMessageKeyserverIDExtractor(request: { + +targetMessageID: string, + ... +}): string { + const id = extractKeyserverIDFromID(request.targetMessageID); + invariant(id, 'keyserver data missing from request'); + return id; +} + +export { threadIDKeyserverIDExtractor, targetMessageKeyserverIDExtractor }; diff --git a/native/chat/message-list.react.js b/native/chat/message-list.react.js --- a/native/chat/message-list.react.js +++ b/native/chat/message-list.react.js @@ -8,9 +8,11 @@ import { fetchMessagesBeforeCursorActionTypes, - fetchMessagesBeforeCursor, + useFetchMessagesBeforeCursor, fetchMostRecentMessagesActionTypes, - fetchMostRecentMessages, + useFetchMostRecentMessages, + type FetchMostRecentMessagesInput, + type FetchMessagesBeforeCursorInput, } from 'lib/actions/message-actions.js'; import { useOldestMessageServerID } from 'lib/hooks/message-hooks.js'; import { registerFetchKey } from 'lib/reducers/loading-reducer.js'; @@ -21,7 +23,6 @@ import { type ThreadInfo } from 'lib/types/thread-types.js'; import { type DispatchActionPromise, - useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils.js'; @@ -66,11 +67,10 @@ +indicatorStyle: IndicatorStyle, +dispatchActionPromise: DispatchActionPromise, +fetchMessagesBeforeCursor: ( - threadID: string, - beforeMessageID: string, + input: FetchMessagesBeforeCursorInput, ) => Promise, +fetchMostRecentMessages: ( - threadID: string, + input: FetchMostRecentMessagesInput, ) => Promise, +overlayContext: ?OverlayContextType, +keyboardState: ?KeyboardState, @@ -292,15 +292,15 @@ if (oldestMessageServerID) { await this.props.dispatchActionPromise( fetchMessagesBeforeCursorActionTypes, - this.props.fetchMessagesBeforeCursor( + this.props.fetchMessagesBeforeCursor({ threadID, - oldestMessageServerID, - ), + beforeMessageID: oldestMessageServerID, + }), ); } else { await this.props.dispatchActionPromise( fetchMostRecentMessagesActionTypes, - this.props.fetchMostRecentMessages(threadID), + this.props.fetchMostRecentMessages({ threadID }), ); } } finally { @@ -344,10 +344,8 @@ const indicatorStyle = useIndicatorStyle(); const dispatchActionPromise = useDispatchActionPromise(); - const callFetchMessagesBeforeCursor = useServerCall( - fetchMessagesBeforeCursor, - ); - const callFetchMostRecentMessages = useServerCall(fetchMostRecentMessages); + const callFetchMessagesBeforeCursor = useFetchMessagesBeforeCursor(); + const callFetchMostRecentMessages = useFetchMostRecentMessages(); const oldestMessageServerID = useOldestMessageServerID(threadID); diff --git a/native/chat/message-results-screen.react.js b/native/chat/message-results-screen.react.js --- a/native/chat/message-results-screen.react.js +++ b/native/chat/message-results-screen.react.js @@ -5,12 +5,11 @@ import { View } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; -import { fetchPinnedMessages } from 'lib/actions/message-actions.js'; +import { useFetchPinnedMessages } from 'lib/actions/message-actions.js'; import { messageListData } from 'lib/selectors/chat-selectors.js'; import { createMessageInfo } from 'lib/shared/message-utils.js'; import { isComposableMessageType } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; -import { useServerCall } from 'lib/utils/action-utils.js'; import { useHeightMeasurer } from './chat-context.js'; import type { ChatNavigationProp } from './chat.react'; @@ -42,7 +41,7 @@ const [messageVerticalBounds, setMessageVerticalBounds] = React.useState(); const scrollViewContainerRef = React.useRef(); - const callFetchPinnedMessages = useServerCall(fetchPinnedMessages); + const callFetchPinnedMessages = useFetchPinnedMessages(); const userInfos = useSelector(state => state.userStore.userInfos); React.useEffect(() => { diff --git a/native/chat/reaction-message-utils.js b/native/chat/reaction-message-utils.js --- a/native/chat/reaction-message-utils.js +++ b/native/chat/reaction-message-utils.js @@ -4,16 +4,13 @@ import * as React from 'react'; import { - sendReactionMessage, + useSendReactionMessage, sendReactionMessageActionTypes, } from 'lib/actions/message-actions.js'; import type { ReactionInfo } from 'lib/selectors/chat-selectors.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; import type { RawReactionMessageInfo } from 'lib/types/messages/reaction.js'; -import { - useDispatchActionPromise, - useServerCall, -} from 'lib/utils/action-utils.js'; +import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; import { cloneError } from 'lib/utils/errors.js'; import { useSelector } from '../redux/redux-utils.js'; @@ -33,7 +30,7 @@ state => state.currentUserInfo && state.currentUserInfo.id, ); - const callSendReactionMessage = useServerCall(sendReactionMessage); + const callSendReactionMessage = useSendReactionMessage(); const dispatchActionPromise = useDispatchActionPromise(); return React.useCallback( diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -11,9 +11,13 @@ import { createLocalMessageActionType, sendMultimediaMessageActionTypes, - sendMultimediaMessage, + useSendMultimediaMessage, sendTextMessageActionTypes, - sendTextMessage, + useSendTextMessage, +} from 'lib/actions/message-actions.js'; +import type { + SendMultimediaMessageInput, + SendTextMessageInput, } from 'lib/actions/message-actions.js'; import { queueReportsActionType } from 'lib/actions/report-actions.js'; import { newThread } from 'lib/actions/thread-actions.js'; @@ -67,10 +71,7 @@ type SendMessagePayload, } from 'lib/types/message-types.js'; import type { RawImagesMessageInfo } from 'lib/types/messages/images.js'; -import type { - MediaMessageServerDBContent, - RawMediaMessageInfo, -} from 'lib/types/messages/media.js'; +import type { RawMediaMessageInfo } from 'lib/types/messages/media.js'; import { getMediaMessageServerDBContentsFromMedia } from 'lib/types/messages/media.js'; import type { RawTextMessageInfo } from 'lib/types/messages/text.js'; import type { Dispatch } from 'lib/types/redux-types.js'; @@ -151,17 +152,9 @@ input: UploadMediaMetadataRequest, ) => Promise, +sendMultimediaMessage: ( - threadID: string, - localID: string, - mediaMessageContents: $ReadOnlyArray, - sidebarCreation?: boolean, - ) => Promise, - +sendTextMessage: ( - threadID: string, - localID: string, - text: string, - sidebarCreation?: boolean, + input: SendMultimediaMessageInput, ) => Promise, + +sendTextMessage: (input: SendTextMessageInput) => Promise, +newThread: (request: ClientNewThreadRequest) => Promise, +textMessageCreationSideEffectsFunc: CreationSideEffectsFunc, }; @@ -377,12 +370,12 @@ messageInfo.media, ); try { - const result = await this.props.sendMultimediaMessage( + const result = await this.props.sendMultimediaMessage({ threadID, localID, mediaMessageContents, sidebarCreation, - ); + }); this.pendingSidebarCreationMessageLocalIDs.delete(localID); return { localID, @@ -576,12 +569,12 @@ ); const sidebarCreation = this.pendingSidebarCreationMessageLocalIDs.has(localID); - const result = await this.props.sendTextMessage( - messageInfo.threadID, + const result = await this.props.sendTextMessage({ + threadID: messageInfo.threadID, localID, - messageInfo.text, + text: messageInfo.text, sidebarCreation, - ); + }); this.pendingSidebarCreationMessageLocalIDs.delete(localID); return { localID, @@ -1802,8 +1795,8 @@ const calendarQuery = useCalendarQuery(); const callUploadMultimedia = useServerCall(uploadMultimedia); const callUploadMediaMetadata = useServerCall(uploadMediaMetadata); - const callSendMultimediaMessage = useServerCall(sendMultimediaMessage); - const callSendTextMessage = useServerCall(sendTextMessage); + const callSendMultimediaMessage = useSendMultimediaMessage(); + const callSendTextMessage = useSendTextMessage(); const callNewThread = useServerCall(newThread); const dispatchActionPromise = useDispatchActionPromise(); const dispatch = useDispatch(); diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js --- a/web/chat/chat-message-list.react.js +++ b/web/chat/chat-message-list.react.js @@ -8,9 +8,13 @@ import { fetchMessagesBeforeCursorActionTypes, - fetchMessagesBeforeCursor, + useFetchMessagesBeforeCursor, fetchMostRecentMessagesActionTypes, - fetchMostRecentMessages, + useFetchMostRecentMessages, +} from 'lib/actions/message-actions.js'; +import type { + FetchMostRecentMessagesInput, + FetchMessagesBeforeCursorInput, } from 'lib/actions/message-actions.js'; import { useOldestMessageServerID } from 'lib/hooks/message-hooks.js'; import { registerFetchKey } from 'lib/reducers/loading-reducer.js'; @@ -25,7 +29,6 @@ import { type ThreadInfo } from 'lib/types/thread-types.js'; import { type DispatchActionPromise, - useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils.js'; @@ -61,11 +64,10 @@ +startReached: boolean, +dispatchActionPromise: DispatchActionPromise, +fetchMessagesBeforeCursor: ( - threadID: string, - beforeMessageID: string, + input: FetchMessagesBeforeCursorInput, ) => Promise, +fetchMostRecentMessages: ( - threadID: string, + input: FetchMostRecentMessagesInput, ) => Promise, +inputState: ?InputState, +clearTooltip: () => mixed, @@ -383,12 +385,15 @@ if (oldestMessageServerID) { await this.props.dispatchActionPromise( fetchMessagesBeforeCursorActionTypes, - this.props.fetchMessagesBeforeCursor(threadID, oldestMessageServerID), + this.props.fetchMessagesBeforeCursor({ + threadID, + beforeMessageID: oldestMessageServerID, + }), ); } else { await this.props.dispatchActionPromise( fetchMostRecentMessagesActionTypes, - this.props.fetchMostRecentMessages(threadID), + this.props.fetchMostRecentMessages({ threadID }), ); } } finally { @@ -428,10 +433,8 @@ }); const dispatchActionPromise = useDispatchActionPromise(); - const callFetchMessagesBeforeCursor = useServerCall( - fetchMessagesBeforeCursor, - ); - const callFetchMostRecentMessages = useServerCall(fetchMostRecentMessages); + const callFetchMessagesBeforeCursor = useFetchMessagesBeforeCursor(); + const callFetchMostRecentMessages = useFetchMostRecentMessages(); const inputState = React.useContext(InputStateContext); diff --git a/web/chat/reaction-message-utils.js b/web/chat/reaction-message-utils.js --- a/web/chat/reaction-message-utils.js +++ b/web/chat/reaction-message-utils.js @@ -4,17 +4,14 @@ import * as React from 'react'; import { - sendReactionMessage, + useSendReactionMessage, sendReactionMessageActionTypes, } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import type { ReactionInfo } from 'lib/selectors/chat-selectors'; import { messageTypes } from 'lib/types/message-types-enum.js'; import type { RawReactionMessageInfo } from 'lib/types/messages/reaction.js'; -import { - useDispatchActionPromise, - useServerCall, -} from 'lib/utils/action-utils.js'; +import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; import { cloneError } from 'lib/utils/errors.js'; import Alert from '../modals/alert.react.js'; @@ -37,7 +34,7 @@ state => state.currentUserInfo && state.currentUserInfo.id, ); - const callSendReactionMessage = useServerCall(sendReactionMessage); + const callSendReactionMessage = useSendReactionMessage(); const dispatchActionPromise = useDispatchActionPromise(); return React.useCallback( diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js --- a/web/input/input-state-container.react.js +++ b/web/input/input-state-container.react.js @@ -16,9 +16,13 @@ import { createLocalMessageActionType, sendMultimediaMessageActionTypes, - legacySendMultimediaMessage, + useLegacySendMultimediaMessage, sendTextMessageActionTypes, - sendTextMessage, + useSendTextMessage, +} from 'lib/actions/message-actions.js'; +import type { + LegacySendMultimediaMessageInput, + SendTextMessageInput, } from 'lib/actions/message-actions.js'; import { queueReportsActionType } from 'lib/actions/report-actions.js'; import { newThread } from 'lib/actions/thread-actions.js'; @@ -139,17 +143,9 @@ ) => Promise, +deleteUpload: (id: string) => Promise, +sendMultimediaMessage: ( - threadID: string, - localID: string, - mediaIDs: $ReadOnlyArray, - sidebarCreation?: boolean, - ) => Promise, - +sendTextMessage: ( - threadID: string, - localID: string, - text: string, - sidebarCreation?: boolean, + input: LegacySendMultimediaMessageInput, ) => Promise, + +sendTextMessage: (input: SendTextMessageInput) => Promise, +newThread: (request: ClientNewThreadRequest) => Promise, +pushModal: PushModal, +sendCallbacks: $ReadOnlyArray<() => mixed>, @@ -508,12 +504,12 @@ mediaIDs.push(id); } try { - const result = await this.props.sendMultimediaMessage( + const result = await this.props.sendMultimediaMessage({ threadID, localID, mediaIDs, sidebarCreation, - ); + }); this.pendingSidebarCreationMessageLocalIDs.delete(localID); this.setState(prevState => { const newThreadID = this.getRealizedOrPendingThreadID(threadID); @@ -1436,12 +1432,12 @@ ); const sidebarCreation = this.pendingSidebarCreationMessageLocalIDs.has(localID); - const result = await this.props.sendTextMessage( - messageInfo.threadID, + const result = await this.props.sendTextMessage({ + threadID: messageInfo.threadID, localID, - messageInfo.text, + text: messageInfo.text, sidebarCreation, - ); + }); this.pendingSidebarCreationMessageLocalIDs.delete(localID); return { localID, @@ -1738,10 +1734,8 @@ const callUploadMultimedia = useServerCall(uploadMultimedia); const callUploadMediaMetadata = useServerCall(uploadMediaMetadata); const callDeleteUpload = useServerCall(deleteUpload); - const callSendMultimediaMessage = useServerCall( - legacySendMultimediaMessage, - ); - const callSendTextMessage = useServerCall(sendTextMessage); + const callSendMultimediaMessage = useLegacySendMultimediaMessage(); + const callSendTextMessage = useSendTextMessage(); const callNewThread = useServerCall(newThread); const dispatch = useDispatch(); const dispatchActionPromise = useDispatchActionPromise(); diff --git a/web/modals/chat/message-results-modal.react.js b/web/modals/chat/message-results-modal.react.js --- a/web/modals/chat/message-results-modal.react.js +++ b/web/modals/chat/message-results-modal.react.js @@ -3,8 +3,8 @@ import * as React from 'react'; import { - fetchPinnedMessages, fetchPinnedMessageActionTypes, + useFetchPinnedMessages, } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { messageListData } from 'lib/selectors/chat-selectors.js'; @@ -15,10 +15,7 @@ } from 'lib/shared/message-utils.js'; import { isComposableMessageType } from 'lib/types/message-types.js'; import { type ThreadInfo } from 'lib/types/thread-types.js'; -import { - useServerCall, - useDispatchActionPromise, -} from 'lib/utils/action-utils.js'; +import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; import css from './message-results-modal.css'; import MessageResult from '../../components/message-result.react.js'; @@ -41,7 +38,7 @@ const { popModal } = useModalContext(); const [rawMessageResults, setRawMessageResults] = React.useState([]); - const callFetchPinnedMessages = useServerCall(fetchPinnedMessages); + const callFetchPinnedMessages = useFetchPinnedMessages(); const dispatchActionPromise = useDispatchActionPromise(); const userInfos = useSelector(state => state.userStore.userInfos);