Spaces:
Running
Running
import { FC, useCallback, useMemo, useState } from "react"; | |
import { GoChevronLeft, GoChevronRight } from "react-icons/go"; | |
import Select from "react-select"; | |
import Button from "@/components/generics/button/Button"; | |
import { PaginationType } from "@/api/documents/types"; | |
import "./Pagination.scss"; | |
import Input from "@/components/generics/input/Input"; | |
interface PageSizeOption { | |
value: number; | |
label: string; | |
} | |
export type PaginationProps = PaginationType & { | |
setPage: React.Dispatch<React.SetStateAction<number>>; | |
setPageSize: React.Dispatch<React.SetStateAction<number>>; | |
}; | |
const pageSizeOptions: PageSizeOption[] = [ | |
{ value: 10, label: "10 / стр." }, | |
{ value: 20, label: "20 / стр." }, | |
{ value: 50, label: "50 / стр." }, | |
{ value: 100, label: "100 / стр." }, | |
]; | |
export const Pagination: FC<PaginationProps> = ({ total, pageNumber, pageSize, setPage, setPageSize }) => { | |
const [searchPage, setSearchPage] = useState<string | null>(null); | |
const totalPages = Math.ceil(total / pageSize); | |
const handleChange = useCallback( | |
(page: number) => { | |
setPage(page); | |
}, | |
[setPage] | |
); | |
const handlePageSizeChange = (selectedOption: PageSizeOption | null) => { | |
if (selectedOption) { | |
setPageSize(selectedOption.value); | |
setPage(0); | |
} | |
}; | |
const pages = useMemo(() => { | |
let startPage = 1; | |
let endPage = totalPages; | |
if (totalPages > 5) { | |
if (pageNumber + 1 <= 3) { | |
endPage = 5; | |
} else if (pageNumber + 3 >= totalPages) { | |
startPage = totalPages - 4; | |
} else { | |
startPage = pageNumber - 1; | |
endPage = pageNumber + 3; | |
} | |
} | |
const pageNumbers = []; | |
if (startPage > 1) { | |
pageNumbers.push( | |
<Button | |
key={1} | |
name={`${1}`} | |
onClick={() => { | |
handleChange(0); | |
}} | |
className={`item ${pageNumber + 1 === 1 ? "active" : ""}`} | |
/> | |
); | |
if (startPage > 2) { | |
pageNumbers.push(<span key="ellipsis-start">...</span>); | |
} | |
} | |
for (let i = startPage; i <= endPage; i++) { | |
pageNumbers.push( | |
<Button | |
key={i} | |
name={`${i}`} | |
onClick={() => { | |
handleChange(i - 1); | |
}} | |
className={`item ${pageNumber + 1 === i ? "active" : ""}`} | |
/> | |
); | |
} | |
if (endPage < totalPages) { | |
if (endPage < totalPages - 1) { | |
pageNumbers.push(<span key="ellipsis-end">...</span>); | |
} | |
pageNumbers.push( | |
<Button | |
key={totalPages} | |
name={`${totalPages}`} | |
onClick={() => { | |
handleChange(totalPages - 1); | |
}} | |
className={`item ${pageNumber + 1 === totalPages ? "active" : ""}`} | |
/> | |
); | |
} | |
return pageNumbers; | |
}, [handleChange, pageNumber, totalPages]); | |
const handleEnterPress = (event: React.KeyboardEvent<HTMLInputElement>) => { | |
if (event.key === "Enter" && searchPage) { | |
const pageNumberToGo = Number(searchPage); | |
if (pageNumberToGo >= 1 && pageNumberToGo <= totalPages) { | |
setPage(pageNumberToGo - 1); | |
} | |
} | |
}; | |
return ( | |
<div className="pagination"> | |
<Button | |
onClick={() => { | |
handleChange(pageNumber - 1); | |
}} | |
icon={<GoChevronLeft />} | |
buttonType="link" | |
disabled={pageNumber === 0} | |
/> | |
{pages} | |
<Button | |
onClick={() => { | |
handleChange(pageNumber + 1); | |
}} | |
icon={<GoChevronRight />} | |
buttonType="link" | |
disabled={pageNumber === totalPages - 1} | |
/> | |
<div className="page-actions"> | |
<Input | |
name="" | |
type="number" | |
max={totalPages.toString()} | |
min="0" | |
step="1" | |
placeholder="Номер страницы" | |
value={searchPage?.toString()} | |
onSetValue={(value) => setSearchPage(value)} | |
onKeyDown={handleEnterPress} | |
extra={ | |
<Button | |
disabled={!searchPage} | |
icon={<GoChevronRight style={{ width: "18px", height: "18px" }} />} | |
onClick={() => (Number(searchPage) && Number(searchPage) >= 1 ? setPage(Number(searchPage) - 1) : null)} | |
buttonType="link" | |
/> | |
} | |
/> | |
<Select | |
options={pageSizeOptions} | |
value={pageSizeOptions.find((option) => option.value === pageSize)} | |
onChange={handlePageSizeChange} | |
isSearchable={false} | |
classNamePrefix="react-select" | |
theme={(theme) => ({ | |
...theme, | |
colors: { | |
...theme.colors, | |
text: "orangered", | |
primary25: "var(--primary-color)", | |
primary50: "var(--primary-color)", | |
primary: "var(--secondary-color)", | |
}, | |
})} | |
/> | |
</div> | |
</div> | |
); | |
}; | |