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
|
|
@ -68,3 +68,12 @@ td {
|
||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: var(--prj-spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--prj--primary-bg);
|
||||||
|
color: var(--prj--primary-text);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,9 @@ export default function Table({ data, headers }: Props): JSX.Element {
|
||||||
});
|
});
|
||||||
}, [data, filters]);
|
}, [data, filters]);
|
||||||
|
|
||||||
const { items, changeOffset } = usePagination<DataItem>({
|
const { items, changeOffset, getPaginationRange } = usePagination<DataItem>({
|
||||||
items: filteredItems,
|
items: filteredItems,
|
||||||
|
limit: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleUpdateFilters = (
|
const handleUpdateFilters = (
|
||||||
|
|
@ -179,6 +180,19 @@ export default function Table({ data, headers }: Props): JSX.Element {
|
||||||
>
|
>
|
||||||
Prev
|
Prev
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{getPaginationRange().map((item) => (
|
||||||
|
<button
|
||||||
|
className={item.current ? 'btn-primary' : ''}
|
||||||
|
key={item.page}
|
||||||
|
onClick={() => {
|
||||||
|
changeOffset(Offset.To, item.page);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.page}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
changeOffset(Offset.Next);
|
changeOffset(Offset.Next);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,19 @@
|
||||||
import { useReducer } from 'react';
|
import { useReducer } from 'react';
|
||||||
|
|
||||||
|
interface Page {
|
||||||
|
page: number;
|
||||||
|
current: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IUsePagination<T> {
|
export interface IUsePagination<T> {
|
||||||
items: T[];
|
items: T[];
|
||||||
changeOffset: (offset: Offset) => void;
|
changeOffset: (offset: Offset, newValue?: number) => void;
|
||||||
|
getPaginationRange: () => Page[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props<T> {
|
interface Props<T> {
|
||||||
items: T[];
|
items: T[];
|
||||||
|
limit: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
|
@ -24,10 +31,12 @@ export enum Offset {
|
||||||
Prev,
|
Prev,
|
||||||
First,
|
First,
|
||||||
Last,
|
Last,
|
||||||
|
To,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function usePagination<T>({
|
export default function usePagination<T>({
|
||||||
items,
|
items,
|
||||||
|
limit = 30,
|
||||||
}: Props<T>): IUsePagination<T> {
|
}: Props<T>): IUsePagination<T> {
|
||||||
const reducer = (state: State, action: ActionType): State => {
|
const reducer = (state: State, action: ActionType): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
@ -44,47 +53,69 @@ export default function usePagination<T>({
|
||||||
const [state, dispatch] = useReducer(reducer, {
|
const [state, dispatch] = useReducer(reducer, {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
total: 0,
|
total: 0,
|
||||||
limit: 30,
|
limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
const changeOffset = (offset: Offset): void => {
|
const changeOffset = (offset: Offset, newValue: number = 1): void => {
|
||||||
|
let value = 0;
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case Offset.Next:
|
case Offset.Next:
|
||||||
dispatch({
|
value = state.offset + state.limit;
|
||||||
type: 'update',
|
|
||||||
name: 'offset',
|
|
||||||
value: state.offset + state.limit,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Offset.Prev:
|
case Offset.Prev:
|
||||||
dispatch({
|
value = state.offset - state.limit;
|
||||||
type: 'update',
|
|
||||||
name: 'offset',
|
|
||||||
value: state.offset - state.limit,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Offset.First:
|
case Offset.First:
|
||||||
dispatch({
|
value = 0;
|
||||||
type: 'update',
|
|
||||||
name: 'offset',
|
|
||||||
value: 0,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Offset.Last:
|
case Offset.Last:
|
||||||
dispatch({
|
value = items.length - state.limit;
|
||||||
type: 'update',
|
break;
|
||||||
name: 'offset',
|
case Offset.To:
|
||||||
value: items.length - state.limit,
|
value = (newValue - 1) * state.limit;
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
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 {
|
return {
|
||||||
changeOffset,
|
changeOffset,
|
||||||
|
getPaginationRange,
|
||||||
items: items.slice(state.offset, state.offset + state.limit),
|
items: items.slice(state.offset, state.offset + state.limit),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const rawGames = await getCollection('games');
|
||||||
|
|
||||||
const games = rawGames.map((item, idx) => ({
|
const games = rawGames.map((item, idx) => ({
|
||||||
...item.data,
|
...item.data,
|
||||||
id: idx,
|
id: idx + 1,
|
||||||
slug: item.slug,
|
slug: item.slug,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue