2021-06-08 08:54:13 +00:00
|
|
|
import { useEffect, useState } from "react";
|
2021-06-08 06:58:36 +00:00
|
|
|
|
|
|
|
export interface PageInfo {
|
|
|
|
endCursor: string;
|
|
|
|
hasNextPage: boolean;
|
|
|
|
hasPreviousPage: boolean;
|
|
|
|
startCursor: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface PaginationState {
|
|
|
|
after?: string;
|
|
|
|
before?: string;
|
|
|
|
first?: number;
|
|
|
|
last?: number;
|
|
|
|
}
|
|
|
|
|
2021-12-06 14:41:18 +00:00
|
|
|
/**
|
|
|
|
* Local pagination state.
|
|
|
|
* @param paginateBy Number of items per page.
|
|
|
|
* @returns Pagination state and setter.
|
|
|
|
*/
|
2021-06-08 06:58:36 +00:00
|
|
|
export function useLocalPaginationState(
|
|
|
|
paginateBy: number
|
|
|
|
): [PaginationState, (paginationState: PaginationState) => void] {
|
|
|
|
const [state, setState] = useState<PaginationState>({
|
|
|
|
first: paginateBy
|
|
|
|
});
|
|
|
|
|
|
|
|
const setPaginationState = (paginationState: PaginationState) => {
|
|
|
|
if (paginationState.after) {
|
|
|
|
setState({
|
|
|
|
after: paginationState.after,
|
|
|
|
first: paginateBy
|
|
|
|
});
|
|
|
|
} else if (paginationState.before) {
|
|
|
|
setState({
|
|
|
|
before: paginationState.before,
|
|
|
|
last: paginateBy
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
setState({
|
|
|
|
first: paginateBy
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-06-08 08:54:13 +00:00
|
|
|
useEffect(() => {
|
|
|
|
setPaginationState(state);
|
|
|
|
}, [paginateBy]);
|
|
|
|
|
2021-06-08 06:58:36 +00:00
|
|
|
return [state, setPaginationState];
|
|
|
|
}
|
|
|
|
|
2021-12-06 14:41:18 +00:00
|
|
|
/**
|
|
|
|
* Local pagination state persisted as long as section is not changed.
|
|
|
|
* @param paginateBy Number of items per page.
|
|
|
|
* @param section Section name. When changed, pagination state is reset.
|
|
|
|
* @returns Pagination state and setter.
|
|
|
|
*/
|
|
|
|
export function useSectionLocalPaginationState(
|
|
|
|
paginateBy: number,
|
|
|
|
section: string
|
|
|
|
): [PaginationState, (paginationState: PaginationState) => void] {
|
|
|
|
const [paginationSection, setPaginationSection] = useState(section);
|
|
|
|
const [paginationState, setPaginationState] = useLocalPaginationState(
|
|
|
|
paginateBy
|
|
|
|
);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (section !== paginationSection) {
|
|
|
|
setPaginationState({});
|
|
|
|
}
|
|
|
|
}, [section]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (section !== paginationSection) {
|
|
|
|
setPaginationSection(section);
|
|
|
|
}
|
|
|
|
}, [paginationState]);
|
|
|
|
|
|
|
|
return [
|
|
|
|
section === paginationSection ? paginationState : {},
|
|
|
|
setPaginationState
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2021-06-08 06:58:36 +00:00
|
|
|
function useLocalPaginator(
|
|
|
|
setPaginationState: (paginationState: PaginationState) => void
|
|
|
|
) {
|
|
|
|
function paginate(pageInfo: PageInfo, paginationState: PaginationState) {
|
|
|
|
const loadNextPage = () =>
|
|
|
|
setPaginationState({
|
|
|
|
...paginationState,
|
|
|
|
after: pageInfo.endCursor,
|
|
|
|
before: undefined
|
|
|
|
});
|
|
|
|
|
|
|
|
const loadPreviousPage = () =>
|
|
|
|
setPaginationState({
|
|
|
|
...paginationState,
|
|
|
|
after: undefined,
|
|
|
|
before: pageInfo.startCursor
|
|
|
|
});
|
|
|
|
|
|
|
|
const newPageInfo = pageInfo
|
|
|
|
? {
|
|
|
|
...pageInfo,
|
|
|
|
hasNextPage: !!paginationState.before || pageInfo.hasNextPage,
|
|
|
|
hasPreviousPage: !!paginationState.after || pageInfo.hasPreviousPage
|
|
|
|
}
|
|
|
|
: undefined;
|
|
|
|
|
|
|
|
return {
|
|
|
|
loadNextPage,
|
|
|
|
loadPreviousPage,
|
|
|
|
pageInfo: newPageInfo
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return paginate;
|
|
|
|
}
|
|
|
|
export default useLocalPaginator;
|