From 01afa35a394d9dd8986a7b3f254bc03aa66480e6 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Sun, 3 Jun 2018 12:08:53 -0400 Subject: [PATCH] Displaying buttons depending on proposal state --- .../proposal-manager/proposal-manager.js | 12 +- .../voting-dapp/proposal-container.js | 1 - app/components/voting-dapp/proposal-form.js | 65 ---------- app/components/voting-dapp/proposal.js | 5 +- app/components/voting-dapp/voting-dapp.js | 1 - app/components/voting-dapp/voting.js | 122 ++++++++++++++++++ contracts/democracy/ProposalManager.sol | 17 ++- 7 files changed, 150 insertions(+), 73 deletions(-) delete mode 100644 app/components/voting-dapp/proposal-form.js create mode 100644 app/components/voting-dapp/voting.js diff --git a/app/components/proposal-manager/proposal-manager.js b/app/components/proposal-manager/proposal-manager.js index f578a2c..0a4ea07 100644 --- a/app/components/proposal-manager/proposal-manager.js +++ b/app/components/proposal-manager/proposal-manager.js @@ -108,11 +108,17 @@ const ProposalManager = withFormik({ mapPropsToValues: props => ({ title: '', description: '', url: '' }), validate(values) {}, handleSubmit(values, { setSubmitting}){ - const { title, description, url } = values; - const { saveText } = EmbarkJS.Storage; + + let dataObj = { + title: values.title, + description: values.description, + url: values.url + }; + const { toHex } = web3.utils; const { submitProposal } = ProposalCuration.methods; - saveText(JSON.stringify(description)) + + EmbarkJS.Storage.saveText(JSON.stringify(dataObj)) .then(hash => { const hexHash = toHex(hash); //TODO create toggle for address approval diff --git a/app/components/voting-dapp/proposal-container.js b/app/components/voting-dapp/proposal-container.js index 5a5afb0..163f995 100644 --- a/app/components/voting-dapp/proposal-container.js +++ b/app/components/voting-dapp/proposal-container.js @@ -1,7 +1,6 @@ import web3 from "Embark/web3" import EmbarkJS from 'Embark/EmbarkJS'; import React, {Component, Fragment} from 'react'; -import ProposalForm from './proposal-form'; import Proposal from './proposal'; import ProposalList from './proposal-list'; import Paginator from './paginator'; diff --git a/app/components/voting-dapp/proposal-form.js b/app/components/voting-dapp/proposal-form.js deleted file mode 100644 index 0c4d8bd..0000000 --- a/app/components/voting-dapp/proposal-form.js +++ /dev/null @@ -1,65 +0,0 @@ -import web3 from "Embark/web3" -import EmbarkJS from 'Embark/EmbarkJS'; -import React, {Component, Fragment} from 'react'; -import { Button } from 'react-bootstrap'; -import ProposalManager from 'Embark/contracts/ProposalManager'; -import ProposalCuration from 'Embark/contracts/ProposalCuration'; - -class ProposalForm extends Component { - - constructor(props) { - super(props); - this.state = { - decision: 0 - }; - } - - componentDidMount(){ - __embarkContext.execWhenReady(async () => { - ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call(); - let proposal = await ProposalManager.methods.getProposal(this.props.proposalId).call(); - this.setState({decision: proposal.vote}); - }); - } - - async handleClick(e, vote){ - e.preventDefault(); - - let choice = 0; - if(vote == 'APPROVE') - choice = 2; - else - choice = 1; - - let proposal = this.props.proposalId; - let receipt = await ProposalManager.methods.voteProposal(this.props.proposalId, choice) - .send({from: web3.eth.defaultAccount}); - - if(receipt.status == '0x1'){ - this.setState({ - decision: choice - // TODO: show results - }); - } - console.log(receipt); - - // TODO: handle error - } - - render(){ - console.log(this.state); - return
- { - this.state.decision != 0 ? - You voted for: {this.state.decision.toString() == '1' ? 'REJECT' : 'APPROVE'}
- : '' - } - - -
TODO: Verify if vote is allowed for this proposal
-
TODO: Show time until proposal votation is closed
-
; - } -} - -export default ProposalForm; diff --git a/app/components/voting-dapp/proposal.js b/app/components/voting-dapp/proposal.js index c8790f4..c31c497 100644 --- a/app/components/voting-dapp/proposal.js +++ b/app/components/voting-dapp/proposal.js @@ -1,8 +1,9 @@ +import web3 from "Embark/web3" import React from 'react'; import $ from 'jquery'; import { Button, Alert } from 'react-bootstrap'; import EmbarkJS from 'Embark/EmbarkJS'; -import ProposalForm from './proposal-form'; +import Voting from './voting'; class Proposal extends React.Component { @@ -57,7 +58,7 @@ class Proposal extends React.Component {

{ this.state.title }

{ this.state.description }

{ this.state.url } - + ); } diff --git a/app/components/voting-dapp/voting-dapp.js b/app/components/voting-dapp/voting-dapp.js index 596bed6..cc6a434 100644 --- a/app/components/voting-dapp/voting-dapp.js +++ b/app/components/voting-dapp/voting-dapp.js @@ -1,7 +1,6 @@ import web3 from "Embark/web3" import EmbarkJS from 'Embark/EmbarkJS'; import React from 'react'; -import ProposalForm from './proposal-form'; import ProposalContainer from './proposal-container'; import StatusBar from './status-bar'; diff --git a/app/components/voting-dapp/voting.js b/app/components/voting-dapp/voting.js new file mode 100644 index 0000000..d46e92e --- /dev/null +++ b/app/components/voting-dapp/voting.js @@ -0,0 +1,122 @@ +import web3 from "Embark/web3" +import EmbarkJS from 'Embark/EmbarkJS'; +import React, {Component, Fragment} from 'react'; +import { Button } from 'react-bootstrap'; +import ProposalManager from 'Embark/contracts/ProposalManager'; +import ProposalCuration from 'Embark/contracts/ProposalCuration'; + +class Voting extends Component { + + constructor(props) { + super(props); + this.state = { + decision: 0, + proposal: null, + finalResult: null + }; + } + + componentDidMount(){ + __embarkContext.execWhenReady(async () => { + ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call(); + let _proposal = await ProposalManager.methods.getProposal(this.props.proposalId).call(); + let blockNum = await web3.eth.getBlockNumber(); + let _data = await ProposalManager.methods.getProposalData(this.props.proposalId).call(); + + this.setState({ + proposal: _proposal, + data: _data, + decision: _proposal.vote, + block: blockNum, + finalResult: _data.result + }); + }); + } + + async determineFinalResult(e){ + e.preventDefault(); + + let receipt = await ProposalManager.methods.finalResult(this.props.proposalId) + .send({from: web3.eth.defaultAccount}); + + if(receipt.status == '0x1'){ + this.setState({ + decision: choice, + block: blockNum, + finalResult: receipt.events.ProposalResult.finalResult + }); + } + console.log(receipt); + } + + async handleClick(e, vote){ + e.preventDefault(); + + let choice = 0; + if(vote == 'APPROVE') + choice = 2; + else + choice = 1; + + let proposal = this.props.proposalId; + let receipt = await ProposalManager.methods.voteProposal(this.props.proposalId, choice) + .send({from: web3.eth.defaultAccount}); + let blockNum = await web3.eth.getBlockNumber(); + + + if(receipt.status == '0x1'){ + this.setState({ + decision: choice, + block: blockNum + }); + } + console.log(receipt); + + // TODO: handle error + } + + render(){ + console.log(this.state); + return
+ { + this.state.decision != 0 ? +

You voted for:

+ : '' + } + + { + this.state.data != null && this.state.block < this.state.data.voteBlockEnd ? + + + + + : '' + } + + { + this.state.data != null && this.state.block >= this.state.data.voteBlockEnd && this.state.data.result == 0 ? + + : '' + } + + { this.state.data != null ? +
    +
  • Voting ends on block: {this.state.data.voteBlockEnd }
  • +
  • Current Block: { this.state.block }
  • +
  • Final Result:
  • +
+ : '' } + +
; + } +} + + +const ResultChoice = props => +{props.decision.toString() == '1' ? 'REJECT' : props.decision.toString() == '2' ? 'APPROVE' : ''} + + + + + +export default Voting; diff --git a/contracts/democracy/ProposalManager.sol b/contracts/democracy/ProposalManager.sol index 3a5a490..4f5da4f 100644 --- a/contracts/democracy/ProposalManager.sol +++ b/contracts/democracy/ProposalManager.sol @@ -66,7 +66,7 @@ contract ProposalManager is Controlled { p.txHash = _txHash; p.blockStart = block.number + 0; //will be replaced by configurations - p.voteBlockEnd = p.blockStart + 10000; //dummy value + p.voteBlockEnd = p.blockStart + 10; //dummy value emit ProposalSet(_topic, proposalId, _txHash); } @@ -151,6 +151,21 @@ contract ProposalManager is Controlled { return (p.topic, p.txHash, p.result == Vote.Approve, p.voteMap[msg.sender]); } + function getProposalData(uint _proposalId) + external + view + returns ( + bytes32 topic, + bytes32 txHash, + uint blockStart, + uint voteBlockEnd, + Vote result + ) + { + Proposal storage p = proposals[_proposalId]; + return (p.topic, p.txHash, p.blockStart, p.voteBlockEnd, p.result); + } + function offchainTabulateVoteResult(uint256 _proposalId) external