mirror of
https://github.com/status-im/snt-voting.git
synced 2025-02-23 23:58:13 +00:00
Adding universal link redirection and voting on ballots
This commit is contained in:
parent
ac199c1f40
commit
55f08d90fa
@ -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>
|
||||||
|
@ -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(){
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user