Changeset View
Changeset View
Standalone View
Standalone View
lib/selectors/chat-selectors.js
Show First 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | | { | ||||
+messageInfo: ComposableMessageInfo, | +messageInfo: ComposableMessageInfo, | ||||
+localMessageInfo: ?LocalMessageInfo, | +localMessageInfo: ?LocalMessageInfo, | ||||
+startsConversation: boolean, | +startsConversation: boolean, | ||||
+startsCluster: boolean, | +startsCluster: boolean, | ||||
endsCluster: boolean, | endsCluster: boolean, | ||||
+threadCreatedFromMessage: ?ThreadInfo, | +threadCreatedFromMessage: ?ThreadInfo, | ||||
+reactions: ReactionInfo, | +reactions: ReactionInfo, | ||||
+hasBeenEdited: boolean, | +hasBeenEdited: boolean, | ||||
+isPinned: boolean, | |||||
}; | }; | ||||
export type ChatMessageItem = { itemType: 'loader' } | ChatMessageInfoItem; | export type ChatMessageItem = { itemType: 'loader' } | ChatMessageInfoItem; | ||||
export type ReactionInfo = { +[reaction: string]: MessageReactionInfo }; | export type ReactionInfo = { +[reaction: string]: MessageReactionInfo }; | ||||
type MessageReactionInfo = { | type MessageReactionInfo = { | ||||
+viewerReacted: boolean, | +viewerReacted: boolean, | ||||
+users: $ReadOnlyArray<RelativeUserInfo>, | +users: $ReadOnlyArray<RelativeUserInfo>, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | ): ChatMessageItem[] { | ||||
for (let i = messages.length - 1; i >= 0; i--) { | for (let i = messages.length - 1; i >= 0; i--) { | ||||
const messageInfo = messages[i]; | const messageInfo = messages[i]; | ||||
if (messageInfo.type !== messageTypes.EDIT_MESSAGE) { | if (messageInfo.type !== messageTypes.EDIT_MESSAGE) { | ||||
continue; | continue; | ||||
} | } | ||||
targetMessageEditMap.set(messageInfo.targetMessageID, messageInfo.text); | targetMessageEditMap.set(messageInfo.targetMessageID, messageInfo.text); | ||||
} | } | ||||
const targetMessagePinStatusMap = new Map<string, boolean>(); | |||||
// Once again, we iterate backwards to put the order of messages in | |||||
// chronological order (i.e. oldest to newest) to handle pinned messages. | |||||
// This is important because we want to make sure that the most recent pin | |||||
// action is the one that is used to determine whether a message | |||||
// is pinned or not. | |||||
for (let i = messages.length - 1; i >= 0; i--) { | |||||
const messageInfo = messages[i]; | |||||
if (messageInfo.type !== messageTypes.TOGGLE_PIN) { | |||||
continue; | |||||
} | |||||
targetMessagePinStatusMap.set( | |||||
messageInfo.targetMessageID, | |||||
messageInfo.action === 'pin', | |||||
); | |||||
} | |||||
const chatMessageItems = []; | const chatMessageItems = []; | ||||
let lastMessageInfo = null; | let lastMessageInfo = null; | ||||
for (let i = messages.length - 1; i >= 0; i--) { | for (let i = messages.length - 1; i >= 0; i--) { | ||||
const messageInfo = messages[i]; | const messageInfo = messages[i]; | ||||
if ( | if ( | ||||
messageInfo.type === messageTypes.REACTION || | messageInfo.type === messageTypes.REACTION || | ||||
messageInfo.type === messageTypes.EDIT_MESSAGE | messageInfo.type === messageTypes.EDIT_MESSAGE | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (startsCluster && chatMessageItems.length > 0) { | ||||
invariant(lastMessageItem.itemType === 'message', 'should be message'); | invariant(lastMessageItem.itemType === 'message', 'should be message'); | ||||
lastMessageItem.endsCluster = true; | lastMessageItem.endsCluster = true; | ||||
} | } | ||||
const threadCreatedFromMessage = | const threadCreatedFromMessage = | ||||
messageInfo.id && threadInfos[threadID]?.type !== threadTypes.SIDEBAR | messageInfo.id && threadInfos[threadID]?.type !== threadTypes.SIDEBAR | ||||
? threadInfoFromSourceMessageID[messageInfo.id] | ? threadInfoFromSourceMessageID[messageInfo.id] | ||||
: undefined; | : undefined; | ||||
const isPinned = !!( | |||||
originalMessageInfo.id && | |||||
targetMessagePinStatusMap.get(originalMessageInfo.id) | |||||
); | |||||
const renderedReactions: ReactionInfo = (() => { | const renderedReactions: ReactionInfo = (() => { | ||||
const result = {}; | const result = {}; | ||||
let messageReactsMap; | let messageReactsMap; | ||||
if (originalMessageInfo.id) { | if (originalMessageInfo.id) { | ||||
messageReactsMap = targetMessageReactionsMap.get( | messageReactsMap = targetMessageReactionsMap.get( | ||||
originalMessageInfo.id, | originalMessageInfo.id, | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (isComposableMessageType(originalMessageInfo.type)) { | ||||
messageInfo: originalMessageInfo, | messageInfo: originalMessageInfo, | ||||
localMessageInfo, | localMessageInfo, | ||||
startsConversation, | startsConversation, | ||||
startsCluster, | startsCluster, | ||||
endsCluster: false, | endsCluster: false, | ||||
threadCreatedFromMessage, | threadCreatedFromMessage, | ||||
reactions: renderedReactions, | reactions: renderedReactions, | ||||
hasBeenEdited, | hasBeenEdited, | ||||
isPinned, | |||||
}); | }); | ||||
} else { | } else { | ||||
invariant( | invariant( | ||||
originalMessageInfo.type !== messageTypes.TEXT && | originalMessageInfo.type !== messageTypes.TEXT && | ||||
originalMessageInfo.type !== messageTypes.IMAGES && | originalMessageInfo.type !== messageTypes.IMAGES && | ||||
originalMessageInfo.type !== messageTypes.MULTIMEDIA, | originalMessageInfo.type !== messageTypes.MULTIMEDIA, | ||||
"Flow doesn't understand isComposableMessageType above", | "Flow doesn't understand isComposableMessageType above", | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 134 Lines • Show Last 20 Lines |