mirror of https://gitlab.com/ecentrics/concordia
Apostolos Fanakis
7 years ago
7 changed files with 320 additions and 226 deletions
@ -1,200 +0,0 @@ |
|||
import { drizzleConnect } from 'drizzle-react' |
|||
import React, { Component } from 'react' |
|||
import PropTypes from 'prop-types' |
|||
|
|||
import Post from './Post' |
|||
|
|||
const contract = "Forum"; |
|||
const contractMethod = "createTopic"; |
|||
|
|||
class StartTopic extends Component { |
|||
constructor(props, context) { |
|||
super(props); |
|||
|
|||
this.handleInputChange = this.handleInputChange.bind(this); |
|||
this.handlePreviewToggle = this.handlePreviewToggle.bind(this); |
|||
this.validateAndPost = this.validateAndPost.bind(this); |
|||
this.pushToDatabase = this.pushToDatabase.bind(this); |
|||
|
|||
this.transactionProgressText = []; |
|||
this.drizzle = context.drizzle; |
|||
|
|||
this.state = { |
|||
topicSubjectInput: '', |
|||
topicMessageInput: '', |
|||
topicSubjectInputEmptySubmit: false, |
|||
topicMessageInputEmptySubmit: false, |
|||
previewEnabled: false, |
|||
previewDate: "", |
|||
creatingTopic: false, |
|||
transactionState: null, |
|||
savingToOrbitDB: null |
|||
}; |
|||
} |
|||
|
|||
async validateAndPost() { |
|||
if (this.state.topicSubjectInput === '' || this.state.topicMessageInput === ''){ |
|||
this.setState({ |
|||
topicSubjectInputEmptySubmit: this.state.topicSubjectInput === '', |
|||
topicMessageInputEmptySubmit: this.state.topicMessageInput === '' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
this.stackId = this.drizzle.contracts[contract].methods[contractMethod].cacheSend(); |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("Waiting for transaction acceptance..."); |
|||
this.setState({ |
|||
'creatingTopic': true, |
|||
'transactionState': "ACCEPTANCE_PENDING" |
|||
}); |
|||
} |
|||
|
|||
async pushToDatabase() { |
|||
await this.props.orbitDB.topicsDB.put(this.topicIDFetched, { |
|||
subject: this.state.topicSubjectInput, |
|||
content: this.state.topicMessageInput |
|||
}); |
|||
this.setState({'savingToOrbitDB': "SUCCESS"}); |
|||
} |
|||
|
|||
handleInputChange(event) { |
|||
this.setState({[event.target.name]: event.target.value}); |
|||
} |
|||
|
|||
handlePreviewToggle() { |
|||
this.setState((prevState, props) => ({ |
|||
previewEnabled: !prevState.previewEnabled, |
|||
previewDate: this.getDate() |
|||
})); |
|||
} |
|||
|
|||
getDate() { |
|||
const currentdate = new Date(); |
|||
return ((currentdate.getMonth() + 1) + " " |
|||
+ currentdate.getDate() + ", " |
|||
+ currentdate.getFullYear() + ", " |
|||
+ currentdate.getHours() + ":" |
|||
+ currentdate.getMinutes() + ":" |
|||
+ currentdate.getSeconds()); |
|||
} |
|||
|
|||
render() { |
|||
return( |
|||
<div> |
|||
{this.state.creatingTopic && <div id="overlay"> |
|||
<div id="overlay-content"> |
|||
<p><i className="fas fa-spinner fa-3x fa-spin"></i></p> |
|||
<br/> |
|||
{this.transactionProgressText} |
|||
</div> |
|||
</div> |
|||
} |
|||
<div className="pure-u-1-1 start-topic-back-button"> |
|||
<p className="no-margin" onClick={this.props.onClick}> |
|||
<i className="fas fa-arrow-left fa-3x"></i> |
|||
</p> |
|||
</div> |
|||
{this.state.previewEnabled && |
|||
<Post avatarUrl={this.props.user.avatarUrl} |
|||
username={this.props.user.username} |
|||
subject={this.state.topicSubjectInput} |
|||
date={this.state.previewDate} |
|||
postContent={this.state.topicMessageInput} |
|||
id={0}/>} |
|||
<form className="topic-form"> |
|||
{!this.state.previewEnabled && |
|||
[ |
|||
<input key={"topicSubjectInput"} |
|||
name={"topicSubjectInput"} |
|||
className={this.state.topicSubjectInputEmptySubmit && "form-input-required"} |
|||
type="text" |
|||
value={this.state.topicSubjectInput} |
|||
placeholder="Subject" |
|||
id="topicSubjectInput" |
|||
onChange={this.handleInputChange} />, |
|||
<textarea key={"topicMessageInput"} |
|||
name={"topicMessageInput"} |
|||
className={this.state.topicMessageInputEmptySubmit && "form-input-required"} |
|||
value={this.state.topicMessageInput} |
|||
placeholder="Post" |
|||
id="topicMessageInput" |
|||
onChange={this.handleInputChange} /> |
|||
]} |
|||
<button key="submit" |
|||
className="pure-button" |
|||
type="button" |
|||
onClick={this.validateAndPost}> |
|||
Post |
|||
</button> |
|||
<button className="pure-button margin-left-small" |
|||
type="button" |
|||
onClick={this.handlePreviewToggle}> |
|||
{this.state.previewEnabled ? "Edit" : "Preview"} |
|||
</button> |
|||
</form> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
componentWillReceiveProps(){ //Maybe change it with this: https://redux.js.org/api-reference/store#subscribe
|
|||
let currentDrizzleState = this.drizzle.store.getState(); |
|||
|
|||
if(this.state.creatingTopic){ |
|||
if (this.state.transactionState === "ACCEPTANCE_PENDING" && |
|||
currentDrizzleState.transactionStack[this.stackId]) { |
|||
|
|||
this.txHash = currentDrizzleState.transactionStack[this.stackId]; |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("Transaction in progress: txHash = " + this.txHash); |
|||
this.setState({'transactionState': "IN_PROGRESS"}); |
|||
} else if (this.state.transactionState === "IN_PROGRESS") { |
|||
if (currentDrizzleState.transactions[this.txHash].status === "success"){ |
|||
this.topicIDFetched = currentDrizzleState.transactions[this.txHash].receipt |
|||
.events.TopicCreated.returnValues.topicID; |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("Transaction completed successfully."); |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("TopicID = " + this.topicIDFetched); |
|||
this.setState({'transactionState': "SUCCESS"}); |
|||
} else if (currentDrizzleState.transactions[this.txHash].status === "error"){ |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("Transaction failed to complete."); |
|||
this.setState({'transactionState': "ERROR"}); |
|||
} |
|||
} else if (this.state.transactionState === "SUCCESS") { |
|||
this.pushToDatabase(); |
|||
if (this.state.savingToOrbitDB === "SUCCESS"){ |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push("Post successfully saved in OrbitDB."); |
|||
this.setState({creatingTopic: false}); |
|||
} else if (this.state.savingToOrbitDB === "ERROR"){ |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push(<span style={{color: 'red'}}><strong> |
|||
An error occurred while trying to save post in OrbitDB. |
|||
</strong></span>); |
|||
this.setState({creatingTopic: false}); |
|||
} |
|||
} else if (this.state.transactionState === "ERROR"){ |
|||
this.transactionProgressText.push(<br/>); |
|||
this.transactionProgressText.push(<span style={{color: 'red'}}><strong> |
|||
An error occurred while trying to complete transaction. |
|||
</strong></span>); |
|||
this.setState({creatingTopic: false}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
StartTopic.contextTypes = { |
|||
drizzle: PropTypes.object |
|||
}; |
|||
|
|||
const mapStateToProps = state => { |
|||
return { |
|||
orbitDB: state.orbitDB, |
|||
user: state.user |
|||
} |
|||
}; |
|||
|
|||
export default drizzleConnect(StartTopic, mapStateToProps); |
@ -0,0 +1,297 @@ |
|||
import { drizzleConnect } from 'drizzle-react'; |
|||
import React, { Component } from 'react'; |
|||
import PropTypes from 'prop-types'; |
|||
import uuidv4 from 'uuid/v4'; |
|||
|
|||
import Post from '../components/Post' |
|||
|
|||
const contract = "Forum"; |
|||
const contractMethod = "createTopic"; |
|||
|
|||
class StartTopic extends Component { |
|||
constructor(props, context) { |
|||
super(props); |
|||
|
|||
this.handleInputChange = this.handleInputChange.bind(this); |
|||
this.handlePreviewToggle = this.handlePreviewToggle.bind(this); |
|||
this.validateAndPost = this.validateAndPost.bind(this); |
|||
this.pushToDatabase = this.pushToDatabase.bind(this); |
|||
|
|||
this.transactionProgressText = []; |
|||
this.drizzle = context.drizzle; |
|||
|
|||
this.state = { |
|||
topicSubjectInput: '', |
|||
topicMessageInput: '', |
|||
topicSubjectInputEmptySubmit: false, |
|||
topicMessageInputEmptySubmit: false, |
|||
previewEnabled: false, |
|||
previewDate: "", |
|||
creatingTopic: false, |
|||
transactionState: null, |
|||
savingToOrbitDB: null, |
|||
transactionOutputTimerActive: false |
|||
}; |
|||
} |
|||
|
|||
async validateAndPost() { |
|||
if (this.state.topicSubjectInput === '' || this.state.topicMessageInput === ''){ |
|||
this.setState({ |
|||
topicSubjectInputEmptySubmit: this.state.topicSubjectInput === '', |
|||
topicMessageInputEmptySubmit: this.state.topicMessageInput === '' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
this.stackId = this.drizzle.contracts[contract].methods[contractMethod].cacheSend(); |
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push("Waiting for transaction acceptance..."); |
|||
this.setState({ |
|||
'creatingTopic': true, |
|||
'transactionState': "ACCEPTANCE_PENDING" |
|||
}); |
|||
} |
|||
|
|||
async pushToDatabase() { |
|||
await this.props.orbitDB.topicsDB.put(this.topicIDFetched, { |
|||
subject: this.state.topicSubjectInput, |
|||
content: this.state.topicMessageInput |
|||
}); |
|||
this.setState({'savingToOrbitDB': "SUCCESS"}); |
|||
} |
|||
|
|||
handleInputChange(event) { |
|||
this.setState({[event.target.name]: event.target.value}); |
|||
} |
|||
|
|||
handlePreviewToggle() { |
|||
this.setState((prevState, props) => ({ |
|||
previewEnabled: !prevState.previewEnabled, |
|||
previewDate: this.getDate() |
|||
})); |
|||
} |
|||
|
|||
getDate() { |
|||
const currentdate = new Date(); |
|||
return ((currentdate.getMonth() + 1) + " " |
|||
+ currentdate.getDate() + ", " |
|||
+ currentdate.getFullYear() + ", " |
|||
+ currentdate.getHours() + ":" |
|||
+ currentdate.getMinutes() + ":" |
|||
+ currentdate.getSeconds()); |
|||
} |
|||
|
|||
render() { |
|||
return( |
|||
<div> |
|||
{this.state.creatingTopic && <div id="overlay"> |
|||
<div id="overlay-content"> |
|||
<p><i className="fas fa-spinner fa-3x fa-spin"></i></p> |
|||
<br/> |
|||
{this.transactionProgressText} |
|||
</div> |
|||
</div> |
|||
} |
|||
{this.state.previewEnabled && |
|||
<Post avatarUrl={this.props.user.avatarUrl} |
|||
username={this.props.user.username} |
|||
subject={this.state.topicSubjectInput} |
|||
date={this.state.previewDate} |
|||
postContent={this.state.topicMessageInput} |
|||
id={0}/>} |
|||
<form className="topic-form"> |
|||
{!this.state.previewEnabled && |
|||
[ |
|||
<input key={"topicSubjectInput"} |
|||
name={"topicSubjectInput"} |
|||
className={this.state.topicSubjectInputEmptySubmit ? "form-input-required" : ""} |
|||
type="text" |
|||
value={this.state.topicSubjectInput} |
|||
placeholder="Subject" |
|||
id="topicSubjectInput" |
|||
onChange={this.handleInputChange} />, |
|||
<textarea key={"topicMessageInput"} |
|||
name={"topicMessageInput"} |
|||
className={this.state.topicMessageInputEmptySubmit ? "form-input-required" : ""} |
|||
value={this.state.topicMessageInput} |
|||
placeholder="Post" |
|||
id="topicMessageInput" |
|||
onChange={this.handleInputChange} /> |
|||
]} |
|||
<button key="submit" |
|||
className="pure-button" |
|||
type="button" |
|||
onClick={this.validateAndPost}> |
|||
Post |
|||
</button> |
|||
<button className="pure-button margin-left-small" |
|||
type="button" |
|||
onClick={this.handlePreviewToggle}> |
|||
{this.state.previewEnabled ? "Edit" : "Preview"} |
|||
</button> |
|||
</form> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
componentWillReceiveProps(){ |
|||
if(this.state.creatingTopic && !this.state.transactionOutputTimerActive){ |
|||
/* User submitted a new Topic */ |
|||
|
|||
if (this.state.transactionState === "ACCEPTANCE_PENDING" && |
|||
this.props.transactionStack[this.stackId]) { |
|||
/* User confirmed the transaction */ |
|||
|
|||
//Gets transaciton's hash
|
|||
this.txHash = this.props.transactionStack[this.stackId]; |
|||
|
|||
//Updates output and state
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push("Transaction in progress: txHash = " + this.txHash); |
|||
this.setState({'transactionState': "IN_PROGRESS"}); |
|||
} |
|||
else if (this.state.transactionState === "IN_PROGRESS") { |
|||
if (this.props.transactions[this.txHash].status === "success"){ |
|||
/* Transaction completed successfully */ |
|||
|
|||
//Gets topic's id returned by contract
|
|||
this.topicIDFetched = this.props.transactions[this.txHash].receipt |
|||
.events.TopicCreated.returnValues.topicID; |
|||
|
|||
//Updates output and state
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'green'}}> |
|||
<strong> |
|||
Transaction completed successfully. |
|||
</strong> |
|||
</span>); |
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'green'}}> |
|||
<strong> |
|||
TopicID = {this.topicIDFetched} |
|||
</strong> |
|||
</span>); |
|||
this.setState({'transactionState': "SUCCESS"}); |
|||
} else if (this.props.transactions[this.txHash].status === "error"){ |
|||
/* Transaction failed to complete */ |
|||
|
|||
//Updates output and state
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'red'}}> |
|||
<strong> |
|||
Transaction failed to complete with error: |
|||
</strong> |
|||
</span>); |
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'red'}}> |
|||
<strong> |
|||
{this.props.transactions[this.txHash].error} |
|||
</strong> |
|||
</span>); |
|||
this.setState({ |
|||
'transactionState': "ERROR", |
|||
'transactionOutputTimerActive': true |
|||
}); |
|||
this.transactionOutputTimer = setTimeout(() => { |
|||
this.transactionProgressText = []; |
|||
this.setState({ |
|||
'creatingTopic': false, |
|||
'transactionState': null, |
|||
'savingToOrbitDB': null, |
|||
'transactionOutputTimerActive': false |
|||
}); |
|||
}, 5000); |
|||
} |
|||
} |
|||
else if (this.state.transactionState === "SUCCESS") { |
|||
/* Transaction completed successfully */ |
|||
|
|||
//Tries to store data in OrbitDB
|
|||
this.pushToDatabase(); |
|||
if (this.state.savingToOrbitDB === "SUCCESS"){ |
|||
/* Data successfully saved in OrbitDB */ |
|||
|
|||
//Updates output and state
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'green'}}> |
|||
<strong> |
|||
Post successfully saved in OrbitDB. |
|||
</strong> |
|||
</span>); |
|||
this.setState({'transactionOutputTimerActive': true}); |
|||
this.transactionOutputTimer = setTimeout(() => { |
|||
this.transactionProgressText = []; |
|||
this.setState({ |
|||
'creatingTopic': false, |
|||
'transactionState': null, |
|||
'savingToOrbitDB': null, |
|||
'transactionOutputTimerActive': false |
|||
}); |
|||
}, 5000); |
|||
} |
|||
else if (this.state.savingToOrbitDB === "ERROR"){ |
|||
/* Failed to save data in OrbitDB */ |
|||
|
|||
//Updates output and state
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'red'}}> |
|||
<strong> |
|||
An error occurred while trying to save post in OrbitDB. |
|||
</strong> |
|||
</span>); |
|||
this.setState({'transactionOutputTimerActive': true}); |
|||
this.transactionOutputTimer = setTimeout(() => { |
|||
this.transactionProgressText = []; |
|||
this.setState({ |
|||
'creatingTopic': false, |
|||
'transactionState': null, |
|||
'savingToOrbitDB': null, |
|||
'transactionOutputTimerActive': false |
|||
}); |
|||
}, 5000); |
|||
} |
|||
} |
|||
else if (this.state.transactionState === "ACCEPTANCE_PENDING" && |
|||
this.props.transactions.undefined !== undefined && |
|||
this.props.transactions.undefined.status === "error"){ |
|||
/* User probably canceled the transaction */ |
|||
|
|||
//TODO user can't post after this!
|
|||
this.transactionProgressText.push(<br key={uuidv4()}/>); |
|||
this.transactionProgressText.push(<span key={uuidv4()} style={{color: 'orange'}}> |
|||
<strong> |
|||
Transaction canceled. |
|||
</strong> |
|||
</span>); |
|||
this.setState({'transactionState': "SUCCESS"}); |
|||
this.setState({'transactionOutputTimerActive': true}); |
|||
this.transactionOutputTimer = setTimeout(() => { |
|||
this.transactionProgressText = []; |
|||
this.setState({ |
|||
'creatingTopic': false, |
|||
'transactionState': null, |
|||
'savingToOrbitDB': null, |
|||
'transactionOutputTimerActive': false |
|||
}); |
|||
}, 5000); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
StartTopic.contextTypes = { |
|||
drizzle: PropTypes.object |
|||
}; |
|||
|
|||
const mapStateToProps = state => { |
|||
return { |
|||
transactions: state.transactions, |
|||
transactionStack: state.transactionStack, |
|||
orbitDB: state.orbitDB, |
|||
user: state.user |
|||
} |
|||
}; |
|||
|
|||
const StartTopicContainer = drizzleConnect(StartTopic, mapStateToProps) |
|||
|
|||
export default StartTopicContainer; |
Loading…
Reference in new issue