diff --git a/ts/state/selectors/message.ts b/ts/state/selectors/message.ts index b9c09c60a..a9a9ee626 100644 --- a/ts/state/selectors/message.ts +++ b/ts/state/selectors/message.ts @@ -1070,11 +1070,14 @@ function processQuoteAttachment( } export function canReply( - message: MessageAttributesType, + message: Pick< + MessageAttributesType, + 'conversationId' | 'deletedForEveryone' | 'sent_to' | 'type' + >, conversationSelector: GetConversationByIdType ): boolean { const conversation = getConversation(message, conversationSelector); - const { delivered, errors } = message; + const { deletedForEveryone, sent_to: sentTo } = message; if (!conversation) { return false; @@ -1097,17 +1100,17 @@ export function canReply( } // We cannot reply if this message is deleted for everyone - if (message.deletedForEveryone) { + if (deletedForEveryone) { return false; } - // We can reply if this is outgoing and delivered to at least one recipient - if (isOutgoing(message) && delivered && delivered > 0) { - return true; + // We can reply if this is outgoing and sent to at least one recipient + if (isOutgoing(message)) { + return (sentTo || []).length > 0; } - // We can reply if there are no errors - if (!errors || (errors && errors.length === 0)) { + // We can reply to incoming messages + if (isIncoming(message)) { return true; } diff --git a/ts/test-electron/state/selectors/messages_test.ts b/ts/test-electron/state/selectors/messages_test.ts index 6749e6db8..e67b9c4d9 100644 --- a/ts/test-electron/state/selectors/messages_test.ts +++ b/ts/test-electron/state/selectors/messages_test.ts @@ -2,8 +2,11 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; +import { v4 as uuid } from 'uuid'; +import { ConversationType } from '../../../state/ducks/conversations'; import { + canReply, isEndSession, isGroupUpdate, isIncoming, @@ -11,6 +14,80 @@ import { } from '../../../state/selectors/message'; describe('state/selectors/messages', () => { + describe('canReply', () => { + const defaultConversation: ConversationType = { + id: uuid(), + type: 'direct', + title: 'Test conversation', + isMe: false, + sharedGroupNames: [], + acceptedMessageRequest: true, + }; + + it('returns false for disabled v1 groups', () => { + const message = { + conversationId: 'fake-conversation-id', + type: 'incoming' as const, + }; + const getConversationById = () => ({ + ...defaultConversation, + type: 'group' as const, + isGroupV1AndDisabled: true, + }); + + assert.isFalse(canReply(message, getConversationById)); + }); + + // NOTE: This is missing a test for mandatory profile sharing. + + it('returns false if the message was deleted for everyone', () => { + const message = { + conversationId: 'fake-conversation-id', + type: 'incoming' as const, + deletedForEveryone: true, + }; + const getConversationById = () => defaultConversation; + + assert.isFalse(canReply(message, getConversationById)); + }); + + it('returns false for outgoing messages that have not been sent', () => { + const message = { + conversationId: 'fake-conversation-id', + type: 'outgoing' as const, + sent_to: [], + }; + const getConversationById = () => defaultConversation; + + assert.isFalse(canReply(message, getConversationById)); + }); + + it('returns true for outgoing messages that have been delivered to at least one person', () => { + const message = { + conversationId: 'fake-conversation-id', + type: 'outgoing' as const, + receipients: [uuid(), uuid()], + sent_to: [uuid()], + }; + const getConversationById = () => ({ + ...defaultConversation, + type: 'group' as const, + }); + + assert.isTrue(canReply(message, getConversationById)); + }); + + it('returns true for incoming messages', () => { + const message = { + conversationId: 'fake-conversation-id', + type: 'incoming' as const, + }; + const getConversationById = () => defaultConversation; + + assert.isTrue(canReply(message, getConversationById)); + }); + }); + describe('isEndSession', () => { it('checks if it is end of the session', () => { assert.isFalse(isEndSession({}));