feat: add state filter to trades list

This commit is contained in:
Jonathan Rainville 2019-07-19 14:53:09 -04:00
parent 4561f56ed1
commit 6c744cc52a
No known key found for this signature in database
GPG Key ID: 5F4630B759727D9C
5 changed files with 106 additions and 45 deletions

View File

@ -11,6 +11,17 @@ export const tradeStates = {
waiting: 'waiting'
};
export const tradeStatesFormatted = {
waiting: 'Open',
paid: 'Paid',
funded: 'Funded',
released: 'Done',
arbitration_open: 'Arbitration',
arbitration_closed: 'Resolved',
canceled: 'Canceled',
expired: 'Expired'
};
export const eventTypes = {
paid: 'Paid',
funded: 'Funded',

View File

@ -132,7 +132,8 @@
"trades": {
"title": "My trades",
"find": "Find offer",
"noOpen": "No open trades"
"noOpen": "No open trades",
"noFilteredTrades": "No trades with that filter"
},
"offers": {
"title": "My offers",

View File

@ -12,7 +12,6 @@ import BuyButton from '../License/components/BuyButton';
import Balance from '../License/components/Balance';
import Loading from '../../components/Loading';
import ErrorInformation from '../../components/ErrorInformation';
import license from "../../features/license";
const LICENSE_TOKEN_SYMBOL = 'SNT';

View File

@ -1,16 +1,18 @@
import React, {Component} from 'react';
import React, {Component, Fragment} from 'react';
import PropTypes from 'prop-types';
import {Card, Row, Col} from 'reactstrap';
import {Card, Row, Col, Form, FormGroup, Label, Input} from 'reactstrap';
import {Link} from "react-router-dom";
import {withNamespaces} from 'react-i18next';
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faArrowRight} from "@fortawesome/free-solid-svg-icons";
import {faArrowRight, faCaretDown} from "@fortawesome/free-solid-svg-icons";
import Identicon from "../../../components/UserInformation/Identicon";
import {formatBalance} from "../../../utils/numbers";
import {tradeStates} from "../../../features/escrow/helpers";
import {tradeStates, tradeStatesFormatted} from "../../../features/escrow/helpers";
import {addressCompare} from "../../../utils/address";
import {ARBITRATION_SOLVED_BUYER, ARBITRATION_SOLVED_SELLER} from "../../../features/arbitration/constants";
import './Trades.scss';
const getTradeStyle = (trade, isBuyer) => {
if (trade.mining) {
return {text: 'Mining', className: 'bg-info'};
@ -24,22 +26,16 @@ const getTradeStyle = (trade, isBuyer) => {
}
}
}
const tradeStyle = {text: tradeStatesFormatted[trade.status]};
switch(trade.status){
case tradeStates.waiting:
return {text: 'Open', className: 'bg-primary'};
case tradeStates.funded:
return {text: 'Funded', className: 'bg-primary'};
case tradeStates.paid:
return {text: 'Paid', className: 'bg-primary'};
case tradeStates.released:
return {text: 'Done', className: 'bg-success'};
case tradeStates.canceled:
return {text: 'Canceled', className: 'bg-secondary text-black'};
case tradeStates.expired:
return {text: 'Expired', className: 'bg-secondary text-black'};
case tradeStates.arbitration_open:
return {text: 'Arbitration', className: 'bg-warning'};
case tradeStates.waiting: tradeStyle.className = 'bg-primary'; break;
case tradeStates.funded: tradeStyle.className = 'bg-primary'; break;
case tradeStates.paid: tradeStyle.className = 'bg-primary'; break;
case tradeStates.released: tradeStyle.className = 'bg-success'; break;
case tradeStates.canceled: tradeStyle.className = 'bg-secondary text-black'; break;
case tradeStates.expired: tradeStyle.className = 'bg-secondary text-black'; break;
case tradeStates.arbitration_open: tradeStyle.className = 'bg-warning'; break;
case tradeStates.arbitration_closed: {
let className;
if (trade.arbitration.result.toString() === ARBITRATION_SOLVED_BUYER) {
@ -49,39 +45,83 @@ const getTradeStyle = (trade, isBuyer) => {
} else {
className = 'bg-primary';
}
return {text: 'Resolved', className};
tradeStyle.className = className; break;
}
default:
return {text: trade.status, className: 'bg-secondary text-black'};
default: tradeStyle.className = 'bg-secondary text-black'; break;
}
return tradeStyle;
};
class Trades extends Component {
state = {
filteredState: '',
showFilters: false
};
filterState(stateName) {
if (stateName === '') {
return this.setState({filteredState: ''});
}
const stateIndex = Object.values(tradeStatesFormatted).findIndex(tradeState => tradeState === stateName);
const filteredState = stateIndex === -1 ? '' : Object.keys(tradeStatesFormatted)[stateIndex];
this.setState({filteredState});
}
renderTrades() {
const address = this.props.address;
return (
<Card body className="py-2 px-3 shadow-sm">
{this.props.trades.map((trade, index) => {
const isBuyer = addressCompare(trade.buyer, address);
const tradeStyle = getTradeStyle(trade, isBuyer);
return <Link key={index} to={"/escrow/" + trade.escrowId}>
<Row className="my-1 border-bottom">
<Col className="align-self-center pr-0" xs="2">
<Identicon seed={ isBuyer ? trade.seller.statusContactCode : trade.buyerInfo.statusContactCode} scale={5} className="align-middle rounded-circle topCircle border"/>
</Col>
<Col className="align-self-center" xs="3">
<span>{isBuyer ? trade.seller.username : trade.buyerInfo.username}</span>
</Col>
<Col className="align-self-center" xs="3" md={4}>
{isBuyer ? 'Buy' : 'Sell' } {formatBalance(trade.tokenAmount)} {trade.token.symbol}
</Col>
<Col className="align-self-center text-center text-success" xs="4" md={3}>
<span className={"p-1 text-uppercase d-inline text-white rounded-sm text-small nowrap " + tradeStyle.className}>{tradeStyle.text}</span>
</Col>
</Row>
</Link>;
})}
</Card>
<Fragment>
{this.state.showFilters && <Form><b>Filters:</b>
<FormGroup row className="state-filters">
<Label for="trade-state-filter" xs={2}>States</Label>
<Col xs={10}>
<Input type="select" name="select" id="trade-state-filter"
onChange={(e) => this.filterState(e.target.value)}>
<option/>
{Object.values(tradeStatesFormatted).map((tradeState, index) => <option
key={`tradeState-${index}`}>{tradeState}</option>)}
</Input>
</Col>
</FormGroup>
</Form>}
{!this.state.showFilters && <p className="text-small text-muted mb-1 clickable" onClick={() => this.setState({showFilters: true})}>Show Filters <FontAwesomeIcon icon={faCaretDown}/></p>}
<Card body className="profile-trades-list py-2 px-3 shadow-sm">
{(() => {
const trades = this.props.trades.map((trade, index) => {
if (this.state.filteredState && trade.status !== this.state.filteredState) {
return null;
}
const isBuyer = addressCompare(trade.buyer, address);
const tradeStyle = getTradeStyle(trade, isBuyer);
return <Link key={index} to={"/escrow/" + trade.escrowId}>
<Row className="my-1 border-bottom">
<Col className="align-self-center pr-0" xs="2">
<Identicon seed={isBuyer ? trade.seller.statusContactCode : trade.buyerInfo.statusContactCode}
scale={5} className="align-middle rounded-circle topCircle border"/>
</Col>
<Col className="align-self-center" xs="3">
<span>{isBuyer ? trade.seller.username : trade.buyerInfo.username}</span>
</Col>
<Col className="align-self-center" xs="3" md={4}>
{isBuyer ? 'Buy' : 'Sell'} {formatBalance(trade.tokenAmount)} {trade.token.symbol}
</Col>
<Col className="align-self-center text-center text-success" xs="4" md={3}>
<span
className={"p-1 text-uppercase d-inline text-white rounded-sm text-small nowrap " + tradeStyle.className}>{tradeStyle.text}</span>
</Col>
</Row>
</Link>;
});
if (trades.every(trade => trade === null)) {
return this.props.t('trades.noFilteredTrades');
}
return trades;
})()}
</Card>
</Fragment>
);
}

View File

@ -0,0 +1,10 @@
.profile-trades-list {
overflow-y: auto;
max-height: 270px;
}
.state-filters {
.form-control {
height: 40px;
}
}