mirror of https://github.com/embarklabs/embark.git
Merge pull request #156 from status-im/features/explorer-pagination
Add pagination to explorer
This commit is contained in:
commit
90c033187d
|
@ -2,11 +2,11 @@ import React from 'react';
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import Pagination from './Pagination';
|
||||||
|
|
||||||
import CardTitleIdenticon from './CardTitleIdenticon';
|
import CardTitleIdenticon from './CardTitleIdenticon';
|
||||||
import LoadMore from "./LoadMore";
|
|
||||||
|
|
||||||
const Blocks = ({blocks, showLoadMore, loadMore}) => (
|
const Blocks = ({blocks, changePage, currentPage, numberOfPages}) => (
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -37,7 +37,7 @@ const Blocks = ({blocks, showLoadMore, loadMore}) => (
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{showLoadMore && <LoadMore loadMore={() => loadMore()}/>}
|
<Pagination changePage={changePage} currentPage={currentPage} numberOfPages={numberOfPages}/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -46,8 +46,9 @@ const Blocks = ({blocks, showLoadMore, loadMore}) => (
|
||||||
|
|
||||||
Blocks.propTypes = {
|
Blocks.propTypes = {
|
||||||
blocks: PropTypes.arrayOf(PropTypes.object),
|
blocks: PropTypes.arrayOf(PropTypes.object),
|
||||||
showLoadMore: PropTypes.bool,
|
changePage: PropTypes.func,
|
||||||
loadMore: PropTypes.func
|
currentPage: PropTypes.number,
|
||||||
|
numberOfPages: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Blocks;
|
export default Blocks;
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
border-top-width: 0 !important; /*Bootstrap uses important, so we need to override it*/
|
border-top-width: 0 !important; /*Bootstrap uses important, so we need to override it*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.explorer-overview .card-body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.explorer-row + .explorer-row {
|
.explorer-row + .explorer-row {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
|
@ -12,3 +16,8 @@
|
||||||
width: 90%;
|
width: 90%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.explorer-row .text-truncate {
|
||||||
|
width: 90%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
|
@ -11,21 +11,21 @@ import TransactionsContainer from '../containers/TransactionsContainer';
|
||||||
import './Explorer.css';
|
import './Explorer.css';
|
||||||
|
|
||||||
const ExplorerDashboardLayout = () => (
|
const ExplorerDashboardLayout = () => (
|
||||||
<React.Fragment>
|
<div className="explorer-overview">
|
||||||
<Row className="mt-4">
|
<Row className="mt-4">
|
||||||
<Col>
|
<Col>
|
||||||
<AccountsContainer />
|
<AccountsContainer />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={6}>
|
<Col xl={6}>
|
||||||
<BlocksContainer />
|
<BlocksContainer />
|
||||||
</Col>
|
</Col>
|
||||||
<Col md={6}>
|
<Col xl={6}>
|
||||||
<TransactionsContainer />
|
<TransactionsContainer />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</React.Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default ExplorerDashboardLayout;
|
export default ExplorerDashboardLayout;
|
||||||
|
|
|
@ -129,7 +129,7 @@ class Layout extends React.Component {
|
||||||
</Nav>
|
</Nav>
|
||||||
<AppHeaderDropdown className="list-unstyled d-xl-none" direction="down">
|
<AppHeaderDropdown className="list-unstyled d-xl-none" direction="down">
|
||||||
<DropdownToggle nav>
|
<DropdownToggle nav>
|
||||||
<FontAwesome name='bars'/>
|
<FontAwesome name="bars"/>
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{HEADER_NAV_ITEMS.map((item) => (
|
{HEADER_NAV_ITEMS.map((item) => (
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import {Row, Col, Button} from 'reactstrap';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const LoadMore = ({loadMore}) => (
|
|
||||||
<Row className="my-3">
|
|
||||||
<Col className="text-center">
|
|
||||||
<Button onClick={loadMore} icon="plus" outline color="primary">Load More</Button>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
|
|
||||||
LoadMore.propTypes = {
|
|
||||||
loadMore: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LoadMore;
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {Pagination as RPagination, PaginationItem, PaginationLink} from 'reactstrap';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const NB_PAGES_MAX = 8;
|
||||||
|
|
||||||
|
const Pagination = ({currentPage, numberOfPages, changePage}) => {
|
||||||
|
let max = currentPage + NB_PAGES_MAX / 2;
|
||||||
|
if (max > numberOfPages) {
|
||||||
|
max = numberOfPages;
|
||||||
|
}
|
||||||
|
let i = max - NB_PAGES_MAX;
|
||||||
|
if (i < 1) {
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
if (max - i < NB_PAGES_MAX) {
|
||||||
|
max += NB_PAGES_MAX - max + 1;
|
||||||
|
}
|
||||||
|
const pageNumbers = [];
|
||||||
|
for (i; i <= max; i++) {
|
||||||
|
pageNumbers.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RPagination aria-label="Explorer navigation" className="mt-4 mb-0 float-right">
|
||||||
|
<PaginationItem disabled={currentPage <= 1}>
|
||||||
|
<PaginationLink previous href="#" onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
changePage(currentPage - 1);
|
||||||
|
}}/>
|
||||||
|
</PaginationItem>
|
||||||
|
{pageNumbers.map(number => (<PaginationItem active={currentPage === number} key={'page-' + number}>
|
||||||
|
<PaginationLink href="#" onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
changePage(number);
|
||||||
|
}}>
|
||||||
|
{number}
|
||||||
|
</PaginationLink>
|
||||||
|
</PaginationItem>))}
|
||||||
|
<PaginationItem disabled={currentPage >= numberOfPages}>
|
||||||
|
<PaginationLink next href="#" onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
changePage(currentPage + 1);
|
||||||
|
}}/>
|
||||||
|
</PaginationItem>
|
||||||
|
</RPagination>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Pagination.propTypes = {
|
||||||
|
numberOfPages: PropTypes.number,
|
||||||
|
currentPage: PropTypes.number,
|
||||||
|
changePage: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Pagination;
|
|
@ -4,9 +4,9 @@ import {Row, Col, Card, CardHeader, CardBody} from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import CardTitleIdenticon from './CardTitleIdenticon';
|
import CardTitleIdenticon from './CardTitleIdenticon';
|
||||||
import LoadMore from "./LoadMore";
|
import Pagination from "./Pagination";
|
||||||
|
|
||||||
const Transactions = ({transactions, showLoadMore, loadMore}) => (
|
const Transactions = ({transactions, changePage, currentPage, numberOfPages}) => (
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -41,7 +41,7 @@ const Transactions = ({transactions, showLoadMore, loadMore}) => (
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{showLoadMore && <LoadMore loadMore={() => loadMore()}/>}
|
<Pagination changePage={changePage} currentPage={currentPage} numberOfPages={numberOfPages}/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -50,8 +50,9 @@ const Transactions = ({transactions, showLoadMore, loadMore}) => (
|
||||||
|
|
||||||
Transactions.propTypes = {
|
Transactions.propTypes = {
|
||||||
transactions: PropTypes.arrayOf(PropTypes.object),
|
transactions: PropTypes.arrayOf(PropTypes.object),
|
||||||
showLoadMore: PropTypes.bool,
|
changePage: PropTypes.func,
|
||||||
loadMore: PropTypes.func
|
currentPage: PropTypes.number,
|
||||||
|
numberOfPages: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Transactions;
|
export default Transactions;
|
||||||
|
|
|
@ -7,7 +7,17 @@ import Blocks from '../components/Blocks';
|
||||||
import DataWrapper from "../components/DataWrapper";
|
import DataWrapper from "../components/DataWrapper";
|
||||||
import {getBlocks} from "../reducers/selectors";
|
import {getBlocks} from "../reducers/selectors";
|
||||||
|
|
||||||
|
const MAX_BLOCKS = 10; // TODO use same constant as API
|
||||||
|
|
||||||
class BlocksContainer extends Component {
|
class BlocksContainer extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {currentPage: 0};
|
||||||
|
this.numberOfBlocks = 0;
|
||||||
|
this.currentBlocks = [];
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchBlocks();
|
this.props.fetchBlocks();
|
||||||
this.props.initBlockHeader();
|
this.props.initBlockHeader();
|
||||||
|
@ -17,23 +27,41 @@ class BlocksContainer extends Component {
|
||||||
this.props.stopBlockHeader();
|
this.props.stopBlockHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMore() {
|
getNumberOfPages() {
|
||||||
this.props.fetchBlocks(this.loadMoreFrom());
|
if (!this.numberOfBlocks) {
|
||||||
|
let blocks = this.props.blocks;
|
||||||
|
if (blocks.length === 0) {
|
||||||
|
this.numberOfBlocks = 0;
|
||||||
|
} else {
|
||||||
|
this.numberOfBlocks = blocks[blocks.length - 1].number - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.ceil(this.numberOfBlocks / MAX_BLOCKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMoreFrom() {
|
changePage(newPage) {
|
||||||
let blocks = this.props.blocks;
|
this.setState({currentPage: newPage});
|
||||||
if (blocks.length === 0) {
|
|
||||||
return 0;
|
this.props.fetchBlocks((newPage * MAX_BLOCKS) + MAX_BLOCKS);
|
||||||
}
|
}
|
||||||
return blocks[blocks.length - 1].number - 1;
|
|
||||||
|
getCurrentBlocks() {
|
||||||
|
const currentPage = this.state.currentPage || this.getNumberOfPages();
|
||||||
|
return this.props.blocks.filter(block => block.number <= (currentPage * MAX_BLOCKS) + MAX_BLOCKS &&
|
||||||
|
block.number > currentPage * MAX_BLOCKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const newBlocks = this.getCurrentBlocks();
|
||||||
|
if (newBlocks.length) {
|
||||||
|
this.currentBlocks = newBlocks;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<DataWrapper shouldRender={this.props.blocks.length > 0} {...this.props} render={({blocks}) => (
|
<DataWrapper shouldRender={this.currentBlocks.length > 0} {...this.props} render={() => (
|
||||||
<Blocks blocks={blocks} showLoadMore={(this.loadMoreFrom() >= 0)} loadMore={() => this.loadMore()} />
|
<Blocks blocks={this.currentBlocks} numberOfPages={this.getNumberOfPages()}
|
||||||
|
changePage={(newPage) => this.changePage(newPage)}
|
||||||
|
currentPage={this.state.currentPage || this.getNumberOfPages()} />
|
||||||
)} />
|
)} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,17 @@ import Transactions from '../components/Transactions';
|
||||||
import DataWrapper from "../components/DataWrapper";
|
import DataWrapper from "../components/DataWrapper";
|
||||||
import {getTransactions} from "../reducers/selectors";
|
import {getTransactions} from "../reducers/selectors";
|
||||||
|
|
||||||
|
const MAX_TXS = 10; // TODO use same constant as API
|
||||||
|
|
||||||
class TransactionsContainer extends Component {
|
class TransactionsContainer extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {currentPage: 0};
|
||||||
|
this.numberOfTxs = 0;
|
||||||
|
this.currentTxs = [];
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchTransactions();
|
this.props.fetchTransactions();
|
||||||
this.props.initBlockHeader();
|
this.props.initBlockHeader();
|
||||||
|
@ -17,24 +27,41 @@ class TransactionsContainer extends Component {
|
||||||
this.props.stopBlockHeader();
|
this.props.stopBlockHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMore() {
|
getNumberOfPages() {
|
||||||
this.props.fetchTransactions(this.loadMoreFrom());
|
if (!this.numberOfTxs) {
|
||||||
|
let transactions = this.props.transactions;
|
||||||
|
if (transactions.length === 0) {
|
||||||
|
this.numberOfTxs = 0;
|
||||||
|
} else {
|
||||||
|
this.numberOfTxs = transactions[transactions.length - 1].blockNumber - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.ceil(this.numberOfTxs / MAX_TXS);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMoreFrom() {
|
changePage(newPage) {
|
||||||
let transactions = this.props.transactions;
|
this.setState({currentPage: newPage});
|
||||||
if (transactions.length === 0) {
|
|
||||||
return 0;
|
this.props.fetchTransactions((newPage * MAX_TXS) + MAX_TXS);
|
||||||
}
|
}
|
||||||
return transactions[transactions.length - 1].blockNumber - 1;
|
|
||||||
|
getCurrentTransactions() {
|
||||||
|
const currentPage = this.state.currentPage || this.getNumberOfPages();
|
||||||
|
return this.props.transactions.filter(tx => tx.blockNumber <= (currentPage * MAX_TXS) + MAX_TXS &&
|
||||||
|
tx.blockNumber > currentPage * MAX_TXS);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const newTxs = this.getCurrentTransactions();
|
||||||
|
if (newTxs.length) {
|
||||||
|
this.currentTxs = newTxs;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<DataWrapper shouldRender={this.props.transactions.length > 0} {...this.props} render={({transactions}) => (
|
<DataWrapper shouldRender={this.currentTxs.length > 0} {...this.props} render={() => (
|
||||||
<Transactions transactions={transactions}
|
<Transactions transactions={this.currentTxs} numberOfPages={this.getNumberOfPages()}
|
||||||
showLoadMore={(this.loadMoreFrom() >= 0)} loadMore={() => this.loadMore()} />
|
changePage={(newPage) => this.changePage(newPage)}
|
||||||
|
currentPage={this.state.currentPage || this.getNumberOfPages()} />
|
||||||
)} />
|
)} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue