diff --git a/packages/concordia-app/package.json b/packages/concordia-app/package.json index afb2d22..cdb1b9c 100644 --- a/packages/concordia-app/package.json +++ b/packages/concordia-app/package.json @@ -34,6 +34,7 @@ "i18next-http-backend": "^1.0.21", "level": "~6.0.1", "lodash": "^4.17.20", + "moment": "^2.29.1", "orbit-db-identity-provider": "~0.3.1", "prop-types": "~15.7.2", "react": "~16.13.1", diff --git a/packages/concordia-app/public/locales/en/translation.json b/packages/concordia-app/public/locales/en/translation.json index c55754f..107d60d 100644 --- a/packages/concordia-app/public/locales/en/translation.json +++ b/packages/concordia-app/public/locales/en/translation.json @@ -19,5 +19,8 @@ "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.create.form.post.button": "Post", + "topic.list.row.author.date": "Posted 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/TopicList/TopicListRow/index.jsx b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx index fec1ce1..7f83bc3 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx @@ -1,34 +1,42 @@ import React, { memo, useEffect, useMemo, useState, } from 'react'; -import { List } from 'semantic-ui-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 TopicListRow = (props) => { - const { id: topicId, topicCallHash } = props; + const { id: topicId, topicCallHash, loading } = props; const getTopicResults = useSelector((state) => state.contracts.Forum.getTopic); const [numberOfReplies, setNumberOfReplies] = useState(null); const [username, setUsername] = useState(null); const [topicAuthor, setTopicAuthor] = useState(null); - const [timestamp, setTimestamp] = useState(null); + const [timeAgo, setTimeAgo] = useState(null); const [topicSubject, setTopicSubject] = useState(null); const userAddress = useSelector((state) => state.user.address); const topics = useSelector((state) => state.orbitData.topics); const dispatch = useDispatch(); + const history = useHistory(); + const { t } = useTranslation(); useEffect(() => { - if (topicCallHash && getTopicResults[topicCallHash] !== undefined) { + if (!loading && topicCallHash && getTopicResults[topicCallHash] !== undefined) { setTopicAuthor(getTopicResults[topicCallHash].value[0]); setUsername(getTopicResults[topicCallHash].value[1]); - setTimestamp(getTopicResults[topicCallHash].value[2] * 1000); + setTimeAgo(moment(getTopicResults[topicCallHash].value[2] * 1000).fromNow()); setNumberOfReplies(getTopicResults[topicCallHash].value[3].length); } - }, [getTopicResults, topicCallHash]); + }, [getTopicResults, loading, topicCallHash]); useEffect(() => { if (topicAuthor && userAddress !== topicAuthor) { @@ -45,30 +53,68 @@ const TopicListRow = (props) => { .find((topic) => topic.id === topicId); if (topicFound) { - setTopicSubject(topicFound); + setTopicSubject(topicFound.subject); } }, [topicId, topics]); - return useMemo(() => ( - <> - - - {topicSubject && topicSubject.subject} - - - {username} - {numberOfReplies} - {' '} - replies - {timestamp} - - - ), [topicSubject, username, numberOfReplies, timestamp]); + return useMemo(() => { + const handleTopicClick = () => { + history.push(`/topics/${topicId}`); + }; + + return ( + + + + + + + + + + {topicSubject !== null + ? topicSubject + : } + + + + {t('topic.list.row.topic.id', { id: topicId })} + + + + + + + + {username !== null && timeAgo !== null + ? t('topic.list.row.author.date', { author: username, timeAgo }) + : } + + + {numberOfReplies !== null + ? ( + + {t('topic.list.row.number.of.replies', { numberOfReplies })} + + ) + : } + + + + + + ); + }, [history, loading, numberOfReplies, t, timeAgo, topicId, topicSubject, username]); +}; + +TopicListRow.defaultProps = { + loading: false, }; TopicListRow.propTypes = { id: PropTypes.number.isRequired, - topicCallHash: PropTypes.string.isRequired, + topicCallHash: PropTypes.string, + loading: PropTypes.bool, }; TopicListRow.whyDidYouRender = true; diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css new file mode 100644 index 0000000..8e808b6 --- /dev/null +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css @@ -0,0 +1,8 @@ +.topic-metadata { + font-size: 12px !important; + font-weight: initial; +} + +.list-item { + text-align: start; +} diff --git a/packages/concordia-app/src/components/TopicList/index.jsx b/packages/concordia-app/src/components/TopicList/index.jsx index b7ac6c5..89786df 100644 --- a/packages/concordia-app/src/components/TopicList/index.jsx +++ b/packages/concordia-app/src/components/TopicList/index.jsx @@ -4,11 +4,7 @@ import React, { import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { List } from 'semantic-ui-react'; -import { useHistory } from 'react-router'; import TopicListRow from './TopicListRow'; -import { PLACEHOLDER_TYPE_TOPIC } from '../../constants/PlaceholderTypes'; -import Placeholder from '../Placeholder'; -import './styles.css'; import { drizzle } from '../../redux/store'; const { contracts: { Forum: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle; @@ -18,7 +14,6 @@ const TopicList = (props) => { const [getTopicCallHashes, setGetTopicCallHashes] = useState([]); const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized); const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed); - const history = useHistory(); useEffect(() => { if (drizzleInitialized && !drizzleInitializationFailed) { @@ -44,27 +39,15 @@ const TopicList = (props) => { .map((topicId) => { const topicHash = getTopicCallHashes.find((getTopicCallHash) => getTopicCallHash.id === topicId); - const handleTopicClick = () => { - history.push(`/topics/${topicId}`); - }; - - if (topicHash) { - return ( - - - - ); - } - return ( - handleTopicClick(topicId)}> - - + ); - }), [getTopicCallHashes, history, topicIds]); + }), [getTopicCallHashes, topicIds]); return ( diff --git a/packages/concordia-app/src/components/TopicList/styles.css b/packages/concordia-app/src/components/TopicList/styles.css index 5e461d1..ac3c53c 100644 --- a/packages/concordia-app/src/components/TopicList/styles.css +++ b/packages/concordia-app/src/components/TopicList/styles.css @@ -1,7 +1,3 @@ #topic-list{ height: 100%; } - -.list-item { - text-align: start; -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1a2a1ea..31f30d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11942,6 +11942,11 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" integrity sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA== +moment@^2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + mortice@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mortice/-/mortice-2.0.0.tgz#7be171409c2115561ba3fc035e4527f9082eefde"