diff --git a/web/search/message-search-state-provider.react.js b/web/search/message-search-state-provider.react.js --- a/web/search/message-search-state-provider.react.js +++ b/web/search/message-search-state-provider.react.js @@ -3,10 +3,19 @@ import invariant from 'invariant'; import * as React from 'react'; +import type { RawMessageInfo } from 'lib/types/message-types.js'; + type MessageSearchState = { +getQuery: (threadID: string) => string, +setQuery: (query: string, threadID: string) => void, +clearQuery: (threadID: string) => void, + +getSearchResults: (threadID: string) => $ReadOnlyArray, + +appendSearchResult: ( + $ReadOnlyArray, + threadID: string, + ) => void, + +getEndReached: (threadID: string) => boolean, + +setEndReached: (threadID: string) => void, }; const MessageSearchContext: React.Context = @@ -17,28 +26,82 @@ }; function MessageSearchStateProvider(props: Props): React.Node { - const [queries, setQueries] = React.useState<{ + const queries = React.useRef<{ [threadID: string]: string, }>({}); - const setQuery = React.useCallback( - (query: string, threadID: string) => - setQueries(prevQueries => ({ ...prevQueries, [threadID]: query })), + const [results, setResults] = React.useState<{ + [threadID: string]: $ReadOnlyArray, + }>({}); + + const [endsReached, setEndsReached] = React.useState(new Set()); + + const setEndReached = React.useCallback( + (threadID: string) => + setEndsReached(ends => new Set([...ends.values(), threadID])), [], ); - const clearQuery = React.useCallback( + const removeEndReached = React.useCallback( (threadID: string) => - setQueries(prevQueries => { - const { [threadID]: deleted, ...newState } = prevQueries; - return newState; + setEndsReached(ends => { + const temp = new Set(ends); + temp.delete(threadID); + return temp; }), [], ); + const getEndReached = React.useCallback( + (threadID: string) => endsReached.has(threadID), + [endsReached], + ); + + const appendResult = React.useCallback( + (result: $ReadOnlyArray, threadID: string) => + setResults(prevResults => { + const prevThreadResults = prevResults[threadID] ?? []; + const newThreadResults = [...prevThreadResults, ...result]; + return { ...prevResults, [threadID]: newThreadResults }; + }), + [], + ); + + const clearResults = React.useCallback( + (threadID: string) => { + removeEndReached(threadID); + setResults(prevResults => { + const { [threadID]: deleted, ...newState } = prevResults; + return newState; + }); + }, + [removeEndReached], + ); + + const getResults = React.useCallback( + (threadID: string) => results[threadID] ?? [], + [results], + ); + const getQuery = React.useCallback( - (threadID: string) => queries[threadID] ?? '', - [queries], + (threadID: string) => queries.current[threadID] ?? '', + [], + ); + + const setQuery = React.useCallback( + (query: string, threadID: string) => { + clearResults(threadID); + queries.current = { ...queries.current, [threadID]: query }; + }, + [clearResults], + ); + + const clearQuery = React.useCallback( + (threadID: string) => { + clearResults(threadID); + delete queries.current[threadID]; + }, + [clearResults], ); const state = React.useMemo( @@ -46,8 +109,20 @@ getQuery, setQuery, clearQuery, + getSearchResults: getResults, + appendSearchResult: appendResult, + getEndReached, + setEndReached, }), - [getQuery, setQuery, clearQuery], + [ + getQuery, + setQuery, + clearQuery, + getResults, + appendResult, + getEndReached, + setEndReached, + ], ); return (