webui/src/components/common/Pagination.tsx

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;