Browse Source

feat: add pagination to topic's posts

develop
Ezerous 4 years ago
parent
commit
b93ca37b86
  1. 4
      packages/concordia-app/src/components/PostList/index.jsx
  2. 82
      packages/concordia-app/src/views/Topic/TopicView/TopicPostList/index.jsx
  3. 12
      packages/concordia-app/src/views/Topic/TopicView/index.jsx
  4. 1
      packages/concordia-app/src/views/Topic/TopicView/styles.css
  5. 17
      packages/concordia-contracts/contracts/Forum.sol

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

@ -51,11 +51,13 @@ const PostList = (props) => {
}, [focusOnPost, getPostCallHashes, loading, postIds]); }, [focusOnPost, getPostCallHashes, loading, postIds]);
return ( return (
<>
<Dimmer.Dimmable as={Feed} blurring dimmed={loading} id="post-list" size="large"> <Dimmer.Dimmable as={Feed} blurring dimmed={loading} id="post-list" size="large">
<Loader active={loading} /> <Loader active={loading} />
{posts} {posts}
<PaginationComponent onPageChange={onPageChange} numberOfItems={numberOfItems} />
</Dimmer.Dimmable> </Dimmer.Dimmable>
<PaginationComponent onPageChange={onPageChange} numberOfItems={numberOfItems} />
</>
); );
}; };

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

@ -0,0 +1,82 @@
import React, {
useEffect, useMemo, useState,
} from 'react';
import { useSelector } from 'react-redux';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import PostList from '../../../../components/PostList';
import { ITEMS_PER_PAGE } from '../../../../components/PaginationComponent';
import { drizzle } from '../../../../redux/store';
const {
contracts: {
[FORUM_CONTRACT]: {
methods: {
getTopicPostCount: { cacheCall: getTopicPostCountChainData },
getTopicPosts: { cacheCall: getTopicPostsChainData },
},
},
},
} = drizzle;
const TopicPostList = (props) => {
const {
topicId, loading, focusOnPost,
} = props;
const [pageNumber, setPageNumber] = useState(1);
const [topicPostCount, setTopicPostCount] = useState(null);
const [postIds, setPostIds] = useState([]);
const [getTopicPostCountCallHash, setGetTopicPostCountCallHash] = useState(null);
const [getTopicPostsCallHash, setGetTopicPostsCallHash] = useState(null);
const getTopicPostCountResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopicPostCount[getTopicPostCountCallHash]);
const getTopicPostsResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopicPosts[getTopicPostsCallHash]);
useEffect(() => {
if (getTopicPostCountCallHash === null) {
setGetTopicPostCountCallHash(getTopicPostCountChainData(topicId));
}
}, [getTopicPostCountCallHash, topicId]);
useEffect(() => {
if (topicPostCount !== null && topicPostCount !== 0) {
const startIndex = Math.max(topicPostCount - ITEMS_PER_PAGE * pageNumber, 0);
const endIndex = topicPostCount - ITEMS_PER_PAGE * (pageNumber - 1) - 1;
setGetTopicPostsCallHash(getTopicPostsChainData(topicId, startIndex, endIndex));
}
}, [pageNumber, topicId, topicPostCount]);
useEffect(() => {
if (getTopicPostCountResult) {
setTopicPostCount(parseInt(getTopicPostCountResult.value, 10));
}
}, [getTopicPostCountResult, topicPostCount]);
useEffect(() => {
if (getTopicPostsResult) {
setPostIds(getTopicPostsResult.value.slice().reverse().map(Number));
}
}, [getTopicPostsResult, topicPostCount]);
const handlePageChange = (event, data) => {
setPageNumber(data.activePage);
};
return useMemo(() => {
if (postIds.length && postIds.length !== 0) {
return (
<PostList
postIds={postIds}
numberOfItems={topicPostCount}
onPageChange={handlePageChange}
loading={loading}
focusOnPost={focusOnPost}
/>
);
}
return null;
}, [postIds, topicPostCount, loading, focusOnPost]);
};
export default TopicPostList;

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

@ -11,7 +11,7 @@ import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/o
import { breeze, drizzle } from '../../../redux/store'; import { breeze, drizzle } from '../../../redux/store';
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions';
import './styles.css'; import './styles.css';
import PostList from '../../../components/PostList'; import TopicPostList from './TopicPostList';
import determineKVAddress from '../../../utils/orbitUtils'; import determineKVAddress from '../../../utils/orbitUtils';
import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys'; import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys';
import PostCreate from '../../../components/PostCreate'; import PostCreate from '../../../components/PostCreate';
@ -24,8 +24,6 @@ const TopicView = (props) => {
topicId, topicAuthorAddress: initialTopicAuthorAddress, topicAuthor: initialTopicAuthor, topicId, topicAuthorAddress: initialTopicAuthorAddress, topicAuthor: initialTopicAuthor,
timestamp: initialTimestamp, postIds: initialPostIds, focusOnPost, timestamp: initialTimestamp, postIds: initialPostIds, focusOnPost,
} = props; } = props;
const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized);
const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed);
const userAddress = useSelector((state) => state.user.address); const userAddress = useSelector((state) => state.user.address);
const hasSignedUp = useSelector((state) => state.user.hasSignedUp); const hasSignedUp = useSelector((state) => state.user.hasSignedUp);
const getTopicResults = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopic); const getTopicResults = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopic);
@ -47,12 +45,10 @@ const TopicView = (props) => {
|| timestamp === null || timestamp === null
|| postIds === null; || postIds === null;
if (drizzleInitialized && !drizzleInitializationFailed && shouldGetTopicDataFromChain) { if (shouldGetTopicDataFromChain) {
setGetTopicCallHash(getTopicChainData(topicId)); setGetTopicCallHash(getTopicChainData(topicId));
} }
}, [ }, [postIds, timestamp, topicAuthor, topicAuthorAddress, topicId]);
drizzleInitializationFailed, drizzleInitialized, postIds, timestamp, topicAuthor, topicAuthorAddress, topicId,
]);
useEffect(() => { useEffect(() => {
if (getTopicCallHash && getTopicResults && getTopicResults[getTopicCallHash]) { if (getTopicCallHash && getTopicResults && getTopicResults[getTopicCallHash]) {
@ -149,7 +145,7 @@ const TopicView = (props) => {
</div> </div>
<Divider /> <Divider />
</Dimmer.Dimmable> </Dimmer.Dimmable>
<PostList postIds={postIds || []} loading={postIds === null} focusOnPost={focusOnPost} /> <TopicPostList topicId={topicId} loading={postIds === null} focusOnPost={focusOnPost} />
</Segment> </Segment>
{topicSubject !== null && postIds !== null && hasSignedUp && ( {topicSubject !== null && postIds !== null && hasSignedUp && (

1
packages/concordia-app/src/views/Topic/TopicView/styles.css

@ -1,5 +1,6 @@
#topic-container { #topic-container {
height: auto !important; height: auto !important;
text-align: center;
} }
#topic-header { #topic-header {

17
packages/concordia-contracts/contracts/Forum.sol

@ -188,9 +188,22 @@ contract Forum {
); );
} }
function getTopicPosts(uint topicID) public view returns (uint[] memory) { function getTopicPostCount(uint topicID) public view returns (uint) {
require(topicExists(topicID), TOPIC_DOES_NOT_EXIST); require(topicExists(topicID), TOPIC_DOES_NOT_EXIST);
return topics[topicID].postIDs; return topics[topicID].postIDs.length;
}
function getTopicPosts(uint topicID, uint startIndex, uint endIndex) public view returns (uint[] memory) {
require(topicExists(topicID), TOPIC_DOES_NOT_EXIST);
require(startIndex <= endIndex && topics[topicID].postIDs.length > endIndex, INVALID_RANGE);
uint length = endIndex - startIndex + 1;
uint[] memory topicPosts = new uint[](length);
uint counter = 0;
for (uint i = startIndex; i <= endIndex; i++) {
topicPosts[counter] = topics[topicID].postIDs[i];
counter++;
}
return topicPosts;
} }
function getTopicAuthor(uint topicID) public view returns (address) { function getTopicAuthor(uint topicID) public view returns (address) {

Loading…
Cancel
Save