diff --git a/lib/hooks/search-sidebars.js b/lib/hooks/search-sidebars.js deleted file mode 100644 --- a/lib/hooks/search-sidebars.js +++ /dev/null @@ -1,97 +0,0 @@ -// @flow - -import * as React from 'react'; - -import { sidebarInfoSelector } from '../selectors/thread-selectors'; -import SearchIndex from '../shared/search-index'; -import { threadSearchText } from '../shared/thread-utils'; -import type { SetState } from '../types/hook-types'; -import type { SidebarInfo, ThreadInfo } from '../types/thread-types'; -import { useSelector } from '../utils/redux-utils'; - -type SidebarSearchState = { - +text: string, - +results: $ReadOnlySet, -}; - -function useSearchSidebars( - threadInfo: ThreadInfo, -): { - +listData: $ReadOnlyArray, - +searchState: SidebarSearchState, - +setSearchState: SetState, - +onChangeSearchInputText: (text: string) => mixed, - +clearQuery: (event: SyntheticEvent) => void, -} { - const [searchState, setSearchState] = React.useState({ - text: '', - results: new Set(), - }); - - const userInfos = useSelector(state => state.userStore.userInfos); - - const sidebarInfos = useSelector( - state => sidebarInfoSelector(state)[threadInfo.id] ?? [], - ); - - const listData = React.useMemo(() => { - if (!searchState.text) { - return sidebarInfos; - } - return sidebarInfos.filter(sidebarInfo => - searchState.results.has(sidebarInfo.threadInfo.id), - ); - }, [sidebarInfos, searchState]); - - const viewerID = useSelector( - state => state.currentUserInfo && state.currentUserInfo.id, - ); - const searchIndex = React.useMemo(() => { - const index = new SearchIndex(); - for (const sidebarInfo of sidebarInfos) { - const threadInfoFromSidebarInfo = sidebarInfo.threadInfo; - index.addEntry( - threadInfoFromSidebarInfo.id, - threadSearchText(threadInfoFromSidebarInfo, userInfos, viewerID), - ); - } - return index; - }, [sidebarInfos, userInfos, viewerID]); - - const onChangeSearchInputText = React.useCallback( - (text: string) => { - setSearchState({ - text, - results: new Set(searchIndex.getSearchResults(text)), - }); - }, - [searchIndex, setSearchState], - ); - - const clearQuery = React.useCallback( - (event: SyntheticEvent) => { - event.preventDefault(); - setSearchState({ text: '', results: new Set() }); - }, - [setSearchState], - ); - - return React.useMemo( - () => ({ - listData, - searchState, - setSearchState, - onChangeSearchInputText, - clearQuery, - }), - [ - listData, - setSearchState, - searchState, - onChangeSearchInputText, - clearQuery, - ], - ); -} - -export { useSearchSidebars }; diff --git a/lib/hooks/search-threads.js b/lib/hooks/search-threads.js new file mode 100644 --- /dev/null +++ b/lib/hooks/search-threads.js @@ -0,0 +1,132 @@ +// @flow + +import * as React from 'react'; + +import type { ChatThreadItem } from '../selectors/chat-selectors'; +import { useFilteredChatListData } from '../selectors/chat-selectors'; +import { sidebarInfoSelector } from '../selectors/thread-selectors'; +import SearchIndex from '../shared/search-index'; +import { threadSearchText } from '../shared/thread-utils'; +import type { SetState } from '../types/hook-types'; +import type { + SidebarInfo, + ThreadInfo, + RawThreadInfo, +} from '../types/thread-types'; +import { threadTypes } from '../types/thread-types'; +import { useSelector } from '../utils/redux-utils'; + +export type ThreadSearchState = { + +text: string, + +results: $ReadOnlySet, +}; + +function useSearchThreads( + threadInfo: ThreadInfo, + childThreadInfos: $ReadOnlyArray, +): { + +listData: $ReadOnlyArray, + +searchState: ThreadSearchState, + +setSearchState: SetState, + +onChangeSearchInputText: (text: string) => mixed, + +clearQuery: (event: SyntheticEvent) => void, +} { + const [searchState, setSearchState] = React.useState({ + text: '', + results: new Set(), + }); + + const userInfos = useSelector(state => state.userStore.userInfos); + + const listData = React.useMemo(() => { + if (!searchState.text) { + return childThreadInfos; + } + return childThreadInfos.filter(thread => + searchState.results.has(thread.threadInfo.id), + ); + }, [childThreadInfos, searchState]); + + const viewerID = useSelector( + state => state.currentUserInfo && state.currentUserInfo.id, + ); + const searchIndex = React.useMemo(() => { + const index = new SearchIndex(); + for (const thread of childThreadInfos) { + const threadInfoFromItem = thread.threadInfo; + index.addEntry( + threadInfoFromItem.id, + threadSearchText(threadInfoFromItem, userInfos, viewerID), + ); + } + return index; + }, [childThreadInfos, userInfos, viewerID]); + + const onChangeSearchInputText = React.useCallback( + (text: string) => { + setSearchState({ + text, + results: new Set(searchIndex.getSearchResults(text)), + }); + }, + [searchIndex, setSearchState], + ); + + const clearQuery = React.useCallback( + (event: SyntheticEvent) => { + event.preventDefault(); + setSearchState({ text: '', results: new Set() }); + }, + [setSearchState], + ); + + return React.useMemo( + () => ({ + listData, + searchState, + setSearchState, + onChangeSearchInputText, + clearQuery, + }), + [ + listData, + setSearchState, + searchState, + onChangeSearchInputText, + clearQuery, + ], + ); +} + +function useSearchSidebars( + threadInfo: ThreadInfo, +): { + +listData: $ReadOnlyArray, + +searchState: ThreadSearchState, + +setSearchState: SetState, + +onChangeSearchInputText: (text: string) => mixed, + +clearQuery: (event: SyntheticEvent) => void, +} { + const childThreadInfos = + useSelector(sidebarInfoSelector)[threadInfo.id] ?? []; + return useSearchThreads(threadInfo, childThreadInfos); +} + +function useSearchSubchannels( + threadInfo: ThreadInfo, +): { + +listData: $ReadOnlyArray, + +searchState: ThreadSearchState, + +setSearchState: SetState, + +onChangeSearchInputText: (text: string) => mixed, + +clearQuery: (event: SyntheticEvent) => void, +} { + const childThreadInfos = useFilteredChatListData( + (thread: ?(ThreadInfo | RawThreadInfo)) => + thread?.type !== threadTypes.SIDEBAR && + thread?.parentThreadID === threadInfo.id, + ); + return useSearchThreads(threadInfo, childThreadInfos); +} + +export { useSearchSubchannels, useSearchSidebars }; diff --git a/native/chat/sidebar-list-modal.react.js b/native/chat/sidebar-list-modal.react.js --- a/native/chat/sidebar-list-modal.react.js +++ b/native/chat/sidebar-list-modal.react.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { TextInput, FlatList, View } from 'react-native'; -import { useSearchSidebars } from 'lib/hooks/search-sidebars'; +import { useSearchSidebars } from 'lib/hooks/search-threads'; import type { ThreadInfo, SidebarInfo } from 'lib/types/thread-types'; import ExtendedArrow from '../components/arrow-extended.react';