Adding universal link redirection and voting on ballots

This commit is contained in:
Richard Ramos 2018-10-17 15:30:11 -04:00
parent ac199c1f40
commit 55f08d90fa
5 changed files with 164 additions and 29 deletions

View File

@ -21,7 +21,8 @@ import ReviewVotes from './flow/ReviewVotes';
class Voting extends PureComponent { class Voting extends PureComponent {
state = { state = {
addPoll: false, addPoll: false,
pollTokenBalances: [] pollTokenBalances: [],
votes: []
}; };
updatePollBalance = (pollId, tokenBalance, ethBalance) => { updatePollBalance = (pollId, tokenBalance, ethBalance) => {
@ -30,6 +31,9 @@ class Voting extends PureComponent {
this.setState({pollTokenBalances}); this.setState({pollTokenBalances});
} }
setVotesToReview = (votes) => {
this.setState({votes});
}
render(){ render(){
const { addPoll, pollTokenBalances } = this.state; const { addPoll, pollTokenBalances } = this.state;
@ -53,7 +57,7 @@ class Voting extends PureComponent {
<Route path="/wallet" render={() => <ConnectYourWallet polls={rawPolls} updateBalances={this.updatePollBalance} />} /> <Route path="/wallet" render={() => <ConnectYourWallet polls={rawPolls} updateBalances={this.updatePollBalance} />} />
<Route path="/otherWallets" render={OtherWallets} /> <Route path="/otherWallets" render={OtherWallets} />
<Route path="/votingCredits" render={() => <VotingCredits polls={rawPolls} balances={pollTokenBalances} />} /> <Route path="/votingCredits" render={() => <VotingCredits polls={rawPolls} balances={pollTokenBalances} />} />
<Route path="/voting" render={() => <PollVoting polls={rawPolls} />} /> <Route path="/voting" render={() => <PollVoting polls={rawPolls} balances={pollTokenBalances} setVotesToReview={this.setVotesToReview} />} />
<Route path="/review" render={() => <ReviewVotes polls={rawPolls} />} /> <Route path="/review" render={() => <ReviewVotes polls={rawPolls} />} />
</Switch> </Switch>
</div> </div>

View File

@ -8,10 +8,15 @@ import { withRouter } from 'react-router-dom'
class ConnectYourWallet extends Component { class ConnectYourWallet extends Component {
connectWallet = async () => { connectWallet = async () => {
const {history, polls, updateBalances} = this.props; const {history, polls, updateBalances} = this.props;
const tokenBalance = await SNT.methods.balanceOfAt(web3.eth.defaultAccount, polls[0]._startBlock).call();
const ethBalance = await web3.eth.getBalance(web3.eth.defaultAccount); if(web3.currentProvider.isStatus){
updateBalances(0, tokenBalance, ethBalance); const tokenBalance = await SNT.methods.balanceOfAt(web3.eth.defaultAccount, polls[0]._startBlock).call();
history.push('/votingCredits'); const ethBalance = await web3.eth.getBalance(web3.eth.defaultAccount);
updateBalances(0, tokenBalance, ethBalance);
history.push('/votingCredits');
} else {
window.location.href = "https://get.status.im/browse/" + location.href.replace(/^http(s?):\/\//, '');
}
} }
render(){ render(){

View File

@ -1,30 +1,158 @@
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import React, {Component} from 'react'; import React, {Component, Fragment} from 'react';
import Typography from '@material-ui/core/Typography' import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles';
import Slider from '@material-ui/lab/Slider';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { withRouter } from 'react-router-dom'
const styles = {
card: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
thumb: {
width: '24px',
height: '24px'
},
appBar: {
position: 'relative',
},
flex: {
flex: 1,
},
};
class PollVoting extends Component { class PollVoting extends Component {
render(){ state = {
votes: [],
originalVotes: []
}
componentDidMount(){
const {polls} = this.props; const {polls} = this.props;
let title; if(!polls || !polls.length){
this.props.history.push('/');
if(polls && polls.length){ console.log("A");
title = polls[0].content.title;
description = polls[0].content.description;
} }
const poll = polls[0];
const votes = [];
for(let i = 0; i < poll._numBallots; i++){
votes[i] = 0; // props.votes[i];
}
this.setState({
originalVotes: votes.slice(0),
votes
});
}
updateVotes = i => numVotes => {
const votes = this.state.votes;
votes[i] = numVotes;
this.setState({votes});
}
sendToReview = () => {
this.props.setVotesToReview(this.state.votes);
this.props.history.push('/review');
}
render(){
const {polls, classes, balances} = this.props;
const {originalVotes, votes} = this.state;
const {fromWei} = web3.utils;
if(!polls || !polls.length){
return null;
}
const symbol = "SNT"; // TODO:
const poll = polls[0];
const title = poll.content.title;
const ballots = poll.content.ballots
return (polls ? <div> const balance = fromWei(balances[0].tokenBalance, "ether");
<div className="section"> const cantVote = balance == 0 || !poll._canVote;
const disableVote = cantVote;
const availableCredits = parseInt(balance, 10) - votes.reduce((prev, curr) => prev + curr * curr, 0);
// Votes calculation
const originalVotesQty = originalVotes.reduce((x,y) => x+y, 0);
const buttonText = originalVotesQty != 0 && !arraysEqual(originalVotes, votes) ? 'Change Vote' : 'Vote';
// Calculating votes availables
const maxVotes = Math.floor(Math.sqrt(balance));
const maxValuesForBallots = [];
let votedSNT = 0;
for(let i = 0; i < poll._numBallots; i++){
if(votes[i] == undefined){
votes[i] = 0;
} else {
votedSNT += votes[i]*votes[i];
}
}
for(let i = 0; i < poll._numBallots; i++){
maxValuesForBallots[i] = Math.floor(Math.sqrt(balance - votedSNT + votes[i]*votes[i]));
}
return <div className="section">
<Typography variant="headline">{title}</Typography> <Typography variant="headline">{title}</Typography>
</div> { ballots.map((item, i) => {
return <BallotSlider key={i} title={item.title} subtitle={item.subtitle} symbol={symbol} classes={classes} votes={votes[i]} cantVote={cantVote} balance={balance} maxVotes={maxVotes} maxVotesAvailable={maxValuesForBallots[i]} updateVotes={this.updateVotes(i)} />
<Link to="/review"><Button variant="text">Review vote</Button></Link>
})}
</div> : null); <Typography>{availableCredits} Credits left</Typography>
<Button disabled={disableVote} variant="text" onClick={this.sendToReview}>Review vote</Button>
</div>
} }
} }
export default PollVoting;
class BallotSlider extends Component {
constructor(props){
super(props);
this.state = {
value: props.votes || 0
}
}
handleChange = (event, value) => {
if(value > this.props.maxVotesAvailable){
value = this.props.maxVotesAvailable;
}
this.setState({value});
this.props.updateVotes(value);
};
render(){
const {maxVotes, maxVotesAvailable, classes, cantVote, balance, symbol, title, subtitle} = this.props;
const {value} = this.state;
const nextVote = value + 1;
return <Card className="card">
<CardContent>
<Typography gutterBottom component="h2">{title}</Typography>
<Typography component="p">{subtitle}</Typography>
<Slider disabled={cantVote} classes={{ thumb: classes.thumb }} style={{ width: '95%' }} value={value} min={0} max={maxVotes} step={1} onChange={this.handleChange} />
{balance > 0 && !cantVote && <b>Your votes: {value} ({value * value} {symbol})</b>}
{ nextVote <= maxVotesAvailable && !cantVote ? <small>- Additional vote will cost {nextVote*nextVote - value*value} {symbol}</small> : (balance > 0 && !cantVote && <small>- Not enough balance available to buy additional votes</small>) }
</CardContent>
</Card>
}
}
export default withRouter(withStyles(styles)(PollVoting));

View File

@ -25,11 +25,9 @@ class VotingCredits extends Component {
let ethBalance = web3.utils.fromWei(balances[0].ethBalance, "ether"); let ethBalance = web3.utils.fromWei(balances[0].ethBalance, "ether");
let tokenBalance = Math.floor(web3.utils.fromWei(balances[0].tokenBalance, "ether")); let tokenBalance = Math.floor(web3.utils.fromWei(balances[0].tokenBalance, "ether"));
return (polls ? <div> return (polls ? <div className="section">
<div className="section">
<Typography variant="headline">{title}</Typography> <Typography variant="headline">{title}</Typography>
<Typography variant="body1" component="div" dangerouslySetInnerHTML={{__html: description}}></Typography> <Typography variant="body1" component="div" dangerouslySetInnerHTML={{__html: description}}></Typography>
</div>
<Card className="card"> <Card className="card">
<CardContent> <CardContent>
<Typography component="p"> <Typography component="p">
@ -68,7 +66,7 @@ class VotingCredits extends Component {
</CardContent> </CardContent>
</Card> } </Card> }
{ ethBalance == 0 || tokenBalance == 0 && <Link to="/wallet"><Button variant="text">Back</Button></Link> } { ethBalance == 0 || tokenBalance == 0 && <Link to="/wallet"><Button variant="text">Back</Button></Link> }
{ ethBalance > 0 || tokenBalance > 0 &&<Link to="/voting"><Button variant="text">Vote</Button></Link> } { ethBalance > 0 && tokenBalance > 0 && <Link to="/voting"><Button variant="text">Vote</Button></Link> }
</div> : null); </div> : null);
} }
} }

View File

@ -233,7 +233,7 @@ const AddPoll = withFormik({
async handleSubmit(values, { setSubmitting, setErrors, props, resetForm }) { async handleSubmit(values, { setSubmitting, setErrors, props, resetForm }) {
const { ballots, startBlock, endTime } = values; const { ballots, startBlock, endTime } = values;
const { eth: { getBlockNumber }, utils: { toHex } } = window.web3; const { utils: { toHex } } = window.web3;
const addPollCustomBlock = PollManager.methods["addPoll(uint256,uint256,bytes,uint8)"]; const addPollCustomBlock = PollManager.methods["addPoll(uint256,uint256,bytes,uint8)"];
const addPollOnlyEndTime = PollManager.methods["addPoll(uint256,bytes,uint8)"]; const addPollOnlyEndTime = PollManager.methods["addPoll(uint256,bytes,uint8)"];
@ -243,15 +243,15 @@ const AddPoll = withFormik({
const d90 = date.getTime() / 1000; const d90 = date.getTime() / 1000;
const endTime90 = parseInt(endTime ? endTime : d90); const endTime90 = parseInt(endTime ? endTime : d90);
const options = JSON.parse(ballots); const jsonObj = JSON.parse(ballots);
const ipfsHash = await EmbarkJS.Storage.saveText(ballots); const ipfsHash = await EmbarkJS.Storage.saveText(ballots);
const encodedDesc = toHex(ipfsHash); const encodedDesc = toHex(ipfsHash);
let toSend; let toSend;
if(startBlock){ if(startBlock){
toSend = addPollCustomBlock(startBlock, endTime90, encodedDesc, options.length || 0); toSend = addPollCustomBlock(startBlock, endTime90, encodedDesc, jsonObj.ballots.length || 0);
} else { } else {
toSend = addPollOnlyEndTime(endTime90, encodedDesc, options.length || 0); toSend = addPollOnlyEndTime(endTime90, encodedDesc, jsonObj.ballots.length || 0);
} }
setSubmitting(true); setSubmitting(true);