Browse Source

Add Navbar title, Scroll to post requested in the url

develop
Apostolos Fanakis 7 years ago
parent
commit
810e3a5a20
  1. 20
      src/assets/css/App.css
  2. 10
      src/components/NavBar.js
  3. 151
      src/components/Post.js
  4. 1
      src/components/PostList.js
  5. 8
      src/components/ProfileInformation.js
  6. 23
      src/containers/ProfileContainer.js
  7. 11
      src/containers/TopicContainer.js
  8. 2
      src/containers/UsernameFormContainer.js
  9. 12
      src/redux/actions/userInterfaceActions.js
  10. 13
      src/redux/reducer/userInterfaceReducer.js

20
src/assets/css/App.css

@ -66,6 +66,22 @@ strong {
/* MISC */ /* MISC */
.navBarText {
height: 61px;
width: 1192px;
position: absolute;
left: calc(50% - 596px);
text-align: center;
}
.navBarText span {
color: #00b5ad;
height: 61px;
line-height: 61px;
vertical-align: middle;
font-size: 1.5em;
}
.form-textarea-required { .form-textarea-required {
color: rgb(159, 58, 56) !important; color: rgb(159, 58, 56) !important;
outline-color: rgb(159, 58, 56) !important; outline-color: rgb(159, 58, 56) !important;
@ -167,8 +183,4 @@ a {
.fill { .fill {
width: 100%; width: 100%;
height: 100%; height: 100%;
}
.vis { /* For UX developing */
border: 1px solid red;
} }

10
src/components/NavBar.js

@ -41,6 +41,9 @@ class NavBar extends Component {
</Menu.Item> </Menu.Item>
</Menu.Menu> </Menu.Menu>
} }
<div className="navBarText">
{this.props.navBarTitle !== '' && <span>{this.props.navBarTitle}</span>}
</div>
</Menu> </Menu>
); );
} }
@ -51,9 +54,10 @@ NavBar.contextTypes = {
}; };
const mapStateToProps = state => { const mapStateToProps = state => {
return { return {
hasSignedUp: state.user.hasSignedUp hasSignedUp: state.user.hasSignedUp,
} navBarTitle: state.interface.navBarTitle
}
}; };
export default drizzleConnect(NavBar, mapStateToProps); export default drizzleConnect(NavBar, mapStateToProps);

151
src/components/Post.js

@ -3,6 +3,7 @@ import { Link, withRouter } from 'react-router';
import { drizzleConnect } from 'drizzle-react'; import { drizzleConnect } from 'drizzle-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Transition } from 'semantic-ui-react'
import { Grid, Divider, Button, Icon, Label } from 'semantic-ui-react' import { Grid, Divider, Button, Icon, Label } from 'semantic-ui-react'
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
@ -15,12 +16,18 @@ class Post extends Component {
super(props); super(props);
this.fetchPost = this.fetchPost.bind(this); this.fetchPost = this.fetchPost.bind(this);
if (props.getFocus){
this.postRef = React.createRef();
}
this.orbitPostData = { this.orbitPostData = {
content: "", content: "",
subject: "" subject: ""
}; };
this.orbitPostDataFetchStatus = "pending"; this.orbitPostDataFetchStatus = "pending";
this.state = {
animateOnToggle: true
}
} }
async fetchPost(postID) { async fetchPost(postID) {
@ -44,6 +51,7 @@ class Post extends Component {
} }
} }
this.orbitPostDataFetchStatus = "fetched"; this.orbitPostDataFetchStatus = "fetched";
this.readyForAnimation = true;
} }
render(){ render(){
@ -57,74 +65,76 @@ class Post extends Component {
); );
return ( return (
<div className="post"> <Transition animation='tada' duration={500} visible={this.state.animateOnToggle}>
<Divider horizontal> <div className="post" ref={this.postRef ? this.postRef : null}>
<span className="grey-text">#{this.props.postIndex}</span> <Divider horizontal>
</Divider> <span className="grey-text">#{this.props.postIndex}</span>
<Grid> </Divider>
<Grid.Row columns={16} stretched> <Grid>
<Grid.Column width={1} className="user-avatar"> <Grid.Row columns={16} stretched>
{this.props.blockchainData[0].returnData !== null <Grid.Column width={1} className="user-avatar">
?<Link to={"/profile/" + this.props.blockchainData[0].returnData[1] {this.props.blockchainData[0].returnData !== null
+ "/" + this.props.blockchainData[0].returnData[2]} ?<Link to={"/profile/" + this.props.blockchainData[0].returnData[1]
onClick={(event) => {event.stopPropagation()}}> + "/" + this.props.blockchainData[0].returnData[2]}
{avatarView} onClick={(event) => {event.stopPropagation()}}>
</Link> {avatarView}
:avatarView </Link>
} :avatarView
</Grid.Column> }
<Grid.Column width={15}> </Grid.Column>
<div className=""> <Grid.Column width={15}>
<div className="stretch-space-between"> <div className="">
<span className={this.props.blockchainData[0].returnData !== null ? "" : "grey-text"}> <div className="stretch-space-between">
<strong> <span className={this.props.blockchainData[0].returnData !== null ? "" : "grey-text"}>
{this.props.blockchainData[0].returnData !== null <strong>
?this.props.blockchainData[0].returnData[2] {this.props.blockchainData[0].returnData !== null
:"Username" ?this.props.blockchainData[0].returnData[2]
:"Username"
}
</strong>
</span>
<span className="grey-text">
{this.props.blockchainData[0].returnData !== null &&
<TimeAgo date={epochTimeConverter(this.props.blockchainData[0].returnData[3])}/>
} }
</strong> </span>
</span> </div>
<span className="grey-text"> <div className="stretch-space-between">
{this.props.blockchainData[0].returnData !== null && <span className={this.orbitPostData.subject ? "" : "grey-text"}>
<TimeAgo date={epochTimeConverter(this.props.blockchainData[0].returnData[3])}/> <strong>
Subject: {this.orbitPostData.subject}
</strong>
</span>
</div>
<div className="post-content">
{this.orbitPostData.content
? <ReactMarkdown source={this.orbitPostData.content} />
: <p className="grey-text">Post content...</p>
} }
</span> </div>
</div>
<div className="stretch-space-between">
<span className={this.orbitPostData.subject ? "" : "grey-text"}>
<strong>
Subject: {this.orbitPostData.subject}
</strong>
</span>
</div> </div>
<div className="post-content"> </Grid.Column>
{this.orbitPostData.content </Grid.Row>
? <ReactMarkdown source={this.orbitPostData.content} /> <Grid.Row>
: <p className="grey-text">Post content...</p> <Grid.Column floated="right" textAlign="right">
} <Button icon size='mini' style={{marginRight: "0px"}}>
</div> <Icon name='chevron up' />
</div> </Button>
</Grid.Column> <Label color="teal">8000</Label>
</Grid.Row> <Button icon size='mini'>
<Grid.Row> <Icon name='chevron down' />
<Grid.Column floated="right" textAlign="right"> </Button>
<Button icon size='mini' style={{marginRight: "0px"}}> <Button icon size='mini'
<Icon name='chevron up' /> onClick={() => { this.context.router.push("/topic/"
</Button> + this.props.blockchainData[0].returnData[4] + "/"
<Label color="teal">8000</Label> + this.props.postID)}}>
<Button icon size='mini'> <Icon name='linkify' />
<Icon name='chevron down' /> </Button>
</Button> </Grid.Column>
<Button icon size='mini' </Grid.Row>
onClick={() => { this.context.router.push("/topic/" </Grid>
+ this.props.blockchainData[0].returnData[4] + "/" </div>
+ this.props.postID)}}> </Transition>
<Icon name='linkify' />
</Button>
</Grid.Column>
</Grid.Row>
</Grid>
</div>
); );
} }
@ -133,6 +143,17 @@ class Post extends Component {
&& this.orbitPostDataFetchStatus === "pending") { && this.orbitPostDataFetchStatus === "pending") {
this.fetchPost(this.props.postID); this.fetchPost(this.props.postID);
} }
if (this.readyForAnimation){
if (this.postRef){
setTimeout(() => {
this.postRef.current.scrollIntoView({ block: 'start', behavior: 'smooth' });
setTimeout(() => {
this.setState({ animateOnToggle: false });
}, 300);
}, 100);
this.readyForAnimation = false;
}
}
} }
}; };

1
src/components/PostList.js

@ -17,6 +17,7 @@ const PostList = (props) => {
avatarUrl={""} avatarUrl={""}
postIndex={index} postIndex={index}
postID={postID} postID={postID}
getFocus={props.focusOnPost === postID ? true : false}
key={postID} key={postID}
/> />
); );

8
src/components/ProfileInformation.js

@ -7,10 +7,6 @@ import UsernameFormContainer from '../containers/UsernameFormContainer';
const ProfileInformation = (props) => { const ProfileInformation = (props) => {
let transaction = props.blockchainData let transaction = props.blockchainData
.find(transaction => transaction.callInfo.method === "getUsername");
let username = transaction ? transaction.returnData : "";
transaction = props.blockchainData
.find(transaction => transaction.callInfo.method === "getUserDateOfRegister"); .find(transaction => transaction.callInfo.method === "getUserDateOfRegister");
let dateOfRegister = transaction ? transaction.returnData : ""; let dateOfRegister = transaction ? transaction.returnData : "";
@ -24,12 +20,12 @@ const ProfileInformation = (props) => {
size="40" size="40"
className="inline user-avatar" className="inline user-avatar"
src={props.avatarUrl} src={props.avatarUrl}
name={username}/>} name={props.username}/>}
<table className="highlight centered responsive-table"> <table className="highlight centered responsive-table">
<tbody> <tbody>
<tr> <tr>
<td><strong>Username:</strong></td> <td><strong>Username:</strong></td>
<td>{username}</td> <td>{props.username}</td>
</tr> </tr>
<tr> <tr>
<td><strong>Account address:</strong></td> <td><strong>Account address:</strong></td>

23
src/containers/ProfileContainer.js

@ -9,6 +9,7 @@ import ProfileInformation from '../components/ProfileInformation';
import TopicList from '../components/TopicList'; import TopicList from '../components/TopicList';
import PostList from '../components/PostList'; import PostList from '../components/PostList';
import LoadingSpinner from '../components/LoadingSpinner'; import LoadingSpinner from '../components/LoadingSpinner';
import { setNavBarTitle } from '../redux/actions/userInterfaceActions';
class Profile extends Component { class Profile extends Component {
constructor(props, context) { constructor(props, context) {
@ -34,10 +35,6 @@ class Profile extends Component {
(<WithBlockchainData (<WithBlockchainData
component={ProfileInformation} component={ProfileInformation}
callsInfo={[{ callsInfo={[{
contract: 'Forum',
method: 'getUsername',
params: [this.state.userAddress]
},{
contract: 'Forum', contract: 'Forum',
method: 'getUserDateOfRegister', method: 'getUserDateOfRegister',
params: [this.state.userAddress] params: [this.state.userAddress]
@ -47,6 +44,7 @@ class Profile extends Component {
params: [this.state.userAddress] params: [this.state.userAddress]
}]} }]}
address={this.state.userAddress} address={this.state.userAddress}
username={this.username}
numberOfTopics={this.topicIDs && this.topicIDs.length} numberOfTopics={this.topicIDs && this.topicIDs.length}
numberOfPosts={this.postIDs && this.postIDs.length} numberOfPosts={this.postIDs && this.postIDs.length}
self={this.state.userAddress === this.props.user.address} self={this.state.userAddress === this.props.user.address}
@ -102,6 +100,13 @@ class Profile extends Component {
} }
propsToView(){ propsToView(){
if (!this.username){
let transaction = this.props.blockchainData
.find(transaction => transaction.callInfo.method === "getUsername");
if (transaction.returnData){
this.username = transaction.returnData;
}
}
if (!this.topicIDs){ if (!this.topicIDs){
let transaction = this.props.blockchainData let transaction = this.props.blockchainData
.find(transaction => transaction.callInfo.method === "getUserTopics"); .find(transaction => transaction.callInfo.method === "getUserTopics");
@ -117,6 +122,12 @@ class Profile extends Component {
} }
} }
} }
componentDidUpdate(){
if (this.username){
this.props.store.dispatch(setNavBarTitle(this.username));
}
}
} }
Profile.contextTypes = { Profile.contextTypes = {
@ -145,6 +156,10 @@ class ProfileContainer extends Component {
this.profile = <WithBlockchainData this.profile = <WithBlockchainData
component={drizzleConnect(Profile, mapStateToProps)} component={drizzleConnect(Profile, mapStateToProps)}
callsInfo={[{ callsInfo={[{
contract: 'Forum',
method: 'getUsername',
params: [userAddress]
},{
contract: 'Forum', contract: 'Forum',
method: 'getUserTopics', method: 'getUserTopics',
params: [userAddress] params: [userAddress]

11
src/containers/TopicContainer.js

@ -6,7 +6,11 @@ import PostList from '../components/PostList';
import NewPost from '../components/NewPost'; import NewPost from '../components/NewPost';
import FloatingButton from '../components/FloatingButton'; import FloatingButton from '../components/FloatingButton';
import { showProgressBar, hideProgressBar } from '../redux/actions/userInterfaceActions'; import {
showProgressBar,
hideProgressBar,
setNavBarTitle
} from '../redux/actions/userInterfaceActions';
class Topic extends Component { class Topic extends Component {
constructor(props) { constructor(props) {
@ -50,6 +54,7 @@ class Topic extends Component {
} }
this.props.store.dispatch(hideProgressBar()); this.props.store.dispatch(hideProgressBar());
this.props.store.dispatch(setNavBarTitle(orbitData['subject']));
this.setState({ this.setState({
'topicSubject': orbitData['subject'], 'topicSubject': orbitData['subject'],
fetchTopicSubjectStatus: "fetched" fetchTopicSubjectStatus: "fetched"
@ -69,7 +74,6 @@ class Topic extends Component {
this.setState(prevState => ({ this.setState(prevState => ({
posting: false posting: false
})); }));
//TODO reload topic
} }
render() { render() {
@ -77,7 +81,8 @@ class Topic extends Component {
if (this.props.blockchainData[0].status === "success") { if (this.props.blockchainData[0].status === "success") {
topicContents = ( topicContents = (
(<div> (<div>
<PostList postIDs={this.props.blockchainData[0].returnData[4]}/> <PostList postIDs={this.props.blockchainData[0].returnData[4]}
focusOnPost={this.state.postFocus ? this.state.postFocus : null}/>
{this.state.posting && {this.state.posting &&
<NewPost topicID={this.state.topicID} <NewPost topicID={this.state.topicID}
subject={this.state.topicSubject} subject={this.state.topicSubject}

2
src/containers/UsernameFormContainer.js

@ -92,7 +92,7 @@ class UsernameFormContainer extends Component {
</Form> </Form>
<Dimmer active={this.state.signingUp} page> <Dimmer active={this.state.signingUp} page>
<Header as='h2' inverted> <Header as='h2' inverted>
<Loader size='large'>Magic elfs are processing your nobel request.</Loader> <Loader size='large'>Magic elves are processing your noble request.</Loader>
</Header> </Header>
</Dimmer> </Dimmer>
</div> </div>

12
src/redux/actions/userInterfaceActions.js

@ -2,11 +2,19 @@
export const SHOW_PROGRESS_BAR = 'SHOW_PROGRESS_BAR'; export const SHOW_PROGRESS_BAR = 'SHOW_PROGRESS_BAR';
export const HIDE_PROGRESS_BAR = 'HIDE_PROGRESS_BAR'; export const HIDE_PROGRESS_BAR = 'HIDE_PROGRESS_BAR';
export const SET_NAVBAR_TITLE = 'SET_NAVBAR_TITLE';
export function showProgressBar(){ export function showProgressBar(){
return { type: 'SHOW_PROGRESS_BAR'}; return { type: SHOW_PROGRESS_BAR};
} }
export function hideProgressBar(){ export function hideProgressBar(){
return { type: 'HIDE_PROGRESS_BAR'}; return { type: HIDE_PROGRESS_BAR};
}
export function setNavBarTitle(newTitle){
return {
type: SET_NAVBAR_TITLE,
title: newTitle
};
} }

13
src/redux/reducer/userInterfaceReducer.js

@ -1,7 +1,12 @@
import { SHOW_PROGRESS_BAR, HIDE_PROGRESS_BAR } from '../actions/userInterfaceActions'; import {
SHOW_PROGRESS_BAR,
HIDE_PROGRESS_BAR,
SET_NAVBAR_TITLE
} from '../actions/userInterfaceActions';
const initialState = { const initialState = {
displayProgressBar: false displayProgressBar: false,
navBarTitle: ''
}; };
const userInterfaceReducer = (state = initialState, action) => { const userInterfaceReducer = (state = initialState, action) => {
@ -14,6 +19,10 @@ const userInterfaceReducer = (state = initialState, action) => {
return { return {
displayProgressBar: false displayProgressBar: false
}; };
case SET_NAVBAR_TITLE:
return {
navBarTitle: action.title
}
default: default:
return state; return state;
} }

Loading…
Cancel
Save