Changeset View
Changeset View
Standalone View
Standalone View
lib/hooks/search-sidebars.js
// @flow | // @flow | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { sidebarInfoSelector } from '../selectors/thread-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 { SetState } from '../types/hook-types'; | ||||
import type { SidebarInfo, ThreadInfo } from '../types/thread-types'; | import type { SidebarInfo, ThreadInfo } from '../types/thread-types'; | ||||
import { useSelector } from '../utils/redux-utils'; | import { useSelector } from '../utils/redux-utils'; | ||||
type SidebarSearchState = { | type SidebarSearchState = { | ||||
+text: string, | +text: string, | ||||
+results: $ReadOnlySet<string>, | +results: $ReadOnlySet<string>, | ||||
}; | }; | ||||
function useSearchSidebars( | function useSearchSidebars( | ||||
threadInfo: ThreadInfo, | threadInfo: ThreadInfo, | ||||
): { | ): { | ||||
+listData: $ReadOnlyArray<SidebarInfo>, | +listData: $ReadOnlyArray<SidebarInfo>, | ||||
+searchState: SidebarSearchState, | +searchState: SidebarSearchState, | ||||
+setSearchState: SetState<SidebarSearchState>, | +setSearchState: SetState<SidebarSearchState>, | ||||
+searchIndex: SearchIndex, | |||||
} { | } { | ||||
const [searchState, setSearchState] = React.useState({ | const [searchState, setSearchState] = React.useState({ | ||||
text: '', | text: '', | ||||
results: new Set<string>(), | results: new Set<string>(), | ||||
}); | }); | ||||
const userInfos = useSelector(state => state.userStore.userInfos); | |||||
const sidebarInfos = useSelector( | const sidebarInfos = useSelector( | ||||
state => sidebarInfoSelector(state)[threadInfo.id] ?? [], | state => sidebarInfoSelector(state)[threadInfo.id] ?? [], | ||||
); | ); | ||||
const listData = React.useMemo(() => { | const listData = React.useMemo(() => { | ||||
if (!searchState.text) { | if (!searchState.text) { | ||||
return sidebarInfos; | return sidebarInfos; | ||||
} | } | ||||
return sidebarInfos.filter(sidebarInfo => | return sidebarInfos.filter(sidebarInfo => | ||||
searchState.results.has(sidebarInfo.threadInfo.id), | searchState.results.has(sidebarInfo.threadInfo.id), | ||||
); | ); | ||||
}, [sidebarInfos, searchState]); | }, [sidebarInfos, searchState]); | ||||
return React.useMemo(() => ({ listData, searchState, setSearchState }), [ | const viewerID = useSelector( | ||||
listData, | state => state.currentUserInfo && state.currentUserInfo.id, | ||||
setSearchState, | ); | ||||
searchState, | 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]); | |||||
React.useEffect(() => { | |||||
setSearchState(curState => ({ | |||||
...curState, | |||||
results: new Set(searchIndex.getSearchResults(curState.text)), | |||||
})); | |||||
}, [searchIndex, setSearchState]); | |||||
return React.useMemo( | |||||
() => ({ listData, searchState, setSearchState, searchIndex }), | |||||
[listData, setSearchState, searchState, searchIndex], | |||||
); | |||||
} | } | ||||
export { useSearchSidebars }; | export { useSearchSidebars }; |