diff --git a/package.json b/package.json
index e674ce3..c463321 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"react-user-avatar": "^1.10.0",
"redux": "^3.7.2",
"redux-saga": "0.16.0",
+ "uuid": "^3.2.1",
"web3": "^1.0.0-beta.34"
},
"scripts": {
diff --git a/src/assets/css/App.css b/src/assets/css/App.css
index d87580a..781c76f 100644
--- a/src/assets/css/App.css
+++ b/src/assets/css/App.css
@@ -170,7 +170,7 @@ body,
}
.topic-form textarea {
- height: 200px;
+ min-height: 200px;
}
.form-input-required {
diff --git a/src/components/StartTopic.js b/src/components/StartTopic.js
deleted file mode 100644
index 464eda5..0000000
--- a/src/components/StartTopic.js
+++ /dev/null
@@ -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(
);
- 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(
-
@@ -46,20 +36,25 @@ class Board extends Component {
}
return (
- this.state.startingNewTopic
- ?(
-
-
)
- :(
+
{boardContents}
-
-
)
+
+
+
+
);
}
componentWillReceiveProps() {
+ if (this.state.transactionState === null){
+ if (this.drizzle.contracts[contract]){
+ //This gets called only once but should be called every time someone posts
+ this.dataKey = this.drizzle.contracts[contract].methods[contractMethod].cacheCall();
+ this.setState({'transactionState': "IN_PROGRESS"});
+ }
+ }
if (!this.numberOfTopics) {
- let currentDrizzleState = this.drizzle.store.getState()
+ let currentDrizzleState = this.drizzle.store.getState();
let dataFetched = (currentDrizzleState.contracts[contract][contractMethod])[this.dataKey];
if (dataFetched){
this.numberOfTopics = dataFetched.value
@@ -75,8 +70,7 @@ Board.contextTypes = {
const mapStateToProps = state => {
return {
- user: state.user,
- orbitDB: state.orbitDB,
+ user: state.user
}
};
diff --git a/src/containers/StartTopicContainer.js b/src/containers/StartTopicContainer.js
new file mode 100644
index 0000000..7d0606c
--- /dev/null
+++ b/src/containers/StartTopicContainer.js
@@ -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(
);
+ 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(
+
+ {this.state.creatingTopic &&
+
+
+
+ {this.transactionProgressText}
+
+
+ }
+ {this.state.previewEnabled &&
+
}
+
+
+ );
+ }
+
+ 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(
);
+ 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(
);
+ this.transactionProgressText.push(
+
+ Transaction completed successfully.
+
+ );
+ this.transactionProgressText.push(
);
+ this.transactionProgressText.push(
+
+ TopicID = {this.topicIDFetched}
+
+ );
+ this.setState({'transactionState': "SUCCESS"});
+ } else if (this.props.transactions[this.txHash].status === "error"){
+ /* Transaction failed to complete */
+
+ //Updates output and state
+ this.transactionProgressText.push(
);
+ this.transactionProgressText.push(
+
+ Transaction failed to complete with error:
+
+ );
+ this.transactionProgressText.push(
);
+ this.transactionProgressText.push(
+
+ {this.props.transactions[this.txHash].error}
+
+ );
+ 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(
);
+ this.transactionProgressText.push(
+
+ Post successfully saved in OrbitDB.
+
+ );
+ 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(
);
+ this.transactionProgressText.push(
+
+ An error occurred while trying to save post in OrbitDB.
+
+ );
+ 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(
);
+ this.transactionProgressText.push(
+
+ Transaction canceled.
+
+ );
+ 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;
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 8614530..204b53b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -13,6 +13,7 @@ import PrivateRouteContainer from './containers/PrivateRouteContainer';
import HomeContainer from './containers/HomeContainer';
import TopicContainer from './containers/TopicContainer';
+import StartTopicContainer from './containers/StartTopicContainer';
import ProfileContainer from './containers/ProfileContainer';
import NotFoundView from './components/NotFoundView';
@@ -32,6 +33,7 @@ render((
+