feat: arbitration approval UI (#358)

* feat: arbitration approval UI
* feat: display number of pending requests (#359)
This commit is contained in:
Richard Ramos 2019-07-09 10:12:55 -04:00 committed by GitHub
parent 8808fb7f56
commit 44650d0adb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 224 additions and 30 deletions

View File

@ -1,4 +1,4 @@
import {ARBITRATION_UNSOLVED, GET_DISPUTED_ESCROWS, RESOLVE_DISPUTE, RESOLVE_DISPUTE_FAILED, BUY_LICENSE,CANCEL_ARBITRATOR_SELECTION_ACTIONS, CHECK_LICENSE_OWNER, LOAD_PRICE, LOAD_ARBITRATION, GET_ARBITRATORS, OPEN_DISPUTE, CANCEL_DISPUTE, REQUEST_ARBITRATOR, CANCEL_ARBITRATOR_REQUEST, CHANGE_ACCEPT_EVERYONE} from './constants';
import {ARBITRATION_UNSOLVED, GET_DISPUTED_ESCROWS, RESOLVE_DISPUTE, RESOLVE_DISPUTE_FAILED, BUY_LICENSE,CANCEL_ARBITRATOR_SELECTION_ACTIONS, CHECK_LICENSE_OWNER, LOAD_PRICE, LOAD_ARBITRATION, GET_ARBITRATORS, OPEN_DISPUTE, CANCEL_DISPUTE, REQUEST_ARBITRATOR, CANCEL_ARBITRATOR_REQUEST, CHANGE_ACCEPT_EVERYONE, GET_ARBITRATION_REQUESTS, ACCEPT_ARBITRATOR_REQUEST, REJECT_ARBITRATOR_REQUEST} from './constants';
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
import ArbitrationLicense from '../../../embarkArtifacts/contracts/ArbitrationLicense';
import OwnedUpgradeabilityProxy from '../../../embarkArtifacts/contracts/OwnedUpgradeabilityProxy';
@ -44,3 +44,9 @@ export const cancelArbitratorRequest = (arbitrator) => ({type: CANCEL_ARBITRATOR
export const cancelArbitratorActions = () => ({type: CANCEL_ARBITRATOR_SELECTION_ACTIONS});
export const changeAcceptEveryone = (acceptAny) => ({type: CHANGE_ACCEPT_EVERYONE, acceptAny, toSend: ArbitrationLicense.methods.changeAcceptAny(acceptAny)});
export const getArbitratorRequests = (arbitrator) => ({type: GET_ARBITRATION_REQUESTS, arbitrator});
export const acceptRequest = (id) => ({type: ACCEPT_ARBITRATOR_REQUEST, id, toSend: ArbitrationLicense.methods.acceptRequest(id)});
export const rejectRequest = (id) => ({type: REJECT_ARBITRATOR_REQUEST, id, toSend: ArbitrationLicense.methods.rejectRequest(id)});

View File

@ -60,9 +60,22 @@ export const CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS = 'CHANGE_ACCEPT_EVERYONE_PRE_SU
export const CHANGE_ACCEPT_EVERYONE_SUCCEEDED = 'CHANGE_ACCEPT_EVERYONE_SUCCEEDED';
export const CHANGE_ACCEPT_EVERYONE_FAILED = 'CHANGE_ACCEPT_EVERYONE_FAILED';
export const GET_ARBITRATION_REQUESTS = 'GET_ARBITRATION_REQUESTS';
export const GET_ARBITRATION_REQUESTS_SUCCEEDED = 'GET_ARBITRATION_REQUESTS_SUCCEEDED';
export const GET_ARBITRATION_REQUESTS_FAILED = 'GET_ARBITRATION_REQUESTS_FAILED';
export const NONE = '0';
export const AWAIT = '1';
export const ACCEPTED = '2';
export const REJECTED = '3';
export const CLOSED = '4';
export const ACCEPT_ARBITRATOR_REQUEST = 'ACCEPT_ARBITRATOR_REQUEST';
export const ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS = 'ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS';
export const ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED = 'ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED';
export const ACCEPT_ARBITRATOR_REQUEST_FAILED = 'ACCEPT_ARBITRATOR_REQUEST_FAILED';
export const REJECT_ARBITRATOR_REQUEST = 'REJECT_ARBITRATOR_REQUEST';
export const REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS = 'REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS';
export const REJECT_ARBITRATOR_REQUEST_SUCCEEDED = 'REJECT_ARBITRATOR_REQUEST_SUCCEEDED';
export const REJECT_ARBITRATOR_REQUEST_FAILED = 'REJECT_ARBITRATOR_REQUEST_FAILED';

View File

@ -41,7 +41,19 @@ import {
CHANGE_ACCEPT_EVERYONE,
CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS,
CHANGE_ACCEPT_EVERYONE_FAILED,
CHANGE_ACCEPT_EVERYONE_SUCCEEDED
CHANGE_ACCEPT_EVERYONE_SUCCEEDED,
GET_ARBITRATION_REQUESTS_SUCCEEDED,
GET_ARBITRATION_REQUESTS_FAILED,
ACCEPT_ARBITRATOR_REQUEST,
ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS,
ACCEPT_ARBITRATOR_REQUEST_FAILED,
ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED,
REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS,
REJECT_ARBITRATOR_REQUEST_FAILED,
REJECT_ARBITRATOR_REQUEST,
REJECT_ARBITRATOR_REQUEST_SUCCEEDED,
REJECTED,
ACCEPTED
} from './constants';
import { fromTokenDecimals } from '../../utils/numbers';
import {RESET_STATE, PURGE_STATE} from "../network/constants";
@ -52,7 +64,8 @@ const DEFAULT_STATE = {
receipt: null,
price: Number.MAX_SAFE_INTEGER,
loading: false,
error: ''
error: '',
arbitratorRequests: []
};
function reducer(state = DEFAULT_STATE, action) {
@ -70,6 +83,8 @@ function reducer(state = DEFAULT_STATE, action) {
case REQUEST_ARBITRATOR_PRE_SUCCESS:
case CANCEL_ARBITRATOR_REQUEST_PRE_SUCCESS:
case CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS:
case ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS:
case REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS:
return {
...state, ...{
txHash: action.txHash
@ -112,6 +127,9 @@ function reducer(state = DEFAULT_STATE, action) {
case REQUEST_ARBITRATOR_FAILED:
case CANCEL_ARBITRATOR_REQUEST_FAILED:
case CHANGE_ACCEPT_EVERYONE_FAILED:
case GET_ARBITRATION_REQUESTS_FAILED:
case ACCEPT_ARBITRATOR_REQUEST_FAILED:
case REJECT_ARBITRATOR_REQUEST_FAILED:
return {
...state, ...{
errorGet: action.error,
@ -123,6 +141,8 @@ function reducer(state = DEFAULT_STATE, action) {
case OPEN_DISPUTE:
case RESOLVE_DISPUTE:
case CHANGE_ACCEPT_EVERYONE:
case ACCEPT_ARBITRATOR_REQUEST:
case REJECT_ARBITRATOR_REQUEST:
return {
...state, ...{
loading: true
@ -231,6 +251,33 @@ function reducer(state = DEFAULT_STATE, action) {
error: action.error,
loading: false
};
case GET_ARBITRATION_REQUESTS_SUCCEEDED:
return {
...state,
arbitratorRequests: action.requests
};
case REJECT_ARBITRATOR_REQUEST_SUCCEEDED:
{
const arbitratorRequests = [...state.arbitratorRequests];
arbitratorRequests.find(x => x.id === action.id).status = REJECTED;
return {
...state,
arbitratorRequests,
loading: false
};
}
case ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED:
{
const arbitratorRequests = [...state.arbitratorRequests];
arbitratorRequests.find(x => x.id === action.id).status = ACCEPTED;
return {
...state,
arbitratorRequests,
loading: false
};
}
case RESET_STATE: {
return Object.assign({}, state, {
arbitration: null,

View File

@ -6,14 +6,15 @@ import MetadataStore from '../../../embarkArtifacts/contracts/MetadataStore';
import moment from 'moment';
import {promiseEventEmitter, doTransaction} from '../../utils/saga';
import {eventChannel} from "redux-saga";
import {fork, takeEvery, call, put, take} from 'redux-saga/effects';
import {fork, takeEvery, call, put, take, all} from 'redux-saga/effects';
import {
CLOSED, NONE,
GET_DISPUTED_ESCROWS, GET_DISPUTED_ESCROWS_FAILED, GET_DISPUTED_ESCROWS_SUCCEEDED,
RESOLVE_DISPUTE, RESOLVE_DISPUTE_FAILED, RESOLVE_DISPUTE_SUCCEEDED,
RESOLVE_DISPUTE_PRE_SUCCESS, LOAD_ARBITRATION, LOAD_ARBITRATION_FAILED, LOAD_ARBITRATION_SUCCEEDED, GET_ARBITRATORS,
GET_ARBITRATORS_SUCCEEDED, GET_ARBITRATORS_FAILED, BUY_LICENSE, BUY_LICENSE_FAILED, BUY_LICENSE_PRE_SUCCESS, BUY_LICENSE_SUCCEEDED,
LOAD_PRICE, LOAD_PRICE_FAILED, LOAD_PRICE_SUCCEEDED, CHECK_LICENSE_OWNER, CHECK_LICENSE_OWNER_FAILED, CHECK_LICENSE_OWNER_SUCCEEDED,
OPEN_DISPUTE, OPEN_DISPUTE_SUCCEEDED, OPEN_DISPUTE_FAILED, OPEN_DISPUTE_PRE_SUCCESS, CANCEL_DISPUTE, CANCEL_DISPUTE_PRE_SUCCESS, CANCEL_DISPUTE_SUCCEEDED, CANCEL_DISPUTE_FAILED, REQUEST_ARBITRATOR, REQUEST_ARBITRATOR_PRE_SUCCESS, REQUEST_ARBITRATOR_SUCCEEDED, REQUEST_ARBITRATOR_FAILED, CANCEL_ARBITRATOR_REQUEST, CANCEL_ARBITRATOR_REQUEST_SUCCEEDED, CANCEL_ARBITRATOR_REQUEST_FAILED, CANCEL_ARBITRATOR_REQUEST_PRE_SUCCESS, CHANGE_ACCEPT_EVERYONE, CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS, CHANGE_ACCEPT_EVERYONE_FAILED, CHANGE_ACCEPT_EVERYONE_SUCCEEDED
OPEN_DISPUTE, OPEN_DISPUTE_SUCCEEDED, OPEN_DISPUTE_FAILED, OPEN_DISPUTE_PRE_SUCCESS, CANCEL_DISPUTE, CANCEL_DISPUTE_PRE_SUCCESS, CANCEL_DISPUTE_SUCCEEDED, CANCEL_DISPUTE_FAILED, REQUEST_ARBITRATOR, REQUEST_ARBITRATOR_PRE_SUCCESS, REQUEST_ARBITRATOR_SUCCEEDED, REQUEST_ARBITRATOR_FAILED, CANCEL_ARBITRATOR_REQUEST, CANCEL_ARBITRATOR_REQUEST_SUCCEEDED, CANCEL_ARBITRATOR_REQUEST_FAILED, CANCEL_ARBITRATOR_REQUEST_PRE_SUCCESS, CHANGE_ACCEPT_EVERYONE, CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS, CHANGE_ACCEPT_EVERYONE_FAILED, CHANGE_ACCEPT_EVERYONE_SUCCEEDED, GET_ARBITRATION_REQUESTS, GET_ARBITRATION_REQUESTS_FAILED, GET_ARBITRATION_REQUESTS_SUCCEEDED, ACCEPT_ARBITRATOR_REQUEST, ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS, ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED, ACCEPT_ARBITRATOR_REQUEST_FAILED, REJECT_ARBITRATOR_REQUEST, REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS, REJECT_ARBITRATOR_REQUEST_SUCCEEDED, REJECT_ARBITRATOR_REQUEST_FAILED
} from './constants';
import OwnedUpgradeabilityProxy from '../../../embarkArtifacts/contracts/OwnedUpgradeabilityProxy';
Escrow.options.address = OwnedUpgradeabilityProxy.options.address;
@ -116,6 +117,31 @@ export function *onLoadArbitration() {
yield takeEvery(LOAD_ARBITRATION, doLoadArbitration);
}
export function *onGetArbitratorApprovalRequests() {
yield takeEvery(GET_ARBITRATION_REQUESTS, doGetArbitratorApprovalRequests);
}
export function *doGetArbitratorApprovalRequests({address}) {
try {
const events = yield ArbitrationLicense.getPastEvents('ArbitratorRequested', {fromBlock: 1, filter: {arbitrator: address} });
const requests = yield all(events.map(function *(event) {
const request = event.returnValues;
const requestDetail = yield ArbitrationLicense.methods.requests(request.id).call();
if([NONE, CLOSED].indexOf(requestDetail.status) > -1) return null;
request.status = requestDetail.status;
return request;
}));
yield put({type: GET_ARBITRATION_REQUESTS_SUCCEEDED, requests: requests.filter(x => x !== null)});
} catch (error) {
console.error(error);
yield put({type: GET_ARBITRATION_REQUESTS_FAILED, error: error.message});
}
}
export function *doBuyLicense() {
try {
@ -197,6 +223,14 @@ export function *onChangeAcceptAll() {
yield takeEvery(CHANGE_ACCEPT_EVERYONE, doTransaction.bind(null, CHANGE_ACCEPT_EVERYONE_PRE_SUCCESS, CHANGE_ACCEPT_EVERYONE_SUCCEEDED, CHANGE_ACCEPT_EVERYONE_FAILED));
}
export function *onAcceptRequest() {
yield takeEvery(ACCEPT_ARBITRATOR_REQUEST, doTransaction.bind(null, ACCEPT_ARBITRATOR_REQUEST_PRE_SUCCESS, ACCEPT_ARBITRATOR_REQUEST_SUCCEEDED, ACCEPT_ARBITRATOR_REQUEST_FAILED));
}
export function *onRejectRequest() {
yield takeEvery(REJECT_ARBITRATOR_REQUEST, doTransaction.bind(null, REJECT_ARBITRATOR_REQUEST_PRE_SUCCESS, REJECT_ARBITRATOR_REQUEST_SUCCEEDED, REJECT_ARBITRATOR_REQUEST_FAILED));
}
export default [
fork(onGetEscrows),
fork(onResolveDispute),
@ -209,5 +243,8 @@ export default [
fork(onCancelDispute),
fork(onRequestArbitrator),
fork(onCancelArbitratorRequest),
fork(onChangeAcceptAll)
fork(onChangeAcceptAll),
fork(onGetArbitratorApprovalRequests),
fork(onAcceptRequest),
fork(onRejectRequest)
];

View File

@ -27,3 +27,5 @@ export const isLicenseOwner = state => state.arbitration.licenseOwner;
export const acceptsEveryone = state => state.arbitration.acceptAny;
export const isLoading = state => state.arbitration.loading;
export const getLicensePrice = state => parseInt(state.arbitration.price, 10);
export const getArbitratorRequests = state => state.arbitration.arbitratorRequests;

View File

@ -11,6 +11,7 @@ import Loading from '../../components/Loading';
import ErrorInformation from '../../components/ErrorInformation';
import moment from 'moment';
import PropTypes from 'prop-types';
import { formatArbitratorName } from '../../utils/strings';
class Arbitrators extends Component {
constructor(props) {
@ -21,7 +22,7 @@ class Arbitrators extends Component {
}
componentDidUpdate(prevProps) {
if ((!prevProps.arbitrators && this.props.arbitrators) || prevProps.arbitrators.length !== this.props.arbitrators.length || Object.keys(this.props.users).length < this.props.arbitrators.length) {
if ((!prevProps.arbitrators && this.props.arbitrators) || Object.keys(prevProps.arbitrators).length !== Object.keys(this.props.arbitrators).length || Object.keys(this.props.users).length === Object.keys(this.props.arbitrators).length) {
Object.keys(this.props.arbitrators).forEach(arbitratorAddr => {
if (!this.props.users[arbitratorAddr] && !this.loadedUsers.includes(arbitratorAddr)) {
this.props.getUser(arbitratorAddr);
@ -56,12 +57,15 @@ class Arbitrators extends Component {
const isUser = addressCompare(address, arb);
const enableDate = parseInt(arbitrators[arb].request.date, 10) + (86400 * 3) + 20;
const isDisabled = (Date.now() / 1000) < enableDate;
const text = formatArbitratorName(users[arb], arb) + (isUser ? " (You)" : "");
return <ListGroupItem key={i}>
<Row>
<Col xs="12" sm="9" className="pb-3">
<span className="text-small">{arb}</span>
<br />
<span className={classnames("font-weight-bold", {'text-success': isUser})}>{(users[arb] && users[arb].username ? users[arb].username : "Arbitrator has no username") + (isUser ? " (You)" : "") }</span>
<span className={classnames("font-weight-bold", {'text-success': isUser})}>{text}</span>
</Col>
<Col xs="12" sm="3" className="text-center">
{ !isUser && !arbitrators[arb].isAllowed && [arbitration.constants.NONE, arbitration.constants.REJECTED, arbitration.constants.CLOSED].indexOf(arbitrators[arb].request.status) > -1 && <Button disabled={isDisabled} onClick={this.requestArbitrator(arb)}>Request</Button> }

View File

@ -40,6 +40,7 @@ class MyProfile extends Component {
componentDidMount() {
this.props.loadProfile(this.props.address);
this.props.getDisputedEscrows();
this.props.getArbitratorRequests();
}
componentDidUpdate(oldProps){
@ -65,7 +66,7 @@ class MyProfile extends Component {
}
render() {
const {profile, address, deleteOfferStatus, txHash} = this.props;
const {profile, address, deleteOfferStatus, txHash, requests} = this.props;
if(!profile) return <Loading page={true} />;
if(deleteOfferStatus === States.pending) {
@ -80,12 +81,16 @@ class MyProfile extends Component {
return x;
});
const pendingRequests = requests.reduce((a, b) => {
return a + (b.status === arbitration.constants.AWAIT ? 1 : 0);
}, 0);
return (
<Fragment>
<UserInformation isArbitrator={profile.isArbitrator} reputation={profile.reputation} identiconSeed={profile.statusContactCode} username={profile.username}/>
{profile.isArbitrator && <Fragment>
<Link to={"/sellers"}>Seller Management (TODO: Add number of pending requests)</Link>
<Link to={"/sellers"}>Seller Management {pendingRequests > 0 && <span className="text-warining">({pendingRequests} pending requests)</span>}</Link>
<Disputes disputes={this.props.disputes.filter(x => x.arbitration.open && !addressCompare(x.seller, address) && !addressCompare(x.buyer, address) && addressCompare(x.arbitrator, address))} open={true} showDate={true} />
<Disputes disputes={this.props.disputes.filter(x => !x.arbitration.open && !addressCompare(x.seller, address) && !addressCompare(x.buyer, address) && addressCompare(x.arbitrator, address))} open={false} showDate={false} />
</Fragment>}
@ -115,7 +120,9 @@ MyProfile.propTypes = {
watchEscrow: PropTypes.func,
deleteOffer: PropTypes.func,
deleteOfferStatus: PropTypes.string,
txHash: PropTypes.string
txHash: PropTypes.string,
requests: PropTypes.array,
getArbitratorRequests: PropTypes.func
};
const mapStateToProps = state => {
@ -128,7 +135,8 @@ const mapStateToProps = state => {
disputes: arbitration.selectors.escrows(state),
escrowEvents: events.selectors.getEscrowEvents(state),
deleteOfferStatus: metadata.selectors.getDeleteOfferStatus(state),
txHash: metadata.selectors.txHash(state)
txHash: metadata.selectors.txHash(state),
requests: arbitration.selectors.getArbitratorRequests(state)
};
};
@ -138,5 +146,6 @@ export default connect(
loadProfile: metadata.actions.load,
getDisputedEscrows: arbitration.actions.getDisputedEscrows,
watchEscrow: escrow.actions.watchEscrow,
deleteOffer: metadata.actions.deleteOffer
deleteOffer: metadata.actions.deleteOffer,
getArbitratorRequests: arbitration.actions.getArbitratorRequests
})(withRouter(MyProfile));

View File

@ -1,6 +1,6 @@
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import {withRouter} from "react-router-dom";
import {withRouter, Link} from "react-router-dom";
import network from '../../features/network';
import arbitration from '../../features/arbitration';
import metadata from '../../features/metadata';
@ -8,20 +8,51 @@ import Loading from '../../components/Loading';
import ErrorInformation from '../../components/ErrorInformation';
import PropTypes from 'prop-types';
import BootstrapSwitchButton from 'bootstrap-switch-button-react';
import { ListGroup, ListGroupItem, Button, Row, Col } from 'reactstrap';
import classnames from 'classnames';
import { formatArbitratorName } from '../../utils/strings';
const requestStatus = {
[arbitration.constants.AWAIT]: "Pending",
[arbitration.constants.ACCEPTED]: "Accepted",
[arbitration.constants.REJECTED]: "Rejected"
};
class SellerApproval extends Component {
componentDidMount(){
this.props.checkLicenseOwner();
constructor(props) {
super(props);
props.checkLicenseOwner();
props.getArbitratorRequests();
this.loadedUsers = [];
}
onToggleCheckbox = (checked) => {
this.props.changeAcceptEveryone(checked);
}
componentDidUpdate(prevProps) {
if ((!prevProps.requests && this.props.requests) || prevProps.requests.length !== this.props.requests) {
this.props.requests.map(x => x.seller).forEach(seller => {
if (!this.props.users[seller] && !this.loadedUsers.includes(seller)) {
this.props.getUser(seller);
this.loadedUsers.push(seller);
}
});
}
}
acceptRequest = id => () => {
this.props.acceptRequest(id);
}
rejectRequest = id => () => {
this.props.rejectRequest(id);
}
render(){
const {loading, error, txHash, cancelArbitratorsActions, profile, acceptsEveryone} = this.props;
const {loading, error, txHash, cancelArbitratorsActions, profile, acceptsEveryone, requests, users} = this.props;
if(error) {
return <ErrorInformation transaction message={error} cancel={cancelArbitratorsActions}/>;
}
@ -37,9 +68,39 @@ class SellerApproval extends Component {
<h2 className="mb-4">Seller Management</h2>
<h3 className="mb-2">Accept all sellers</h3>
{<BootstrapSwitchButton onlabel="ON" offlabel="OFF" checked={acceptsEveryone} onChange={this.onToggleCheckbox}/>}
<p><br /><br /><br />TODO: show list of requests for arbitrator</p>
{ !acceptsEveryone && <Fragment>
<h3 className="mb-2 mt-5">Requests for arbitrator</h3>
<ListGroup>
{requests.map((request, i) => {
const text = formatArbitratorName(users[request.seller], request.seller);
return <ListGroupItem key={i}>
<Row>
<Col xs="12" sm="9" className="pb-3" tag={Link} to={`/profile/${request.seller}`}>
<span className="text-small">{request.seller}</span>
<br />
<span className={classnames("font-weight-bold")}>{text}</span>
</Col>
<Col xs="12" sm="3" className="text-center">
{request.status === arbitration.constants.AWAIT && <Button onClick={this.acceptRequest(request.id)} className="m-2">Accept</Button> }
{(request.status === arbitration.constants.AWAIT || request.status === arbitration.constants.ACCEPTED) && <Button className="m-2" onClick={this.rejectRequest(request.id)}>Reject</Button> }
<p className={classnames('text-small', {
'text-success': request.status === arbitration.constants.ACCEPTED,
'text-danger': request.status === arbitration.constants.REJECTED,
'text-muted': request.status === arbitration.constants.AWAIT
})}>
({requestStatus[request.status]})
</p>
</Col>
</Row>
</ListGroupItem>;
}
)}
</ListGroup>
</Fragment>
}
</Fragment>
);
}
@ -55,7 +116,13 @@ SellerApproval.propTypes = {
changeAcceptEveryone: PropTypes.func,
checkLicenseOwner: PropTypes.func,
acceptsEveryone: PropTypes.bool,
profile: PropTypes.object
profile: PropTypes.object,
requests: PropTypes.array,
getArbitratorRequests: PropTypes.func,
getUser: PropTypes.func,
users: PropTypes.object,
acceptRequest: PropTypes.func,
rejectRequest: PropTypes.func
};
@ -67,8 +134,10 @@ const mapStateToProps = state => {
error: arbitration.selectors.errorGet(state),
txHash: arbitration.selectors.txHash(state),
profile: metadata.selectors.getProfile(state, address) ,
acceptsEveryone: arbitration.selectors.acceptsEveryone(state)
};
acceptsEveryone: arbitration.selectors.acceptsEveryone(state),
requests: arbitration.selectors.getArbitratorRequests(state),
users: metadata.selectors.getAllUsers(state)
};
};
export default connect(
@ -76,5 +145,9 @@ export default connect(
{
cancelArbitratorsActions: arbitration.actions.cancelArbitratorActions,
changeAcceptEveryone: arbitration.actions.changeAcceptEveryone,
checkLicenseOwner: arbitration.actions.checkLicenseOwner
checkLicenseOwner: arbitration.actions.checkLicenseOwner,
getArbitratorRequests: arbitration.actions.getArbitratorRequests,
getUser: metadata.actions.loadUserOnly,
acceptRequest: arbitration.actions.acceptRequest,
rejectRequest: arbitration.actions.rejectRequest
})(withRouter(SellerApproval));

5
src/js/utils/strings.js Normal file
View File

@ -0,0 +1,5 @@
export const formatArbitratorName = (user, address, noUsernameLabel, index) => {
if (!user) return address + ' - Loading...';
return `${index >= 0 ? index + 1 + ' - ' : ""}${user.username || (noUsernameLabel ? noUsernameLabel : "No username available") }${user.location ? ' from ' + user.location : ''} - ${user.upCount || 0}${user.downCount || 0}`;
};

View File

@ -5,6 +5,8 @@ import {Typeahead} from 'react-bootstrap-typeahead';
import {withNamespaces, Trans} from 'react-i18next';
import {compactAddress} from '../../../../utils/address';
import {Link} from "react-router-dom";
import {formatArbitratorName} from '../../../../utils/strings';
class ArbitratorSelectorForm extends Component {
onChange = (items) => {
@ -22,12 +24,8 @@ class ArbitratorSelectorForm extends Component {
const arbitratorStrings = this.props.arbitrators.map((arbitratorAddr, index) => {
const user = this.props.users[arbitratorAddr];
let text;
if (!user) {
text = arbitratorAddr + ' - Loading...';
} else {
text = `${index} - ${user.username || compactAddress(arbitratorAddr, 3)}${user.location ? ' from ' + user.location : ''} - ${user.upCount || 0}${user.downCount || 0}`;
}
let text = formatArbitratorName(user, arbitratorAddr, compactAddress(arbitratorAddr, 3), index);
if (value && value === arbitratorAddr) {
defaultSelectedValue.push(text);
}

View File

@ -29,7 +29,7 @@ class SelectArbitrator extends Component {
}
componentDidUpdate(prevProps) {
if ((!prevProps.arbitrators && this.props.arbitrators) || prevProps.arbitrators.length !== this.props.arbitrators.length || Object.keys(this.props.users).length !== this.props.arbitrators.length) {
if ((!prevProps.arbitrators && this.props.arbitrators) || prevProps.arbitrators.length !== this.props.arbitrators.length || Object.keys(this.props.users).length !== Object.keys(this.props.arbitrators).length) {
Object.keys(this.props.arbitrators).forEach(arbitratorAddr => {
if (!this.props.users[arbitratorAddr] && !this.loadedUsers.includes(arbitratorAddr)) {
this.props.getUser(arbitratorAddr);