Browse Source

Init topics list

develop
Apostolos Fanakis 4 years ago
parent
commit
6ae974f708
  1. 49
      packages/concordia-app/src/components/Placeholder/index.jsx
  2. 52
      packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx
  3. 79
      packages/concordia-app/src/components/TopicList/index.jsx
  4. 7
      packages/concordia-app/src/components/TopicList/styles.css
  5. 2
      packages/concordia-app/src/constants/PlaceholderTypes.js
  6. 19
      packages/concordia-app/src/views/Home/Board/index.jsx
  7. 5
      packages/concordia-app/src/views/Home/index.jsx
  8. 3
      packages/concordia-app/src/views/Home/styles.css
  9. 2
      packages/concordia-app/src/views/Topic/TopicView/index.jsx

49
packages/concordia-app/src/components/Placeholder/index.jsx

@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { List } from 'semantic-ui-react';
import { PLACEHOLDER_TYPE_POST, PLACEHOLDER_TYPE_TOPIC } from '../../constants/PlaceholderTypes';
const Placeholder = (props) => {
const { placeholderType, extra } = props;
switch (placeholderType) {
case PLACEHOLDER_TYPE_TOPIC:
return (
<>
<List.Header>
<List.Icon name="right triangle" />
topicSubject
</List.Header>
<List.Content>
username
Number of Replies
timestamp
</List.Content>
</>
);
case PLACEHOLDER_TYPE_POST:
return (
<div>LOADING POST</div>
);
default:
return <div />;
}
};
const TopicPlaceholderExtra = PropTypes.PropTypes.shape({
topicId: PropTypes.number.isRequired,
});
const PostPlaceholderExtra = PropTypes.PropTypes.shape({
postIndex: PropTypes.number.isRequired,
});
Placeholder.propTypes = {
placeholderType: PropTypes.string.isRequired,
extra: PropTypes.oneOfType([
TopicPlaceholderExtra.isRequired,
PostPlaceholderExtra.isRequired,
]),
};
export default Placeholder;

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

@ -0,0 +1,52 @@
import React, { useContext, useMemo } from 'react';
import { List } from 'semantic-ui-react';
import PropTypes from 'prop-types';
import AppContext from '../../AppContext';
const TopicListRow = (props) => {
const { topicData, topicId } = props;
const {
breeze: {
orbit: {
stores,
},
},
} = useContext(AppContext.Context);
const topicSubject = useMemo(() => {
const topicsDb = Object.values(stores).find((store) => store.dbname === 'topics');
return topicsDb.get(topicId);
}, [stores, topicId]);
return (
<>
<List.Header>
<List.Icon name="right triangle" />
{topicSubject && topicSubject.subject}
</List.Header>
<List.Content>
{topicData.username}
{topicData.numberOfReplies}
{' '}
replies
timestamp
</List.Content>
</>
);
};
const TopicData = PropTypes.PropTypes.shape({
userAddress: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
timestamp: PropTypes.string.isRequired,
numberOfReplies: PropTypes.number.isRequired,
});
TopicListRow.propTypes = {
topicData: TopicData.isRequired,
topicId: PropTypes.number.isRequired,
};
export default TopicListRow;

79
packages/concordia-app/src/components/TopicList/index.jsx

@ -0,0 +1,79 @@
import React, {
useCallback,
useContext, useEffect, useMemo, useState,
} from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { List } from 'semantic-ui-react';
import AppContext from '../AppContext';
import TopicListRow from './TopicListRow';
import { PLACEHOLDER_TYPE_TOPIC } from '../../constants/PlaceholderTypes';
import Placeholder from '../Placeholder';
import './styles.css';
import { useHistory } from 'react-router';
const TopicList = (props) => {
const { topicIds } = props;
const { drizzle: { contracts: { Forum: { methods: { getTopic } } } } } = useContext(AppContext.Context);
const [getTopicCallHashes, setGetTopicCallHashes] = useState([]);
const getTopicResults = useSelector((state) => state.contracts.Forum.getTopic);
const drizzleStatus = useSelector((state) => state.drizzleStatus);
const history = useHistory();
useEffect(() => {
// TODO: is the drizzleStatus check necessary?
if (drizzleStatus.initialized && !drizzleStatus.failed && getTopicCallHashes.length === 0) {
setGetTopicCallHashes(topicIds.map((topicId) => ({
id: topicId,
hash: getTopic.cacheCall(topicId),
})));
}
}, [drizzleStatus.failed, drizzleStatus.initialized, getTopic, getTopicCallHashes, topicIds]);
const handleTopicClick = useCallback((topicId) => {
history.push(`/topics/${topicId}`);
}, [history]);
const topics = useMemo(() => topicIds
.map((topicId) => {
const getTopicHash = getTopicCallHashes.find((getTopicCallHash) => getTopicCallHash.id === topicId);
if (getTopicHash && getTopicResults[getTopicHash.hash] !== undefined) {
const topicData = {
userAddress: getTopicResults[getTopicHash.hash].value[0],
username: getTopicResults[getTopicHash.hash].value[1],
timestamp: getTopicResults[getTopicHash.hash].value[2] * 1000,
numberOfReplies: getTopicResults[getTopicHash.hash].value[3].length,
};
return (
<List.Item key={topicId} className="list-item" name={topicId} onClick={() => handleTopicClick(topicId)}>
<TopicListRow
topicData={topicData}
topicId={topicId}
/>
</List.Item>
);
}
return (
<List.Item key={topicId} className="list-item" name={topicId} onClick={() => handleTopicClick(topicId)}>
<Placeholder
placeholderType={PLACEHOLDER_TYPE_TOPIC}
extra={{ topicId }}
/>
</List.Item>
);
}), [getTopicCallHashes, getTopicResults, handleTopicClick, topicIds]);
return (
<List selection divided id="topic-list" size="big">
{topics}
</List>
);
};
TopicList.propTypes = {
topicIds: PropTypes.arrayOf(PropTypes.number).isRequired,
};
export default TopicList;

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

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

2
packages/concordia-app/src/constants/PlaceholderTypes.js

@ -0,0 +1,2 @@
export const PLACEHOLDER_TYPE_TOPIC = 'PLACEHOLDER_TYPE_TOPIC';
export const PLACEHOLDER_TYPE_POST = 'PLACEHOLDER_TYPE_POST';

19
packages/concordia-app/src/views/Home/Board/index.jsx

@ -1,20 +1,19 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo } from 'react';
import { Header } from 'semantic-ui-react'; import { Header } from 'semantic-ui-react';
import _ from 'lodash'; import _ from 'lodash';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import TopicList from '../../../components/TopicList';
const Board = (props) => { const Board = (props) => {
const { numberOfTopics } = props; const { numberOfTopics } = props;
const userHasSignedUp = useSelector((state) => state.user.hasSignedUp); const userHasSignedUp = useSelector((state) => state.user.hasSignedUp);
const [topicIds, setTopicIds] = useState([]);
const { t } = useTranslation(); const { t } = useTranslation();
const boardContents = useMemo(() => { const boardContents = useMemo(() => {
if (numberOfTopics > 0) { if (numberOfTopics > 0) {
setTopicIds(_.range(0, numberOfTopics)); return (<TopicList topicIds={_.rangeRight(0, numberOfTopics)} />);
return (<div>TODO</div>);
} if (!userHasSignedUp) { } if (!userHasSignedUp) {
return ( return (
<div className="vertical-center-in-parent"> <div className="vertical-center-in-parent">
@ -40,11 +39,11 @@ const Board = (props) => {
); );
}, [numberOfTopics, userHasSignedUp, t]); }, [numberOfTopics, userHasSignedUp, t]);
return ( return (boardContents);
<div> };
{boardContents}
</div> Board.propTypes = {
); numberOfTopics: PropTypes.number.isRequired,
}; };
export default Board; export default Board;

5
packages/concordia-app/src/views/Home/index.jsx

@ -5,11 +5,12 @@ import { Container } from 'semantic-ui-react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import AppContext from '../../components/AppContext'; import AppContext from '../../components/AppContext';
import Board from './Board'; import Board from './Board';
import './styles.css';
const Home = () => { const Home = () => {
const getNumberOfTopicsResults = useSelector((state) => state.contracts.Forum.getNumberOfTopics);
const { drizzle: { contracts: { Forum: { methods: { getNumberOfTopics } } } } } = useContext(AppContext.Context); const { drizzle: { contracts: { Forum: { methods: { getNumberOfTopics } } } } } = useContext(AppContext.Context);
const [numberOfTopicsCallHash, setNumberOfTopicsCallHash] = useState(''); const [numberOfTopicsCallHash, setNumberOfTopicsCallHash] = useState('');
const getNumberOfTopicsResults = useSelector((state) => state.contracts.Forum.getNumberOfTopics);
useEffect(() => { useEffect(() => {
setNumberOfTopicsCallHash(getNumberOfTopics.cacheCall()); setNumberOfTopicsCallHash(getNumberOfTopics.cacheCall());
@ -21,7 +22,7 @@ const Home = () => {
[getNumberOfTopicsResults, numberOfTopicsCallHash]); [getNumberOfTopicsResults, numberOfTopicsCallHash]);
return ( return (
<Container textAlign="center"> <Container id="home-container" textAlign="center">
{numberOfTopics !== null && <Board numberOfTopics={numberOfTopics} />} {numberOfTopics !== null && <Board numberOfTopics={numberOfTopics} />}
</Container> </Container>
); );

3
packages/concordia-app/src/views/Home/styles.css

@ -0,0 +1,3 @@
#home-container {
height: 100%;
}

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

@ -12,7 +12,7 @@ const TopicView = (props) => {
}; };
TopicView.propTypes = { TopicView.propTypes = {
topicId: PropTypes.number, topicId: PropTypes.number.isRequired,
}; };
export default TopicView; export default TopicView;

Loading…
Cancel
Save