From 8aad624e92e522ffb124f9a9886b5d6f87564076 Mon Sep 17 00:00:00 2001 From: Apostolof Date: Sun, 15 Nov 2020 03:04:37 +0200 Subject: [PATCH] Init post list UI --- .../public/locales/en/translation.json | 8 +- .../components/PostList/PostListRow/index.jsx | 103 ++++++++++++++++++ .../PostList/PostListRow/styles.css | 8 ++ .../src/components/PostList/index.jsx | 70 ++++++++++++ .../src/components/PostList/styles.css | 3 + .../src/views/Topic/TopicView/index.jsx | 2 + 6 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 packages/concordia-app/src/components/PostList/PostListRow/index.jsx create mode 100644 packages/concordia-app/src/components/PostList/PostListRow/styles.css create mode 100644 packages/concordia-app/src/components/PostList/index.jsx create mode 100644 packages/concordia-app/src/components/PostList/styles.css diff --git a/packages/concordia-app/public/locales/en/translation.json b/packages/concordia-app/public/locales/en/translation.json index 107d60d..c4834b6 100644 --- a/packages/concordia-app/public/locales/en/translation.json +++ b/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}}" } \ No newline at end of file diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx new file mode 100644 index 0000000..b03d475 --- /dev/null +++ b/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(() => ( + + + + + + + {postSubject !== null + ? postSubject + : } + + + + {t('post.list.row.post.id', { id: postId })} + + + + + + + + {postAuthor !== null && timeAgo !== null + ? t('post.list.row.author.date', { author: postAuthor, timeAgo }) + : } + + + + + + ), [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); diff --git a/packages/concordia-app/src/components/PostList/PostListRow/styles.css b/packages/concordia-app/src/components/PostList/PostListRow/styles.css new file mode 100644 index 0000000..0058f79 --- /dev/null +++ b/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; +} diff --git a/packages/concordia-app/src/components/PostList/index.jsx b/packages/concordia-app/src/components/PostList/index.jsx new file mode 100644 index 0000000..d961233 --- /dev/null +++ b/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 ( + + ); + }); + }, [getPostCallHashes, loading, postIds]); + + return ( + + + {posts} + + ); +}; + +PostList.propTypes = { + postIds: PropTypes.arrayOf(PropTypes.number).isRequired, + loading: PropTypes.bool, +}; + +export default PostList; diff --git a/packages/concordia-app/src/components/PostList/styles.css b/packages/concordia-app/src/components/PostList/styles.css new file mode 100644 index 0000000..baf2856 --- /dev/null +++ b/packages/concordia-app/src/components/PostList/styles.css @@ -0,0 +1,3 @@ +#post-list{ + height: 100%; +} diff --git a/packages/concordia-app/src/views/Topic/TopicView/index.jsx b/packages/concordia-app/src/views/Topic/TopicView/index.jsx index abc9f89..c5e4687 100644 --- a/packages/concordia-app/src/views/Topic/TopicView/index.jsx +++ b/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) => { + ); };