From 7fb7139dff8a5b90b4d9b60b757ff314014560ab Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 5 Mar 2018 21:49:40 -0800 Subject: [PATCH] feat(disputes): implement new dispute shape UI --- package.json | 2 +- src/components/anchored-list/index.js | 13 ++- src/constants/dispute.js | 2 + src/containers/dispute/index.js | 104 ++++++++++-------- .../components/disputes-table/index.js | 11 +- src/reducers/dispute.js | 36 ++++-- src/sagas/dispute.js | 48 +++++++- yarn.lock | 32 +----- 8 files changed, 154 insertions(+), 94 deletions(-) diff --git a/package.json b/package.json index df7d608..970b6d4 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/anchored-list/index.js b/src/components/anchored-list/index.js index 4721fc4..c489303 100644 --- a/src/components/anchored-list/index.js +++ b/src/components/anchored-list/index.js @@ -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 } @@ -86,7 +89,7 @@ class AnchoredList extends PureComponent { >
- {items.map((item, i) => ( + {items.filter(i => i).map((item, i) => (
- {dateToString(new Date(), { + {dateToString(today, { withTime: false })} @@ -85,61 +86,74 @@ class Dispute extends PureComponent { anchor: 'Details', element: (
) }, - ...dispute.data.evidence.map(e => ({ - anchor: 'Evidence', - element: ( - - ) - })), - ...(dispute.data.hasRuled - ? [ - { - anchor: 'Ruling', + ...dispute.data.events.map(e => { + switch (e.type) { + case EVENT_TYPE_ENUM[0]: + return { + anchor: 'Appeal', element: ( - + ) + } + case EVENT_TYPE_ENUM[1]: + return { + anchor: 'Evidence', + element: ( + ) } - ] - : [ - { - anchor: 'Vote', + case EVENT_TYPE_ENUM[2]: + return { + anchor: 'Ruling', element: ( -
- - -
+ ) } - ]) + default: + return null + } + }), + dispute.data.appealJuror[dispute.data.numberOfAppeals] + .canRule && [ + { + anchor: 'Vote', + element: ( +
+ + +
+ ) + } + ] ]} /> ) diff --git a/src/containers/disputes/components/disputes-table/index.js b/src/containers/disputes/components/disputes-table/index.js index 89b9bfd..284fd48 100644 --- a/src/containers/disputes/components/disputes-table/index.js +++ b/src/containers/disputes/components/disputes-table/index.js @@ -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', diff --git a/src/reducers/dispute.js b/src/reducers/dispute.js index c2a227f..d548b14 100644 --- a/src/reducers/dispute.js +++ b/src/reducers/dispute.js @@ -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, @@ -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 diff --git a/src/sagas/dispute.js b/src/sagas/dispute.js index 26b84d1..57c495b 100644 --- a/src/sagas/dispute.js +++ b/src/sagas/dispute.js @@ -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. @@ -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) { @@ -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)) diff --git a/yarn.lock b/yarn.lock index c3d0839..1ad242e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1615,7 +1615,7 @@ babel-polyfill@6.26.0, babel-polyfill@^6.3.14: core-js "^2.5.0" regenerator-runtime "^0.10.5" -babel-preset-env@1.6.1, babel-preset-env@^1.6.0, babel-preset-env@^1.6.1: +babel-preset-env@1.6.1, babel-preset-env@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" dependencies: @@ -1856,10 +1856,6 @@ big.js@^3.1.3: version "2.0.7" resolved "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" -bignumber@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bignumber/-/bignumber-1.1.0.tgz#e6ab0a743da5f3ea018e5c17597d121f7868c159" - binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" @@ -4145,12 +4141,6 @@ eth-contract-class@0.0.6: dependencies: web3-core-promievent "^1.0.0-beta.21" -ethereumjs-testrpc@^4.1.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ethereumjs-testrpc/-/ethereumjs-testrpc-4.1.3.tgz#74db90c9075fdfa3ba2513f08595baac36a86c7e" - dependencies: - webpack "^3.0.0" - ethereumjs-testrpc@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/ethereumjs-testrpc/-/ethereumjs-testrpc-6.0.3.tgz#7a0b87bf3670f92f607f98fa6a78801d9741b124" @@ -6349,7 +6339,7 @@ jest-validate@^21.1.0: leven "^2.1.0" pretty-format "^21.2.1" -jest@20.0.4, jest@^20.0.4: +jest@20.0.4: version "20.0.4" resolved "https://registry.yarnpkg.com/jest/-/jest-20.0.4.tgz#3dd260c2989d6dad678b1e9cc4d91944f6d602ac" dependencies: @@ -6548,21 +6538,11 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -kleros-api@^0.0.59: - version "0.0.59" - resolved "https://registry.yarnpkg.com/kleros-api/-/kleros-api-0.0.59.tgz#045f4d0b88ec5346ab23305cc208e2f76f771fd0" +kleros-api@^0.0.64: + version "0.0.64" + resolved "https://registry.yarnpkg.com/kleros-api/-/kleros-api-0.0.64.tgz#207c87b790f5d0ebe715596264c46f50edc313ee" dependencies: - babel-plugin-transform-runtime "^6.23.0" - babel-preset-env "^1.6.0" - babel-preset-react "^6.24.1" - bignumber "^1.1.0" - dotenv-webpack "^1.5.4" - esdoc "^1.0.4" - esdoc-ecmascript-proposal-plugin "^1.0.0" - esdoc-standard-plugin "^1.0.0" - ethereumjs-testrpc "^4.1.1" - global "^4.3.2" - jest "^20.0.4" + babel-runtime "^6.26.0" kleros "^0.0.5" kleros-interaction "^0.0.8" lodash "^4.17.4"