Files
musiclist-client/src/components/Paginate.jsx
Daniel Cortes d67cb49f04 Scroll global
2020-06-06 23:23:33 -04:00

158 lines
5.3 KiB
JavaScript

import React, {Fragment, useState} from 'react';
const SPACE_A = 'SPACE_A';
const SPACE_B = 'SPACE_B';
/**
* Helper method for creating a range of numbers
* range(1, 5) => [1, 2, 3, 4, 5]
*/
const range = (from, to, step = 1) => {
let i = from;
const range = [];
while (i <= to) {
range.push(i);
i += step;
}
return range;
}
export const Paginate = (props) => {
const pageLimit = typeof props.pageLimit === 'number' ? props.pageLimit : 30;
const totalRecords = typeof props.totalRecords === 'number' ? props.totalRecords : 0;
const pageNeighbours = typeof props.pageNeighbours === 'number' ? Math.max(0, Math.min(props.pageNeighbours, 2)) : 0;
const totalPages = Math.ceil(totalRecords / pageLimit);
const [currentPage, setCurrentPage] = useState(typeof props.currentPage === 'number' ? props.currentPage : 1);
let hasLeft = false;
let hasRight = false;
const gotoPage = (page) => {
const currentPage = Math.max(0, Math.min(page, totalPages));
props.onPageChanged(page)
setCurrentPage(currentPage);
}
const handleClick = (page) => (evt) => {
evt.preventDefault();
document.getElementById('root').scrollIntoView({behavior: 'smooth'});
if (currentPage !== page) gotoPage(page);
}
const handleMoveLeft = (evt) => {
evt.preventDefault();
gotoPage(currentPage - 1);
}
const handleMoveRight = (evt) => {
evt.preventDefault();
gotoPage(currentPage + 1);
}
const makePageLink = (page) => props.makeLink(page);
/**
* 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 = () => {
/**
* totalNumbers: the total page numbers to show on the control
* totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
*/
const totalNumbers = (pageNeighbours * 2) + 3;
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);
// handle: (1) < {5 6} [7] {8 9} (10)
if (hasLeftSpill && !hasRightSpill) {
const extraPages = range(startPage - spillOffset, startPage - 1);
hasLeft = true;
pages = [1, SPACE_A, ...extraPages, ...pages];
// handle: (1) {2 3} [4] {5 6} > (10)
} else if (!hasLeftSpill && hasRightSpill) {
const extraPages = range(endPage + 1, endPage + spillOffset);
hasRight = true;
pages = [1, ...pages, ...extraPages, SPACE_B, totalPages];
// handle: (1) < {4 5} [6] {7 8} > (10)
} else if (hasLeftSpill && hasRightSpill) {
hasLeft = true;
hasRight = true;
pages = [1, SPACE_A, ...pages, SPACE_B, totalPages];
}
return pages;
}
return range(1, totalPages);
}
if (!totalRecords || totalPages === 1) return null;
const pages = fetchPageNumbers();
const blocks = pages.map((page, index) => {
if (page === SPACE_A || page === SPACE_B) return (
<span key={page} className='spacing'></span>
);
return (
<li key={page} className='page-item '>
<a className={`page-link ${currentPage === page ? 'active' : ''}`} href={makePageLink(page)} onClick={handleClick(page)}>{page}</a>
</li>
);
})
return (
<Fragment>
<ul className="pagination">
{ hasLeft ?
<li key='left' className="page-item left">
<a className="page-link" href={makePageLink(currentPage - 1)} onClick={handleMoveLeft}>
<span>Anterior</span>
</a>
</li>
:
<li key='left' className="page-item left"/>
}
<ul key='center' className='page-center'>
{blocks}
</ul>
{hasRight ?
<li key='right' className="page-item right">
<a className="page-link" href={makePageLink(currentPage + 1)} onClick={handleMoveRight}>
<span>Siguiente</span>
</a>
</li>
:
<li key='right' className="page-item right"/>
}
</ul>
</Fragment>
);
}