Paginate funcional
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
import React, {Component, Fragment} from 'react';
|
import React, {Fragment, useState} from 'react';
|
||||||
|
|
||||||
const LEFT_PAGE = 'LEFT';
|
const LEFT_PAGE = 'LEFT';
|
||||||
const RIGHT_PAGE = 'RIGHT';
|
const RIGHT_PAGE = 'RIGHT';
|
||||||
const SPACE = 'SPACE';
|
const SPACE_A = 'SPACE_A';
|
||||||
|
const SPACE_B = 'SPACE_B';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for creating a range of numbers
|
* Helper method for creating a range of numbers
|
||||||
@@ -20,59 +21,35 @@ const range = (from, to, step = 1) => {
|
|||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Paginate extends Component {
|
export const Paginate = (props) => {
|
||||||
constructor(props) {
|
const pageLimit = typeof props.pageLimit === 'number' ? props.pageLimit : 30;
|
||||||
super(props);
|
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);
|
||||||
|
|
||||||
this.loadProps = this.loadProps.bind(this);
|
const gotoPage = (page) => {
|
||||||
this.gotoPage = this.gotoPage.bind(this);
|
const currentPage = Math.max(0, Math.min(page, totalPages));
|
||||||
this.handleClick = this.handleClick.bind(this);
|
props.onPageChanged(page)
|
||||||
this.handleMoveLeft = this.handleMoveLeft.bind(this);
|
setCurrentPage(currentPage);
|
||||||
this.handleMoveRight = this.handleMoveRight.bind(this);
|
|
||||||
this.makePageLink = this.makePageLink.bind(this);
|
|
||||||
this.fetchPageNumbers = this.fetchPageNumbers.bind(this);
|
|
||||||
|
|
||||||
this.loadProps();
|
|
||||||
this.state = {currentPage: this.currentPage};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadProps() {
|
const handleClick = (page) => (evt) => {
|
||||||
const {totalRecords = 0, pageLimit = 30, pageNeighbours = 0, currentPage = 1} = this.props;
|
|
||||||
|
|
||||||
this.pageLimit = typeof pageLimit === 'number' ? pageLimit : 30;
|
|
||||||
this.totalRecords = typeof totalRecords === 'number' ? totalRecords : 0;
|
|
||||||
this.pageNeighbours = typeof pageNeighbours === 'number' ? Math.max(0, Math.min(pageNeighbours, 2)) : 0;
|
|
||||||
this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);
|
|
||||||
this.currentPage = typeof currentPage === 'number' ? currentPage : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
gotoPage(page) {
|
|
||||||
const {onPageChanged = f => f} = this.props;
|
|
||||||
const currentPage = Math.max(0, Math.min(page, this.totalPages));
|
|
||||||
this.setState({currentPage: currentPage}, () => onPageChanged(page));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick(page) {
|
|
||||||
return (evt) => {
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
if (this.state.currentPage !== page) this.gotoPage(page);
|
if (currentPage !== page) gotoPage(page);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMoveLeft(evt) {
|
const handleMoveLeft = (evt) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
this.gotoPage(this.state.currentPage - 1);
|
gotoPage(currentPage - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMoveRight(evt) {
|
const handleMoveRight = (evt) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
this.gotoPage(this.state.currentPage + 1);
|
gotoPage(currentPage + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
makePageLink(page) {
|
const makePageLink = (page) => props.makeLink(page);
|
||||||
const {makeLink = f => f} = this.props;
|
|
||||||
return makeLink(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let's say we have 10 pages and we set pageNeighbours to 2
|
* Let's say we have 10 pages and we set pageNeighbours to 2
|
||||||
@@ -85,16 +62,12 @@ export default class Paginate extends Component {
|
|||||||
* [x] => represents current page
|
* [x] => represents current page
|
||||||
* {...x} => represents page neighbours
|
* {...x} => represents page neighbours
|
||||||
*/
|
*/
|
||||||
fetchPageNumbers() {
|
const fetchPageNumbers = () => {
|
||||||
const totalPages = this.totalPages;
|
|
||||||
const currentPage = this.state.currentPage;
|
|
||||||
const pageNeighbours = this.pageNeighbours;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* totalNumbers: the total page numbers to show on the control
|
* totalNumbers: the total page numbers to show on the control
|
||||||
* totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
|
* totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
|
||||||
*/
|
*/
|
||||||
const totalNumbers = (this.pageNeighbours * 2) + 3;
|
const totalNumbers = (pageNeighbours * 2) + 3;
|
||||||
const totalBlocks = totalNumbers + 2;
|
const totalBlocks = totalNumbers + 2;
|
||||||
|
|
||||||
if (totalPages > totalBlocks) {
|
if (totalPages > totalBlocks) {
|
||||||
@@ -115,14 +88,14 @@ export default class Paginate extends Component {
|
|||||||
// handle: (1) < {5 6} [7] {8 9} (10)
|
// handle: (1) < {5 6} [7] {8 9} (10)
|
||||||
if (hasLeftSpill && !hasRightSpill) {
|
if (hasLeftSpill && !hasRightSpill) {
|
||||||
const extraPages = range(startPage - spillOffset, startPage - 1);
|
const extraPages = range(startPage - spillOffset, startPage - 1);
|
||||||
pages = [LEFT_PAGE, 1, SPACE, ...extraPages, ...pages];
|
pages = [LEFT_PAGE, 1, SPACE_A, ...extraPages, ...pages];
|
||||||
// handle: (1) {2 3} [4] {5 6} > (10)
|
// handle: (1) {2 3} [4] {5 6} > (10)
|
||||||
} else if (!hasLeftSpill && hasRightSpill) {
|
} else if (!hasLeftSpill && hasRightSpill) {
|
||||||
const extraPages = range(endPage + 1, endPage + spillOffset);
|
const extraPages = range(endPage + 1, endPage + spillOffset);
|
||||||
pages = [1, ...pages, ...extraPages, SPACE, totalPages, RIGHT_PAGE];
|
pages = [1, ...pages, ...extraPages, SPACE_B, totalPages, RIGHT_PAGE];
|
||||||
// handle: (1) < {4 5} [6] {7 8} > (10)
|
// handle: (1) < {4 5} [6] {7 8} > (10)
|
||||||
} else if (hasLeftSpill && hasRightSpill) {
|
} else if (hasLeftSpill && hasRightSpill) {
|
||||||
pages = [LEFT_PAGE, 1, SPACE, ...pages, SPACE, totalPages, RIGHT_PAGE];
|
pages = [LEFT_PAGE, 1, SPACE_A, ...pages, SPACE_B, totalPages, RIGHT_PAGE];
|
||||||
}
|
}
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
@@ -130,37 +103,34 @@ export default class Paginate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return range(1, totalPages);
|
return range(1, totalPages);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
|
||||||
this.loadProps();
|
|
||||||
|
|
||||||
if (!this.totalRecords || this.totalPages === 1) return null;
|
if (!totalRecords || totalPages === 1) return null;
|
||||||
|
|
||||||
const currentPage = this.state.currentPage;
|
const pages = fetchPageNumbers();
|
||||||
const pages = this.fetchPageNumbers();
|
|
||||||
const blocks = pages.map((page, index) => {
|
const blocks = pages.map((page, index) => {
|
||||||
if (page === LEFT_PAGE) return (
|
if (page === LEFT_PAGE) return (
|
||||||
<li key={page} className="page-item">
|
<li key={page} className="page-item">
|
||||||
<a className="page-link" href={this.makePageLink(this.state.currentPage - 1)} onClick={this.handleMoveLeft}>
|
<a className="page-link" href={makePageLink(currentPage - 1)} onClick={handleMoveLeft}>
|
||||||
<span>Anterior</span>
|
<span>Anterior</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
if (page === RIGHT_PAGE) return (
|
if (page === RIGHT_PAGE) return (
|
||||||
<li key={page} className="page-item">
|
<li key={page} className="page-item">
|
||||||
<a className="page-link" href={this.makePageLink(this.state.currentPage + 1)} onClick={this.handleMoveRight}>
|
<a className="page-link" href={makePageLink(currentPage + 1)} onClick={handleMoveRight}>
|
||||||
<span>Siguiente</span>
|
<span>Siguiente</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
if (page === SPACE) return (
|
if (page === SPACE_A || page === SPACE_B) return (
|
||||||
<span className='spacing'>…</span>
|
<span key={page} className='spacing'>…</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={page} className='page-item '>
|
<li key={page} className='page-item '>
|
||||||
<a className={`page-link ${currentPage === page ? 'active' : ''}`} href={this.makePageLink(page)} onClick={this.handleClick(page)}>{page}</a>
|
<a className={`page-link ${currentPage === page ? 'active' : ''}`} href={makePageLink(page)} onClick={handleClick(page)}>{page}</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -174,5 +144,4 @@ export default class Paginate extends Component {
|
|||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import queryString from "query-string";
|
|||||||
|
|
||||||
import {searchArtist, searchDisc, searchSong} from "../services/search_service";
|
import {searchArtist, searchDisc, searchSong} from "../services/search_service";
|
||||||
import SearchBar from "./SearchBar";
|
import SearchBar from "./SearchBar";
|
||||||
import Paginate from "./Paginate";
|
import {Paginate} from "./Paginate";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Tab, TabList, TabPanel, Tabs} from "react-tabs";
|
import {Tab, TabList, TabPanel, Tabs} from "react-tabs";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user