import {Fragment, useEffect, useState} from "react"; export default function Pagination({totalPages, onNewPage}) { const LEFT_PAGE = 'LEFT'; const RIGHT_PAGE = 'RIGHT'; const range = (from, to, step = 1) => { let i = from; const range = []; while (i <= to) { range.push(i); i += step; } return range; } const [currentPage, setCurrentPage] = useState(1) useEffect(() => { gotoPage(1); }, []) const gotoPage = page => { setCurrentPage(page) } const handleClick = page => evt => { evt.preventDefault(); gotoPage(page); onNewPage(page) } const handleMoveLeft = evt => { evt.preventDefault(); gotoPage(currentPage - 3); } const handleMoveRight = evt => { evt.preventDefault(); gotoPage(currentPage + 5); } /** * Let's say we have 10 pages and we set pageNeighbours to 2 * Given that the current page is 6 * The pagination control will look like the following: * * (1) < {4 5} [6] {7 8} > (10) * * (x) => terminal pages: first and last page(always visible) * [x] => represents current page * {...x} => represents page neighbours */ const fetchPageNumbers = () => { const pageNeighbours = 2; /** * totalNumbers: the total page numbers to show on the control * totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls */ const totalNumbers = 7; const totalBlocks = totalNumbers + 2; if (totalPages > totalBlocks) { const startPage = Math.max(2, currentPage - pageNeighbours); const endPage = Math.min(totalPages - 1, currentPage + pageNeighbours); let pages = range(startPage, endPage); /** * hasLeftSpill: has hidden pages to the left * hasRightSpill: has hidden pages to the right * spillOffset: number of hidden pages either to the left or to the right */ const hasLeftSpill = startPage > 2; const hasRightSpill = (totalPages - endPage) > 1; const spillOffset = totalNumbers - (pages.length + 1); switch (true) { // handle: (1) < {5 6} [7] {8 9} (10) case (hasLeftSpill && !hasRightSpill): { const extraPages = range(startPage - spillOffset, startPage - 1); pages = [LEFT_PAGE, ...extraPages, ...pages]; break; } // handle: (1) {2 3} [4] {5 6} > (10) case (!hasLeftSpill && hasRightSpill): { const extraPages = range(endPage + 1, endPage + spillOffset); pages = [...pages, ...extraPages, RIGHT_PAGE]; break; } // handle: (1) < {4 5} [6] {7 8} > (10) case (hasLeftSpill && hasRightSpill): default: { pages = [LEFT_PAGE, ...pages, RIGHT_PAGE]; break; } } return [1, ...pages, totalPages]; } return range(1, totalPages); } if (totalPages === 1) return null; const pages = fetchPageNumbers(); return ( ); }