Paginate servers on frontend; closes #2106
This commit is contained in:
parent
03abc1764d
commit
6c0d308348
5 changed files with 122 additions and 20 deletions
87
resources/scripts/components/elements/Pagination.tsx
Normal file
87
resources/scripts/components/elements/Pagination.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
import React from 'react';
|
||||
import { PaginatedResult } from '@/api/http';
|
||||
import tw from 'twin.macro';
|
||||
import styled from 'styled-components/macro';
|
||||
import Button from '@/components/elements/Button';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
interface RenderFuncProps<T> {
|
||||
items: T[];
|
||||
isLastPage: boolean;
|
||||
isFirstPage: boolean;
|
||||
}
|
||||
|
||||
interface Props<T> {
|
||||
data: PaginatedResult<T>;
|
||||
showGoToLast?: boolean;
|
||||
showGoToFirst?: boolean;
|
||||
onPageSelect: (page: number) => void;
|
||||
children: (props: RenderFuncProps<T>) => React.ReactNode;
|
||||
}
|
||||
|
||||
const Block = styled(Button)`
|
||||
${tw`p-0 w-10 h-10`}
|
||||
|
||||
&:not(:last-of-type) {
|
||||
${tw`mr-2`};
|
||||
}
|
||||
`;
|
||||
|
||||
function Pagination<T> ({ data: { items, pagination }, onPageSelect, children }: Props<T>) {
|
||||
const isFirstPage = pagination.currentPage === 1;
|
||||
const isLastPage = pagination.currentPage >= pagination.totalPages;
|
||||
|
||||
const pages = [];
|
||||
|
||||
// Start two spaces before the current page. If that puts us before the starting page default
|
||||
// to the first page as the starting point.
|
||||
const start = Math.max(pagination.currentPage - 2, 1);
|
||||
const end = Math.min(pagination.totalPages, pagination.currentPage + 5);
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{children({ items, isFirstPage, isLastPage })}
|
||||
{(pages.length > 1) &&
|
||||
<div css={tw`mt-4 flex justify-center`}>
|
||||
{(pages[0] > 1 && !isFirstPage) &&
|
||||
<Block
|
||||
isSecondary
|
||||
color={'primary'}
|
||||
onClick={() => onPageSelect(1)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAngleDoubleLeft}/>
|
||||
</Block>
|
||||
}
|
||||
{
|
||||
pages.map(i => (
|
||||
<Block
|
||||
isSecondary={pagination.currentPage !== i}
|
||||
color={'primary'}
|
||||
key={`block_page_${i}`}
|
||||
onClick={() => onPageSelect(i)}
|
||||
>
|
||||
{i}
|
||||
</Block>
|
||||
))
|
||||
}
|
||||
{(pages[4] < pagination.totalPages && !isLastPage) &&
|
||||
<Block
|
||||
isSecondary
|
||||
color={'primary'}
|
||||
onClick={() => onPageSelect(pagination.totalPages)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAngleDoubleRight}/>
|
||||
</Block>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Pagination;
|
Reference in a new issue