Init(Core): add project to new repo
This commit is contained in:
152
src/Components/common/Pagination.jsx
Normal file
152
src/Components/common/Pagination.jsx
Normal file
@@ -0,0 +1,152 @@
|
||||
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 (
|
||||
<Fragment>
|
||||
<nav aria-label="Pagination">
|
||||
<ul className="pagination">
|
||||
{ pages.map((page, index) => {
|
||||
|
||||
if (page === LEFT_PAGE) return (
|
||||
<li key={index} className="page-item">
|
||||
<a className="page-link" href="#" aria-label="Previous" onClick={handleMoveLeft}>
|
||||
<span aria-hidden="true">«</span>
|
||||
<span className="sr-only">قبلی</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
|
||||
if (page === RIGHT_PAGE) return (
|
||||
<li key={index} className="page-item">
|
||||
<a className="page-link" href="#" aria-label="Next" onClick={handleMoveRight}>
|
||||
<span className="sr-only">بعدی</span>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={index} className={`page-item${ currentPage === page ? ' active' : ''}`}>
|
||||
<a className="page-link" href="#" onClick={ handleClick(page) }>{ page }</a>
|
||||
</li>
|
||||
);
|
||||
|
||||
}) }
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user