import React, { useEffect, useMemo, useState } from 'react' import styles from './_pagination.module.scss' import Button from '../Button/Button' import Icon from '../Icons/Icon' import { useIsMobileView } from '../../hooks/useIsMobileView/useIsMobileView' import PaginationEllipsis from './PaginationEllipsis/PaginationEllipsis' import { c } from '../../translations/LibraryTranslationService' export type PaginationProps = { /** Total number of pages */ totalPages: number /** Function to call when a new page is selected */ callout: (page: number) => void /** The current page passed in by the parent */ currentPage: number /** Optional prop to add a test id to the Pagination for QA testing */ qaTestId?: string } const Pagination = ({ totalPages, callout, currentPage, qaTestId = 'pagination', }: PaginationProps): React.JSX.Element => { const [activePage, setActivePage] = useState(currentPage - 1) const lastPage = totalPages - 1 const updatePage = (page: number) => { setActivePage(page) callout(page + 1) } const isMobileView = useIsMobileView() useEffect(() => { setActivePage(currentPage - 1) }, [currentPage]) const options = useMemo( () => Array.from({ length: totalPages }, (_, i) => ({ name: (i + 1).toString(), label: (i + 1).toString(), })), [totalPages], ) const renderPageButton = (page: number) => { // Digits counts the number of characters in the page number. This is used to help calculate how wide a button should be. const digits = (page + 1).toString().length <= 2 ? 1 : (page + 1).toString().length const width = { 1: '32px', 3: '40px', 4: '48px', 5: '56px', 6: '64px', }[digits] return ( ) } const renderPageButtons = () => { if (isMobileView) { return ( ) } const buttons = [] const maxNumOfPages = 7 // Always show the first page buttons.push(renderPageButton(0)) if (totalPages > maxNumOfPages) { const maxNumOfEllipsis = 2 const showEllipsisAtStart = activePage > maxNumOfEllipsis + 1 const showEllipsisAtEnd = lastPage - activePage > maxNumOfEllipsis + 1 const paginationEllipsisProps = { updatePage, lastPage, activePage, pageOptions: options, } if (showEllipsisAtStart && showEllipsisAtEnd) { // Example: Ellipsis, 3, 4, 5, Ellipsis buttons.push( , ) for (let i = activePage - 1; i <= activePage + 1; i++) { buttons.push(renderPageButton(i)) } buttons.push( , ) } else if (showEllipsisAtStart) { // Example: Ellipsis, 3, 4, 5, 6 buttons.push( , ) for (let i = lastPage - maxNumOfPages + 4; i <= lastPage; i++) { buttons.push(renderPageButton(i - 1)) } } else if (showEllipsisAtEnd) { // Example: 2, 3, 4, 5, Ellipsis for (let i = 2; i <= maxNumOfPages - 2; i++) { buttons.push(renderPageButton(i - 1)) } buttons.push( , ) } } else { // Show all pages if total pages are less than or equal to maxNumOfPages for (let i = 2; i <= lastPage; i++) { buttons.push(renderPageButton(i - 1)) } } // Always show the last page if there is more than one page totalPages > 1 && buttons.push(renderPageButton(lastPage)) return buttons } if (currentPage <= 0) { throw new Error(c('errorPagination')) } return (
{renderPageButtons()}
) } export default Pagination