diff --git a/lib/shared/chat-message-item-utils.js b/lib/shared/chat-message-item-utils.js --- a/lib/shared/chat-message-item-utils.js +++ b/lib/shared/chat-message-item-utils.js @@ -1,9 +1,40 @@ // @flow +import { messageKey } from './message-utils.js'; import type { ReactionInfo } from '../selectors/chat-selectors.js'; import { getMessageLabel } from '../shared/edit-messages-utils.js'; +import type { + RobotextMessageInfo, + ComposableMessageInfo, +} from '../types/message-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; +type ChatMessageItemMessageInfo = ComposableMessageInfo | RobotextMessageInfo; + +// This complicated type matches both ChatMessageItem and +// ChatMessageItemWithHeight, and is a disjoint union of types +type BaseChatMessageInfoItem = { + +itemType: 'message', + +messageInfo: ChatMessageItemMessageInfo, + +messageInfos?: ?void, + ... +}; +type BaseChatMessageItem = + | BaseChatMessageInfoItem + | { + +itemType: 'loader', + +messageInfo?: ?void, + +messageInfos?: ?void, + ... + }; + +function chatMessageItemKey(item: BaseChatMessageItem): string { + if (item.itemType === 'loader') { + return 'loader'; + } + return messageKey(item.messageInfo); +} + type BaseChatMessageItemForEngagementCheck = { +threadCreatedFromMessage: ?ThreadInfo, +reactions: ReactionInfo, @@ -22,4 +53,4 @@ ); } -export { chatMessageItemHasEngagement }; +export { chatMessageItemKey, chatMessageItemHasEngagement }; diff --git a/native/chat/chat-item-height-measurer.react.js b/native/chat/chat-item-height-measurer.react.js --- a/native/chat/chat-item-height-measurer.react.js +++ b/native/chat/chat-item-height-measurer.react.js @@ -3,6 +3,7 @@ import invariant from 'invariant'; import * as React from 'react'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; import { getMessageLabel } from 'lib/shared/edit-messages-utils.js'; import { getInlineEngagementSidebarText, @@ -23,7 +24,6 @@ import type { NativeChatMessageItem } from './message-data.react.js'; import { MessageListContextProvider } from './message-list-types.js'; import { multimediaMessageContentSizes } from './multimedia-message-utils.js'; -import { chatMessageItemKey } from './utils.js'; import NodeHeightMeasurer from '../components/node-height-measurer.react.js'; import { InputStateContext } from '../input/input-state.js'; diff --git a/native/chat/chat-list.react.js b/native/chat/chat-list.react.js --- a/native/chat/chat-list.react.js +++ b/native/chat/chat-list.react.js @@ -18,11 +18,12 @@ } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; import { localIDPrefix } from 'lib/shared/message-utils.js'; import type { ChatNavigationProp } from './chat.react.js'; import NewMessagesPill from './new-messages-pill.react.js'; -import { chatMessageItemHeight, chatMessageItemKey } from './utils.js'; +import { chatMessageItemHeight } from './utils.js'; import { InputStateContext } from '../input/input-state.js'; import type { InputState } from '../input/input-state.js'; import { diff --git a/native/chat/message-list.react.js b/native/chat/message-list.react.js --- a/native/chat/message-list.react.js +++ b/native/chat/message-list.react.js @@ -6,7 +6,8 @@ import { TouchableWithoutFeedback, View } from 'react-native'; import { createSelector } from 'reselect'; -import { messageKey, useFetchMessages } from 'lib/shared/message-utils.js'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; +import { useFetchMessages } from 'lib/shared/message-utils.js'; import { useWatchThread } from 'lib/shared/watch-thread-utils.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { threadTypeIsPersonal } from 'lib/types/thread-types-enum.js'; @@ -165,8 +166,7 @@ const messageInfoItem: ChatMessageInfoItemWithHeight = row.item; const { messageListVerticalBounds, focusedMessageKey, navigation, route } = this.flatListExtraData; - const focused = - messageKey(messageInfoItem.messageInfo) === focusedMessageKey; + const focused = chatMessageItemKey(messageInfoItem) === focusedMessageKey; return ( { const didDismiss = keyboardState && keyboardState.dismissKeyboardIfShowing(); @@ -181,7 +183,7 @@ } if (!focused) { - toggleFocus(messageKey(item.messageInfo)); + toggleFocus(key); } invariant(overlayContext, 'RobotextMessage should have OverlayContext'); @@ -189,7 +191,7 @@ viewRef.current?.measure(openRobotextTooltipModal); }, [ focused, - item, + key, keyboardState, overlayContext, toggleFocus, diff --git a/native/chat/utils.js b/native/chat/utils.js --- a/native/chat/utils.js +++ b/native/chat/utils.js @@ -6,18 +6,15 @@ import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js'; import { useThreadChatMentionCandidates } from 'lib/hooks/chat-mention-hooks.js'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; import { colorIsDark } from 'lib/shared/color-utils.js'; -import { messageKey } from 'lib/shared/message-utils.js'; import { viewerIsMember } from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { clusterEndHeight } from './chat-constants.js'; import { ChatContext, useHeightMeasurer } from './chat-context.js'; import { failedSendHeight } from './failed-send.react.js'; -import { - type NativeChatMessageItem, - useNativeMessageListData, -} from './message-data.react.js'; +import { useNativeMessageListData } from './message-data.react.js'; import { authorNameHeight } from './message-header.react.js'; import { multimediaMessageItemHeight } from './multimedia-message-utils.js'; import { getUnresolvedSidebarThreadInfo } from './sidebar-navigation.js'; @@ -312,7 +309,7 @@ } function getMessageTooltipKey(item: ChatMessageInfoItemWithHeight): string { - return `tooltip|${messageKey(item.messageInfo)}`; + return `tooltip|${chatMessageItemKey(item)}`; } function isMessageTooltipKey(key: string): boolean { @@ -383,15 +380,6 @@ ]); } -function chatMessageItemKey( - item: ChatMessageItemWithHeight | NativeChatMessageItem, -): string { - if (item.itemType === 'loader') { - return 'loader'; - } - return messageKey(item.messageInfo); -} - function modifyItemForResultScreen( item: ChatMessageInfoItemWithHeight, ): ChatMessageInfoItemWithHeight { @@ -431,7 +419,6 @@ } export { - chatMessageItemKey, chatMessageItemHeight, useAnimatedMessageTooltipButton, messageItemHeight, diff --git a/native/search/message-search.react.js b/native/search/message-search.react.js --- a/native/search/message-search.react.js +++ b/native/search/message-search.react.js @@ -6,6 +6,7 @@ import { FlatList } from 'react-native-gesture-handler'; import { messageListData } from 'lib/selectors/chat-selectors.js'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; import { createMessageInfo } from 'lib/shared/message-utils.js'; import { filterChatMessageInfosForSearch, @@ -168,7 +169,7 @@ } return ( { if (item.itemType === 'loader') { return ( @@ -186,7 +180,7 @@ item={item} threadInfo={threadInfo} shouldDisplayPinIndicator={true} - key={ChatMessageList.keyExtractor(item)} + key={chatMessageItemKey(item)} /> ); }; diff --git a/web/components/message-result.react.js b/web/components/message-result.react.js --- a/web/components/message-result.react.js +++ b/web/components/message-result.react.js @@ -55,7 +55,6 @@ item={item} threadInfo={threadInfo} shouldDisplayPinIndicator={false} - key={item.messageInfo.id} /> diff --git a/web/modals/chat/pinned-messages-modal.react.js b/web/modals/chat/pinned-messages-modal.react.js --- a/web/modals/chat/pinned-messages-modal.react.js +++ b/web/modals/chat/pinned-messages-modal.react.js @@ -12,6 +12,7 @@ messageListData, } from 'lib/selectors/chat-selectors.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; +import { chatMessageItemKey } from 'lib/shared/chat-message-item-utils.js'; import { createMessageInfo, isInvalidPinSourceForThread, @@ -136,7 +137,7 @@ const items = modifiedItems.map(item => ( (