diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -1337,6 +1337,30 @@ return chatItems; } +function reorderThreadSearchResults( + threadInfos: $ReadOnlyArray, + threadSearchResults: $ReadOnlyArray, +): T[] { + const privateThreads = []; + const personalThreads = []; + const otherThreads = []; + const threadSearchResultsSet = new Set(threadSearchResults); + for (const threadInfo of threadInfos) { + if (!threadSearchResultsSet.has(threadInfo.id)) { + continue; + } + if (threadInfo.type === threadTypes.PRIVATE) { + privateThreads.push(threadInfo); + } else if (threadInfo.type === threadTypes.PERSONAL) { + personalThreads.push(threadInfo); + } else { + otherThreads.push(threadInfo); + } + } + + return [...privateThreads, ...personalThreads, ...otherThreads]; +} + function useAvailableThreadMemberActions( memberInfo: RelativeMemberInfo, threadInfo: ThreadInfo, @@ -1663,6 +1687,7 @@ getContainingThreadID, getCommunity, getThreadListSearchResults, + reorderThreadSearchResults, useAvailableThreadMemberActions, threadMembersWithoutAddedAdmin, patchThreadInfoToIncludeMentionedMembersOfParent, diff --git a/native/components/thread-list.react.js b/native/components/thread-list.react.js --- a/native/components/thread-list.react.js +++ b/native/components/thread-list.react.js @@ -6,6 +6,7 @@ import { createSelector } from 'reselect'; import SearchIndex from 'lib/shared/search-index.js'; +import { reorderThreadSearchResults } from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import Search from './search.react.js'; @@ -39,13 +40,13 @@ }; type State = { +searchText: string, - +searchResults: Set, + +searchResults: $ReadOnlyArray, }; type PropsAndState = { ...Props, ...State }; class ThreadList extends React.PureComponent { state: State = { searchText: '', - searchResults: new Set(), + searchResults: [], }; textInput: ?React.ElementRef; @@ -59,13 +60,11 @@ ( threadInfos: $ReadOnlyArray, text: string, - searchResults: Set, + searchResults: $ReadOnlyArray, ): $ReadOnlyArray => - text - ? threadInfos.filter(threadInfo => searchResults.has(threadInfo.id)) - : // We spread to make sure the result of this selector updates when - // any input param (namely itemStyle or itemTextStyle) changes - [...threadInfos], + // We spread to make sure the result of this selector updates when + // any input param (namely itemStyle or itemTextStyle) changes + text ? [...searchResults] : [...threadInfos], ); get listData(): $ReadOnlyArray { @@ -126,7 +125,11 @@ onChangeSearchText = (searchText: string) => { invariant(this.props.searchIndex, 'should be set'); const results = this.props.searchIndex.getSearchResults(searchText); - this.setState({ searchText, searchResults: new Set(results) }); + const threadInfoResults = reorderThreadSearchResults( + this.props.threadInfos, + results, + ); + this.setState({ searchText, searchResults: threadInfoResults }); }; searchRef = async (textInput: ?React.ElementRef) => { diff --git a/web/modals/threads/thread-picker-modal.react.js b/web/modals/threads/thread-picker-modal.react.js --- a/web/modals/threads/thread-picker-modal.react.js +++ b/web/modals/threads/thread-picker-modal.react.js @@ -4,7 +4,10 @@ import * as React from 'react'; import { useGlobalThreadSearchIndex } from 'lib/selectors/nav-selectors.js'; -import { useOnScreenEntryEditableThreadInfos } from 'lib/shared/thread-utils.js'; +import { + useOnScreenEntryEditableThreadInfos, + reorderThreadSearchResults, +} from 'lib/shared/thread-utils.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js'; @@ -60,9 +63,9 @@ ); const [searchText, setSearchText] = React.useState(''); - const [searchResults, setSearchResults] = React.useState>( - new Set(), - ); + const [searchResults, setSearchResults] = React.useState< + $ReadOnlyArray, + >([]); const searchRef = React.useRef(); @@ -74,16 +77,17 @@ (text: string) => { const results = searchIndex.getSearchResults(text); setSearchText(text); - setSearchResults(new Set(results)); + const threadInfoResults = reorderThreadSearchResults( + onScreenThreadInfos, + results, + ); + setSearchResults(threadInfoResults); }, - [searchIndex], + [searchIndex, onScreenThreadInfos], ); const threads = React.useMemo( - () => - searchText - ? onScreenThreadInfos.filter(thread => searchResults.has(thread.id)) - : onScreenThreadInfos, + () => (searchText ? searchResults : onScreenThreadInfos), [searchText, onScreenThreadInfos, searchResults], );