remove voting artifacts

This commit is contained in:
Barry Gitarts 2018-07-23 15:33:16 -04:00
parent 7fa2acb3c4
commit 7e76511615
16 changed files with 0 additions and 1104 deletions

View File

@ -1,46 +0,0 @@
import React, { Fragment, PureComponent } from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import 'typeface-roboto';
import AppBar from './standard/AppBar';
import AddPoll from './simple-voting/AddPoll';
import PollsList from './simple-voting/PollsList';
import StatusLogo from '../ui/components/StatusLogo';
import Collapse from '@material-ui/core/Collapse';
import Hidden from '@material-ui/core/Hidden';
import Typography from '@material-ui/core/Typography';
import LinearProgress from '@material-ui/core/LinearProgress';
import { VotingContext } from '../context';
class Voting extends PureComponent {
state = { addPoll: false };
render(){
const { addPoll } = this.state;
const togglePoll = () => { this.setState({ addPoll: !addPoll })};
return (
<VotingContext.Consumer>
{({ getPolls, rawPolls, loading }) =>
<div>
<CssBaseline />
<AppBar togglePoll={togglePoll} />
{loading && <LinearProgress />}
<div style={{ margin: '30px', textAlign: 'center' }}>
<img src="images/logo.png" width="200" />
<Hidden smUp>
<Typography variant="headline" color="inherit">
What should we build next?
</Typography>
</Hidden>
</div>
<Collapse in={addPoll}>
<AddPoll togglePoll={togglePoll} getPolls={getPolls} />
</Collapse>
{rawPolls && <PollsList rawPolls={rawPolls} />}
</div>
}
</VotingContext.Consumer>
)
}
}
export default Voting

View File

@ -1,186 +0,0 @@
import EmbarkJS from 'Embark/EmbarkJS';
import ERC20Token from 'Embark/contracts/ERC20Token';
import ProposalCuration from 'Embark/contracts/ProposalCuration';
import SNT from 'Embark/contracts/SNT';
import React, { PureComponent, Fragment } from 'react';
import { Form, FormGroup, FormControl, HelpBlock, Button, Alert } from 'react-bootstrap';
import web3 from "Embark/web3";
import { withFormik } from 'formik';
import FieldGroup from '../standard/FieldGroup';
import TokenPermissions from '../standard/TokenPermission'
const { setSubmitPrice } = ProposalCuration.methods;
class InnerForm extends PureComponent {
constructor(props) {
super(props);
this.state = {
submitPrice: "Loading...",
canSubmit: true
};
}
componentDidMount(){
this._loadPrice();
}
componentWillReceiveProps(){
this._loadPrice();
}
_loadPrice(){
__embarkContext.execWhenReady(async () => {
try {
let _b = await ProposalCuration.methods.getSubmitPrice(web3.eth.defaultAccount).call();
this.setState({
submitPrice: _b,
canSubmit: true
});
} catch(err){
this.setState({
canSubmit: false,
submitPrice: "-"
});
}
});
}
setPrice = (address = web3.eth.defaultAccount, allowed = true, stakeValue = 1) => {
setSubmitPrice(address, allowed, stakeValue)
.send()
.then(res => {
this.setState({ ...this.state, canSubmit: true });
console.log(res);
})
.catch(err => { console.log(err) })
}
render() {
const { values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting, setFieldValue } = this.props;
const { canSubmit } = this.state;
return (
<Fragment>
{!canSubmit &&
<Alert bsStyle="warning">
Account not allowed to submit proposals <Button onClick={(e) => this.setPrice()}>Click to enable (Admin only)</Button>
</Alert>
}
<TokenPermissions methods={SNT.methods} spender={ProposalCuration._address} symbol='SNT' />
<hr/>
<h2>Add proposal</h2>
<h3>Price: {this.state.submitPrice}</h3>
<Form onSubmit={handleSubmit}>
<FieldGroup
id="title"
name="title"
type="text"
label="Title"
onChange={handleChange}
onBlur={handleBlur}
value={values.title}
/>
<FieldGroup
id="description"
name="description"
type="text"
label="Description"
onChange={handleChange}
onBlur={handleBlur}
value={values.description}
/>
<FieldGroup
id="url"
name="url"
type="text"
label="URL"
onChange={handleChange}
onBlur={handleBlur}
value={values.url}
/>
<FieldGroup
id="topic"
name="topic"
type="text"
label="Topic"
onChange={handleChange}
onBlur={handleBlur}
value={values.topic}
/>
<FieldGroup
id="to"
name="to"
type="text"
label="To"
onChange={handleChange}
onBlur={handleBlur}
value={values.to}
/>
<FieldGroup
id="data"
name="data"
type="text"
label="Data"
onChange={handleChange}
onBlur={handleBlur}
value={values.data}
/>
<FieldGroup
id="value"
name="value"
type="text"
label="Value"
onChange={handleChange}
onBlur={handleBlur}
value={values.value}
/>
<Button type="submit" disabled={!canSubmit || isSubmitting}>{isSubmitting ? 'Submission in progress' : 'Submit'}</Button>
</Form>
</Fragment>
)
}
}
const ProposalManager = withFormik({
mapPropsToValues: props => ({ title: '', description: '', url: '', data: '0x00', value: '0', topic: '0x00', to: '0x0000000000000000000000000000000000000000' }),
validate(values) {},
handleSubmit(values, { setSubmitting}){
let dataObj = {
title: values.title,
description: values.description,
url: values.url,
};
const { toHex } = web3.utils;
const { submitProposal } = ProposalCuration.methods;
EmbarkJS.Storage.saveText(JSON.stringify(dataObj))
.then(hash => {
const hexHash = toHex(hash);
//TODO create toggle for address approval
submitProposal(
values.topic,
values.to,
values.value,
values.data,
hexHash
)
.send({from: web3.eth.defaultAccount, gasLimit: 1000000})
.then(res => {
setSubmitting(false);
console.log(res);
})
.catch(err => {
setSubmitting(false);
//TODO show error
console.log('Storage saveText Error: ', err.message)
});
})
}
})(InnerForm)
export default ProposalManager;

View File

@ -1,121 +0,0 @@
import React, { Fragment } from 'react';
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import PollManager from 'Embark/contracts/PollManager';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import CircularProgress from '@material-ui/core/CircularProgress';
import { withStyles } from '@material-ui/core/styles';
import { withFormik } from 'formik';
const oneDayinBlocks = 5760;
const styles = theme => ({
button: {
margin: theme.spacing.unit,
},
extendedIcon: {
marginRight: theme.spacing.unit,
},
textField: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit
},
inputLabel: {
fontSize: '16px'
},
form: {
display: 'flex',
flexDirection: 'column'
},
textFieldInput: {
fontSize: '16px'
},
textFieldFormLabel: {
fontSize: 18,
}
});
const InnerForm = ({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
classes
}) => (
<Card>
<CardContent>
<form onSubmit={handleSubmit} className={classes.form}>
<TextField
id="description"
label="Enter your proposal description"
className={classes.textField}
value={values.description}
onChange={handleChange}
margin="normal"
fullWidth
error={!!errors.description}
InputProps={{
classes: {
input: classes.textFieldInput
},
}}
InputLabelProps={{
className: classes.textFieldFormLabel
}}
helperText={errors.description}
/>
{!isSubmitting ?
<Button type="submit" variant="extendedFab" aria-label="add" className={classes.button}>Submit</Button> :
<CircularProgress style={{ margin: '10px 10px 10px 50%' }} />
}
</form>
</CardContent>
</Card>
)
const StyledForm = withStyles(styles)(InnerForm);
const AddPoll = withFormik({
mapPropsToValues: props => ({ description: ''}),
validate(values, props){
const errors = {};
const { description } = values;
if(description.toString().trim() === "") errors.description = true;
return errors;
},
async handleSubmit(values, { setSubmitting, setErrors, props }) {
const { description } = values;
const { eth: { getBlockNumber } } = window.web3;
const { addPoll } = PollManager.methods;
const currentBlock = await getBlockNumber();
const endTime = currentBlock + (oneDayinBlocks * 90);
const toSend = addPoll(endTime, description);
setSubmitting(true);
toSend.estimateGas()
.then(gasEstimated => {
console.log("addPoll gas estimated: "+gasEstimated);
return toSend.send({gas: gasEstimated + 100000});
})
.then(res => {
console.log('sucess:', res);
props.getPolls();
setSubmitting(false);
props.togglePoll();
})
.catch(res => {
console.log('fail:', res);
setErrors({ 'description': res.message.split('Error:').pop().trim() });
})
.finally(() => {
setSubmitting(false);
});
}
})(StyledForm)
export default AddPoll;

View File

@ -1,102 +0,0 @@
import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import ListItemText from '@material-ui/core/ListItemText';
import ListItem from '@material-ui/core/ListItem';
import List from '@material-ui/core/List';
import Divider from '@material-ui/core/Divider';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import CloseIcon from '@material-ui/icons/Close';
import Slide from '@material-ui/core/Slide';
import Checkbox from '@material-ui/core/Checkbox';
import { VotingContext } from '../../context';
export const constants = { MOST_VOTES: 'Most Votes', MOST_VOTERS: 'Most Voters', NEWEST_ADDED: 'Newest Added', ENDING_SOONEST: 'Ending Soonest' };
const styles = {
appBar: {
position: 'relative',
},
flex: {
flex: 1,
},
};
function Transition(props) {
return <Slide direction="up" {...props} />;
}
const ListButton = ({ name, setPollOrder, selected, handleClose }) => (
<Fragment>
<ListItem button onClick={() => {
setPollOrder(name);
handleClose();
}}>
<Checkbox
checked={selected}
color="primary"
disableRipple
/>
<ListItemText primary={constants[name]} />
</ListItem>
<Divider />
</Fragment>
)
class OrderingDialog extends PureComponent {
state = {
open: false,
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
const { handleClose } = this;
return (
<VotingContext.Consumer>
{({ setPollOrder, pollOrder }) =>
<div>
<Button color="inherit" variant="outlined" onClick={this.handleClickOpen}>Open Filters</Button>
<Dialog
fullScreen
open={this.state.open}
onClose={this.handleClose}
TransitionComponent={Transition}
>
<AppBar className={classes.appBar} onClick={this.handleClose}>
<Toolbar>
<IconButton color="inherit" aria-label="Close">
<CloseIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
close
</Typography>
</Toolbar>
</AppBar>
<List>
{Object.keys(constants).map((name, i) => <ListButton key={i} name={name} setPollOrder={setPollOrder} selected={pollOrder === name} handleClose={handleClose} />)}
</List>
</Dialog>
</div>
}
</VotingContext.Consumer>
);
}
}
OrderingDialog.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(OrderingDialog);

View File

@ -1,193 +0,0 @@
import React, { Fragment, PureComponent } from 'react';
import { toString } from 'lodash';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import Slide from '@material-ui/core/Slide';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/lab/Slider';
import PollManager from 'Embark/contracts/PollManager';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import web3 from "Embark/web3"
import CircularProgress from '@material-ui/core/CircularProgress';
import { withStyles } from '@material-ui/core/styles';
import { VotingContext } from '../../context';
const styles = {
card: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
thumb: {
width: '24px',
height: '24px'
},
appBar: {
position: 'relative',
},
flex: {
flex: 1,
},
};
function Transition(props) {
return <Slide direction="up" {...props} />;
};
const getIdeaFromStr = str => {
const match = str.match(/\(([^)]+)\)/)
if (match) return match[1].toLowerCase();
return match;
}
const sortingFn = {
MOST_VOTES: (a, b) => b._qvResults - a._qvResults,
MOST_VOTERS: (a, b) => b._voters - a._voters,
NEWEST_ADDED: (a, b) => b._startBlock - a._startBlock,
ENDING_SOONEST: (a, b) => a._endBlock - b._endBlock
};
class Poll extends PureComponent {
constructor(props){
super(props);
this.state = { value: props.votes, originalValue: props.votes, balance: 0, isSubmitting: false, open: false };
}
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
handleChange = (event, value) => {
this.setState({ value })
};
handleClick = (event) => {
event.preventDefault();
this.setState({isSubmitting: true});
const { customVote, poll, unvote } = PollManager.methods;
const { updatePoll, idPoll } = this.props;
const { value } = this.state;
const { toWei } = web3.utils;
const balance4Voting = toWei(toString(value * value));
const toSend = balance4Voting == 0 ? unvote(idPoll) : customVote(idPoll, balance4Voting);
toSend.estimateGas()
.then(gasEstimated => {
console.log("voting gas estimated: " + gasEstimated);
return toSend.send({gas: gasEstimated + 100000});
})
.then(res => {
console.log('sucess:', res);
this.setState({ isSubmitting: false, originalValue: value });
return updatePoll(idPoll);
})
.catch(res => {
console.log('fail:', res, res.messsage);
this.setState({ error: res.message })
})
.finally(() => {
this.setState({isSubmitting: false});
});
}
render(){
const {
_description,
_totalCensus,
_voters,
_qvResults,
_results,
_canVote,
balance,
classes,
ideaSites
} = this.props;
const { value, originalValue, isSubmitting, error } = this.state;
const cantVote = balance == 0 || !_canVote;
const disableVote = cantVote || isSubmitting;
const { fromWei } = web3.utils;
const maxValue = Math.floor(Math.sqrt(balance));
const buttonText = originalValue != 0 && value != originalValue ? 'Change Vote' : 'Vote';
const idea = getIdeaFromStr(_description)
const ideaSite = ideaSites && ideaSites.filter(site => site.includes(idea));
return (
<Card>
<CardContent>
<Typography variant="headline">{_description}</Typography>
<Typography variant="subheading" color="textSecondary">
<b>Total:</b> {_voters} voters. {_qvResults} votes ({fromWei(_results)} SNT)
</Typography>
<Typography variant="subheading" color="textSecondary">
<b>Your vote:</b> {value} votes ({value * value} SNT)
</Typography>
{cantVote && <Typography variant="body2" color="error">
{balance == 0 && <span>Voting disabled for proposals made when there was no SNT in the account</span>}
{balance != 0 && !_canVote && <span>You can not vote on this poll</span>}
</Typography>}
{error && <Typography variant="body2" color="error">{error}</Typography>}
{ideaSite && ideaSite.length > 0 && <Typography onClick={this.handleClickOpen} variant="subheading" color="primary">{ideaSite}</Typography>}
{ideaSite && <Dialog
fullScreen
open={this.state.open}
onClose={this.handleClose}
TransitionComponent={Transition}
>
<AppBar className={classes.appBar} onClick={this.handleClose}>
<Toolbar>
<IconButton color="inherit" aria-label="Close">
<CloseIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
close
</Typography>
</Toolbar>
</AppBar>
<div
style={{ overflow: "auto", height: '100%', width: '100%', position: "fixed", top: 0, left: 0, zIndex: 1, overflowScrolling: "touch", WebkitOverflowScrolling: "touch" }}
>
<iframe
className="contentIframe"
frameBorder="0"
src={ideaSite[0]}
style={{ height: "100%", width: "100%" }}
height="100%"
width="100%"
>
</iframe>
</div>
</Dialog>}
</CardContent>
{!cantVote && <CardActions className={classes.card}>
<Slider style={{ width: '95%' }} classes={{ thumb: classes.thumb }} disabled={disableVote} value={value || 0} min={0} max={maxValue} step={1} onChange={this.handleChange} />
{isSubmitting ? <CircularProgress /> : <Button variant="contained" disabled={disableVote} color="primary" onClick={this.handleClick}>{buttonText}</Button>}
</CardActions>}
</Card>
)
}
}
const PollsList = ({ classes }) => (
<VotingContext.Consumer>
{({ updatePoll, rawPolls, pollOrder, appendToPoll, ideaSites }) =>
<Fragment>
{rawPolls
.sort(sortingFn[pollOrder])
.map((poll) => <Poll key={poll._token} classes={classes} appendToPoll={appendToPoll} updatePoll={updatePoll} ideaSites={ideaSites} {...poll} />)}
</Fragment>
}
</VotingContext.Consumer>
)
export default withStyles(styles)(PollsList);

View File

@ -1,25 +0,0 @@
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS';
import React, {Fragment} from 'react';
import {Button} from 'react-bootstrap';
const Paginator = props => {
let ln = Math.ceil(props.total / props.recordsByPage);
let btnArray = []
for(let i = 1; i <= ln; i++){
btnArray.push(<Button
bsStyle="link"
className={i == props.pageNum ? 'current' : ''}
onClick={(e) => props.pageHandler(e, i)}>{i}</Button>)
}
return <div>{
btnArray.map((component, index) => (
<Fragment key={index}>
{ component }
</Fragment>
))
}</div>;
};
export default Paginator;

View File

@ -1,67 +0,0 @@
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS';
import React, {Component, Fragment} from 'react';
import Proposal from './proposal';
import ProposalList from './proposal-list';
import Paginator from './paginator';
import ProposalManager from 'Embark/contracts/ProposalManager';
import ProposalCuration from 'Embark/contracts/ProposalCuration';
const pageLength = 4;
class ProposalContainer extends Component {
constructor(props) {
super(props);
this.state = {
proposals: [],
total: 0,
page: 1
};
window['ProposalCuration'] = ProposalCuration;
}
componentDidMount(){
__embarkContext.execWhenReady(async () => {
ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call();
await this.getTotalProposals();
await this.getProposalsOnPage(this.state.page);
});
}
async getTotalProposals(){
let proposalCount = await ProposalManager.methods.getProposalCount().call();
this.setState({
total: parseInt(proposalCount)
});
}
async getProposalsOnPage(pageNum){
this.fetchProposals((pageNum - 1) * pageLength, pageLength,
_p => {
this.setState({
proposals: _p,
page: pageNum
});
});
}
async fetchProposals(from, qty, cb){
let proposalList = [];
for(let i = from; i < from + qty && i < this.state.total; i++){
let res = await ProposalCuration.methods.proposals(i).call();
res.id = i;
proposalList.push(res);
}
cb(proposalList);
}
render(){
return <Fragment>
<ProposalList proposals={this.state.proposals} />
<Paginator total={this.state.total} recordsByPage={pageLength} page={this.state.page} pageHandler={(e, pageNum) => this.getProposalsOnPage(pageNum) } />
</Fragment>;
}
}
export default ProposalContainer;

View File

@ -1,11 +0,0 @@
import React, {Fragment} from 'react';
import Proposal from './proposal';
const ProposalList = props =>
<Fragment>
{props.proposals.map((u, i) => (
<Proposal key={i} data={u} />
))}
</Fragment>
export default ProposalList;

View File

@ -1,68 +0,0 @@
import web3 from "Embark/web3"
import React from 'react';
import $ from 'jquery';
import { Button, Alert } from 'react-bootstrap';
import EmbarkJS from 'Embark/EmbarkJS';
import Voting from './voting';
class Proposal extends React.Component {
constructor(props) {
super(props);
this.state = {
url: null,
title: null,
description: null,
error: null
};
}
componentDidUpdate(prevProps, prevState, snapshot){
if(prevProps.data.description !== this.props.data.description)
this.getProposalData();
}
componentDidMount(){
__embarkContext.execWhenReady(() => {
this.getProposalData();
});
}
getProposalData(){
let hash = web3.utils.toAscii(this.props.data.description);
EmbarkJS.Storage.get(hash)
.then((content) => {
let jsonObj = JSON.parse(content);
this.setState({
url: jsonObj.url,
title: jsonObj.title,
description: jsonObj.description
})
})
.catch((err) => {
if(err){
console.log("Storage get Error => " + err.message);
}
});
}
render(){
return (<div>
{
this.state.error !== null ?
<Alert bsStyle="warning">
{ this.state.error }
</Alert>
: ''
}
<h3>{ this.state.title }</h3>
<p>{ this.state.description }</p>
<a href={ this.state.url } target="_blank">{ this.state.url }</a>
<Voting proposalId={this.props.data.id} />
</div>);
}
}
export default Proposal;

View File

@ -1,32 +0,0 @@
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS';
import React, {Component} from 'react';
import SNT from 'Embark/contracts/SNT'; // TODO change this to SNT
class StatusBar extends Component {
constructor(props) {
super(props);
this.state = {
balance: 0
};
}
componentWillReceiveProps(){
__embarkContext.execWhenReady(async () => {
let _b = await SNT.methods.balanceOf(web3.eth.defaultAccount).call();
this.setState({
balance: _b
});
});
}
render(){
return <div className="SNTBalance">
SNT Voting Balance: <span>{this.state.balance}</span>
</div>;
}
}
export default StatusBar;

View File

@ -1,13 +0,0 @@
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import ProposalContainer from './proposal-container';
import StatusBar from './status-bar';
const VotingDapp = props =>
<div>
<StatusBar {...props} />
<ProposalContainer />
</div>;
export default VotingDapp;

View File

@ -1,159 +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 Voting extends Component {
constructor(props) {
super(props);
this.state = {
decision: 0,
finalResult: null,
data: null,
tabulationAvailable: false,
votingAvailable: false
};
}
componentWillReceiveProps(){
__embarkContext.execWhenReady(async () => {
this._loadProposalData();
});
}
async _loadProposalData() {
ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call();
const _votingInfo = await ProposalManager.methods.getVoteInfo(this.props.proposalId, web3.eth.defaultAccount).call();
const _blockNum = await web3.eth.getBlockNumber();
const _data = await ProposalManager.methods.proposals(this.props.proposalId).call();
const _votingAvailable = await ProposalManager.methods.isVotingAvailable(this.props.proposalId).call();
const _tabulationAvailable = await ProposalManager.methods.isTabulationAvailable(this.props.proposalId).call();
const _voteTabulated = await ProposalManager.methods.isDelegatorVoteTabulated(this.props.proposalId, web3.eth.defaultAccount).call();
const _canCalculateFinalResult = await ProposalManager.methods.canCalculateFinalResult(this.props.proposalId).call();
this.setState({
data: _data,
decision: _votingInfo.vote,
block: _blockNum,
finalResult: _data.result,
votingAvailable: _votingAvailable,
tabulationAvailable: _tabulationAvailable,
finalResultAvailable: _canCalculateFinalResult,
voteTabulated: _voteTabulated
});
}
async determineFinalResult(e){
e.preventDefault();
let receipt = await ProposalManager.methods.finalResult(this.props.proposalId)
.send({from: web3.eth.defaultAccount, gasLimit: 1000000});
if(receipt.status == '0x1'){
this.setState({
finalResult: receipt.events.ProposalResult.returnValues.finalResult,
finalResultAvailable: false
});
}
}
async tabulateVote(e){
e.preventDefault();
const receipt = await ProposalManager.methods.tabulateVote(this.props.proposalId, web3.eth.defaultAccount)
.send({from: web3.eth.defaultAccount, gasLimit: 1000000});
// TODO: handle error
this._loadProposalData();
}
async handleClick(e, vote){
e.preventDefault();
let choice = 0;
if(vote == 'APPROVE')
choice = 2;
else
choice = 1;
const proposal = this.props.proposalId;
const receipt = await ProposalManager.methods.voteProposal(this.props.proposalId, choice)
.send({from: web3.eth.defaultAccount});
const _votingAvailable = await ProposalManager.methods.isVotingAvailable(this.props.proposalId).call();
const _tabulationAvailable = await ProposalManager.methods.isTabulationAvailable(this.props.proposalId).call();
const _voteTabulated = await ProposalManager.methods.isDelegatorVoteTabulated(this.props.proposalId, web3.eth.defaultAccount).call();
const _canCalculateFinalResult = await ProposalManager.methods.canCalculateFinalResult(this.props.proposalId).call();
const blockNum = await web3.eth.getBlockNumber();
if(receipt.status == '0x1'){
this.setState({
decision: choice,
block: blockNum,
votingAvailable: _votingAvailable,
tabulationAvailable: _tabulationAvailable,
finalResultAvailable: _canCalculateFinalResult,
voteTabulated: _voteTabulated
});
}
// 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.votingAvailable ?
<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.tabulationAvailable && !this.state.voteTabulated ?
<Button onClick={(e) => this.tabulateVote(e) }>Tabulate your vote</Button>
: ''
}
{
this.state.finalResultAvailable ?
<Button onClick={(e) => this.determineFinalResult(e) }>Determine final result</Button>
: !this.state.tabulationAvailable && !this.state.voteTabulated ?
<p>Final results aren't available yet</p> : ''
}
{ 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

@ -1,3 +0,0 @@
import React from 'react';
export const VotingContext = React.createContext(null);

View File

@ -2,14 +2,8 @@ import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS';
import PollManager from 'Embark/contracts/PollManager';
import AdminView from './components/AdminView';
import Voting from './components/Voting';
import SNT from 'Embark/contracts/SNT';
import { VotingContext } from './context';
import Web3Render from './components/standard/Web3Render';
import fetchIdeas from './utils/fetchIdeas';
import { getPolls, omitPolls } from './utils/polls';
import DrawField from './components/draw/DrawField';
import ContractClient from './contract_client'
window['SNT'] = SNT;

View File

@ -1,30 +0,0 @@
import axios from 'axios';
const repoFilter = (repo) => {
const { path } = repo;
if (path.includes('ideas')) {
const split = path.split('/');
if (split.length < 3) return true;
if (path.includes('README')) return true;
}
return false;
}
const convertToUrl = (repo) => {
const { path } = repo;
const base = 'https://ideas.status.im/';
const suffix = path.split('.md')[0];
return `${base}${suffix}`;
}
const fetchContent = async () => {
const response = await axios.get('https://api.github.com/repos/status-im/ideas/git/trees/master?recursive=1');
return response['data']['tree'].filter(repoFilter).map(convertToUrl);
}
const pluckIdeas = async () => {
const data = await fetchContent();
return data;
}
export default pluckIdeas;

View File

@ -1,42 +0,0 @@
import web3 from "Embark/web3"
import MiniMeTokenInterface from 'Embark/contracts/MiniMeTokenInterface';
import PollManager from 'Embark/contracts/PollManager';
const excluded = {
PROPER_LIGHT_CLIENT_SUPPORT : 3,
IMPLEMENT_SECURITY_PRACTICES : 14,
SHIP_1_0 : 16
};
export const getBalance = async (idPoll, token, startBlock) => {
const { fromWei } = web3.utils;
const { balanceOfAt } = MiniMeTokenInterface.methods;
MiniMeTokenInterface.options.address = token;
const balance = await balanceOfAt(web3.eth.defaultAccount, startBlock - 1).call();
return fromWei(balance);
}
export const getVote = async(idPoll) => {
const { fromWei } = web3.utils;
const votes = await PollManager.methods.getVote(idPoll, web3.eth.defaultAccount).call();
return parseInt(Math.sqrt(fromWei(votes)));
}
const fetchPollData = async (index, pollMethod) => {
const poll = await pollMethod(index).call();
const balance = await getBalance(index, poll._token, poll._startBlock);
const votes = await getVote(index);
return { ...poll, idPoll: index, balance, votes };
}
export const getPolls = (number, pollMethod) => {
const polls = [];
for (let i = number-1; i >= 0; i--) {
polls.push(fetchPollData(i, pollMethod));
}
return Promise.all(polls.reverse());
}
const excludedPolls = new Set(Object.values(excluded));
const exclusionFilter = (poll, idx) => !excludedPolls.has(idx);
export const omitPolls = polls => polls.filter(exclusionFilter);