mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
|
import useSWRInfinite, { SWRInfiniteKeyLoader } from 'swr/infinite';
|
|
|
|
import { getSearchResults } from '~/api/flow';
|
|
import { INode } from '~/types';
|
|
import { GetSearchResultsRequest } from '~/types/flow';
|
|
import { flatten } from '~/utils/ramda';
|
|
|
|
const RESULTS_COUNT = 20;
|
|
|
|
const getKey: (text: string) => SWRInfiniteKeyLoader = text => (
|
|
pageIndex,
|
|
previousPageData: INode[]
|
|
) => {
|
|
if ((pageIndex > 0 && !previousPageData?.length) || !text) return null;
|
|
|
|
const props: GetSearchResultsRequest = {
|
|
text,
|
|
skip: pageIndex * RESULTS_COUNT,
|
|
take: RESULTS_COUNT,
|
|
};
|
|
|
|
return JSON.stringify(props);
|
|
};
|
|
|
|
export const useSearch = () => {
|
|
const [searchText, setSearchText] = useState('');
|
|
const [debouncedSearchText, setDebouncedSearchText] = useState('');
|
|
|
|
const { data, size, setSize, mutate, isValidating } = useSWRInfinite(
|
|
getKey(debouncedSearchText),
|
|
async (key: string) => {
|
|
const props: GetSearchResultsRequest = key && JSON.parse(key);
|
|
|
|
if (!props) {
|
|
return [] as INode[];
|
|
}
|
|
|
|
const result = await getSearchResults(props);
|
|
|
|
return result.nodes;
|
|
}
|
|
);
|
|
|
|
const loadMore = useCallback(() => setSize(size + 1), [setSize, size]);
|
|
const hasMore = (data?.[size - 1]?.length || 0) >= RESULTS_COUNT;
|
|
|
|
const results = useMemo(() => flatten(data || []), [data]);
|
|
|
|
useEffect(() => {
|
|
const timeout = setTimeout(async () => {
|
|
setDebouncedSearchText(searchText.length > 2 ? searchText : '');
|
|
await setSize(0);
|
|
await mutate([]);
|
|
}, 300);
|
|
|
|
return () => clearTimeout(timeout);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [searchText]);
|
|
|
|
return {
|
|
results,
|
|
searchText,
|
|
setSearchText,
|
|
hasMore,
|
|
loadMore,
|
|
isLoading: isValidating,
|
|
};
|
|
};
|