Browse Source

TopicView changes, other fixes

develop
Ezerous 4 years ago
parent
commit
2d90c587c0
  1. 1
      packages/concordia-app/public/locales/en/translation.json
  2. 1
      packages/concordia-app/src/assets/css/index.css
  3. 27
      packages/concordia-app/src/components/PostCreate/index.jsx
  4. 12
      packages/concordia-app/src/components/PostCreate/styles.css
  5. 2
      packages/concordia-app/src/components/PostList/PostListRow/index.jsx
  6. 13
      packages/concordia-app/src/components/PostList/PostListRow/styles.css
  7. 6
      packages/concordia-app/src/components/PostList/index.jsx
  8. 30
      packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
  9. 25
      packages/concordia-app/src/components/TopicList/TopicListRow/styles.css
  10. 87
      packages/concordia-app/src/views/Topic/TopicView/index.jsx
  11. 6
      packages/concordia-app/src/views/Topic/TopicView/styles.css

1
packages/concordia-app/public/locales/en/translation.json

@ -72,7 +72,6 @@
"topic.create.form.post.button": "Post", "topic.create.form.post.button": "Post",
"topic.create.form.subject.field.label": "Topic subject", "topic.create.form.subject.field.label": "Topic subject",
"topic.create.form.subject.field.placeholder": "Subject", "topic.create.form.subject.field.placeholder": "Subject",
"topic.list.row.number.of.replies": "{{numberOfReplies}} replies",
"topic.list.row.topic.id": "#{{id}}", "topic.list.row.topic.id": "#{{id}}",
"username.selector.error.username.empty.message": "Username is required", "username.selector.error.username.empty.message": "Username is required",
"username.selector.error.username.taken.message": "The username {{username}} is already taken.", "username.selector.error.username.taken.message": "The username {{username}} is already taken.",

1
packages/concordia-app/src/assets/css/index.css

@ -1,6 +1,7 @@
body.app { body.app {
overflow: auto; overflow: auto;
margin: 0; margin: 0;
background: #E6E6E6;
} }
div { div {

27
packages/concordia-app/src/components/PostCreate/index.jsx

@ -2,7 +2,7 @@ import React, {
memo, useCallback, useEffect, useState, memo, useCallback, useEffect, useState,
} from 'react'; } from 'react';
import { import {
Button, Feed, Form, Icon, Image, TextArea, Button, Feed, Form, Icon, TextArea,
} from 'semantic-ui-react'; } from 'semantic-ui-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -10,7 +10,6 @@ import { useDispatch, useSelector } from 'react-redux';
import determineKVAddress from '../../utils/orbitUtils'; import determineKVAddress from '../../utils/orbitUtils';
import { POSTS_DATABASE, USER_DATABASE } from '../../constants/orbit/OrbitDatabases'; import { POSTS_DATABASE, USER_DATABASE } from '../../constants/orbit/OrbitDatabases';
import { FETCH_USER_DATABASE } from '../../redux/actions/peerDbReplicationActions'; import { FETCH_USER_DATABASE } from '../../redux/actions/peerDbReplicationActions';
import { USER_PROFILE_PICTURE } from '../../constants/orbit/UserDatabaseKeys';
import { breeze, drizzle } from '../../redux/store'; import { breeze, drizzle } from '../../redux/store';
import './styles.css'; import './styles.css';
import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../constants/TransactionStatus'; import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../constants/TransactionStatus';
@ -28,7 +27,6 @@ const PostCreate = (props) => {
const transactionStack = useSelector((state) => state.transactionStack); const transactionStack = useSelector((state) => state.transactionStack);
const transactions = useSelector((state) => state.transactions); const transactions = useSelector((state) => state.transactions);
const [postContent, setPostContent] = useState(''); const [postContent, setPostContent] = useState('');
const [userProfilePictureUrl, setUserProfilePictureUrl] = useState();
const [createPostCacheSendStackId, setCreatePostCacheSendStackId] = useState(''); const [createPostCacheSendStackId, setCreatePostCacheSendStackId] = useState('');
const [posting, setPosting] = useState(false); const [posting, setPosting] = useState(false);
const [storingPost, setStoringPost] = useState(false); const [storingPost, setStoringPost] = useState(false);
@ -44,9 +42,7 @@ const PostCreate = (props) => {
const userFound = users const userFound = users
.find((user) => user.id === userOrbitAddress); .find((user) => user.id === userOrbitAddress);
if (userFound) { if (!userFound) {
setUserProfilePictureUrl(userFound[USER_PROFILE_PICTURE]);
} else {
dispatch({ dispatch({
type: FETCH_USER_DATABASE, type: FETCH_USER_DATABASE,
orbit, orbit,
@ -122,23 +118,6 @@ const PostCreate = (props) => {
return ( return (
<Feed> <Feed>
<Feed.Event> <Feed.Event>
<Feed.Label className="post-profile-picture">
{userProfilePictureUrl
? (
<Image
avatar
src={userProfilePictureUrl}
/>
)
: (
<Icon
name="user circle"
size="big"
inverted
color="black"
/>
)}
</Feed.Label>
<Feed.Content> <Feed.Content>
<Feed.Summary> <Feed.Summary>
<Form> <Form>
@ -152,7 +131,7 @@ const PostCreate = (props) => {
/> />
</Form> </Form>
</Feed.Summary> </Feed.Summary>
<Feed.Meta> <Feed.Meta id="post-button">
<Feed.Like> <Feed.Like>
<Form.Button <Form.Button
animated animated

12
packages/concordia-app/src/components/PostCreate/styles.css

@ -1,7 +1,3 @@
.post-profile-picture {
margin: 5px 0 0 0;
}
.post-summary-meta-index { .post-summary-meta-index {
float: right; float: right;
font-size: 12px; font-size: 12px;
@ -11,3 +7,11 @@
.like:hover .icon { .like:hover .icon {
color: #fff !important; color: #fff !important;
} }
#post-button {
float: right;
}
#post-button button {
margin: 0;
}

2
packages/concordia-app/src/components/PostList/PostListRow/index.jsx

@ -136,7 +136,7 @@ const PostListRow = (props) => {
{authorAvatarLink} {authorAvatarLink}
</Feed.Label> </Feed.Label>
</Ref> </Ref>
<Feed.Content> <Feed.Content className="post-content">
<Feed.Summary> <Feed.Summary>
<Link to={`/topics/${topicId}/#post-${postId}`}> <Link to={`/topics/${topicId}/#post-${postId}`}>
<span className="post-summary-meta-index"> <span className="post-summary-meta-index">

13
packages/concordia-app/src/components/PostList/PostListRow/styles.css

@ -1,5 +1,16 @@
.post-profile-picture { .post-profile-picture {
margin: 5px 0 0 0; margin-top: 1rem;
}
.post-profile-picture img {
border-radius: 50%;
width: 2em !important;
height: 2em !important;
margin: 0 !important;
}
.post-content {
margin-left: 0.5rem !important;
} }
.post-summary-meta-index { .post-summary-meta-index {

6
packages/concordia-app/src/components/PostList/index.jsx

@ -3,7 +3,9 @@ import React, {
} from 'react'; } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Dimmer, Feed, Loader } from 'semantic-ui-react'; import {
Dimmer, Feed, Loader,
} from 'semantic-ui-react';
import PostListRow from './PostListRow'; import PostListRow from './PostListRow';
import { drizzle } from '../../redux/store'; import { drizzle } from '../../redux/store';
import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames'; import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames';
@ -58,10 +60,12 @@ const PostList = (props) => {
}, [focusOnPost, getPostCallHashes, loading, postIds]); }, [focusOnPost, getPostCallHashes, loading, postIds]);
return ( return (
<Dimmer.Dimmable as={Feed} blurring dimmed={loading} id="post-list" size="large"> <Dimmer.Dimmable as={Feed} blurring dimmed={loading} id="post-list" size="large">
<Loader active={loading} /> <Loader active={loading} />
{posts} {posts}
</Dimmer.Dimmable> </Dimmer.Dimmable>
); );
}; };

30
packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx

@ -2,11 +2,12 @@ import React, {
memo, useEffect, useMemo, useState, memo, useEffect, useMemo, useState,
} from 'react'; } from 'react';
import { import {
Dimmer, Grid, Image, Item, List, Placeholder, Segment, Dimmer, Grid, Icon, Image, Item, List, Placeholder, Segment,
} from 'semantic-ui-react'; } from 'semantic-ui-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import { useHistory } from 'react-router';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
@ -33,6 +34,7 @@ const TopicListRow = (props) => {
const topics = useSelector((state) => state.orbitData.topics); const topics = useSelector((state) => state.orbitData.topics);
const users = useSelector((state) => state.orbitData.users); const users = useSelector((state) => state.orbitData.users);
const dispatch = useDispatch(); const dispatch = useDispatch();
const history = useHistory();
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => { useEffect(() => {
@ -40,7 +42,7 @@ const TopicListRow = (props) => {
setTopicAuthorAddress(getTopicResults[topicCallHash].value[0]); setTopicAuthorAddress(getTopicResults[topicCallHash].value[0]);
setTopicAuthor(getTopicResults[topicCallHash].value[1]); setTopicAuthor(getTopicResults[topicCallHash].value[1]);
setTimeAgo(getTopicResults[topicCallHash].value[2] * 1000); setTimeAgo(getTopicResults[topicCallHash].value[2] * 1000);
setNumberOfReplies(getTopicResults[topicCallHash].value[3].length); setNumberOfReplies(getTopicResults[topicCallHash].value[3].length - 1);
} }
}, [getTopicResults, loading, topicCallHash]); }, [getTopicResults, loading, topicCallHash]);
@ -121,17 +123,20 @@ const TopicListRow = (props) => {
return authorAvatar; return authorAvatar;
}, [authorAvatar, topicAuthorAddress]); }, [authorAvatar, topicAuthorAddress]);
return useMemo(() => ( return useMemo(() => {
<Dimmer.Dimmable as={List.Item} blurring dimmed={loading} className="topic-row"> const handleTopicClick = () => {
<Segment raised className="topic-row-segment" as="a"> history.push(`/topics/${topicId}`);
<Grid doubling columns={2}> };
return (
<Dimmer.Dimmable as={List.Item} blurring dimmed={loading} className="topic-row" onClick={handleTopicClick}>
<Segment className="topic-row-segment">
<Grid columns={2}>
<Grid.Column width={1} className="topic-row-avatar"> <Grid.Column width={1} className="topic-row-avatar">
<Item> <Item>
{authorAvatarLink} {authorAvatarLink}
</Item> </Item>
</Grid.Column> </Grid.Column>
<Grid.Column width={15} className="topic-row-content"> <Grid.Column width={15} className="topic-row-content">
<Link to={`/topics/${topicId}`} onClick={stopClickPropagation}>
<Grid verticalAlign="middle" columns={2}> <Grid verticalAlign="middle" columns={2}>
<Grid.Row> <Grid.Row>
<Grid.Column floated="left" width={14} className="topic-row-subject"> <Grid.Column floated="left" width={14} className="topic-row-subject">
@ -163,15 +168,15 @@ const TopicListRow = (props) => {
{numberOfReplies !== null {numberOfReplies !== null
? ( ? (
<span className="topic-row-metadata"> <span className="topic-row-metadata">
{t('topic.list.row.number.of.replies', { numberOfReplies })} <Icon name="reply" fitted />
&nbsp;
{ numberOfReplies }
</span> </span>
) )
: <Placeholder fluid><Placeholder.Line /></Placeholder>} : <Placeholder fluid className="replies-placeholder"><Placeholder.Line /></Placeholder>}
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
</Link>
</Grid.Column> </Grid.Column>
</Grid> </Grid>
@ -179,7 +184,8 @@ const TopicListRow = (props) => {
</Dimmer.Dimmable> </Dimmer.Dimmable>
), [authorAvatarLink, loading, numberOfReplies, t, timeAgo, topicAuthor, topicAuthorAddress, topicId, topicSubject]); );
}, [authorAvatarLink, history, loading, numberOfReplies, t, timeAgo, topicAuthor, topicAuthorAddress, topicId, topicSubject]);
}; };
TopicListRow.defaultProps = { TopicListRow.defaultProps = {

25
packages/concordia-app/src/components/TopicList/TopicListRow/styles.css

@ -1,6 +1,7 @@
.topic-row { .topic-row {
display: flex !important; display: flex !important;
text-align: start; text-align: start;
cursor: pointer;
} }
.topic-row-segment { .topic-row-segment {
@ -8,18 +9,26 @@
} }
.topic-row-segment:hover { .topic-row-segment:hover {
background-color: rgba(0, 0, 0, 0.03); background-color: #F7F7F7;
} }
.topic-row-segment div { .topic-row-segment div {
color: black; color: black;
} }
.topic-row-segment .placeholder{
font-size: 0.9rem;
}
.topic-row-segment .placeholder>.line {
background-color:transparent;
}
.topic-row-avatar { .topic-row-avatar {
margin: auto; margin: auto;
padding-left: 0.75em !important; padding-left: 0.75em !important;
padding-right: 0 !important; padding-right: 0 !important;
font-size: 2em; font-size: 2rem;
} }
.topic-row-avatar i { .topic-row-avatar i {
@ -28,17 +37,16 @@
} }
.topic-row-content { .topic-row-content {
padding-left: 2em !important; padding-left: 2rem !important;
} }
.topic-row-subject { .topic-row-subject {
font-size: 1.25em; font-size: 1.4rem;
font-weight: bold; font-weight: bold;
} }
.topic-row-metadata { .topic-row-metadata {
font-size: 12px !important; font-size: 0.9em !important;
font-weight: initial;
} }
.profile-picture { .profile-picture {
@ -47,3 +55,8 @@
width: 2em; width: 2em;
height: 2em; height: 2em;
} }
.replies-placeholder{
float:right;
width: 6rem;
}

87
packages/concordia-app/src/views/Topic/TopicView/index.jsx

@ -2,10 +2,11 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { import {
Container, Dimmer, Icon, Image, Placeholder, Step, Container, Dimmer, Divider, Header, Icon, Placeholder, Segment,
} from 'semantic-ui-react'; } from 'semantic-ui-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import { breeze, drizzle } from '../../../redux/store'; import { breeze, drizzle } from '../../../redux/store';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
@ -13,7 +14,6 @@ import './styles.css';
import PostList from '../../../components/PostList'; import PostList from '../../../components/PostList';
import { TOPICS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases'; import { TOPICS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases';
import determineKVAddress from '../../../utils/orbitUtils'; import determineKVAddress from '../../../utils/orbitUtils';
import { USER_PROFILE_PICTURE } from '../../../constants/orbit/UserDatabaseKeys';
import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys'; import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys';
import PostCreate from '../../../components/PostCreate'; import PostCreate from '../../../components/PostCreate';
import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames'; import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames';
@ -36,9 +36,9 @@ const TopicView = (props) => {
const [getTopicCallHash, setGetTopicCallHash] = useState([]); const [getTopicCallHash, setGetTopicCallHash] = useState([]);
const [topicAuthorAddress, setTopicAuthorAddress] = useState(initialTopicAuthorAddress || null); const [topicAuthorAddress, setTopicAuthorAddress] = useState(initialTopicAuthorAddress || null);
const [topicAuthor, setTopicAuthor] = useState(initialTopicAuthor || null); const [topicAuthor, setTopicAuthor] = useState(initialTopicAuthor || null);
const [topicAuthorMeta, setTopicAuthorMeta] = useState(null);
const [timestamp, setTimestamp] = useState(initialTimestamp || null); const [timestamp, setTimestamp] = useState(initialTimestamp || null);
const [postIds, setPostIds] = useState(initialPostIds || null); const [postIds, setPostIds] = useState(initialPostIds || null);
const [numberOfReplies, setReplyCount] = useState(0);
const [topicSubject, setTopicSubject] = useState(null); const [topicSubject, setTopicSubject] = useState(null);
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -66,7 +66,9 @@ const TopicView = (props) => {
setTopicAuthorAddress(getTopicResults[getTopicCallHash].value[0]); setTopicAuthorAddress(getTopicResults[getTopicCallHash].value[0]);
setTopicAuthor(getTopicResults[getTopicCallHash].value[1]); setTopicAuthor(getTopicResults[getTopicCallHash].value[1]);
setTimestamp(getTopicResults[getTopicCallHash].value[2] * 1000); setTimestamp(getTopicResults[getTopicCallHash].value[2] * 1000);
setPostIds(getTopicResults[getTopicCallHash].value[3].map((postId) => parseInt(postId, 10))); const postIds = getTopicResults[getTopicCallHash].value[3].map((postId) => parseInt(postId, 10));
setPostIds(postIds);
setReplyCount(postIds.length - 1);
const topicFound = topics const topicFound = topics
.find((topic) => topic.id === topicId); .find((topic) => topic.id === topicId);
@ -89,9 +91,7 @@ const TopicView = (props) => {
const userFound = users const userFound = users
.find((user) => user.id === userOrbitAddress); .find((user) => user.id === userOrbitAddress);
if (userFound) { if (!userFound) {
setTopicAuthorMeta(userFound);
} else {
dispatch({ dispatch({
type: FETCH_USER_DATABASE, type: FETCH_USER_DATABASE,
orbit, orbit,
@ -115,66 +115,43 @@ const TopicView = (props) => {
} }
}, [topicId, topics]); }, [topicId, topics]);
const stopClickPropagation = (event) => {
event.stopPropagation();
};
return ( return (
<Container id="topic-container" textAlign="center"> <Container id="topic-container" textAlign="center">
<Segment>
<Dimmer.Dimmable <Dimmer.Dimmable
blurring blurring
dimmed={topicAuthorAddress === null && topicAuthor === null && timestamp === null} dimmed={topicAuthorAddress === null && topicAuthor === null && timestamp === null}
> >
<Step.Group fluid> <Header as="h2">
<Step key="topic-header-step-user">
<Link to={`/users/${topicAuthorAddress}`}>
{topicAuthorMeta !== null && topicAuthorMeta[USER_PROFILE_PICTURE]
? (
<Image
avatar
src={topicAuthorMeta[USER_PROFILE_PICTURE]}
/>
)
: (
<Icon
name="user circle"
size="big"
inverted
color="black"
/>
)}
</Link>
<Step.Content>
<Step.Title>
<Link to={`/users/${topicAuthorAddress}`}>
{topicAuthor || (
<Placeholder id="author-placeholder" inverted>
<Placeholder.Line length="full" />
</Placeholder>
)}
</Link>
</Step.Title>
</Step.Content>
</Step>
<Step key="topic-header-step-title">
<Step.Content>
<Step.Title>
{topicSubject || ( {topicSubject || (
<Placeholder id="subject-placeholder"> <Placeholder id="subject-placeholder">
<Placeholder.Line length="full" /> <Placeholder.Line />
</Placeholder>
)}
</Step.Title>
<Step.Description>
{timestamp
? <TimeAgo date={timestamp} />
: (
<Placeholder id="date-placeholder">
<Placeholder.Line length="full" />
</Placeholder> </Placeholder>
)} )}
</Step.Description> </Header>
</Step.Content>
</Step> <div id="topic-metadata">
</Step.Group> <Icon name="calendar alternate" fitted />
&nbsp;
<TimeAgo date={timestamp} />
&nbsp;&nbsp;
<Icon name="user" fitted />
&nbsp;
<Link to={`/users/${topicAuthorAddress}`} onClick={stopClickPropagation}>{ topicAuthor }</Link>
&nbsp;&nbsp;
<Icon name="reply" fitted />
&nbsp;
{ numberOfReplies }
</div>
<Divider />
</Dimmer.Dimmable> </Dimmer.Dimmable>
<PostList postIds={postIds || []} loading={postIds === null} focusOnPost={focusOnPost} /> <PostList postIds={postIds || []} loading={postIds === null} focusOnPost={focusOnPost} />
</Segment>
{topicSubject !== null && postIds !== null && hasSignedUp && ( {topicSubject !== null && postIds !== null && hasSignedUp && (
<PostCreate <PostCreate
topicId={topicId} topicId={topicId}

6
packages/concordia-app/src/views/Topic/TopicView/styles.css

@ -6,12 +6,18 @@
height: 100%; height: 100%;
} }
#topic-metadata {
font-size: 0.8em;
color: rgba(0,0,0,.5);
}
#author-placeholder { #author-placeholder {
width: 150px !important; width: 150px !important;
} }
#subject-placeholder { #subject-placeholder {
width: 250px !important; width: 250px !important;
margin:auto;
} }
#date-placeholder { #date-placeholder {

Loading…
Cancel
Save