create-plume-react-project
Version:
CLI to create Plume React Project
78 lines (70 loc) • 2.89 kB
text/typescript
import { PaginatedSearch, PaginationType } from '@lib/plume-search/SearchTypes';
import { SortOption } from '@lib/plume-search/sorts/SortTypes';
import { useEffect, useState } from 'react';
import usePagination from './pagination/PaginationHook';
type SearchLoadedDataHookOptions<TData, TFilter, TSort extends string> = {
filter: {
values: Partial<TFilter>,
isElementDisplayed: (value: TData, filters: Partial<TFilter>) => boolean,
},
sort: {
value: SortOption<TSort>,
sortElement: Record<TSort, (value: TData, compared: TData, isDesc: boolean) => number>,
},
defaultPageSize: number,
};
/**
* Hook to handle search with pagination with data already loaded
* This search relies on results provided in the parameters
*
* @param data the loaded data to be paginated
* @param options options to apply to the given data
* filter : provide the filter values and the function to apply it
* sort : provide the sort object and the function to apply it
*
* @return displayedItems the elements to display
* @return totalCount total elements of the list you are paginating
* @return hasMore boolean set to false if at the end of the list you are paginating
* @return onDisplayMore function to call to display the next page of the list you are paginating
*/
function useInMemoryPaginatedSearch<TData, TFilter, TSort extends string>(
data: TData[],
options?: Partial<SearchLoadedDataHookOptions<TData, TFilter, TSort>>,
): PaginatedSearch<TData> {
const [elements, setElements] = useState<TData[]>([]);
const [totalElements, setTotalElements] = useState<number>(0);
const pagination: PaginationType = usePagination({
pageSize: options?.defaultPageSize ?? 10,
});
const displayPage = (page: number) => {
pagination.setPage(page);
const filteredElements: TData[] = data
.filter((value: TData) => options?.filter?.isElementDisplayed(value, options?.filter?.values) ?? true)
.sort((value: TData, compared: TData) => (options?.sort
? (options.sort.sortElement[options.sort.value.id](value, compared, options.sort.value.desc) ?? 0)
: 0),
);
setTotalElements(filteredElements.length);
pagination.setElementCount(filteredElements.length);
setElements(
(currentElements: TData[]) => [
...currentElements,
...filteredElements.slice(
(page - 1) * pagination.pageSize,
page * pagination.pageSize,
),
]);
};
useEffect(() => {
setElements([]);
displayPage(1);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [options?.filter?.values, data, options?.sort?.value]);
return {
displayedItems: elements,
totalCount: totalElements,
hasMore: pagination.currentPage < pagination.totalPages,
onDisplayMore: () => displayPage(pagination.currentPage + 1),
};
}
export default useInMemoryPaginatedSearch;