import * as React from 'react'; import * as _ from 'lodash'; import * as DefaultStyles from './style'; import { PAGER_ELEMENT, Control, PrevControls, NextControls, PrevSetControl, NextSetControl } from './constants'; import { PagerControl } from './PagerControl'; export namespace Pager { export interface Props { pagesToShow: number; totalItems: number; itemsPerPage: number startingPage?: number; styles?: Styles; onPageChange: (newPage: number) => void; id?: string; name?: string; } export interface State { currentPageNumber: number } export interface Styles { Container?: any; PagerContainer?: any; PagerItemSelected?: any; PagerItemUnselected?: any; PagerItemContent?: any; } } export default class Pager extends React.Component { constructor(props: Pager.Props) { super(props); this.state = { currentPageNumber: props.startingPage ? props.startingPage : 0 }; } componentWillReceiveProps(props: Pager.Props): void { if (props.startingPage) this.setState({ currentPageNumber: props.startingPage }) } onPagerItemClicked = (action: string): void => { const pagesToShow: number = this.props.pagesToShow; const totalItems: number = this.getTotalPages(); let currentPageNumber: number = this.state.currentPageNumber; const currentPageSet: number = this.getCurrentPageSet(currentPageNumber); switch (action) { case PAGER_ELEMENT.NEXT_SET: { currentPageNumber = (currentPageSet + 1) * pagesToShow; break; } case PAGER_ELEMENT.PREVIOUS_SET: { currentPageNumber = (currentPageSet - 1) * pagesToShow; break; } case PAGER_ELEMENT.NEXT_PAGE: { currentPageNumber = Math.min(this.state.currentPageNumber + 1, totalItems - 1); break; } case PAGER_ELEMENT.PREVIOUS_PAGE: { currentPageNumber = Math.max(this.state.currentPageNumber - 1, 0); break; } case PAGER_ELEMENT.LAST_PAGE: { currentPageNumber = totalItems - 1; break; } case PAGER_ELEMENT.FIRST_PAGE: { currentPageNumber = 0; break; } default: { const pageSelected = _.toNumber(action) - 1; currentPageNumber = pageSelected; break; } } this.setState({ currentPageNumber }) this.props.onPageChange(currentPageNumber); } getCurrentPageSet = (currentPageNumber: number): number => { return (currentPageNumber < this.props.pagesToShow) ? 0 : Math.floor(currentPageNumber / this.props.pagesToShow); } getPagesInCurrentPageSet = (currentPageNumber: number, currentPageSet: number, totalPageSet: number, totalItems: number): number[] => { const totalPages: number = this.getTotalPages() const pagesToShow: number = this.props.pagesToShow; if ((totalPages % (pagesToShow) !== 0) && (currentPageNumber >= ((totalPageSet - 1) * pagesToShow))) { const rest: number = totalPages - ((totalPageSet - 1) * pagesToShow) return _.times(rest, (i) => ((totalPageSet - 1) * pagesToShow) + i + 1); } return _.times(Math.min(totalPages, pagesToShow), (i) => (currentPageSet * pagesToShow) + i + 1); } getTotalPageSets = (): number => { const totalPages: number = this.getTotalPages(); const pagesToShow: number = this.props.pagesToShow; return (totalPages < pagesToShow ? 1 : 0) + Math.floor(totalPages / pagesToShow) + (totalPages % pagesToShow !== 0 ? 1 : 0); } getTotalPages = (): number => { return Math.floor(this.props.totalItems / this.props.itemsPerPage) + (this.props.totalItems % this.props.itemsPerPage === 0 ? 0 : 1); } renderControls = (styles: Pager.Styles, controlList: Control[]): JSX.Element[] => { return controlList.map(control => { return ( ) }) } renderPages = (Styles: Pager.Styles, pagesInPageSet: number[]): JSX.Element[] => { return pagesInPageSet.map(i => { const pageNumber: number = i const label: string = "" + pageNumber; const pagerItemContent: JSX.Element = {label} ; const pagerItem: JSX.Element = pageNumber === this.state.currentPageNumber + 1 ? this.onPagerItemClicked(label)} id={this.props.id && this.props.id + '-pager-item-selected'} name={this.props.name && this.props.name + '-pager-item-selected'} /> : this.onPagerItemClicked(label)} id={this.props.id && this.props.id + '-pager-item-unselected'} name={this.props.name && this.props.name + '-pager-item-unselected'} />; return pagerItem }) } renderPageSetNav = (styles: Pager.Styles, action: Control): JSX.Element => { return ; } render(): JSX.Element { const Styles: Pager.Styles = _.merge(DefaultStyles, this.props.styles); const totalPages: number = this.getTotalPages(); const totalPageSet: number = this.getTotalPageSets(); const currentPageSet: number = this.getCurrentPageSet(this.state.currentPageNumber); const pagesInPageSet: number[] = this.getPagesInCurrentPageSet(this.state.currentPageNumber, currentPageSet, totalPageSet, this.props.totalItems); const canShowPrevSetControl: boolean = currentPageSet > 0; const canShowNextSetControl: boolean = (currentPageSet + 1) * this.props.pagesToShow < totalPages; return ( {this.renderControls(Styles, PrevControls)} {canShowPrevSetControl && this.renderPageSetNav(Styles, PrevSetControl)} {this.renderPages(Styles, pagesInPageSet)} {canShowNextSetControl && this.renderPageSetNav(Styles, NextSetControl)} {this.renderControls(Styles, NextControls)} ); } }