diff --git a/web/modals/search/message-search-modal.react.js b/web/modals/search/message-search-modal.react.js --- a/web/modals/search/message-search-modal.react.js +++ b/web/modals/search/message-search-modal.react.js @@ -3,26 +3,19 @@ import * as React from 'react'; import { useModalContext } from 'lib/components/modal-provider.react.js'; -import { - type ChatMessageItem, - messageListData, -} from 'lib/selectors/chat-selectors.js'; -import { - createMessageInfo, - modifyItemForResultScreen, -} from 'lib/shared/message-utils.js'; +import { type ChatMessageItem } from 'lib/selectors/chat-selectors.js'; import { useSearchMessages } from 'lib/shared/search-utils.js'; import type { RawMessageInfo } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/thread-types.js'; import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js'; import css from './message-search-modal.css'; +import { useParseSearchResults } from './message-search-utils.react.js'; import { useTooltipContext } from '../../chat/tooltip-provider.js'; import Button from '../../components/button.react.js'; import MessageResult from '../../components/message-result.react.js'; import Search from '../../components/search.react.js'; import LoadingIndicator from '../../loading-indicator.react.js'; -import { useSelector } from '../../redux/redux-utils.js'; import { useMessageSearchContext } from '../../search/message-search-state-provider.react.js'; import Modal from '../modal.react.js'; @@ -59,54 +52,7 @@ [appendSearchResults, lastID, query, searchMessages, threadInfo.id], ); - const userInfos = useSelector(state => state.userStore.userInfos); - - const translatedSearchResults = React.useMemo(() => { - const threadInfos = { [threadInfo.id]: threadInfo }; - return searchResults - .map(rawMessageInfo => - createMessageInfo(rawMessageInfo, null, userInfos, threadInfos), - ) - .filter(Boolean); - }, [searchResults, threadInfo, userInfos]); - - const chatMessageInfos = useSelector( - messageListData(threadInfo.id, translatedSearchResults), - ); - - const filteredChatMessageInfos = React.useMemo(() => { - if (!chatMessageInfos) { - return []; - } - - const idSet = new Set(translatedSearchResults.map(item => item.id)); - - const chatMessageInfoItems = chatMessageInfos.filter( - item => item.messageInfo && idSet.has(item.messageInfo.id), - ); - - const uniqueChatMessageInfoItemsMap = new Map(); - chatMessageInfoItems.forEach( - item => - item.messageInfo && - item.messageInfo.id && - uniqueChatMessageInfoItemsMap.set(item.messageInfo.id, item), - ); - - const sortedChatMessageInfoItems = []; - for (let i = 0; i < translatedSearchResults.length; i++) { - sortedChatMessageInfoItems.push( - uniqueChatMessageInfoItemsMap.get(translatedSearchResults[i].id), - ); - } - - return sortedChatMessageInfoItems.filter(Boolean); - }, [chatMessageInfos, translatedSearchResults]); - - const modifiedItems = React.useMemo( - () => filteredChatMessageInfos.map(item => modifyItemForResultScreen(item)), - [filteredChatMessageInfos], - ); + const modifiedItems = useParseSearchResults(threadInfo, searchResults); const renderItem = React.useCallback( item => ( diff --git a/web/modals/search/message-search-utils.react.js b/web/modals/search/message-search-utils.react.js new file mode 100644 --- /dev/null +++ b/web/modals/search/message-search-utils.react.js @@ -0,0 +1,70 @@ +// @flow + +import * as React from 'react'; + +import { type ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; +import { messageListData } from 'lib/selectors/chat-selectors.js'; +import { + createMessageInfo, + modifyItemForResultScreen, +} from 'lib/shared/message-utils.js'; +import type { RawMessageInfo } from 'lib/types/message-types.js'; +import type { ThreadInfo } from 'lib/types/thread-types.js'; + +import { useSelector } from '../../redux/redux-utils.js'; + +function useParseSearchResults( + threadInfo: ThreadInfo, + searchResults: $ReadOnlyArray, +): $ReadOnlyArray { + const userInfos = useSelector(state => state.userStore.userInfos); + + const translatedSearchResults = React.useMemo(() => { + const threadInfos = { [threadInfo.id]: threadInfo }; + return searchResults + .map(rawMessageInfo => + createMessageInfo(rawMessageInfo, null, userInfos, threadInfos), + ) + .filter(Boolean); + }, [searchResults, threadInfo, userInfos]); + + const chatMessageInfos = useSelector( + messageListData(threadInfo.id, translatedSearchResults), + ); + + const filteredChatMessageInfos = React.useMemo(() => { + if (!chatMessageInfos) { + return []; + } + + const idSet = new Set(translatedSearchResults.map(item => item.id)); + + const chatMessageInfoItems = chatMessageInfos.filter( + item => item.messageInfo && idSet.has(item.messageInfo.id), + ); + + const uniqueChatMessageInfoItemsMap = new Map(); + chatMessageInfoItems.forEach( + item => + item.messageInfo && + item.messageInfo.id && + uniqueChatMessageInfoItemsMap.set(item.messageInfo.id, item), + ); + + const sortedChatMessageInfoItems = []; + for (let i = 0; i < translatedSearchResults.length; i++) { + sortedChatMessageInfoItems.push( + uniqueChatMessageInfoItemsMap.get(translatedSearchResults[i].id), + ); + } + + return sortedChatMessageInfoItems.filter(Boolean); + }, [chatMessageInfos, translatedSearchResults]); + + return React.useMemo( + () => filteredChatMessageInfos.map(item => modifyItemForResultScreen(item)), + [filteredChatMessageInfos], + ); +} + +export { useParseSearchResults };