Update pagination in table.

Add getPaginationRage to usePagination hook.
Use the getPaginationRage to create dynamic buttons in the table.
This commit is contained in:
Alexander Navarro 2023-11-05 10:32:49 -03:00
parent b1979d7351
commit e593354cb4
4 changed files with 80 additions and 26 deletions

View file

@ -1,12 +1,19 @@
import { useReducer } from 'react';
interface Page {
page: number;
current: boolean;
}
export interface IUsePagination<T> {
items: T[];
changeOffset: (offset: Offset) => void;
changeOffset: (offset: Offset, newValue?: number) => void;
getPaginationRange: () => Page[];
}
interface Props<T> {
items: T[];
limit: number;
}
interface State {
@ -24,10 +31,12 @@ export enum Offset {
Prev,
First,
Last,
To,
}
export default function usePagination<T>({
items,
limit = 30,
}: Props<T>): IUsePagination<T> {
const reducer = (state: State, action: ActionType): State => {
switch (action.type) {
@ -44,47 +53,69 @@ export default function usePagination<T>({
const [state, dispatch] = useReducer(reducer, {
offset: 0,
total: 0,
limit: 30,
limit,
});
const changeOffset = (offset: Offset): void => {
const changeOffset = (offset: Offset, newValue: number = 1): void => {
let value = 0;
switch (offset) {
case Offset.Next:
dispatch({
type: 'update',
name: 'offset',
value: state.offset + state.limit,
});
value = state.offset + state.limit;
break;
case Offset.Prev:
dispatch({
type: 'update',
name: 'offset',
value: state.offset - state.limit,
});
value = state.offset - state.limit;
break;
case Offset.First:
dispatch({
type: 'update',
name: 'offset',
value: 0,
});
value = 0;
break;
case Offset.Last:
dispatch({
type: 'update',
name: 'offset',
value: items.length - state.limit,
});
value = items.length - state.limit;
break;
case Offset.To:
value = (newValue - 1) * state.limit;
break;
default:
break;
}
if (value < 0 || value > items.length - state.limit) {
return;
}
dispatch({
type: 'update',
name: 'offset',
value,
});
};
/** Returns an array with the aviables pages to directly navigate.
* This pages are centered in the current page and offest to 5 items to each side.
*/
const getPaginationRange = (): Page[] => {
// NOTE: this is made to work with uneven numbers,
// So the current page is always aligned in the center.
const paginationToSides = 5;
const currentPage = Math.ceil(state.offset / state.limit) + 1;
const lastPage = Math.ceil(items.length / state.limit);
const start = Math.max(currentPage - paginationToSides - 1, 0);
const end = Math.min(currentPage + paginationToSides, lastPage);
return Array.from(
{
length: end - start,
},
(_, idx) => {
const page = idx + 1 + start;
return { page, current: page === currentPage };
},
);
};
return {
changeOffset,
getPaginationRange,
items: items.slice(state.offset, state.offset + state.limit),
};
}