diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js --- a/lib/shared/dm-ops/process-dm-ops.js +++ b/lib/shared/dm-ops/process-dm-ops.js @@ -26,6 +26,7 @@ sendDMActionTypes, type SendDMOpsPayload, } from '../../types/dm-ops.js'; +import type { LocalMessageInfo } from '../../types/message-types.js'; import type { RawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; import type { DispatchMetadata } from '../../types/redux-types.js'; import type { OutboundP2PMessage } from '../../types/sqlite-types.js'; @@ -259,4 +260,37 @@ ); } -export { useProcessDMOperation, useProcessAndSendDMOperation }; +function useRetrySendDMOperation(): ( + messageID: string, + localMessageInfo: LocalMessageInfo, +) => Promise { + const { processOutboundMessages, getDMOpsSendingPromise } = + usePeerToPeerCommunication(); + const dispatchActionPromise = useDispatchActionPromise(); + + return React.useCallback( + async (messageID: string, localMessageInfo: LocalMessageInfo) => { + const { promise, dmOpID } = getDMOpsSendingPromise(); + console.log('retying'); + processOutboundMessages(localMessageInfo.outboundP2PMessageIDs, dmOpID); + + const sendingPromise: Promise = (async () => { + const outboundP2PMessageIDs = await promise; + return { + messageID, + outboundP2PMessageIDs, + }; + })(); + void dispatchActionPromise(sendDMActionTypes, sendingPromise, undefined, { + messageID, + }); + }, + [dispatchActionPromise, getDMOpsSendingPromise, processOutboundMessages], + ); +} + +export { + useProcessDMOperation, + useProcessAndSendDMOperation, + useRetrySendDMOperation, +}; 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 @@ -5,11 +5,16 @@ import { Text, View } from 'react-native'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; +import { useRetrySendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js'; import { messageID } from 'lib/shared/message-utils.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; -import type { RawComposableMessageInfo } from 'lib/types/message-types.js'; -import { assertComposableRawMessage } from 'lib/types/message-types.js'; +import { + type RawComposableMessageInfo, + assertComposableRawMessage, + type LocalMessageInfo, +} from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; +import { threadTypeIsThick } from 'lib/types/thread-types-enum.js'; import { multimediaMessageSendFailed } from './multimedia-message-utils.js'; import textMessageSendFailed from './text-message-send-failed.js'; @@ -47,6 +52,10 @@ +styles: $ReadOnly, +inputState: ?InputState, +parentThreadInfo: ?ThreadInfo, + +retrySendDMOperation: ( + messageID: string, + localMessageInfo: LocalMessageInfo, + ) => Promise, }; class FailedSend extends React.PureComponent { retryingText = false; @@ -135,6 +144,18 @@ this.retryingMedia = true; } + if (threadTypeIsThick(this.props.item.threadInfo.type)) { + const failedMessageID = this.props.rawMessageInfo?.id; + invariant(failedMessageID, 'failedMessageID should be set for DMs'); + const localMessageInfo = this.props.item.localMessageInfo; + invariant( + localMessageInfo, + 'localMessageInfo should be set for failed message', + ); + void this.props.retrySendDMOperation(failedMessageID, localMessageInfo); + return; + } + const { inputState } = this.props; invariant( inputState, @@ -163,6 +184,8 @@ const parentThreadInfo = useSelector(state => parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, ); + const retrySendDMOperation = useRetrySendDMOperation(); + 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 @@ -5,13 +5,16 @@ import { type ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; +import { useRetrySendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js'; import { messageID } from 'lib/shared/message-utils.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; import { assertComposableMessageType, + type LocalMessageInfo, type RawComposableMessageInfo, } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; +import { threadTypeIsThick } from 'lib/types/thread-types-enum.js'; import css from './chat-message-list.css'; import multimediaMessageSendFailed from './multimedia-message-send-failed.js'; @@ -29,6 +32,10 @@ +rawMessageInfo: RawComposableMessageInfo, +inputState: ?InputState, +parentThreadInfo: ?ThreadInfo, + +retrySendDMOperation: ( + messageID: string, + localMessageInfo: LocalMessageInfo, + ) => Promise, }; class FailedSend extends React.PureComponent { retryingText = false; @@ -106,6 +113,17 @@ return; } this.retryingText = true; + if (threadTypeIsThick(this.props.threadInfo.type)) { + const failedMessageID = this.props.rawMessageInfo.id; + invariant(failedMessageID, 'failedMessageID should be set for DMs'); + const localMessageInfo = this.props.item.localMessageInfo; + invariant( + localMessageInfo, + 'localMessageInfo should be set for failed message', + ); + void this.props.retrySendDMOperation(failedMessageID, localMessageInfo); + return; + } void inputState.sendTextMessage( { ...rawMessageInfo, @@ -149,12 +167,15 @@ const parentThreadInfo = useSelector(state => parentThreadID ? threadInfoSelector(state)[parentThreadID] : null, ); + const retrySendDMOperation = useRetrySendDMOperation(); + return ( ); });