mirror of
https://github.com/ershisan99/flashcards-example-project.git
synced 2025-12-18 12:33:22 +00:00
201 lines
4.9 KiB
TypeScript
201 lines
4.9 KiB
TypeScript
import { FC } from 'react'
|
||
|
||
import { usePagination } from './usePagination'
|
||
import { KeyboardArrowLeft, KeyboardArrowRight } from '@/assets'
|
||
import { clsx } from 'clsx'
|
||
|
||
import s from './pagination.module.scss'
|
||
|
||
type PaginationConditionals =
|
||
| {
|
||
onPerPageChange: (itemPerPage: number) => void
|
||
perPage: number
|
||
perPageOptions: number[]
|
||
}
|
||
| {
|
||
onPerPageChange?: never
|
||
perPage?: null
|
||
perPageOptions?: never
|
||
}
|
||
|
||
export type PaginationProps = {
|
||
count: number
|
||
onChange: (page: number) => void
|
||
onPerPageChange?: (itemPerPage: number) => void
|
||
page: number
|
||
perPage?: number
|
||
perPageOptions?: number[]
|
||
siblings?: number
|
||
} & PaginationConditionals
|
||
|
||
const classNames = {
|
||
container: s.container,
|
||
dots: s.dots,
|
||
icon: s.icon,
|
||
item: s.item,
|
||
pageButton(selected?: boolean) {
|
||
return clsx(this.item, selected && s.selected)
|
||
},
|
||
root: s.root,
|
||
select: s.select,
|
||
selectBox: s.selectBox,
|
||
}
|
||
|
||
export const Pagination: FC<PaginationProps> = ({
|
||
count,
|
||
onChange,
|
||
onPerPageChange,
|
||
page,
|
||
perPage = null,
|
||
perPageOptions,
|
||
siblings,
|
||
}) => {
|
||
const {
|
||
handleMainPageClicked,
|
||
handleNextPageClicked,
|
||
handlePreviousPageClicked,
|
||
isFirstPage,
|
||
isLastPage,
|
||
paginationRange,
|
||
} = usePagination({
|
||
count,
|
||
onChange,
|
||
page,
|
||
siblings,
|
||
})
|
||
|
||
const showPerPageSelect = !!perPage && !!perPageOptions && !!onPerPageChange
|
||
|
||
return (
|
||
<div className={classNames.root}>
|
||
<div className={classNames.container}>
|
||
<PrevButton disabled={isFirstPage} onClick={handlePreviousPageClicked} />
|
||
|
||
<MainPaginationButtons
|
||
currentPage={page}
|
||
onClick={handleMainPageClicked}
|
||
paginationRange={paginationRange}
|
||
/>
|
||
|
||
<NextButton disabled={isLastPage} onClick={handleNextPageClicked} />
|
||
</div>
|
||
|
||
{showPerPageSelect && (
|
||
<PerPageSelect
|
||
{...{
|
||
onPerPageChange,
|
||
perPage,
|
||
perPageOptions,
|
||
}}
|
||
/>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
type NavigationButtonProps = {
|
||
disabled?: boolean
|
||
onClick: () => void
|
||
}
|
||
|
||
type PageButtonProps = NavigationButtonProps & {
|
||
page: number
|
||
selected: boolean
|
||
}
|
||
|
||
const Dots: FC = () => {
|
||
return <span className={classNames.dots}>…</span>
|
||
}
|
||
const PageButton: FC<PageButtonProps> = ({ disabled, onClick, page, selected }) => {
|
||
return (
|
||
<button
|
||
className={classNames.pageButton(selected)}
|
||
disabled={selected || disabled}
|
||
onClick={onClick}
|
||
>
|
||
{page}
|
||
</button>
|
||
)
|
||
}
|
||
const PrevButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
||
return (
|
||
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
||
<KeyboardArrowLeft className={classNames.icon} />
|
||
</button>
|
||
)
|
||
}
|
||
|
||
const NextButton: FC<NavigationButtonProps> = ({ disabled, onClick }) => {
|
||
return (
|
||
<button className={classNames.item} disabled={disabled} onClick={onClick}>
|
||
<KeyboardArrowRight className={classNames.icon} />
|
||
</button>
|
||
)
|
||
}
|
||
|
||
type MainPaginationButtonsProps = {
|
||
currentPage: number
|
||
onClick: (pageNumber: number) => () => void
|
||
paginationRange: (number | string)[]
|
||
}
|
||
|
||
const MainPaginationButtons: FC<MainPaginationButtonsProps> = ({
|
||
currentPage,
|
||
onClick,
|
||
paginationRange,
|
||
}) => {
|
||
return (
|
||
<>
|
||
{paginationRange.map((page: number | string, index) => {
|
||
const isSelected = page === currentPage
|
||
|
||
if (typeof page !== 'number') {
|
||
return <Dots key={index} />
|
||
}
|
||
|
||
return (
|
||
<PageButton
|
||
key={index}
|
||
onClick={onClick(page)}
|
||
page={page}
|
||
selected={isSelected}
|
||
/>
|
||
)
|
||
})}
|
||
</>
|
||
)
|
||
}
|
||
|
||
export type PerPageSelectProps = {
|
||
onPerPageChange: (itemPerPage: number) => void
|
||
perPage: number
|
||
perPageOptions: number[]
|
||
}
|
||
|
||
export const PerPageSelect: FC<PerPageSelectProps> = (
|
||
{
|
||
// perPage,
|
||
// perPageOptions,
|
||
// onPerPageChange,
|
||
}
|
||
) => {
|
||
// const selectOptions = perPageOptions.map(value => ({
|
||
// label: value,
|
||
// value,
|
||
// }))
|
||
|
||
return (
|
||
<div className={classNames.selectBox}>
|
||
Показать
|
||
{/*<Select*/}
|
||
{/* className={classNames.select}*/}
|
||
{/* value={perPage}*/}
|
||
{/* options={selectOptions}*/}
|
||
{/* onChange={onPerPageChange}*/}
|
||
{/* variant="pagination"*/}
|
||
{/*/>*/}
|
||
на странице
|
||
</div>
|
||
)
|
||
}
|