Update pagination in table.
Add getPaginationRage to usePagination hook. Use the getPaginationRage to create dynamic buttons in the table.
This commit is contained in:
parent
b1979d7351
commit
e593354cb4
4 changed files with 80 additions and 26 deletions
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue