Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 6.9 KiB |
@ -0,0 +1,25 @@ |
|||
import React from 'react'; |
|||
|
|||
class SVGArrowRight extends React.Component { |
|||
render() { |
|||
return ( |
|||
<svg enableBackground="new 0 0 32 32" height="32px" id="Layer_1" version="1.1" viewBox="0 0 32 32" width="32px"> |
|||
<g> |
|||
<polyline fill="none" points=" 649,137.999 675,137.999 675,155.999 661,155.999 " stroke="#FFFFFF" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2"/> |
|||
<polyline fill="none" points=" 653,155.999 649,155.999 649,141.999 " stroke="#FFFFFF" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2"/> |
|||
<polyline fill="none" points=" 661,156 653,162 653,156 " stroke="#FFFFFF" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2"/> |
|||
</g> |
|||
<g> |
|||
<g> |
|||
<path d="M2.982,17h26.035c0.397,0,0.756-0.244,0.908-0.617c0.152-0.374,0.068-0.804-0.213-1.09l-11.789-12 c-0.384-0.391-1.005-0.391-1.389,0s-0.384,1.023,0,1.414L26.646,15H2.982C2.439,15,2,15.448,2,16S2.439,17,2.982,17z"/> |
|||
</g> |
|||
<g> |
|||
<path d="M17.228,29c0.251,0,0.503-0.098,0.695-0.293l7.86-8c0.384-0.391,0.384-1.023,0-1.414s-1.005-0.391-1.389,0l-7.86,8 c-0.384,0.391-0.384,1.023,0,1.414C16.725,28.902,16.977,29,17.228,29z"/> |
|||
</g> |
|||
</g> |
|||
</svg> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default SVGArrowRight; |
@ -1,19 +0,0 @@ |
|||
import React from 'react'; |
|||
|
|||
class SVGMNZ extends React.Component { |
|||
render() { |
|||
return ( |
|||
<svg version="1.1" id="Calque_1" x="0px" y="0px" viewBox="0 0 50 50" style={{ enableBackground: 'new 0 0 148 50' }}> |
|||
<g> |
|||
<path className="st1" d="M15.9,17.9"></path> |
|||
<path d="M39.9,34.5c-0.2-1.2-0.6-2.4-0.9-3.5c-0.3-1.2-0.6-2.4-0.9-3.6c-0.8-3-1.6-6-2.4-9c-0.2-0.7-0.3-1.4-0.5-2.1 c-0.1-0.3-0.2-0.7-0.5-0.9c-0.3-0.1-0.6-0.1-0.9-0.1c-0.4,0-0.8,0-1.2,0c-0.8,0-1.7,0-2.5,0c-0.6,0-1.1,0-1.7,0.1 c-0.5,0.1-1,0.4-1.2,0.9c-0.1,0.2,0,0.5,0.2,0.6c0.1,0.1,0.3,0,0.4-0.1c0.1,0,0.4-0.3,0.5-0.3l4.7,17.3l0,0c0,0,0,0.1,0,0.1 c0.1,0.4,0.3,0.8,0.6,0.9c0.2,0.1,0.4,0.2,0.7,0.2h0.5h0.8h2.4h1.3C39.6,35.1,40,34.9,39.9,34.5z"></path> |
|||
<path d="M28.3,34.5c-0.2-1.2-0.6-2.4-0.9-3.5c-0.3-1.2-0.6-2.4-0.9-3.6c-0.8-3-1.6-6-2.4-9c-0.2-0.7-0.3-1.4-0.5-2.1 c-0.1-0.3-0.2-0.7-0.5-0.9c-0.3-0.1-0.6-0.1-0.9-0.1c-0.4,0-0.8,0-1.2,0c-0.8,0-1.7,0-2.5,0c-0.6,0-1.1,0-1.7,0.1 c-0.5,0.1-1,0.4-1.2,0.9c-0.1,0.2,0,0.5,0.2,0.6c0.1,0.1,0.3,0,0.4-0.1c0.1,0,0.4-0.3,0.5-0.3l4.7,17.3l0,0c0,0,0,0.1,0,0.1 c0.1,0.4,0.3,0.8,0.6,0.9c0.2,0.1,0.4,0.2,0.7,0.2h0.5h0.8h2.4h1.3C28,35.1,28.4,34.9,28.3,34.5z"></path> |
|||
<path d="M19.1,30.7l-3.2-12.5h0c0-0.2-0.2-0.4-0.5-0.4c-0.2,0-0.4,0.2-0.5,0.4l0,0L10.7,34l0,0c0,0.1,0,0.2,0,0.2 c0,0.5,0.4,1,1,1H17c0.4,0,0.8-0.3,0.9-0.7l0,0L19.1,30.7z"></path> |
|||
<path d="M30.9,30.4l-3.5-12.6h0c0-0.2-0.2-0.3-0.4-0.3c-0.2,0-0.4,0.1-0.4,0.3h0l-0.7,2.5l3.5,12.2l0,0l0,0 c0.1,0.2,0.2,0.3,0.4,0.3c0.2,0,0.3-0.1,0.4-0.3l0,0L30.9,30.4z"></path> |
|||
</g> |
|||
</svg> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default SVGMNZ; |
@ -0,0 +1,216 @@ |
|||
import React from 'react'; |
|||
import ReactTable from 'react-table'; |
|||
import TablePaginationRenderer from './pagination'; |
|||
import { connect } from 'react-redux'; |
|||
import { translate } from '../../../translate/translate'; |
|||
import { sortByDate } from '../../../util/sort'; |
|||
import { formatValue } from '../../../util/formatValue'; |
|||
import Config from '../../../config'; |
|||
import { |
|||
triggerToaster, |
|||
} from '../../../actions/actionCreators'; |
|||
import Store from '../../../store'; |
|||
import { secondsToString } from '../../../util/time'; |
|||
|
|||
const BOTTOM_BAR_DISPLAY_THRESHOLD = 15; |
|||
|
|||
class DexSwapsTable extends React.Component { |
|||
constructor(props) { |
|||
super(props); |
|||
this.state = { |
|||
itemsList: [], |
|||
filteredItemsList: [], |
|||
itemsListColumns: this.generateItemsListColumns(), |
|||
defaultPageSize: 20, |
|||
pageSize: 20, |
|||
showPagination: true, |
|||
searchTerm: null, |
|||
loading: false, |
|||
}; |
|||
} |
|||
|
|||
// https://react-table.js.org/#/custom-sorting
|
|||
tableSorting(a, b) { // ugly workaround, override default sort
|
|||
if (Date.parse(a)) { // convert date to timestamp
|
|||
a = Date.parse(a); |
|||
} |
|||
if (Date.parse(b)) { |
|||
b = Date.parse(b); |
|||
} |
|||
// force null and undefined to the bottom
|
|||
a = (a === null || a === undefined) ? -Infinity : a; |
|||
b = (b === null || b === undefined) ? -Infinity : b; |
|||
// force any string values to lowercase
|
|||
a = typeof a === 'string' ? a.toLowerCase() : a; |
|||
b = typeof b === 'string' ? b.toLowerCase() : b; |
|||
// Return either 1 or -1 to indicate a sort priority
|
|||
if (a > b) { |
|||
return 1; |
|||
} |
|||
if (a < b) { |
|||
return -1; |
|||
} |
|||
// returning 0 or undefined will use any subsequent column sorting methods or the row index as a tiebreaker
|
|||
return 0; |
|||
} |
|||
|
|||
generateItemsListColumns(itemsCount) { |
|||
let columns = []; |
|||
let _col; |
|||
|
|||
_col = [{ |
|||
id: 'direction', |
|||
Header: translate('INDEX.DIRECTION'), |
|||
Footer: translate('INDEX.DIRECTION'), |
|||
className: 'colum--direction', |
|||
headerClassName: 'colum--direction', |
|||
footerClassName: 'colum--direction', |
|||
accessor: (item) => (item.iambob === 0) ? 'Buyer' : 'Seller', |
|||
}, |
|||
{ |
|||
id: 'pair', |
|||
Header: 'Pair', |
|||
Footer: 'Pair', |
|||
className: 'colum--pair', |
|||
headerClassName: 'colum--pair', |
|||
footerClassName: 'colum--pair', |
|||
accessor: (item) => (item.iambob === 0) ? `${item.alice}/${item.bob}` : `${item.bob}/${item.alice}`, |
|||
}, |
|||
{ |
|||
id: 'sent', |
|||
Header: 'Sent', |
|||
Footer: 'Sent', |
|||
className: 'colum--sent', |
|||
headerClassName: 'colum--sent', |
|||
footerClassName: 'colum--sent', |
|||
accessor: (item) => (item.iambob === 0) ? `${formatValue(parseFloat(item.values[3]) + parseFloat(item.values[6]))} ${item.alice}` : `${formatValue(parseFloat(item.values[0]) + parseFloat(item.bobtxfee))} ${item.bob}`, |
|||
}, |
|||
{ |
|||
id: 'received', |
|||
Header: 'Received', |
|||
Footer: 'Recevied', |
|||
className: 'colum--received', |
|||
headerClassName: 'colum--received', |
|||
footerClassName: 'colum--received', |
|||
accessor: (item) => (item.iambob === 0) ? `${formatValue(item.srcamount)} ${item.bob}` : `${formatValue(item.values[3])} ${item.alice}`, |
|||
}, |
|||
{ |
|||
id: 'rate', |
|||
Header: 'Rate', |
|||
Footer: 'Rate', |
|||
className: 'colum--rate', |
|||
headerClassName: 'colum--rate', |
|||
footerClassName: 'colum--rate', |
|||
accessor: (item) => (item.iambob === 0) ? `${formatValue(parseFloat(parseFloat(item.values[3]) + parseFloat(item.values[6])) / parseFloat(item.srcamount))} (${parseFloat(item.values[3]) + parseFloat(item.values[6])} ${item.alice} / ${item.srcamount} ${item.bob})`: `${formatValue(parseFloat(item.values[3]) / parseFloat(parseFloat(item.values[0]) + parseFloat(item.bobtxfee)))} (${formatValue(item.values[3])} ${item.bob} / ${formatValue(parseFloat(item.values[0]) + parseFloat(item.bobtxfee))} ${item.bob})`, |
|||
}, |
|||
{ |
|||
id: 'finishtime', |
|||
Header: translate('INDEX.TIME'), |
|||
Footer: translate('INDEX.TIME'), |
|||
accessor: (item) => secondsToString(item.finishtime), |
|||
}]; |
|||
|
|||
if (itemsCount <= BOTTOM_BAR_DISPLAY_THRESHOLD) { |
|||
delete _col[0].Footer; |
|||
delete _col[1].Footer; |
|||
delete _col[2].Footer; |
|||
delete _col[3].Footer; |
|||
} |
|||
|
|||
columns.push(..._col); |
|||
|
|||
return columns; |
|||
} |
|||
|
|||
componentWillMount() { |
|||
const _swaps = this.props.Dex.swaps.swaps.filter(swap => swap.alice && swap.finishtime); |
|||
|
|||
this.setState({ |
|||
itemsList: _swaps, |
|||
filteredItemsList: this.filterData(_swaps, this.state.searchTerm), |
|||
showPagination: _swaps && _swaps.length >= this.state.defaultPageSize, |
|||
itemsListColumns: this.generateItemsListColumns(_swaps.length), |
|||
}); |
|||
} |
|||
|
|||
componentWillReceiveProps(props) { |
|||
console.warn('table will receive props'); |
|||
|
|||
this.setState({ |
|||
itemsList: this.props.Dex.swaps.swaps, |
|||
filteredItemsList: this.filterData(this.props.Dex.swaps.swaps, this.state.searchTerm), |
|||
showPagination: this.props.Dex.swaps.swaps && this.props.Dex.swaps.swaps.length >= this.state.defaultPageSize, |
|||
itemsListColumns: this.generateItemsListColumns(this.props.Dex.swaps.swaps.length), |
|||
}); |
|||
|
|||
console.warn(this.state); |
|||
} |
|||
|
|||
onPageSizeChange(pageSize, pageIndex) { |
|||
this.setState(Object.assign({}, this.state, { |
|||
pageSize: pageSize, |
|||
showPagination: this.state.itemsList && this.state.itemsList.length >= this.state.defaultPageSize, |
|||
})) |
|||
} |
|||
|
|||
onSearchTermChange(newSearchTerm) { |
|||
this.setState(Object.assign({}, this.state, { |
|||
searchTerm: newSearchTerm, |
|||
filteredItemsList: this.filterData(this.state.itemsList, newSearchTerm), |
|||
})); |
|||
} |
|||
|
|||
filterData(list, searchTerm) { |
|||
return list.filter(item => this.filterDataByProp(item, searchTerm)); |
|||
} |
|||
|
|||
filterDataByProp(item, term) { |
|||
if (!term) { |
|||
return true; |
|||
} |
|||
|
|||
return this.contains(item.alice.toLowerCase(), term) || |
|||
this.contains(item.bob.toLowerCase(), term) || |
|||
this.contains(secondsToString(item.finishtime).toLowerCase(), term); |
|||
} |
|||
|
|||
contains(value, property) { |
|||
return (value + '').indexOf(property) !== -1; |
|||
} |
|||
|
|||
render() { |
|||
return ( |
|||
<div className="dex-table"> |
|||
<input |
|||
className="form-control" |
|||
onChange={ e => this.onSearchTermChange(e.target.value) } |
|||
placeholder={ translate('DASHBOARD.SEARCH') } /> |
|||
<ReactTable |
|||
data={ this.state.filteredItemsList } |
|||
columns={ this.state.itemsListColumns } |
|||
minRows="0" |
|||
sortable={ true } |
|||
className="-striped -highlight" |
|||
PaginationComponent={ TablePaginationRenderer } |
|||
nextText={ translate('INDEX.NEXT_PAGE') } |
|||
previousText={ translate('INDEX.PREVIOUS_PAGE') } |
|||
showPaginationBottom={ this.state.showPagination } |
|||
pageSize={ this.state.pageSize } |
|||
defaultSortMethod={ this.tableSorting } |
|||
defaultSorted={[{ // default sort
|
|||
id: 'finishtime', |
|||
desc: true, |
|||
}]} |
|||
onPageSizeChange={ (pageSize, pageIndex) => this.onPageSizeChange(pageSize, pageIndex) } /> |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
const mapStateToProps = (state) => { |
|||
return { |
|||
Dex: state.Dex, |
|||
}; |
|||
}; |
|||
|
|||
export default connect(mapStateToProps)(DexSwapsTable); |
@ -0,0 +1,50 @@ |
|||
import React, { Component } from 'react'; |
|||
import PaginationRender from './pagination.render'; |
|||
|
|||
export default class TablePaginationRenderer extends Component { |
|||
constructor(props) { |
|||
super(); |
|||
this.state = { |
|||
page: props.page, |
|||
}; |
|||
this.getSafePage = this.getSafePage.bind(this); |
|||
this.changePage = this.changePage.bind(this); |
|||
this.applyPage = this.applyPage.bind(this); |
|||
} |
|||
|
|||
componentWillReceiveProps(nextProps) { |
|||
this.setState({ |
|||
page: nextProps.page, |
|||
}); |
|||
} |
|||
|
|||
getSafePage(page) { |
|||
if (isNaN(page)) { |
|||
page = this.props.page; |
|||
} |
|||
|
|||
return Math.min(Math.max(page, 0), this.props.pages - 1); |
|||
} |
|||
|
|||
changePage(page) { |
|||
page = this.getSafePage(page); |
|||
this.setState({ |
|||
page, |
|||
}); |
|||
|
|||
if (this.props.page !== page) { |
|||
this.props.onPageChange(page); |
|||
} |
|||
} |
|||
|
|||
applyPage(e) { |
|||
const page = this.state.page; |
|||
|
|||
e && e.preventDefault(); |
|||
this.changePage(page === '' ? this.props.page : page); |
|||
} |
|||
|
|||
render() { |
|||
return PaginationRender.call(this); |
|||
} |
|||
} |
@ -0,0 +1,103 @@ |
|||
import React from 'react'; |
|||
import classnames from 'classnames'; |
|||
|
|||
const defaultButton = props => |
|||
<button |
|||
type="button" |
|||
className="-btn" |
|||
{...props}> |
|||
{props.children} |
|||
</button> |
|||
|
|||
const PaginationRender = function() { |
|||
const { |
|||
// Computed
|
|||
pages, |
|||
// Props
|
|||
page, |
|||
showPageSizeOptions, |
|||
pageSizeOptions, |
|||
pageSize, |
|||
showPageJump, |
|||
canPrevious, |
|||
canNext, |
|||
onPageSizeChange, |
|||
className, |
|||
PreviousComponent = defaultButton, |
|||
NextComponent = defaultButton, |
|||
} = this.props; |
|||
|
|||
return ( |
|||
<div |
|||
className={classnames(className, '-pagination')} |
|||
style={this.props.paginationStyle}> |
|||
<div className="-previous"> |
|||
<PreviousComponent |
|||
onClick={e => { |
|||
if (!canPrevious) return; |
|||
this.changePage(page - 1) |
|||
}} |
|||
disabled={!canPrevious}> |
|||
{this.props.previousText} |
|||
</PreviousComponent> |
|||
</div> |
|||
<div className="-center"> |
|||
<span className="-pageInfo"> |
|||
{this.props.pageText}{' '} |
|||
{showPageJump |
|||
? |
|||
<div className="-pageJump"> |
|||
<input |
|||
type={this.state.page === '' ? 'text' : 'number'} |
|||
onChange={e => { |
|||
const val = e.target.value; |
|||
this.changePage(val - 1); |
|||
}} |
|||
value={this.state.page === '' ? '' : this.state.page + 1} |
|||
onBlur={this.applyPage} |
|||
onKeyPress={e => { |
|||
if (e.which === 13 || e.keyCode === 13) { |
|||
this.applyPage(); |
|||
} |
|||
}} /> |
|||
</div> |
|||
: |
|||
<span className="-currentPage"> |
|||
{page + 1} |
|||
</span>}{' '} |
|||
{this.props.ofText}{' '} |
|||
<span className="-totalPages">{pages || 1}</span> |
|||
</span> |
|||
{ showPageSizeOptions && |
|||
<span className="select-wrap -pageSizeOptions"> |
|||
<select |
|||
onChange={e => onPageSizeChange(Number(e.target.value))} |
|||
value={pageSize}> |
|||
{ pageSizeOptions.map((option, i) => { |
|||
return ( |
|||
<option |
|||
key={i} |
|||
value={option}> |
|||
{option} {this.props.rowsText} |
|||
</option> |
|||
); |
|||
})} |
|||
</select> |
|||
</span> |
|||
} |
|||
</div> |
|||
<div className="-next"> |
|||
<NextComponent |
|||
onClick={e => { |
|||
if (!canNext) return; |
|||
this.changePage(page + 1); |
|||
}} |
|||
disabled={!canNext}> |
|||
{this.props.nextText} |
|||
</NextComponent> |
|||
</div> |
|||
</div> |
|||
) |
|||
}; |
|||
|
|||
export default PaginationRender; |
@ -0,0 +1,92 @@ |
|||
.search-box { |
|||
float: right; |
|||
padding-right: 0; |
|||
} |
|||
.basilisk-progress-bar { |
|||
position: absolute; |
|||
width: 100%; |
|||
} |
|||
.breadcrumb--basilisk, |
|||
.breadcrumb--native { |
|||
top: 0; |
|||
} |
|||
.dropdown-menu { |
|||
.no--hover { |
|||
pointer-events: none; |
|||
} |
|||
} |
|||
.ReactTable { |
|||
border: none; |
|||
|
|||
.pagination-bottom { |
|||
margin-top: 35px; |
|||
} |
|||
.rt-td { |
|||
text-align: center; |
|||
} |
|||
.rt-table { |
|||
border: 1px solid rgba(0, 0, 0, 0.1); |
|||
} |
|||
.rt-thead .rt-th, |
|||
.rt-thead .rt-td { |
|||
padding: 10px 5px; |
|||
} |
|||
.rt-tr.-odd div, |
|||
.rt-tr.-even div { |
|||
padding-top: 10px; |
|||
padding-bottom: 10px; |
|||
} |
|||
.-pagination, |
|||
.rt-thead, |
|||
.rt-tfoot { |
|||
border: none; |
|||
} |
|||
.rt-tfoot { |
|||
border-top: 1px solid rgba(0, 0, 0, 0.1); |
|||
} |
|||
.rt-thead { |
|||
border-bottom: 1px solid rgba(0, 0, 0, 0.1); |
|||
} |
|||
.colum--direction { |
|||
width: 40px !important; |
|||
flex: 40 0 auto !important; |
|||
padding-right: 10px; |
|||
} |
|||
.colum--txinfo { |
|||
width: 40px !important; |
|||
flex: 40 0 auto !important; |
|||
} |
|||
.colum--type { |
|||
width: 40px !important; |
|||
flex: 40 0 auto !important; |
|||
} |
|||
.-pagination { |
|||
.-pageJump { |
|||
margin-right: 5px; |
|||
margin-left: 5px; |
|||
} |
|||
.-btn { |
|||
color: #757575; |
|||
background-color: #efefef; |
|||
border: 1px solid #e0e0e0; |
|||
|
|||
&:hover { |
|||
color: #fff; |
|||
} |
|||
} |
|||
.-btn[disabled]:hover { |
|||
color: #757575; |
|||
} |
|||
} |
|||
.rt-noData { |
|||
top: 46px; |
|||
width: 100%; |
|||
text-align: center; |
|||
height: 98px; |
|||
padding: 38px; |
|||
background: rgba(255, 255, 255, 0.85); |
|||
} |
|||
} |
|||
.table-cell-offset-16 { |
|||
padding-left: 16px; |
|||
} |