405 lines
12 KiB
React
Raw Normal View History

2019-04-03 15:46:09 -04:00
import React, { createRef, useState, useContext } from 'react'
2019-04-01 15:59:38 -04:00
import { Formik } from 'formik'
2019-04-03 15:46:09 -04:00
import LiquidPledging from 'Embark/contracts/LiquidPledging'
2019-04-01 15:59:38 -04:00
import TextField from '@material-ui/core/TextField'
import Divider from '@material-ui/core/Divider'
2019-04-01 15:59:38 -04:00
import FormControlLabel from '@material-ui/core/FormControlLabel'
import Switch from '@material-ui/core/Switch'
import Button from '@material-ui/core/Button'
2019-04-02 15:10:20 -04:00
import InputAdornment from '@material-ui/core/InputAdornment'
import CloudUpload from '@material-ui/icons/CloudUpload'
import { withStyles } from '@material-ui/core/styles'
2019-04-04 12:49:09 -04:00
import { formatForIpfs, uploadToIpfs, formatMedia, isWeb } from '../../utils/ipfs'
2019-04-03 15:46:09 -04:00
import { FundingContext } from '../../context'
const { addProject } = LiquidPledging.methods
const hoursToSeconds = hours => hours * 60 * 60
const helperText = 'The length of time the Project has to veto when the project delegates to another delegate and they pledge those funds to a project'
const styles = theme => ({
root: {
display: 'grid',
gridTemplateColumns: 'repeat(12, [col] 1fr)',
gridTemplateRows: 'repeat(5, [row] auto)',
gridColumnGap: '1em',
2019-04-01 15:59:38 -04:00
gridRowGap: '3ch',
fontFamily: theme.typography.fontFamily,
[theme.breakpoints.up('sm')]: {
margin: '1.75rem 4.5rem'
}
},
title: {
display: 'grid',
fontSize: '2.5rem',
gridColumnStart: '1',
gridColumnEnd: '13',
gridRowStart: '1',
gridRowEnd: '6',
textAlign: 'center'
},
submissionRoot: {
2019-04-01 15:59:38 -04:00
display: 'grid',
gridTemplateColumns: 'repeat(12, [col] 1fr)',
gridTemplateRows: 'repeat(5, [row] auto)',
gridColumnGap: '1em',
gridColumnStart: '1',
2019-04-01 15:59:38 -04:00
gridColumnEnd: '13',
gridRowGap: '2ch',
},
formControl: {
gridColumnStart: '6'
},
formButton: {
gridColumnStart: '1',
gridColumnEnd: '13',
height: '50px'
},
textField: {
2019-04-01 15:59:38 -04:00
gridColumnStart: '1',
gridColumnEnd: '13'
},
textInput: {
fontSize: '2rem'
}
})
2019-04-04 12:49:09 -04:00
2019-04-02 13:48:05 -04:00
const createJSON = values => {
const {
title,
subtitle,
creator,
avatar,
goal,
goalToken,
video,
isPlaying,
description
} = values
const manifest = {
title,
subtitle,
creator,
2019-04-03 15:46:09 -04:00
avatar: formatMedia(avatar),
2019-04-02 13:48:05 -04:00
goal,
goalToken,
description,
media: {
isPlaying,
type: 'video'
}
}
2019-04-04 10:53:28 -04:00
if (isWeb(video)) Object.assign(manifest.media, { url: formatMedia(video) })
else Object.assign(manifest.media, { file: formatMedia(video) })
2019-04-03 14:57:50 -04:00
return JSON.stringify(manifest, null, 2)
2019-04-02 13:48:05 -04:00
}
const Title = ({ className }) => (
<div className={className}>
<div style={{ alignSelf: 'center' }}>Create Project</div>
<Divider />
</div>
)
2019-04-02 15:10:20 -04:00
let uploadInput = createRef()
const getProjectId = response => {
const { events: { ProjectAdded: { returnValues: { idProject } } } } = response
return idProject
}
2019-04-03 15:46:09 -04:00
const addProjectSucessMsg = response => {
const { events: { ProjectAdded: { returnValues: { idProject } } } } = response
return `Project created with ID of ${idProject}, will redirect to your new project page in a few seconds`
2019-04-03 15:46:09 -04:00
}
const SubmissionSection = ({ classes, history }) => {
2019-04-03 14:57:50 -04:00
const [uploads, setUploads] = useState({})
2019-04-03 15:46:09 -04:00
const { account, openSnackBar } = useContext(FundingContext)
2019-04-01 15:59:38 -04:00
return (
<Formik
2019-04-02 13:48:05 -04:00
initialValues={{
title: '',
subtitle: '',
creator: '',
avatar: '',
goal: '',
goalToken: '',
video: '',
isPlaying: true,
2019-04-03 15:46:09 -04:00
description: '',
commitTime: 24
2019-04-02 13:48:05 -04:00
}}
onSubmit={async (values, { resetForm }) => {
2019-04-03 15:46:09 -04:00
const { title, commitTime } = values
2019-04-02 13:48:05 -04:00
const manifest = createJSON(values)
2019-04-03 14:57:50 -04:00
let fileLists = []
Object.keys(uploads).forEach(k => {
fileLists = [ ...fileLists, formatForIpfs(uploads[k][0]) ]
})
fileLists.push({
path: '/root/manifest.json', content: Buffer.from(manifest)
})
const contentHash = await uploadToIpfs(fileLists)
2019-04-03 15:46:09 -04:00
const args = [title, contentHash, account, 0, hoursToSeconds(commitTime), 0]
addProject(...args)
.estimateGas({ from: account })
.then(async gas => {
addProject(...args)
.send({ from: account, gas: gas + 100 })
.then(res => {
console.log({res})
openSnackBar('success', addProjectSucessMsg(res))
setTimeout(() => {
history.push(`/project/${getProjectId(res)}`)
resetForm()
}, 5000)
2019-04-03 15:46:09 -04:00
})
.catch(e => openSnackBar('error', e))
})
2019-04-03 14:57:50 -04:00
console.log({manifest, values, uploads, fileLists, contentHash})
2019-04-02 13:48:05 -04:00
}}
2019-04-01 15:59:38 -04:00
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
setFieldValue,
setStatus,
status,
isSubmitting
2019-04-01 15:59:38 -04:00
}) => {
return (
<form onSubmit={handleSubmit} className={classes.submissionRoot}>
2019-04-02 15:10:20 -04:00
<input
ref={(input) => { uploadInput = input }}
type="file"
multiple
onChange={
(e) => {
const file = e.target.files
const { activeField } = status
setFieldValue(activeField, file[0]['name'])
2019-04-03 14:57:50 -04:00
setUploads({ ...uploads, [activeField]: file })
2019-04-02 15:10:20 -04:00
setStatus({
...status,
2019-04-03 14:57:50 -04:00
activeField: null
2019-04-02 15:10:20 -04:00
})
}
}
style={{ display: 'none' }}
/>
2019-04-01 15:59:38 -04:00
<TextField
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
2019-04-02 13:48:05 -04:00
id="title"
name="title"
2019-04-01 15:59:38 -04:00
label="Enter Project Name"
placeholder="Enter Project Name"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
2019-04-02 13:48:05 -04:00
value={values.title || ''}
2019-04-01 15:59:38 -04:00
/>
2019-04-03 15:46:09 -04:00
<TextField
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
2019-04-04 10:53:28 -04:00
id="subtitle"
name="subtitle"
label="Enter a sub heading description for your project"
placeholder="Enter a sub heading description for your project"
2019-04-03 15:46:09 -04:00
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
2019-04-04 10:53:28 -04:00
value={values.subtitle || ''}
2019-04-03 15:46:09 -04:00
/>
2019-04-01 15:59:38 -04:00
<TextField
2019-04-04 10:53:28 -04:00
id="commitTime"
name="commitTime"
2019-04-01 15:59:38 -04:00
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
2019-04-04 10:53:28 -04:00
label="Commit time in hours"
placeholder="Commit time in hours"
2019-04-01 15:59:38 -04:00
margin="normal"
variant="outlined"
2019-04-04 10:53:28 -04:00
helperText={helperText}
2019-04-01 15:59:38 -04:00
onChange={handleChange}
onBlur={handleBlur}
2019-04-04 10:53:28 -04:00
value={values.commitTime || ''}
2019-04-01 15:59:38 -04:00
/>
<TextField
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
id="creator"
name="creator"
label="Enter the project creator"
placeholder="Enter the project creator"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.creator || ''}
/>
<TextField
className={classes.textField}
InputProps={{
2019-04-02 15:10:20 -04:00
startAdornment: (
<InputAdornment position="start">
<CloudUpload
style={{ cursor: 'pointer' }}
onClick={() => {
const activeField = 'avatar'
setStatus({ ...status, activeField })
uploadInput.click()
}
}
/>
</InputAdornment>
),
2019-04-01 15:59:38 -04:00
classes: {
input: classes.textInput
}
}}
id="avatar"
name="avatar"
label="Upload or enter link to creator avatar"
placeholder="upload or enter link to creator avatar"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.avatar || ''}
/>
<TextField
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
id="goal"
name="goal"
label="Enter your funding goal"
placeholder="Enter your funding goal"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.goal || ''}
/>
<TextField
className={classes.textField}
InputProps={{
classes: {
input: classes.textInput
}
}}
id="goalToken"
name="goalToken"
label="Select Token"
placeholder="Select Token"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.token || ''}
/>
<TextField
className={classes.textField}
InputProps={{
2019-04-03 14:57:50 -04:00
startAdornment: (
<InputAdornment position="start">
<CloudUpload
style={{ cursor: 'pointer' }}
onClick={() => {
const activeField = 'video'
setStatus({ ...status, activeField })
uploadInput.click()
}
}
/>
</InputAdornment>
),
2019-04-01 15:59:38 -04:00
classes: {
input: classes.textInput
}
}}
id="video"
name="video"
label="Upload video or enter url"
placeholder="Upload video or enter url"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.video || ''}
/>
<FormControlLabel
className={classes.formControl}
control={
<Switch
2019-04-02 13:48:05 -04:00
id="isPlaying"
2019-04-02 15:10:20 -04:00
checked={values.isPlaying}
onChange={handleChange}
value={values.isPlaying}
2019-04-01 15:59:38 -04:00
/>
}
label="Autoplay video?"
/>
<TextField
className={classes.textField}
id="description"
name="description"
multiline
label="Enter extended description here"
placeholder="Enter extended description here"
margin="normal"
variant="outlined"
onChange={handleChange}
onBlur={handleBlur}
value={values.description || ''}
/>
2019-04-04 12:49:09 -04:00
<Button type="submit" color="primary" variant="contained" className={classes.formButton}>{isSubmitting ? 'Ethereum Submission In Progress' : 'Create Project'}</Button>
2019-04-01 15:59:38 -04:00
</form>
)
}
}
</Formik>
)
}
function CreateProject({ classes, history }) {
return (
<div className={classes.root}>
<Title className={classes.title} />
<SubmissionSection classes={classes} history={history} />
</div>
)
}
const StyledProject = withStyles(styles)(CreateProject)
export default StyledProject