diff --git a/app/src/components/LoadingSpinner.js b/app/src/components/LoadingSpinner.js new file mode 100644 index 0000000..e863c6b --- /dev/null +++ b/app/src/components/LoadingSpinner.js @@ -0,0 +1,16 @@ +import React from 'react'; + +const LoadingSpinner = (props) => { + return( +
+
+

+ +

+
+
+ ); +} + +export default LoadingSpinner; \ No newline at end of file diff --git a/app/src/components/ProfileInformation.js b/app/src/components/ProfileInformation.js new file mode 100644 index 0000000..c50543b --- /dev/null +++ b/app/src/components/ProfileInformation.js @@ -0,0 +1,153 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { drizzle } from '../index'; + +import UserAvatar from 'react-user-avatar'; +import epochTimeConverter from '../helpers/EpochTimeConverter'; + +import UsernameFormContainer from '../containers/UsernameFormContainer'; + +const callsInfo = [{ + contract: 'Forum', + method: 'getUserDateOfRegister' + },{ + contract: 'Forum', + method: 'getOrbitDBId' +}] + +class ProfileInformation extends Component { + constructor(props) { + super(props); + + this.dataKey = []; + var pageStatus = 'initialized'; + if (this.props.drizzleStatus['initialized']) { + callsInfo.forEach((call, index) => { + this.dataKey[index] = drizzle.contracts[call.contract] + .methods[call.method].cacheCall(this.props.address); + }) + pageStatus = 'loading'; + } + if (this.dataKey.length !== 0) { + pageStatus = 'loaded'; + callsInfo.forEach((call, index) => { + if (!this.props.contracts[call.contract][call.method][this.dataKey[index]]) { + pageStatus = 'loading'; + return; + } + }) + } + if (pageStatus === 'loaded'){ + var dateOfRegister = ''; + var orbitDBId = ''; + + let transaction = this.props.contracts[callsInfo[0].contract][callsInfo[0].method][this.dataKey[0]]; + if (transaction){ + dateOfRegister = transaction.value; + } + transaction = this.props.contracts[callsInfo[1].contract][callsInfo[1].method][this.dataKey[1]]; + if (transaction){ + orbitDBId = transaction.value; + } + } + + this.state = { + pageStatus: pageStatus, + dateOfRegister: dateOfRegister ? dateOfRegister : '', + orbitDBId: orbitDBId ? orbitDBId : '' + }; + } + + componentDidUpdate(){ + if (this.state.pageStatus === 'initialized' && + this.props.drizzleStatus['initialized']) { + callsInfo.forEach((call, index) => { + this.dataKey[index] = drizzle.contracts[call.contract] + .methods[call.method].cacheCall(this.props.address); + }) + this.setState({ pageStatus: 'loading' }); + } + + if (this.state.pageStatus === 'loading') { + var pageStatus = 'loaded'; + callsInfo.forEach((call, index) => { + if (!this.props.contracts[call.contract][call.method][this.dataKey[index]]) { + pageStatus = 'loading'; + return; + } + }) + + if (pageStatus === 'loaded') { + this.setState({ pageStatus: pageStatus }); + } + } + + if (this.state.pageStatus === 'loaded'){ + if (this.state.dateOfRegister === ''){ + let transaction = this.props.contracts[callsInfo[0].contract][callsInfo[0].method][this.dataKey[0]]; + if (transaction){ + this.setState({ dateOfRegister: transaction.value }); + } + } + if (this.state.orbitDBId === ''){ + let transaction = this.props.contracts[callsInfo[1].contract][callsInfo[1].method][this.dataKey[1]]; + if (transaction){ + this.setState({ orbitDBId: transaction.value }); + } + } + } + } + + render() { + return ( +
+ {this.props.avatarUrl && } + + + + + + + + + + + + + + + + + + + + + + + {this.state.dateOfRegister && + + + + + } + +
Username:{this.props.username}
Account address:{this.props.address}
OrbitDB:{this.state.orbitDBId}
Number of topics created:{this.props.numberOfTopics}
Number of posts:{this.props.numberOfPosts}
Member since:{epochTimeConverter(this.state.dateOfRegister)}
+ {this.props.self && } +
+ ); + } +}; + +const mapStateToProps = state => { + return { + drizzleStatus: state.drizzleStatus, + contracts: state.contracts, + user: state.user + } +}; + +export default connect(mapStateToProps)(ProfileInformation); diff --git a/app/src/containers/ProfileContainer.js b/app/src/containers/ProfileContainer.js new file mode 100644 index 0000000..4cd0e4d --- /dev/null +++ b/app/src/containers/ProfileContainer.js @@ -0,0 +1,217 @@ +import React, { Component } from 'react'; +import { bindActionCreators } from 'redux'; +import { push } from 'connected-react-router' +import { connect } from 'react-redux'; +import { drizzle } from '../index'; + +import { Tab } from 'semantic-ui-react' + +import ProfileInformation from '../components/ProfileInformation'; +import TopicList from '../components/TopicList'; +import PostList from '../components/PostList'; +import LoadingSpinner from '../components/LoadingSpinner'; +import { setNavBarTitle } from '../redux/actions/userInterfaceActions'; + +const callsInfo = [{ + contract: 'Forum', + method: 'getUsername' + },{ + contract: 'Forum', + method: 'getUserTopics' + },{ + contract: 'Forum', + method: 'getUserPosts' + } +]; + +class ProfileContainer extends Component { + constructor(props) { + super(props); + + this.dataKey = []; + var address = this.props.match.params.address + ? this.props.match.params.address + : this.props.user.address; + + var pageStatus = 'initialized'; + if (this.props.drizzleStatus['initialized']) { + callsInfo.forEach((call, index) => { + this.dataKey[index] = drizzle.contracts[call.contract] + .methods[call.method].cacheCall(address); + }) + pageStatus = 'loading'; + } + if (this.dataKey.length !== 0) { + pageStatus = 'loaded'; + callsInfo.forEach((call, index) => { + if (!this.props.contracts[call.contract][call.method][this.dataKey[index]]) { + pageStatus = 'loading'; + return; + } + }) + } + if (pageStatus === 'loaded'){ + var username = ''; + var topicIDs = null; + var postIDs = null; + + let transaction = this.props.contracts[callsInfo[0].contract][callsInfo[0].method][this.dataKey[0]]; + if (transaction){ + username = transaction.value; + this.props.setNavBarTitle(username); + } + transaction = this.props.contracts[callsInfo[1].contract][callsInfo[1].method][this.dataKey[1]]; + if (transaction){ + topicIDs = transaction.value; + } + transaction = this.props.contracts[callsInfo[2].contract][callsInfo[2].method][this.dataKey[2]]; + if (transaction){ + postIDs = transaction.value; + } + + /*this.props.store.dispatch(hideProgressBar());*/ + } + + this.state = { + pageStatus: pageStatus, + userAddress: address, + username: username ? username : '', + topicIDs: topicIDs ? topicIDs : null, + postIDs: postIDs ? postIDs : null + }; + } + + componentDidUpdate(){ + if (this.state.pageStatus === 'initialized' && + this.props.drizzleStatus['initialized']) { + callsInfo.forEach((call, index) => { + this.dataKey[index] = drizzle.contracts[call.contract] + .methods[call.method].cacheCall(this.props.match.params.address); + }) + this.setState({ pageStatus: 'loading' }); + } + + if (this.state.pageStatus === 'loading') { + var pageStatus = 'loaded'; + callsInfo.forEach((call, index) => { + if (!this.props.contracts[call.contract][call.method][this.dataKey[index]]) { + pageStatus = 'loading'; + return; + } + }) + + if (pageStatus === 'loaded') { + this.setState({ pageStatus: pageStatus }); + } + } + + if (this.state.pageStatus === 'loaded'){ + if (this.state.username === ''){ + let transaction = this.props.contracts[callsInfo[0].contract][callsInfo[0].method][this.dataKey[0]]; + if (transaction){ + var username = transaction.value; + this.props.setNavBarTitle(username); + this.setState({ username: username }); + } + } + if (this.state.topicIDs === null){ + let transaction = this.props.contracts[callsInfo[1].contract][callsInfo[1].method][this.dataKey[1]]; + if (transaction){ + this.setState({ topicIDs: transaction.value }); + } + } + if (this.state.postIDs === null){ + let transaction = this.props.contracts[callsInfo[2].contract][callsInfo[2].method][this.dataKey[2]]; + if (transaction){ + this.setState({ postIDs: transaction.value }); + } + } + + /*this.props.store.dispatch(hideProgressBar());*/ + } + } + + render() { + if (!this.props.user.hasSignedUp) { + this.props.navigateTo("/signup"); + return(null); + } + + var infoTab = + (); + var topicsTab = + (
+ {this.state.topicIDs + ? + : + } +
); + var postsTab = + (
+ {this.state.postIDs + ? + : + } +
); + + const profilePanes = [ + { + menuItem: 'INFORMATION', + pane: { + key: 'INFORMATION', + content: (infoTab), + }, + }, + { + menuItem: 'TOPICS', + pane: { + key: 'TOPICS', + content: (topicsTab), + }, + }, + { + menuItem: 'POSTS', + pane: { + key: 'POSTS', + content: (postsTab), + }, + }, + ] + + return ( +
+ +
+ ); + } + + componentWillUnmount() { + this.props.setNavBarTitle(''); + } +} + +const mapDispatchToProps = dispatch => bindActionCreators({ + navigateTo: (location) => push(location), + setNavBarTitle: (navBarTitle) => setNavBarTitle(navBarTitle) +}, dispatch); + +const mapStateToProps = state => { + return { + user: state.user, + drizzleStatus: state.drizzleStatus, + contracts: state.contracts, + orbitDB: state.orbitDB + } +}; + +export default connect(mapStateToProps, mapDispatchToProps)(ProfileContainer); diff --git a/app/src/containers/TransactionsMonitorContainer.js b/app/src/containers/TransactionsMonitorContainer.js index 100b5e5..f8152f8 100644 --- a/app/src/containers/TransactionsMonitorContainer.js +++ b/app/src/containers/TransactionsMonitorContainer.js @@ -29,6 +29,10 @@ class RightSideBar extends Component { this.props.history.push("/profile"); this.handleMessageDismiss(null, index); break; + case 'UsernameUpdated': + this.props.history.push("/profile"); + this.handleMessageDismiss(null, index); + break; case 'TopicCreated': this.props.history.push("/topic/" + this.props.transactions[transactionHash].receipt.events.TopicCreated.returnValues.topicID diff --git a/app/src/containers/UsernameFormContainer.js b/app/src/containers/UsernameFormContainer.js index 833050a..2fb295d 100644 --- a/app/src/containers/UsernameFormContainer.js +++ b/app/src/containers/UsernameFormContainer.js @@ -5,7 +5,7 @@ import { Button, Message, Form, Dimmer, Loader, Header } from 'semantic-ui-react import { drizzle } from '../index'; import { createDatabases } from '../orbit'; -/*import { updateUsername } from '../redux/actions/transactionsMonitorActions';*/ +import { updateUsername } from '../redux/actions/transactionsActions'; const contract = "Forum"; const checkUsernameTakenMethod = "isUserNameTaken"; @@ -62,8 +62,7 @@ class UsernameFormContainer extends Component { async completeAction() { if(this.props.user.hasSignedUp){ - //TODO - /*this.props.store.dispatch(updateUsername(...[this.state.usernameInput], null));*/ + this.props.dispatch(updateUsername(...[this.state.usernameInput], null)); } else { this.setState({ signingUp: true }); const orbitdbInfo = await createDatabases(); @@ -79,13 +78,15 @@ class UsernameFormContainer extends Component { orbitdbInfo.postsDB ], { from: this.props.account}); } - /*this.setState({ usernameInput: '' });*/ + this.setState({ usernameInput: '' }); } componentDidUpdate() { if (this.state.signingUp) { const txHash = this.props.transactionStack[this.stackId]; - if (txHash && this.props.transactions[txHash].status === "error") { + if (txHash && + this.props.transactions[txHash] && + this.props.transactions[txHash].status === "error") { this.setState({signingUp: false}); } } else { diff --git a/app/src/router/routes.js b/app/src/router/routes.js index c15e9f6..f7ed24e 100644 --- a/app/src/router/routes.js +++ b/app/src/router/routes.js @@ -5,6 +5,7 @@ import HomeContainer from '../containers/HomeContainer' import SignUpContainer from '../containers/SignUpContainer' import StartTopicContainer from '../containers/StartTopicContainer' import TopicContainer from '../containers/TopicContainer' +import ProfileContainer from '../containers/ProfileContainer' import NotFound from '../components/NotFound' const routes = ( @@ -15,7 +16,8 @@ const routes = ( - + +