Skip to content

Instantly share code, notes, and snippets.

@RomiC
Created October 17, 2019 07:22
Show Gist options
  • Save RomiC/3601b19b23c5517c29e3c312dfd436d9 to your computer and use it in GitHub Desktop.
Save RomiC/3601b19b23c5517c29e3c312dfd436d9 to your computer and use it in GitHub Desktop.
Pafination React component
import range from 'degiro-frontend-core/lib/utils/range';
import React, {PureComponent} from 'react';
import {NavLink} from 'react-router-dom';
import {paginationLink, paginationLinkActive, paginationList, paginationListItem} from './pagination.css';
interface PaginationProps {
/**
* Total amount of items
*/
itemsTotal: number;
/**
* Current page
* @default 0
*/
currentPage?: number;
/**
* Items per page
* @default 10
*/
itemsPerPage?: number;
/**
* Amount of visible items (odd value recommended):
* [<- prev] 1 2 ... 32 33 34 ... 99 100 [next ->]
* |
* current page
* |______|
* visibleItems
* @default 3
*/
itemsVisible?: number;
/**
* Total amount of pages
* (will be calculated automatically if not provided)
*/
pagesTotal?: number;
/**
* If true, show "<- prev" and "next ->" buttons
*/
showPrevNextButtons?: boolean;
/**
* Function to generate links
* @param page Page number (starting from 1)
* @returns Link for the page
*/
getPageLink?: (page: number) => string;
}
const itemsPerPageDefault: number = 10;
const itemsVisibleDefault: number = 3;
export default class Pagination extends PureComponent<PaginationProps> {
/**
* Return total amount of pages
* @returns {number} Amount of pages
*/
private get pagesTotal(): number {
const {itemsPerPage = itemsPerPageDefault, itemsTotal, pagesTotal} = this.props;
const hasMoreThanOnePage = itemsPerPage >= 1 && itemsTotal;
return pagesTotal ? pagesTotal : hasMoreThanOnePage ? Math.ceil(itemsTotal / itemsPerPage) : 1;
}
/**
* Generate page ranges
* @returns {number[]} Page numbers range
*/
private getPageRages(): number[] {
const lastPageIndex = this.pagesTotal - 1;
const {currentPage = 0} = this.props;
const itemsVisibleHalf = Math.floor((this.props.itemsVisible || itemsVisibleDefault) / 2);
const result: number[] = [];
const mergeThreshold = 2;
const startBlock = range(0, Math.min(itemsVisibleHalf, lastPageIndex));
const middleBlock = range(
Math.max(0, currentPage - itemsVisibleHalf),
Math.min(lastPageIndex, currentPage + itemsVisibleHalf)
);
const endBlock = range(Math.max(0, lastPageIndex - itemsVisibleHalf), lastPageIndex);
for (const val of [
...startBlock,
...(middleBlock[0] < endBlock[0] ? [...middleBlock, ...endBlock] : endBlock)
]) {
const lastElem = typeof result[result.length - 1] !== 'undefined' ? result[result.length - 1] : val - 1;
if (val > lastElem) {
const diff = val - lastElem;
if (diff === 1) {
result.push(val);
} else if (diff <= mergeThreshold) {
result.push(...range(lastElem + 1, val));
} else {
result.push(Infinity, val);
}
}
}
return result;
}
/**
* Function to generate links for pages
* @param {number} page Page number (starting from 0)
* @returns {string} Link to page
*/
private getPageLink(page: number) {
const {getPageLink} = this.props;
if (typeof getPageLink === 'function') {
return getPageLink(page);
}
return `?page=${page}`;
}
render() {
const {showPrevNextButtons = false, currentPage = 0} = this.props;
return (
<nav>
<ul className={paginationList}>
{showPrevNextButtons && currentPage > 0 && (
<li className={paginationListItem}>
<NavLink to={this.getPageLink(currentPage)} className={paginationLink}>
&larr;
</NavLink>
</li>
)}
{this.getPageRages().map((page) => {
if (page === Infinity) {
return <li className={paginationListItem}>&hellip;</li>;
}
return (
<li className={paginationListItem}>
{page !== currentPage ? (
<NavLink to={this.getPageLink(page)} className={paginationLink}>
{page + 1}
</NavLink>
) : (
<span className={paginationLinkActive}>{page + 1}</span>
)}
</li>
);
})}
{showPrevNextButtons && currentPage < this.pagesTotal - 1 && (
<li className={paginationListItem}>
<NavLink to={this.getPageLink(currentPage + 1)} className={paginationLink}>
&rarr;
</NavLink>
</li>
)}
</ul>
</nav>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment