Browse Source

Init post list UI

develop
Apostolos Fanakis 4 years ago
parent
commit
8aad624e92
  1. 8
      packages/concordia-app/public/locales/en/translation.json
  2. 103
      packages/concordia-app/src/components/PostList/PostListRow/index.jsx
  3. 8
      packages/concordia-app/src/components/PostList/PostListRow/styles.css
  4. 70
      packages/concordia-app/src/components/PostList/index.jsx
  5. 3
      packages/concordia-app/src/components/PostList/styles.css
  6. 2
      packages/concordia-app/src/views/Topic/TopicView/index.jsx

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

@ -2,6 +2,8 @@
"board.header.no.topics.message": "There are no topics yet!",
"board.sub.header.no.topics.guest": "Sign up and be the first to post.",
"board.sub.header.no.topics.user": "Be the first to post.",
"post.list.row.author.date": "Posted by {{author}}, {{timeAgo}}",
"post.list.row.post.id": "#{{id}}",
"register.card.header": "Sign Up",
"register.form.button.back": "Back",
"register.form.button.guest": "Continue as guest",
@ -15,12 +17,12 @@
"topbar.button.create.topic": "Create topic",
"topbar.button.profile": "Profile",
"topbar.button.register": "Sign Up",
"topic.create.form.subject.field.label": "Topic subject",
"topic.create.form.subject.field.placeholder": "Subject",
"topic.create.form.message.field.label": "First post message",
"topic.create.form.message.field.placeholder": "Message",
"topic.create.form.post.button": "Post",
"topic.list.row.author.date": "Posted by {{author}}, {{timeAgo}}",
"topic.create.form.subject.field.label": "Topic subject",
"topic.create.form.subject.field.placeholder": "Subject",
"topic.list.row.author.date": "Created by {{author}}, {{timeAgo}}",
"topic.list.row.number.of.replies": "{{numberOfReplies}} replies",
"topic.list.row.topic.id": "#{{id}}"
}

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

@ -0,0 +1,103 @@
import React, {
memo, useEffect, useMemo, useState,
} from 'react';
import {
Dimmer, Grid, List, Loader, Placeholder,
} from 'semantic-ui-react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import moment from 'moment';
import { useHistory } from 'react-router';
import { useDispatch, useSelector } from 'react-redux';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import { breeze } from '../../../redux/store';
import './styles.css';
const { orbit } = breeze;
const PostListRow = (props) => {
const { id: postId, postCallHash, loading } = props;
const getPostResults = useSelector((state) => state.contracts.Forum.getPost);
const [postAuthorAddress, setPostAuthorAddress] = useState(null);
const [postAuthor, setPostAuthor] = useState(null);
const [timeAgo, setTimeAgo] = useState(null);
const [postSubject, setPostSubject] = useState(null);
const [postMessage, setPostMessage] = useState(null);
const userAddress = useSelector((state) => state.user.address);
const posts = useSelector((state) => state.orbitData.posts);
const dispatch = useDispatch();
const history = useHistory();
const { t } = useTranslation();
useEffect(() => {
if (!loading && postCallHash && getPostResults[postCallHash] !== undefined) {
setPostAuthorAddress(getPostResults[postCallHash].value[0]);
setPostAuthor(getPostResults[postCallHash].value[1]);
setTimeAgo(moment(getPostResults[postCallHash].value[2] * 1000).fromNow());
}
}, [getPostResults, loading, postCallHash]);
useEffect(() => {
if (postAuthorAddress && userAddress !== postAuthorAddress) {
dispatch({
type: FETCH_USER_DATABASE,
orbit,
dbName: 'posts',
userAddress: postAuthorAddress,
});
}
}, [dispatch, postAuthorAddress, userAddress]);
useEffect(() => {
const postFound = posts
.find((post) => post.id === postId);
if (postFound) {
setPostSubject(postFound.subject);
setPostMessage(postFound.message);
}
}, [postId, posts]);
return useMemo(() => (
<Dimmer.Dimmable as={List.Item} blurring dimmed={loading} className="list-item">
<List.Icon name="user circle" size="big" inverted color="black" verticalAlign="middle" />
<List.Content>
<List.Header>
<Grid>
<Grid.Column floated="left" width={14}>
{postSubject !== null
? postSubject
: <Placeholder><Placeholder.Line length="very long" /></Placeholder>}
</Grid.Column>
<Grid.Column floated="right" width={2} textAlign="right">
<span className="post-metadata">
{t('post.list.row.post.id', { id: postId })}
</span>
</Grid.Column>
</Grid>
</List.Header>
<List.Description>
<Grid verticalAlign="middle">
<Grid.Column floated="left" width={14}>
{postAuthor !== null && timeAgo !== null
? t('post.list.row.author.date', { author: postAuthor, timeAgo })
: <Placeholder><Placeholder.Line length="long" /></Placeholder>}
</Grid.Column>
</Grid>
</List.Description>
</List.Content>
</Dimmer.Dimmable>
), [loading, postAuthor, postId, postSubject, t, timeAgo]);
};
PostListRow.defaultProps = {
loading: false,
};
PostListRow.propTypes = {
id: PropTypes.number.isRequired,
postCallHash: PropTypes.string,
loading: PropTypes.bool,
};
export default memo(PostListRow);

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

@ -0,0 +1,8 @@
.post-metadata {
font-size: 12px !important;
font-weight: initial;
}
.list-item {
text-align: start;
}

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

@ -0,0 +1,70 @@
import React, {
useEffect, useMemo, useState,
} from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { Dimmer, List, Loader } from 'semantic-ui-react';
import PostListRow from './PostListRow';
import { drizzle } from '../../redux/store';
const { contracts: { Forum: { methods: { getPost: { cacheCall: getPostChainData } } } } } = drizzle;
const PostList = (props) => {
const { postIds, loading } = props;
const [getPostCallHashes, setGetPostCallHashes] = useState([]);
const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized);
const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed);
useEffect(() => {
if (drizzleInitialized && !drizzleInitializationFailed && !loading) {
const newPostsFound = postIds
.filter((postId) => !getPostCallHashes
.map((getPostCallHash) => getPostCallHash.id)
.includes(postId));
if (newPostsFound.length > 0) {
setGetPostCallHashes([
...getPostCallHashes,
...newPostsFound
.map((postId) => ({
id: postId,
hash: getPostChainData(postId),
})),
]);
}
}
}, [drizzleInitializationFailed, drizzleInitialized, getPostCallHashes, loading, postIds]);
const posts = useMemo(() => {
if (loading) {
return null;
}
return postIds
.map((postId) => {
const postHash = getPostCallHashes.find((getPostCallHash) => getPostCallHash.id === postId);
return (
<PostListRow
id={postId}
key={postId}
postCallHash={postHash && postHash.hash}
loading={postHash === undefined}
/>
);
});
}, [getPostCallHashes, loading, postIds]);
return (
<Dimmer.Dimmable as={List} blurring dimmed={loading} selection divided id="post-list" size="big">
<Loader active={loading} />
{posts}
</Dimmer.Dimmable>
);
};
PostList.propTypes = {
postIds: PropTypes.arrayOf(PropTypes.number).isRequired,
loading: PropTypes.bool,
};
export default PostList;

3
packages/concordia-app/src/components/PostList/styles.css

@ -0,0 +1,3 @@
#post-list{
height: 100%;
}

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

@ -8,6 +8,7 @@ import moment from 'moment';
import { breeze, drizzle } from '../../../redux/store';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import './styles.css';
import PostList from '../../../components/PostList';
const { contracts: { Forum: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle;
const { orbit } = breeze;
@ -115,6 +116,7 @@ const TopicView = (props) => {
</Step>
</Step.Group>
</Dimmer.Dimmable>
<PostList postIds={postIds || []} loading={postIds === null} />
</Container>
);
};

Loading…
Cancel
Save