Browse Source

Improve topics list UI

develop
Apostolos Fanakis 4 years ago
parent
commit
a17b316845
  1. 1
      packages/concordia-app/package.json
  2. 5
      packages/concordia-app/public/locales/en/translation.json
  3. 92
      packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
  4. 8
      packages/concordia-app/src/components/TopicList/TopicListRow/styles.css
  5. 31
      packages/concordia-app/src/components/TopicList/index.jsx
  6. 4
      packages/concordia-app/src/components/TopicList/styles.css
  7. 5
      yarn.lock

1
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",

5
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}}"
}

92
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(() => (
<>
<List.Header>
<List.Icon name="right triangle" />
{topicSubject && topicSubject.subject}
</List.Header>
<List.Content>
{username}
{numberOfReplies}
{' '}
replies
{timestamp}
</List.Content>
</>
), [topicSubject, username, numberOfReplies, timestamp]);
return useMemo(() => {
const handleTopicClick = () => {
history.push(`/topics/${topicId}`);
};
return (
<Dimmer.Dimmable as={List.Item} onClick={handleTopicClick} blurring dimmed={loading} className="list-item">
<Dimmer>
<Loader />
</Dimmer>
<List.Icon name="user circle" size="big" inverted color="black" verticalAlign="middle" />
<List.Content>
<List.Header>
<Grid>
<Grid.Column floated="left" width={14}>
{topicSubject !== null
? topicSubject
: <Placeholder><Placeholder.Line length="very long" /></Placeholder>}
</Grid.Column>
<Grid.Column floated="right" width={2} textAlign="right">
<span className="topic-metadata">
{t('topic.list.row.topic.id', { id: topicId })}
</span>
</Grid.Column>
</Grid>
</List.Header>
<List.Description>
<Grid verticalAlign="middle">
<Grid.Column floated="left" width={14}>
{username !== null && timeAgo !== null
? t('topic.list.row.author.date', { author: username, timeAgo })
: <Placeholder><Placeholder.Line length="long" /></Placeholder>}
</Grid.Column>
<Grid.Column floated="right" width={2} textAlign="right">
{numberOfReplies !== null
? (
<span className="topic-metadata">
{t('topic.list.row.number.of.replies', { numberOfReplies })}
</span>
)
: <Placeholder fluid><Placeholder.Line /></Placeholder>}
</Grid.Column>
</Grid>
</List.Description>
</List.Content>
</Dimmer.Dimmable>
);
}, [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;

8
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;
}

31
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 (
<List.Item key={topicId} className="list-item" name={topicId} onClick={handleTopicClick}>
<TopicListRow id={topicId} topicCallHash={topicHash.hash} />
</List.Item>
);
}
return (
<List.Item key={topicId} className="list-item" name={topicId} onClick={() => handleTopicClick(topicId)}>
<Placeholder
placeholderType={PLACEHOLDER_TYPE_TOPIC}
extra={{ topicId }}
/>
</List.Item>
<TopicListRow
id={topicId}
key={topicId}
topicCallHash={topicHash && topicHash.hash}
loading={topicHash === undefined}
/>
);
}), [getTopicCallHashes, history, topicIds]);
}), [getTopicCallHashes, topicIds]);
return (
<List selection divided id="topic-list" size="big">

4
packages/concordia-app/src/components/TopicList/styles.css

@ -1,7 +1,3 @@
#topic-list{
height: 100%;
}
.list-item {
text-align: start;
}

5
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"

Loading…
Cancel
Save