Browse Source

Fix Routes, Add other users profiles view, Other minor fixes

develop
Apostolos Fanakis 7 years ago
parent
commit
64d95f8d94
  1. 6
      src/components/Post.js
  2. 17
      src/components/PostList.js
  3. 4
      src/components/TopicList.js
  4. 41
      src/containers/PrivateRouteContainer.js
  5. 47
      src/containers/ProfileContainer.js
  6. 2
      src/containers/StartTopicContainer.js
  7. 35
      src/containers/TopicContainer.js
  8. 16
      src/index.js

6
src/components/Post.js

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { Link, withRouter } from 'react-router';
import UserAvatar from 'react-user-avatar'; import UserAvatar from 'react-user-avatar';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
@ -9,11 +10,14 @@ const Post = (props) => {
? <div className="pure-u-1-1 post card"> ? <div className="pure-u-1-1 post card">
<div className="post-header"> <div className="post-header">
<div className="vertical-center-children"> <div className="vertical-center-children">
<Link to={"/profile/" + props.post.userAddress + "/" + props.post.username}
onClick={(event) => {event.stopPropagation()}}>
<UserAvatar <UserAvatar
size="40" size="40"
className="inline user-avatar" className="inline user-avatar"
src={props.post.avatarUrl} src={props.post.avatarUrl}
name={props.post.username}/> name={props.post.username}/>
</Link>
<p className="inline no-margin"> <p className="inline no-margin">
<strong> <strong>
{props.post.username} {props.post.username}
@ -60,4 +64,4 @@ const Post = (props) => {
); );
}; };
export default Post; export default withRouter(Post);

17
src/components/PostList.js

@ -1,6 +1,5 @@
import { drizzleConnect } from 'drizzle-react'; import { drizzleConnect } from 'drizzle-react';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Link } from 'react-router';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Post from './Post'; import Post from './Post';
@ -45,12 +44,15 @@ class PostList extends Component {
const posts = this.postsData.map((post, index) => { const posts = this.postsData.map((post, index) => {
if (post) { if (post) {
return ( return (
<Link to={"/topic/" + post[4] + "/" + <div onClick={() => {
((this.orbitPostsData[index] !== undefined) ? this.orbitPostsData[index].subject + "/" + this.context.router.push("/topic/" + post[4] + "/" +
this.props.postIDs[index] : "")} ((this.orbitPostsData[index] !== undefined)
? this.orbitPostsData[index].subject + "/" + this.props.postIDs[index]
: ""))}}
key={index}> key={index}>
<Post post={{ <Post post={{
avatarUrl: post.avatarUrl, avatarUrl: post.avatarUrl,
userAddress: post[1],
username: post[2], username: post[2],
subject: (this.orbitPostsData[index] !== undefined) && this.orbitPostsData[index].subject, subject: (this.orbitPostsData[index] !== undefined) && this.orbitPostsData[index].subject,
date: epochTimeConverter(post[3]), date: epochTimeConverter(post[3]),
@ -59,7 +61,7 @@ class PostList extends Component {
}} }}
id={index} id={index}
key={index}/> key={index}/>
</Link> </div>
); );
} else { } else {
return ( return (
@ -94,13 +96,14 @@ class PostList extends Component {
}; };
PostList.contextTypes = { PostList.contextTypes = {
drizzle: PropTypes.object drizzle: PropTypes.object,
router: PropTypes.object
}; };
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
user: state.user, //Needed!! user: state.user, //Needed!!
orbitDB: state.orbitDB, orbitDB: state.orbitDB
} }
}; };

4
src/components/TopicList.js

@ -56,7 +56,7 @@ class TopicList extends Component {
const topics = this.topicsData.map((topic, index) => { const topics = this.topicsData.map((topic, index) => {
if (topic){ if (topic){
return ( return (
<Link to={"/topic/" + index + "/" + <Link to={"/topic/" + this.props.topicIDs[index] + "/" +
((this.topicsSubjects[index] !== undefined) ? this.topicsSubjects[index] + "/" + 0 : "")} ((this.topicsSubjects[index] !== undefined) ? this.topicsSubjects[index] + "/" + 0 : "")}
key={index}> key={index}>
<Topic topic={{ <Topic topic={{
@ -71,7 +71,7 @@ class TopicList extends Component {
); );
} else { } else {
return ( return (
<Link to={"/topic/" + index + "/"} <Link to={"/topic/" + this.props.topicIDs[index] + "/"}
key={index}> key={index}>
<Topic topic={null} <Topic topic={null}
id={index} id={index}

41
src/containers/PrivateRouteContainer.js

@ -2,45 +2,24 @@ import React from 'react';
import { drizzleConnect } from 'drizzle-react'; import { drizzleConnect } from 'drizzle-react';
import { Route } from "react-router"; import { Route } from "react-router";
import { Redirect } from "react-router-dom"; import { Redirect } from "react-router-dom";
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux'
const PrivateRoute = ({ component, redirectTo, user, ...rest }) => { const PrivateRoute = (props) => {
console.log("rest");
console.log(JSON.stringify(component));
return ( return (
<Route props.user.hasSignedUp
{...rest} render={routeProps => { ? <Route path={props.path} component={props.component} />
return user.hasSignedUp : <Redirect
? (renderMergedProps(component, routeProps, rest)) from={props.path}
: (<Redirect to="/login"
to={{ />
pathname: redirectTo,
state: { from: routeProps.location }
}}
/>);
}}/>
); );
}; };
const renderMergedProps = (component, ...rest) => { const mapStateToProps = state => {
const finalProps = Object.assign({}, ...rest);
return (
React.createElement(component, finalProps)
);
}
const PrivateRouteContainer = withRouter(connect(state => ({
hasSignedUp: state.user.hasSignedUp
}))(PrivateRoute));
/*const mapStateToProps = state => {
return { return {
user: state.user user: state.user
} }
};*/ };
/*const PrivateRouteContainer = withRouter(drizzleConnect(PrivateRoute, mapStateToProps));*/ const PrivateRouteContainer = drizzleConnect(PrivateRoute, mapStateToProps);
export default PrivateRouteContainer; export default PrivateRouteContainer;

47
src/containers/ProfileContainer.js

@ -10,6 +10,7 @@ import epochTimeConverter from '../helpers/EpochTimeConverter';
const contract = "Forum"; const contract = "Forum";
const contractMethods = { const contractMethods = {
getUsername: "getUsername",
getDateOfRegister: "getUserDateOfRegister", getDateOfRegister: "getUserDateOfRegister",
getOrbitDB: "getOrbitDBId", getOrbitDB: "getOrbitDBId",
getUserTopics: "getUserTopics", getUserTopics: "getUserTopics",
@ -20,10 +21,20 @@ class Profile extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
//THIS WILL CHANGE WITH ACTUAL DATA if (this.props.params.address){
this.match = { this.profile = {
userAddress: this.props.params.address,
username: this.props.params.username ? this.props.params.username : "",
orbitId: "",
self: false
}
} else {
this.profile = {
userAddress: this.props.user.address,
username: this.props.user.username, username: this.props.user.username,
userAddress: this.props.user.address orbitId: this.props.orbitDB.id,
self: true
}
} }
this.handleTabClick = this.handleTabClick.bind(this); this.handleTabClick = this.handleTabClick.bind(this);
@ -32,12 +43,13 @@ class Profile extends Component {
this.state = { this.state = {
viewSelected: "topics", viewSelected: "topics",
username: this.match.username, // TODO actually get them from match username: this.profile.username,
userAddress: this.match.userAddress, // when router is fixed userAddress: this.profile.userAddress,
dateOfRegister: null, dateOfRegister: null,
orbitDBId: this.match.address === this.props.user.address ? this.props.orbitDB.id : "", orbitDBId: this.profile.orbitId,
getUsernameTransactionState: null,
getDateOfRegisterTransactionState: null, getDateOfRegisterTransactionState: null,
getOrbitDBTransactionState: this.match.address === this.props.user.address ? "SUCCESS" : null, getOrbitDBTransactionState: this.profile.orbitId ? "SUCCESS" : null,
getTopicsTransactionState: null, getTopicsTransactionState: null,
getPostsTransactionState: null, getPostsTransactionState: null,
topicIDs: [], topicIDs: [],
@ -58,7 +70,7 @@ class Profile extends Component {
numberOfTopics={this.state.topicIDs.length} numberOfTopics={this.state.topicIDs.length}
numberOfPosts={this.state.postIDs.length} numberOfPosts={this.state.postIDs.length}
dateOfRegister={this.state.dateOfRegister} dateOfRegister={this.state.dateOfRegister}
self/> self={this.profile.self}/>
<div className="pure-u-1-1 profile-tabs-header"> <div className="pure-u-1-1 profile-tabs-header">
<p onClick={() => (this.handleTabClick("topics"))} <p onClick={() => (this.handleTabClick("topics"))}
className={this.state.viewSelected === "topics" ? "profile-tab-selected" : ""}> className={this.state.viewSelected === "topics" ? "profile-tab-selected" : ""}>
@ -88,6 +100,25 @@ class Profile extends Component {
} }
componentWillReceiveProps() { componentWillReceiveProps() {
if (this.state.getUsernameTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
this.usernameKey = this.drizzle.contracts[contract]
.methods[contractMethods.getUsername].cacheCall(this.state.userAddress);
this.setState({'getUsernameTransactionState': "IN_PROGRESS"});
}
}
if (this.state.getUsernameTransactionState === "IN_PROGRESS") {
let currentDrizzleState = this.drizzle.store.getState();
let dataFetched = (currentDrizzleState
.contracts[contract][contractMethods.getUsername])[this.usernameKey];
if (dataFetched){
this.setState({
'username': dataFetched.value,
'getUsernameTransactionState': "SUCCESS"
});
}
}
if (this.state.getDateOfRegisterTransactionState === null){ if (this.state.getDateOfRegisterTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
this.dateOfRegisterKey = this.drizzle.contracts[contract] this.dateOfRegisterKey = this.drizzle.contracts[contract]

2
src/containers/StartTopicContainer.js

@ -235,6 +235,8 @@ class StartTopic extends Component {
'savingToOrbitDB': null, 'savingToOrbitDB': null,
'transactionOutputTimerActive': false 'transactionOutputTimerActive': false
}); });
this.props.router.push("/topic/" + this.topicIDFetched + "/"
+ this.state.topicSubjectInput);
}, 5000); }, 5000);
} }
else if (this.state.savingToOrbitDB === "ERROR"){ else if (this.state.savingToOrbitDB === "ERROR"){

35
src/containers/TopicContainer.js

@ -14,6 +14,10 @@ class Topic extends Component {
constructor(props, context) { constructor(props, context) {
super(props); super(props);
if (!/^[0-9]+$/.test(this.props.params.topicId)){
this.props.router.push("/404");
}
this.fetchTopicSubject = this.fetchTopicSubject.bind(this); this.fetchTopicSubject = this.fetchTopicSubject.bind(this);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
this.postCreated = this.postCreated.bind(this); this.postCreated = this.postCreated.bind(this);
@ -21,21 +25,25 @@ class Topic extends Component {
this.drizzle = context.drizzle; this.drizzle = context.drizzle;
this.state = { this.state = {
topicID: this.props.params.topicId,
topicSubject: this.props.params.topicSubject ? this.props.params.topicSubject : null,
postFocus: this.props.params.postId && /^[0-9]+$/.test(this.props.params.postId)
? this.props.params.postId
: null,
getPostsTransactionState: null, getPostsTransactionState: null,
posting: false, posting: false
topicSubject: null
}; };
} }
async fetchTopicSubject(orbitDBAddress, topicID) { async fetchTopicSubject(orbitDBAddress) {
/*const fullAddress = this.topicsData[topicID][1]; /*const fullAddress = this.topicsData[this.state.topicID][1];
const store = await this.props.orbitDB.orbitdb.keyvalue(JSON.stringify(fullAddress)); const store = await this.props.orbitDB.orbitdb.keyvalue(JSON.stringify(fullAddress));
await store.load(); await store.load();
var som = store.get(JSON.stringify(topicID)); var som = store.get(JSON.stringify(this.state.topicID));
this.topicsSubjects[topicID] = som['subject']; this.topicsSubjects[this.state.topicID] = som['subject'];
this.topicsSubjectsFetchStatus[topicID] = "fetched";*/ this.topicsSubjectsFetchStatus[this.state.topicID] = "fetched";*/
var som =this.props.orbitDB.topicsDB.get(JSON.stringify(topicID)); var som =this.props.orbitDB.topicsDB.get(JSON.stringify(this.state.topicID));
this.setState({'topicSubject': som['subject']}); this.setState({'topicSubject': som['subject']});
} }
@ -65,7 +73,7 @@ class Topic extends Component {
topicContents = ( topicContents = (
(<div style={{marginBottom: '100px'}}> (<div style={{marginBottom: '100px'}}>
{this.state.posting && {this.state.posting &&
<NewPost topicID={1} <NewPost topicID={this.state.topicID}
subject={this.state.topicSubject} subject={this.state.topicSubject}
onCancelClick={() => {this.handleClick()}} onCancelClick={() => {this.handleClick()}}
onPostCreated={() => {this.postCreated()}} onPostCreated={() => {this.postCreated()}}
@ -90,7 +98,8 @@ class Topic extends Component {
if (this.state.getPostsTransactionState === null){ if (this.state.getPostsTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
//This gets called only once but should be called every time someone posts //This gets called only once but should be called every time someone posts
this.getPostsDataKey = this.drizzle.contracts[contract].methods[contractMethod].cacheCall(1); this.getPostsDataKey = this.drizzle.contracts[contract].methods[contractMethod]
.cacheCall(this.state.topicID);
this.setState({'getPostsTransactionState': "IN_PROGRESS"}); this.setState({'getPostsTransactionState': "IN_PROGRESS"});
} }
} }
@ -98,9 +107,13 @@ class Topic extends Component {
let currentDrizzleState = this.drizzle.store.getState(); let currentDrizzleState = this.drizzle.store.getState();
let dataFetched = (currentDrizzleState.contracts[contract][contractMethod])[this.getPostsDataKey]; let dataFetched = (currentDrizzleState.contracts[contract][contractMethod])[this.getPostsDataKey];
if (dataFetched){ if (dataFetched){
if (dataFetched.value){
this.posts = dataFetched.value[4]; this.posts = dataFetched.value[4];
this.setState({'getPostsTransactionState': "SUCCESS"}); this.setState({'getPostsTransactionState': "SUCCESS"});
this.fetchTopicSubject(dataFetched.value[0], 1); this.fetchTopicSubject(dataFetched.value[0]);
} else if (dataFetched.error){
//TODO
}
} }
} }
} }

16
src/index.js

@ -31,9 +31,12 @@ render((
<Router history={history}> <Router history={history}>
<Route path="/" component={CoreLayout}> <Route path="/" component={CoreLayout}>
<IndexRoute component={HomeContainer} /> <IndexRoute component={HomeContainer} />
<PrivateRouteContainer path="/topic/:topicId/:topicSubject/:postId" component={TopicContainer} redirectTo="/" /> <Route path="/topic/:topicId(/:topicSubject)(/:postId)"
<PrivateRouteContainer path='/profile' component={ProfileContainer} redirectTo="/" /> component={TopicContainer} />
<PrivateRouteContainer path='/startTopic' component={StartTopicContainer} redirectTo="/" /> <Route path='/profile(/:address)(/:username)'
component={ProfileContainer} />
<Route path='/startTopic'
component={StartTopicContainer} />
<Route path='/404' component={NotFoundView} /> <Route path='/404' component={NotFoundView} />
<Route path='*' component={NotFoundView} /> <Route path='*' component={NotFoundView} />
</Route> </Route>
@ -43,3 +46,10 @@ render((
), ),
document.getElementById('root') document.getElementById('root')
); );
/*<PrivateRouteContainer path="/topic/:topicId(/:topicSubject)(/:postId)"
component={TopicContainer} />
<PrivateRouteContainer path='/profile(/:address)(/:username)'
component={ProfileContainer} />
<PrivateRouteContainer path='/startTopic'
component={StartTopicContainer} />*/
Loading…
Cancel
Save