Displaying buttons depending on proposal state

This commit is contained in:
Richard Ramos 2018-06-03 12:08:53 -04:00
parent c6f7e54cac
commit 01afa35a39
7 changed files with 150 additions and 73 deletions

View File

@ -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

View File

@ -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';

View File

@ -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 <div>
{
this.state.decision != 0 ?
<span>You voted for: {this.state.decision.toString() == '1' ? 'REJECT' : 'APPROVE'}<br /></span>
: ''
}
<Button onClick={(e) => this.handleClick(e, 'APPROVE') }>Approve</Button>
<Button onClick={(e) => this.handleClick(e, 'REJECT') }>Reject</Button>
<b><br />TODO: Verify if vote is allowed for this proposal</b>
<b><br />TODO: Show time until proposal votation is closed</b>
</div>;
}
}
export default ProposalForm;

View File

@ -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 {
<h3>{ this.state.title }</h3>
<p>{ this.state.description }</p>
<a href={ this.state.url } target="_blank">{ this.state.url }</a>
<ProposalForm proposalId={this.props.data.id} />
<Voting proposalId={this.props.data.id} />
</div>);
}

View File

@ -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';

View File

@ -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 <div>
{
this.state.decision != 0 ?
<p>You voted for: <ResultChoice decision={this.state.decision} /></p>
: ''
}
{
this.state.data != null && this.state.block < this.state.data.voteBlockEnd ?
<Fragment>
<Button onClick={(e) => this.handleClick(e, 'APPROVE') }>Approve</Button>
<Button onClick={(e) => this.handleClick(e, 'REJECT') }>Reject</Button>
</Fragment>
: ''
}
{
this.state.data != null && this.state.block >= this.state.data.voteBlockEnd && this.state.data.result == 0 ?
<Button onClick={(e) => this.determineFinalResult(e) }>Determine final result</Button>
: ''
}
{ this.state.data != null ?
<ul>
<li>Voting ends on block: {this.state.data.voteBlockEnd }</li>
<li>Current Block: { this.state.block }</li>
<li>Final Result: <ResultChoice decision={this.state.finalResult} /></li>
</ul>
: '' }
</div>;
}
}
const ResultChoice = props =>
<span>{props.decision.toString() == '1' ? 'REJECT' : props.decision.toString() == '2' ? 'APPROVE' : ''}</span>
export default Voting;

View File

@ -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