diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -28,6 +28,7 @@ newThreadActionTypes, } from 'lib/actions/thread-actions.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; +import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { relativeMemberInfoSelectorForMembersOfThread, userStoreSearchIndex, @@ -120,7 +121,6 @@ }; type Props = { ...BaseProps, - // Redux state +viewerID: ?string, +draft: string, +joinThreadLoadingStatus: LoadingStatus, @@ -132,19 +132,15 @@ +styles: typeof unboundStyles, +onInputBarLayout?: (event: LayoutEvent) => mixed, +openCamera: () => mixed, - // connectNav +isActive: boolean, - // withKeyboardState +keyboardState: ?KeyboardState, - // Redux dispatch functions +dispatch: Dispatch, +dispatchActionPromise: DispatchActionPromise, - // async functions that hit server APIs +joinThread: (request: ClientThreadJoinRequest) => Promise, - // withInputState +inputState: ?InputState, +userSearchIndex: SearchIndex, +threadMembers: $ReadOnlyArray, + +parentThreadInfo: ?ThreadInfo, }; type State = { +text: string, @@ -738,6 +734,7 @@ time: Date.now(), }, this.props.threadInfo, + this.props.parentThreadInfo, ); }; @@ -946,6 +943,11 @@ relativeMemberInfoSelectorForMembersOfThread(props.threadInfo.id), ); + const { parentThreadID } = props.threadInfo; + const parentThreadInfo = useSelector(state => + parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, + ); + return ( ); } diff --git a/native/chat/failed-send.react.js b/native/chat/failed-send.react.js --- a/native/chat/failed-send.react.js +++ b/native/chat/failed-send.react.js @@ -4,12 +4,14 @@ import * as React from 'react'; import { Text, View } from 'react-native'; +import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { messageID } from 'lib/shared/message-utils.js'; import { assertComposableRawMessage, messageTypes, } from 'lib/types/message-types.js'; import type { RawComposableMessageInfo } from 'lib/types/message-types.js'; +import type { ThreadInfo } from 'lib/types/thread-types.js'; import { multimediaMessageSendFailed } from './multimedia-message-utils.js'; import textMessageSendFailed from './text-message-send-failed.js'; @@ -26,11 +28,10 @@ }; type Props = { ...BaseProps, - // Redux state +rawMessageInfo: ?RawComposableMessageInfo, +styles: typeof unboundStyles, - // withInputState +inputState: ?InputState, + +parentThreadInfo: ?ThreadInfo, }; class FailedSend extends React.PureComponent { retryingText = false; @@ -126,7 +127,11 @@ ); const { localID } = rawMessageInfo; invariant(localID, 'failed RawMessageInfo should have localID'); - inputState.retryMessage(localID, this.props.item.threadInfo); + inputState.retryMessage( + localID, + this.props.item.threadInfo, + this.props.parentThreadInfo, + ); }; } @@ -156,12 +161,17 @@ }); const styles = useStyles(unboundStyles); const inputState = React.useContext(InputStateContext); + const { parentThreadID } = props.item.threadInfo; + const parentThreadInfo = useSelector(state => + parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, + ); return ( ); }); 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 @@ -387,13 +387,14 @@ sendTextMessage = async ( messageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) => { this.sendCallbacks.forEach(callback => callback()); if (!threadIsPending(threadInfo.id)) { this.props.dispatchActionPromise( sendTextMessageActionTypes, - this.sendTextMessageAction(messageInfo), + this.sendTextMessageAction(messageInfo, threadInfo, parentThreadInfo), undefined, messageInfo, ); @@ -427,9 +428,17 @@ threadID: newThreadID, time: Date.now(), }; + const newThreadInfo = { + ...threadInfo, + id: newThreadID, + }; this.props.dispatchActionPromise( sendTextMessageActionTypes, - this.sendTextMessageAction(newMessageInfo), + this.sendTextMessageAction( + newMessageInfo, + newThreadInfo, + parentThreadInfo, + ), undefined, newMessageInfo, ); @@ -457,6 +466,10 @@ async sendTextMessageAction( messageInfo: RawTextMessageInfo, + // eslint-disable-next-line no-unused-vars + threadInfo: ThreadInfo, + // eslint-disable-next-line no-unused-vars + parentThreadInfo: ?ThreadInfo, ): Promise { try { const { localID } = messageInfo; @@ -1052,6 +1065,7 @@ retryTextMessage = async ( rawMessageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) => { await this.sendTextMessage( { @@ -1059,6 +1073,7 @@ time: Date.now(), }, threadInfo, + parentThreadInfo, ); }; @@ -1268,12 +1283,16 @@ await this.uploadFiles(localMessageID, uploadFileInputs); }; - retryMessage = async (localMessageID: string, threadInfo: ThreadInfo) => { + retryMessage = async ( + localMessageID: string, + threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, + ) => { const rawMessageInfo = this.props.messageStoreMessages[localMessageID]; invariant(rawMessageInfo, `rawMessageInfo ${localMessageID} should exist`); if (rawMessageInfo.type === messageTypes.TEXT) { - await this.retryTextMessage(rawMessageInfo, threadInfo); + await this.retryTextMessage(rawMessageInfo, threadInfo, parentThreadInfo); } else if ( rawMessageInfo.type === messageTypes.IMAGES || rawMessageInfo.type === messageTypes.MULTIMEDIA diff --git a/native/input/input-state.js b/native/input/input-state.js --- a/native/input/input-state.js +++ b/native/input/input-state.js @@ -27,6 +27,7 @@ +sendTextMessage: ( messageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) => Promise, +sendMultimediaMessage: ( selections: $ReadOnlyArray, @@ -39,6 +40,7 @@ +retryMessage: ( localMessageID: string, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) => Promise, +registerSendCallback: (() => void) => void, +unregisterSendCallback: (() => void) => void, diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js --- a/web/chat/chat-input-bar.react.js +++ b/web/chat/chat-input-bar.react.js @@ -11,6 +11,7 @@ } from 'lib/actions/thread-actions.js'; import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; +import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { userStoreSearchIndex, relativeMemberInfoSelectorForMembersOfThread, @@ -65,7 +66,6 @@ }; type Props = { ...BaseProps, - // Redux state +viewerID: ?string, +joinThreadLoadingStatus: LoadingStatus, +threadCreationInProgress: boolean, @@ -73,12 +73,11 @@ +nextLocalID: number, +isThreadActive: boolean, +userInfos: UserInfos, - // Redux dispatch functions +dispatchActionPromise: DispatchActionPromise, - // async functions that hit server APIs +joinThread: (request: ClientThreadJoinRequest) => Promise, +typeaheadMatchedStrings: ?TypeaheadMatchedStrings, +suggestedUsers: $ReadOnlyArray, + +parentThreadInfo: ?ThreadInfo, }; class ChatInputBar extends React.PureComponent { @@ -478,6 +477,7 @@ time: Date.now(), }, this.props.threadInfo, + this.props.parentThreadInfo, ); } @@ -609,6 +609,11 @@ typeaheadMatchedStrings, ]); + const { parentThreadID } = props.threadInfo; + const parentThreadInfo = useSelector(state => + parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, + ); + return ( ); }); diff --git a/web/chat/failed-send.react.js b/web/chat/failed-send.react.js --- a/web/chat/failed-send.react.js +++ b/web/chat/failed-send.react.js @@ -4,6 +4,7 @@ import * as React from 'react'; import { type ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; +import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { messageID } from 'lib/shared/message-utils.js'; import { messageTypes, @@ -25,10 +26,9 @@ }; type Props = { ...BaseProps, - // Redux state +rawMessageInfo: RawComposableMessageInfo, - // withInputState +inputState: ?InputState, + +parentThreadInfo: ?ThreadInfo, }; class FailedSend extends React.PureComponent { retryingText = false; @@ -112,6 +112,7 @@ time: Date.now(), }, this.props.threadInfo, + this.props.parentThreadInfo, ); } else if ( rawMessageInfo.type === messageTypes.IMAGES || @@ -144,11 +145,16 @@ 'FailedSend should only be used for composable message types', ); const inputState = React.useContext(InputStateContext); + const { parentThreadID } = props.threadInfo; + const parentThreadInfo = useSelector(state => + parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, + ); return ( ); }); 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 @@ -512,7 +512,8 @@ sendTextMessage: ( messageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, - ) => this.sendTextMessage(messageInfo, threadInfo), + parentThreadInfo: ?ThreadInfo, + ) => this.sendTextMessage(messageInfo, threadInfo, parentThreadInfo), createMultimediaMessage: (localID: number, threadInfo: ThreadInfo) => this.createMultimediaMessage(localID, threadInfo), setDraft: (newDraft: string) => this.setDraft(threadID, newDraft), @@ -986,13 +987,14 @@ async sendTextMessage( messageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) { this.props.sendCallbacks.forEach(callback => callback()); if (!threadIsPending(threadInfo.id)) { this.props.dispatchActionPromise( sendTextMessageActionTypes, - this.sendTextMessageAction(messageInfo), + this.sendTextMessageAction(messageInfo, threadInfo, parentThreadInfo), undefined, messageInfo, ); @@ -1026,9 +1028,17 @@ threadID: newThreadID, time: Date.now(), }; + const newThreadInfo = { + ...threadInfo, + id: newThreadID, + }; this.props.dispatchActionPromise( sendTextMessageActionTypes, - this.sendTextMessageAction(newMessageInfo), + this.sendTextMessageAction( + newMessageInfo, + newThreadInfo, + parentThreadInfo, + ), undefined, newMessageInfo, ); @@ -1036,6 +1046,10 @@ async sendTextMessageAction( messageInfo: RawTextMessageInfo, + // eslint-disable-next-line no-unused-vars + threadInfo: ThreadInfo, + // eslint-disable-next-line no-unused-vars + parentThreadInfo: ?ThreadInfo, ): Promise { try { const { localID } = messageInfo; diff --git a/web/input/input-state.js b/web/input/input-state.js --- a/web/input/input-state.js +++ b/web/input/input-state.js @@ -58,6 +58,7 @@ +sendTextMessage: ( messageInfo: RawTextMessageInfo, threadInfo: ThreadInfo, + parentThreadInfo: ?ThreadInfo, ) => Promise, +createMultimediaMessage: (localID: number, threadInfo: ThreadInfo) => void, +setDraft: (draft: string) => void,