diff --git a/lib/reducers/message-reducer.test.js b/lib/reducers/message-reducer.test.js --- a/lib/reducers/message-reducer.test.js +++ b/lib/reducers/message-reducer.test.js @@ -220,6 +220,7 @@ extras: '{"dimensions":{"width":1920,"height":1440},"loop":false}', }, ], + target_message_id: null, }, { id: 'local10', @@ -240,6 +241,7 @@ '{"dimensions":{"height":3024,"width":4032},"loop":false,"local_media_selection":{"step":"photo_library","dimensions":{"height":3024,"width":4032},"uri":"assets-library://asset/asset.heic?id=CC95F08C-88C3-4012-9D6D-64A413D254B3&ext=heic","filename":"IMG_0006.HEIC","mediaNativeID":"CC95F08C-88C3-4012-9D6D-64A413D254B3/L0/001","selectTime":1658172650370,"sendTime":1658172650370,"retries":0}}', }, ], + target_message_id: null, }, { id: 'local11', @@ -268,6 +270,7 @@ '{"dimensions":{"height":2002,"width":3000},"loop":false,"local_media_selection":{"step":"photo_library","dimensions":{"height":2002,"width":3000},"uri":"assets-library://asset/asset.jpg?id=ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED&ext=jpg","filename":"IMG_0005.JPG","mediaNativeID":"ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED/L0/001","selectTime":1658172656826,"sendTime":1658172656826,"retries":0}}', }, ], + target_message_id: null, }, ]; diff --git a/lib/shared/messages/message-specs.js b/lib/shared/messages/message-specs.js --- a/lib/shared/messages/message-specs.js +++ b/lib/shared/messages/message-specs.js @@ -14,6 +14,7 @@ import { leaveThreadMessageSpec } from './leave-thread-message-spec'; import { type MessageSpec } from './message-spec'; import { multimediaMessageSpec } from './multimedia-message-spec'; +import { reactionMessageSpec } from './reaction-message-spec'; import { removeMembersMessageSpec } from './remove-members-message-spec'; import { restoreEntryMessageSpec } from './restore-entry-message-spec'; import { sidebarSourceMessageSpec } from './sidebar-source-message-spec'; @@ -43,4 +44,5 @@ [messageTypes.UPDATE_RELATIONSHIP]: updateRelationshipMessageSpec, [messageTypes.SIDEBAR_SOURCE]: sidebarSourceMessageSpec, [messageTypes.CREATE_SIDEBAR]: createSidebarMessageSpec, + [messageTypes.REACTION]: reactionMessageSpec, }); diff --git a/lib/shared/messages/reaction-message-spec.js b/lib/shared/messages/reaction-message-spec.js new file mode 100644 --- /dev/null +++ b/lib/shared/messages/reaction-message-spec.js @@ -0,0 +1,89 @@ +// @flow + +import invariant from 'invariant'; + +import { + assertMessageType, + messageTypes, + type ClientDBMessageInfo, + type ReactionMessageData, + type RawReactionMessageInfo, + type ReactionMessageInfo, +} from '../../types/message-types'; +import type { RelativeUserInfo } from '../../types/user-types'; +import { messagePreviewText, removeCreatorAsViewer } from '../message-utils'; +import type { MessageSpec, MessageTitleParam } from './message-spec'; + +export const reactionMessageSpec: MessageSpec< + ReactionMessageData, + RawReactionMessageInfo, + ReactionMessageInfo, +> = Object.freeze({ + messageContentForClientDB(data: RawReactionMessageInfo): string { + return JSON.stringify({ + reaction: data.reaction, + action: data.action, + }); + }, + + messageTitle({ + messageInfo, + threadInfo, + viewerContext, + }: MessageTitleParam) { + let validMessageInfo: ReactionMessageInfo = (messageInfo: ReactionMessageInfo); + if (viewerContext === 'global_viewer') { + validMessageInfo = removeCreatorAsViewer(validMessageInfo); + } + return messagePreviewText(validMessageInfo, threadInfo); + }, + + rawMessageInfoFromClientDB( + clientDBMessageInfo: ClientDBMessageInfo, + ): RawReactionMessageInfo { + const messageType = assertMessageType(parseInt(clientDBMessageInfo.type)); + invariant( + messageType === messageTypes.REACTION, + 'message must be of type REACTION', + ); + invariant( + clientDBMessageInfo.content !== undefined && + clientDBMessageInfo.content !== null && + clientDBMessageInfo.target_message_id !== undefined && + clientDBMessageInfo.target_message_id !== null, + 'content AND target_message_id must be defined', + ); + const content = JSON.parse(clientDBMessageInfo.content); + + const rawReactionMessageInfo: RawReactionMessageInfo = { + type: messageTypes.REACTION, + id: clientDBMessageInfo.id, + threadID: clientDBMessageInfo.thread, + time: parseInt(clientDBMessageInfo.time), + creatorID: clientDBMessageInfo.user, + targetMessageID: clientDBMessageInfo.target_message_id ?? '', + reaction: content.reaction, + action: content.action, + }; + + return rawReactionMessageInfo; + }, + + createMessageInfo( + rawMessageInfo: RawReactionMessageInfo, + creator: RelativeUserInfo, + ): ReactionMessageInfo { + return { + type: messageTypes.REACTION, + id: rawMessageInfo.id, + threadID: rawMessageInfo.threadID, + creator, + time: rawMessageInfo.time, + targetMessageID: rawMessageInfo.targetMessageID, + reaction: rawMessageInfo.reaction, + action: rawMessageInfo.action, + }; + }, + + generatesNotifs: false, +}); diff --git a/lib/types/message-types.js b/lib/types/message-types.js --- a/lib/types/message-types.js +++ b/lib/types/message-types.js @@ -411,6 +411,7 @@ +content: ?string, +time: string, +media_infos: ?$ReadOnlyArray, + +target_message_id: ?string, }; export type ClientDBReplaceMessageOperation = { diff --git a/lib/utils/message-ops-utils.js b/lib/utils/message-ops-utils.js --- a/lib/utils/message-ops-utils.js +++ b/lib/utils/message-ops-utils.js @@ -159,6 +159,10 @@ rawMessageInfo.type === messageTypes.MULTIMEDIA ? translateMediaToClientDBMediaInfos(rawMessageInfo.media) : null, + target_message_id: + rawMessageInfo.type === messageTypes.REACTION + ? rawMessageInfo.targetMessageID.toString() + : null, }; } diff --git a/lib/utils/message-ops-utils.test.js b/lib/utils/message-ops-utils.test.js --- a/lib/utils/message-ops-utils.test.js +++ b/lib/utils/message-ops-utils.test.js @@ -412,6 +412,7 @@ extras: '{"dimensions":{"height":1010,"width":576},"loop":false}', }, ], + target_message_id: null, }; const rawMessageInfo = { type: 15,