2018-06-26 16:34:52 -04:00
|
|
|
import React, { Fragment } from 'react';
|
|
|
|
import Card from '@material-ui/core/Card';
|
|
|
|
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';
|
2018-06-28 10:53:33 -04:00
|
|
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
2018-06-26 16:34:52 -04:00
|
|
|
import { withStyles } from '@material-ui/core/styles';
|
|
|
|
import { withFormik } from 'formik';
|
2018-10-15 16:27:22 -04:00
|
|
|
import rlp from 'rlp';
|
2018-06-26 16:34:52 -04:00
|
|
|
|
2018-06-26 17:05:58 -04:00
|
|
|
|
2018-06-26 16:34:52 -04:00
|
|
|
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'
|
2018-06-27 06:46:55 -04:00
|
|
|
},
|
|
|
|
textFieldInput: {
|
|
|
|
fontSize: '16px'
|
|
|
|
},
|
|
|
|
textFieldFormLabel: {
|
|
|
|
fontSize: 18,
|
2018-06-26 16:34:52 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const InnerForm = ({
|
|
|
|
values,
|
|
|
|
errors,
|
|
|
|
touched,
|
|
|
|
handleChange,
|
|
|
|
handleBlur,
|
|
|
|
handleSubmit,
|
|
|
|
isSubmitting,
|
|
|
|
classes
|
|
|
|
}) => (
|
|
|
|
<Card>
|
|
|
|
<CardContent>
|
|
|
|
<form onSubmit={handleSubmit} className={classes.form}>
|
|
|
|
<TextField
|
2018-09-25 15:24:34 -04:00
|
|
|
id="title"
|
|
|
|
label="Enter your proposal title"
|
2018-06-26 16:34:52 -04:00
|
|
|
className={classes.textField}
|
2018-09-25 15:24:34 -04:00
|
|
|
value={values.title}
|
2018-06-26 16:34:52 -04:00
|
|
|
onChange={handleChange}
|
|
|
|
margin="normal"
|
|
|
|
fullWidth
|
2018-09-25 15:24:34 -04:00
|
|
|
error={!!errors.title}
|
2018-06-27 06:46:55 -04:00
|
|
|
InputProps={{
|
|
|
|
classes: {
|
|
|
|
input: classes.textFieldInput
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
InputLabelProps={{
|
|
|
|
className: classes.textFieldFormLabel
|
|
|
|
}}
|
2018-09-25 15:24:34 -04:00
|
|
|
helperText={errors.title}
|
2018-06-26 16:34:52 -04:00
|
|
|
/>
|
2018-09-25 15:24:34 -04:00
|
|
|
|
|
|
|
<TextField
|
|
|
|
id="ballots"
|
2018-10-15 16:08:11 -04:00
|
|
|
label="Enter the ballots array ([{"title":"", "subtitle":"", "content":""}]) (optional)"
|
2018-09-25 15:24:34 -04:00
|
|
|
className={classes.textField}
|
|
|
|
value={values.ballots}
|
|
|
|
onChange={handleChange}
|
|
|
|
margin="normal"
|
|
|
|
fullWidth
|
2018-10-15 16:08:11 -04:00
|
|
|
multiline={true}
|
|
|
|
rows={10}
|
2018-09-25 15:24:34 -04:00
|
|
|
error={!!errors.ballots}
|
|
|
|
InputProps={{
|
|
|
|
classes: {
|
|
|
|
input: classes.textFieldInput
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
InputLabelProps={{
|
|
|
|
className: classes.textFieldFormLabel
|
|
|
|
}}
|
|
|
|
helperText={errors.ballots}
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
2018-09-27 09:48:24 -04:00
|
|
|
<TextField
|
|
|
|
id="startBlock"
|
|
|
|
label="Start Block (optional)"
|
|
|
|
className={classes.textField}
|
|
|
|
value={values.startBlock}
|
|
|
|
onChange={handleChange}
|
|
|
|
margin="normal"
|
|
|
|
fullWidth
|
|
|
|
error={!!errors.startBlock}
|
|
|
|
InputProps={{
|
|
|
|
classes: {
|
|
|
|
input: classes.textFieldInput
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
InputLabelProps={{
|
|
|
|
className: classes.textFieldFormLabel
|
|
|
|
}}
|
|
|
|
helperText={errors.startBlock}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<TextField
|
2018-10-15 16:27:22 -04:00
|
|
|
id="endTime"
|
|
|
|
label="End Time (optional)"
|
2018-09-27 09:48:24 -04:00
|
|
|
className={classes.textField}
|
2018-10-15 16:27:22 -04:00
|
|
|
value={values.endTime}
|
2018-09-27 09:48:24 -04:00
|
|
|
onChange={handleChange}
|
|
|
|
margin="normal"
|
|
|
|
fullWidth
|
2018-10-15 16:27:22 -04:00
|
|
|
error={!!errors.endTime}
|
2018-09-27 09:48:24 -04:00
|
|
|
InputProps={{
|
|
|
|
classes: {
|
|
|
|
input: classes.textFieldInput
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
InputLabelProps={{
|
|
|
|
className: classes.textFieldFormLabel
|
|
|
|
}}
|
2018-10-15 16:27:22 -04:00
|
|
|
helperText={errors.endTime}
|
2018-09-27 09:48:24 -04:00
|
|
|
/>
|
|
|
|
|
|
|
|
|
2018-06-27 15:34:06 -04:00
|
|
|
{!isSubmitting ?
|
|
|
|
<Button type="submit" variant="extendedFab" aria-label="add" className={classes.button}>Submit</Button> :
|
2018-06-28 10:53:33 -04:00
|
|
|
<CircularProgress style={{ margin: '10px 10px 10px 50%' }} />
|
2018-06-27 15:34:06 -04:00
|
|
|
}
|
2018-06-26 16:34:52 -04:00
|
|
|
</form>
|
|
|
|
</CardContent>
|
|
|
|
</Card>
|
|
|
|
)
|
|
|
|
|
|
|
|
const StyledForm = withStyles(styles)(InnerForm);
|
|
|
|
const AddPoll = withFormik({
|
2018-10-15 16:27:22 -04:00
|
|
|
mapPropsToValues: props => ({ title: '', ballots: '', startBlock: '', endTime: ''}),
|
2018-06-27 15:00:50 -04:00
|
|
|
validate(values, props){
|
2018-09-25 15:24:34 -04:00
|
|
|
|
2018-09-27 09:48:24 -04:00
|
|
|
|
|
|
|
return web3.eth.getBlockNumber()
|
|
|
|
.then(currentBlock => {
|
|
|
|
const errors = {};
|
2018-10-15 16:27:22 -04:00
|
|
|
const { title, ballots, startBlock, endTime } = values;
|
2018-10-15 16:08:11 -04:00
|
|
|
|
2018-09-27 09:48:24 -04:00
|
|
|
if(title.toString().trim() === "") {
|
|
|
|
errors.title = "Required";
|
|
|
|
}
|
2018-10-15 16:08:11 -04:00
|
|
|
|
|
|
|
let ballotOptions;
|
|
|
|
try {
|
|
|
|
ballotOptions = JSON.parse(ballots);
|
|
|
|
|
|
|
|
if(!Array.isArray(ballotOptions)){
|
|
|
|
errors.ballots = "JSON must be an array of objects";
|
|
|
|
} else if(ballotOptions.length == 1) {
|
|
|
|
errors.ballots = "A minimum of 2 options is required if using multiple options";
|
|
|
|
} else {
|
|
|
|
const validOptions = ['title', 'subtitle', 'content'];
|
|
|
|
|
|
|
|
for(let i = 0; i < ballotOptions.length; i++){
|
|
|
|
if(!ballotOptions[i].title){
|
|
|
|
errors.ballots = "Option " + (i+1) + " is missing a title";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const userOptions = Object.keys(ballotOptions[i]);
|
|
|
|
if(userOptions.filter(o1 => validOptions.filter(o2 => o2 === o1).length === 0).length > 0){
|
|
|
|
errors.ballots = "Only 'title', 'subtitle', and 'content' are allowed in option " + (i+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch(err){
|
|
|
|
if(ballots.trim() !== "")
|
|
|
|
errors.ballots = "Invalid JSON";
|
2018-09-27 09:48:24 -04:00
|
|
|
}
|
2018-10-15 16:08:11 -04:00
|
|
|
|
2018-09-27 09:48:24 -04:00
|
|
|
let sBlock;
|
|
|
|
if(startBlock != ""){
|
|
|
|
var parsed = parseInt(startBlock, 10);
|
|
|
|
if (isNaN(parsed)) {
|
|
|
|
errors.startBlock = "Invalid Start Block"
|
|
|
|
} else {
|
|
|
|
sBlock = parsed;
|
|
|
|
|
|
|
|
if(sBlock < currentBlock){
|
|
|
|
errors.startBlock = "Block number is in the past. Recommended: " + (currentBlock + 60) + " (will be mined in ~10min)"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let eBlock;
|
2018-10-15 16:27:22 -04:00
|
|
|
if(endTime != ""){
|
|
|
|
var parsed = parseInt(endTime, 10);
|
2018-09-27 09:48:24 -04:00
|
|
|
if (isNaN(parsed)) {
|
2018-10-15 16:27:22 -04:00
|
|
|
errors.endTime = "Invalid End Time"
|
2018-09-27 09:48:24 -04:00
|
|
|
} else {
|
|
|
|
eBlock = parsed;
|
|
|
|
}
|
|
|
|
|
2018-10-15 16:27:22 -04:00
|
|
|
if(eBlock < ((new Date()).getTime() / 1000)){
|
|
|
|
errors.endTime = "End time must occur in the future"
|
2018-09-27 09:48:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Object.keys(errors).length) {
|
|
|
|
throw errors;
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
2018-06-26 16:34:52 -04:00
|
|
|
},
|
2018-09-25 15:24:34 -04:00
|
|
|
|
2018-09-26 13:44:16 -04:00
|
|
|
async handleSubmit(values, { setSubmitting, setErrors, props, resetForm }) {
|
2018-10-15 16:27:22 -04:00
|
|
|
const { title, ballots, startBlock, endTime } = values;
|
2018-10-15 16:08:11 -04:00
|
|
|
const { eth: { getBlockNumber }, utils: { toHex } } = window.web3;
|
2018-09-27 09:48:24 -04:00
|
|
|
|
|
|
|
const addPollCustomBlock = PollManager.methods["addPoll(uint256,uint256,bytes,uint8)"];
|
2018-10-15 16:27:22 -04:00
|
|
|
const addPollOnlyEndTime = PollManager.methods["addPoll(uint256,bytes,uint8)"];
|
2018-09-27 09:48:24 -04:00
|
|
|
|
2018-10-15 16:27:22 -04:00
|
|
|
let date = new Date();
|
|
|
|
const d90 = date.setDate(date.getDate() + 90).getTime() / 1000;
|
|
|
|
|
|
|
|
const endTime = endTime ? endTime : d90;
|
2018-10-15 16:08:11 -04:00
|
|
|
const options = JSON.parse(ballots);
|
|
|
|
const ipfsHash = await EmbarkJS.Storage.saveText(ballots);
|
2018-10-15 16:27:22 -04:00
|
|
|
const encodedDesc = "0x" + rlp.encode([title, ipfsHash]).toString('hex');
|
2018-09-27 09:48:24 -04:00
|
|
|
|
|
|
|
let toSend;
|
|
|
|
if(startBlock){
|
2018-10-15 16:27:22 -04:00
|
|
|
toSend = addPollCustomBlock(startBlock, endTime, encodedDesc, options.length || 0);
|
2018-09-27 09:48:24 -04:00
|
|
|
} else {
|
2018-10-15 16:27:22 -04:00
|
|
|
toSend = addPollOnlyEndTime(endTime, encodedDesc, options.length || 0);
|
2018-09-27 09:48:24 -04:00
|
|
|
}
|
2018-06-27 15:10:16 -04:00
|
|
|
setSubmitting(true);
|
|
|
|
|
2018-09-27 19:37:13 -04:00
|
|
|
try {
|
|
|
|
const gasEstimated = await toSend.estimateGas();
|
|
|
|
console.log("addPoll gas estimated: "+ gasEstimated);
|
|
|
|
const res = await toSend.send({gas: gasEstimated + 100000});
|
|
|
|
console.log('sucess:', res);
|
|
|
|
resetForm();
|
|
|
|
props.getPolls();
|
|
|
|
setSubmitting(false);
|
|
|
|
props.togglePoll();
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
console.log('fail:', err);
|
|
|
|
setErrors({ 'description': err.message.split('Error:').pop().trim() });
|
|
|
|
}
|
|
|
|
|
|
|
|
setSubmitting(false);
|
2018-06-26 16:34:52 -04:00
|
|
|
}
|
|
|
|
})(StyledForm)
|
|
|
|
|
|
|
|
export default AddPoll;
|