Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Commit

Permalink
feat(disputes): implement new dispute shape UI
Browse files Browse the repository at this point in the history
  • Loading branch information
epiqueras committed Mar 6, 2018
1 parent d0b5057 commit 7fb7139
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 94 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"ethjs": "^0.3.3",
"ethjs-unit": "^0.1.6",
"history": "^4.7.2",
"kleros-api": "^0.0.59",
"kleros-api": "^0.0.64",
"normalize.css": "^7.0.0",
"react": "^16.2.0",
"react-addons-css-transition-group": "^15.6.2",
Expand Down
13 changes: 8 additions & 5 deletions src/components/anchored-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ class AnchoredList extends PureComponent {
static propTypes = {
// State
items: PropTypes.arrayOf(
PropTypes.shape({
anchor: PropTypes.string,
element: PropTypes.element.isRequired
}).isRequired
PropTypes.oneOfType([
PropTypes.shape({
anchor: PropTypes.string,
element: PropTypes.element.isRequired
}),
PropTypes.bool
]).isRequired
).isRequired
}

Expand Down Expand Up @@ -86,7 +89,7 @@ class AnchoredList extends PureComponent {
>
<div className="AnchoredList-container">
<div className="AnchoredList-container-margin" />
{items.map((item, i) => (
{items.filter(i => i).map((item, i) => (
<div
key={item.element.key}
ref={this.getChildRef}
Expand Down
2 changes: 2 additions & 0 deletions src/constants/dispute.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export const STATUS_ENUM = ['waiting', 'appealable', 'resolved']

export const EVENT_TYPE_ENUM = ['appeal', 'evidence', 'ruling']
104 changes: 59 additions & 45 deletions src/containers/dispute/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Icosahedron from '../../components/icosahedron'
import AnchoredList from '../../components/anchored-list'
import Identicon from '../../components/identicon'
import Button from '../../components/button'
import { EVENT_TYPE_ENUM } from '../../constants/dispute'

import Details from './components/details'
import Evidence from './components/evidence'
Expand Down Expand Up @@ -49,7 +50,7 @@ class Dispute extends PureComponent {

render() {
const { dispute } = this.props

const today = new Date()
return (
<div className="Dispute">
<RenderIf
Expand All @@ -63,7 +64,7 @@ class Dispute extends PureComponent {
element: (
<div key={0} className="Dispute-header">
<small>
{dateToString(new Date(), {
{dateToString(today, {
withTime: false
})}
</small>
Expand All @@ -85,61 +86,74 @@ class Dispute extends PureComponent {
anchor: 'Details',
element: (
<Details
key={1}
date={new Date()}
key={dispute.data.appealCreatedAt[0] || 1}
date={dispute.data.appealCreatedAt[0] || today}
partyAAddress={dispute.data.partyA}
partyBAddress={dispute.data.partyB}
arbitrationFee={dispute.data.fee}
arbitrationFee={dispute.data.appealJuror[0].fee}
/>
)
},
...dispute.data.evidence.map(e => ({
anchor: 'Evidence',
element: (
<Evidence
key={e.url}
date={new Date()}
partyAddress={e.submitter}
URI={e.url}
/>
)
})),
...(dispute.data.hasRuled
? [
{
anchor: 'Ruling',
...dispute.data.events.map(e => {
switch (e.type) {
case EVENT_TYPE_ENUM[0]:
return {
anchor: 'Appeal',
element: (
<Ruling
key={2}
date={new Date()}
votesForPartyA={dispute.data.voteCounters[0][1]}
votesForPartyB={dispute.data.voteCounters[0][2]}
netPNK={dispute.data.netPNK}
<Details
key={e.date}
date={e.date}
partyAAddress={dispute.data.partyA}
partyBAddress={dispute.data.partyB}
arbitrationFee={e.fee}
/>
)
}
case EVENT_TYPE_ENUM[1]:
return {
anchor: 'Evidence',
element: (
<Evidence
key={e.date + e.url}
date={e.date}
partyAddress={e.submitter}
URI={e.url}
/>
)
}
]
: [
{
anchor: 'Vote',
case EVENT_TYPE_ENUM[2]:
return {
anchor: 'Ruling',
element: (
<div key={3} className="Dispute-vote">
<Button
id={0}
onClick={this.handleVoteButtonClick}
>
Vote for Party A
</Button>
<Button
id={1}
onClick={this.handleVoteButtonClick}
>
Vote for Party B
</Button>
</div>
<Ruling
key={e.date}
date={e.date}
votesForPartyA={e.voteCounter[0]}
votesForPartyB={e.voteCounter[1]}
netPNK={dispute.data.netPNK}
/>
)
}
])
default:
return null
}
}),
dispute.data.appealJuror[dispute.data.numberOfAppeals]
.canRule && [
{
anchor: 'Vote',
element: (
<div key={today} className="Dispute-vote">
<Button id={0} onClick={this.handleVoteButtonClick}>
Vote for Party A
</Button>
<Button id={1} onClick={this.handleVoteButtonClick}>
Vote for Party B
</Button>
</div>
)
}
]
]}
/>
)
Expand Down
11 changes: 9 additions & 2 deletions src/containers/disputes/components/disputes-table/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,17 @@ const columns = [
accessor: () => 'General Court'
},
{
id: 'deadline',
Header: 'Deadline',
maxWidth: 110,
accessor: 'deadline',
Cell: cell => dateToString(cell.value, { withYear: false })
accessor: d =>
(d.latestAppealForJuror &&
d.appealRulings[d.latestAppealForJuror].deadline) ||
null,
Cell: cell =>
cell.value === null
? 'None'
: dateToString(cell.value, { withYear: false })
},
{
Header: 'Status',
Expand Down
36 changes: 25 additions & 11 deletions src/reducers/dispute.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import createReducer, { createResource } from '../utils/redux'
// Base Shapes
const dispute = PropTypes.shape({
// Arbitrable Contract Data
hash: PropTypes.string.isRequired,
arbitrableContractAddress: PropTypes.string.isRequired,
arbitrableContractStatus: PropTypes.number.isRequired,
arbitratorAddress: PropTypes.string.isRequired,
Expand All @@ -14,32 +13,47 @@ const dispute = PropTypes.shape({

// Dispute Data
disputeId: PropTypes.number.isRequired,
session: PropTypes.number.isRequired,
firstSession: PropTypes.number.isRequired,
lastSession: PropTypes.number.isRequired,
numberOfAppeals: PropTypes.number.isRequired,
fee: PropTypes.number.isRequired,
deadline: PropTypes.instanceOf(Date).isRequired,
disputeState: PropTypes.number.isRequired,
disputeStatus: PropTypes.number.isRequired,
voteCounters: PropTypes.arrayOf(
PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
appealJuror: PropTypes.arrayOf(
PropTypes.shape({
fee: PropTypes.number.isRequired,
draws: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,
canRule: PropTypes.bool.isRequired
}).isRequired
).isRequired,
appealRulings: PropTypes.arrayOf(
PropTypes.shape({
voteCounter: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,
deadline: PropTypes.number.isRequired,
ruledAt: PropTypes.number.isRequired,
ruling: PropTypes.number.isRequired
}).isRequired
).isRequired,
netPNK: PropTypes.number.isRequired,

// Store Data
description: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
evidence: PropTypes.arrayOf(
PropTypes.shape({
_id: PropTypes.string.isRequired,
submittedAt: PropTypes.number.isRequired,
submitter: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
}).isRequired
).isRequired,
isJuror: PropTypes.bool.isRequired,
votes: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,
hasRuled: PropTypes.bool.isRequired,
ruling: PropTypes.number.isRequired
netPNK: PropTypes.number.isRequired,
appealCreatedAt: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,
appealDeadlines: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,
appealRuledAt: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired,

// Derived Data
latestAppealForJuror: PropTypes.number.isRequired
})

// Shapes
Expand Down
48 changes: 44 additions & 4 deletions src/sagas/dispute.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,48 @@ import * as disputeActions from '../actions/dispute'
import * as walletSelectors from '../reducers/wallet'
import { kleros, ARBITRATOR_ADDRESS } from '../bootstrap/dapp-api'
import { action, errorAction } from '../utils/action'
import { EVENT_TYPE_ENUM } from '../constants/dispute'

// Parsers
const parseDispute = d => {
// Find the latest appeal where the juror is drawn
let latestAppealForJuror = null
for (let i = d.appealJuror.length - 1; i >= 0; i--) {
if (d.appealJuror[i].canRule) {
latestAppealForJuror = i
break
}
}

// Build array of appeals, evidence submissions, and rulings as events
let events = [
...d.appealJuror.slice(1).map((a, i) => ({
...a,
type: EVENT_TYPE_ENUM[0],
date: new Date(d.appealCreatedAt[i])
})),
...d.evidence.map(e => ({
...e,
type: EVENT_TYPE_ENUM[1],
date: new Date(e.submittedAt)
})),
...d.appealJuror.slice(1).map(a => ({
...a,
type: EVENT_TYPE_ENUM[2],
date: new Date(a.ruledAt)
}))
]
events = events.sort((a, b) => (a.data <= b.date ? -1 : 1))

return {
...d,
appealCreatedAt: d.appealCreatedAt.map(Date),
appealDeadlines: d.appealDeadlines.map(Date),
appealRuledAt: d.appealRuledAt.map(Date),
latestAppealForJuror,
events
}
}

/**
* Fetches the current wallet's disputes.
Expand All @@ -18,7 +60,7 @@ function* fetchDisputes() {

yield put(
action(disputeActions.disputes.RECEIVE, {
disputes: disputes.map(d => ({ ...d, deadline: new Date(d.deadline) }))
disputes: disputes.map(parseDispute)
})
)
} catch (err) {
Expand All @@ -39,9 +81,7 @@ function* fetchDispute({ payload: { disputeID } }) {
)

yield put(
action(disputeActions.dispute.RECEIVE, {
dispute: { ...dispute, deadline: new Date(dispute.deadline) }
})
action(disputeActions.dispute.RECEIVE, { dispute: parseDispute(dispute) })
)
} catch (err) {
yield put(errorAction(disputeActions.dispute.FAIL_FETCH, err))
Expand Down
Loading

0 comments on commit 7fb7139

Please sign in to comment.