120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
import React, { useCallback } from "react";
|
|
import {
|
|
faAngleDoubleLeft,
|
|
faAngleLeft,
|
|
faAngleRight,
|
|
faAngleDoubleRight,
|
|
} from "@fortawesome/free-solid-svg-icons";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { Paginated } from "../../services/Paginated";
|
|
import Button, { ButtonType } from "./Button";
|
|
import { InputType } from "./Input";
|
|
|
|
interface PaginationProps<T> {
|
|
data: Paginated<T> | null;
|
|
onChangePage: (page: number, pageSize: number) => void;
|
|
onUnselect?: () => void;
|
|
}
|
|
|
|
function Pagination<T>({
|
|
data,
|
|
onChangePage,
|
|
onUnselect,
|
|
}: PaginationProps<T>): JSX.Element {
|
|
const changePage = useCallback(
|
|
(page: number, pageSize: number) => {
|
|
onChangePage(page, pageSize);
|
|
if (onUnselect) onUnselect();
|
|
},
|
|
[onChangePage, onUnselect],
|
|
);
|
|
|
|
if (data === null) return <></>;
|
|
|
|
const { page, pageSize, totalPages, count } = data;
|
|
|
|
const clickFirst = () => changePage(1, pageSize);
|
|
const clickPrevious = () => changePage(page - 1, pageSize);
|
|
const clickNext = () => changePage(page + 1, pageSize);
|
|
const clickLast = () => changePage(totalPages, pageSize);
|
|
|
|
const PageSizeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
const newPageSize = Number(e.currentTarget.value);
|
|
changePage(page, newPageSize);
|
|
};
|
|
|
|
const handlePageSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const newPage = Number(e.currentTarget.value);
|
|
if (1 <= newPage && newPage <= totalPages) {
|
|
changePage(newPage, pageSize);
|
|
}
|
|
};
|
|
|
|
const pageSizeOptions = [10, 25, 50, 100];
|
|
|
|
return (
|
|
<div className="d-flex py-2 bg-body-tertiary pagination">
|
|
<span className="px-2">
|
|
<select
|
|
value={pageSize}
|
|
className="form-select"
|
|
onChange={PageSizeChange}
|
|
>
|
|
{pageSizeOptions.map((n) => (
|
|
<option key={n} value={n}>
|
|
{n}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</span>
|
|
<span>
|
|
<Button
|
|
className="me-1"
|
|
buttonType={ButtonType.primary}
|
|
onClick={clickFirst}
|
|
disabled={page < 2}
|
|
>
|
|
<FontAwesomeIcon icon={faAngleDoubleLeft} />
|
|
</Button>
|
|
<Button
|
|
className="me-1"
|
|
buttonType={ButtonType.primary}
|
|
onClick={clickPrevious}
|
|
disabled={page < 2}
|
|
>
|
|
<FontAwesomeIcon icon={faAngleLeft} />
|
|
</Button>
|
|
<span className="me-1">
|
|
<input
|
|
type={InputType.number}
|
|
value={page}
|
|
min={1}
|
|
max={totalPages}
|
|
onChange={handlePageSelect}
|
|
/>{" "}
|
|
of {totalPages}
|
|
</span>
|
|
<Button
|
|
className="me-1"
|
|
buttonType={ButtonType.primary}
|
|
onClick={clickNext}
|
|
disabled={page >= totalPages}
|
|
>
|
|
<FontAwesomeIcon icon={faAngleRight} />
|
|
</Button>
|
|
<Button
|
|
className="me-1"
|
|
buttonType={ButtonType.primary}
|
|
onClick={clickLast}
|
|
disabled={page >= totalPages}
|
|
>
|
|
<FontAwesomeIcon icon={faAngleDoubleRight} />
|
|
</Button>
|
|
<span className="me-1">{count} Items</span>
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default Pagination;
|