Browse Source

feat: add pagination to home screen topic list

develop
Ezerous 4 years ago
parent
commit
d8c33ec522
  1. 63
      packages/concordia-app/src/components/Pagination/PaginatedTopicList/index.jsx
  2. 4
      packages/concordia-app/src/components/Pagination/PaginatedTopicList/styles.css
  3. 23
      packages/concordia-app/src/components/Pagination/index.jsx
  4. 16
      packages/concordia-app/src/components/TopicList/index.jsx
  5. 8
      packages/concordia-app/src/views/Home/Board/index.jsx
  6. 2
      packages/concordia-contracts/.solhint.json
  7. 5
      packages/concordia-contracts/contracts/Forum.sol
  8. 2
      packages/concordia-contracts/contracts/Migrations.sol
  9. 2
      packages/concordia-contracts/contracts/PostVoting.sol
  10. 2
      packages/concordia-contracts/contracts/Voting.sol
  11. 2
      packages/concordia-contracts/package.json
  12. 2
      packages/concordia-contracts/test/TestVoting.sol
  13. 2
      packages/concordia-contracts/truffle-config.js
  14. 1147
      yarn.lock

63
packages/concordia-app/src/components/Pagination/PaginatedTopicList/index.jsx

@ -0,0 +1,63 @@
import React, {
useEffect, useMemo, useState,
} from 'react';
import { useSelector } from 'react-redux';
import _ from 'lodash';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { drizzle } from '../../../redux/store';
import TopicList from '../../TopicList';
import PaginationComponent, { ITEMS_PER_PAGE } from '../index';
import './styles.css';
const {
contracts: {
[FORUM_CONTRACT]: {
methods: {
numTopics: { cacheCall: numTopicsChainData },
},
},
},
} = drizzle;
const PaginatedTopicList = () => {
const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized);
const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed);
const [pageNumber, setPageNumber] = useState(1);
const [numTopics, setNumTopics] = useState(null);
const [topicIds, setTopicIds] = useState([]);
const [numTopicsCallHash, setNumTopicsCallHash] = useState(null);
const numTopicsResult = useSelector((state) => state.contracts[FORUM_CONTRACT].numTopics[numTopicsCallHash]);
useEffect(() => {
if (drizzleInitialized && !drizzleInitializationFailed && numTopicsCallHash === null) {
setNumTopicsCallHash(numTopicsChainData());
}
}, [drizzleInitializationFailed, drizzleInitialized, numTopicsCallHash]);
useEffect(() => {
if (drizzleInitialized && !drizzleInitializationFailed && numTopics !== null) {
setTopicIds(_.rangeRight(Math.max(numTopics - ITEMS_PER_PAGE * pageNumber, 0),
numTopics - ITEMS_PER_PAGE * (pageNumber - 1)));
}
}, [pageNumber, drizzleInitializationFailed, drizzleInitialized, numTopics]);
useEffect(() => {
if (numTopicsResult) {
setNumTopics(numTopicsResult.value);
}
}, [numTopicsResult]);
const handlePageChange = (event, data) => {
setPageNumber(data.activePage);
};
return useMemo(() => (
<div id="paginated-topic-list">
<TopicList topicIds={topicIds} />
<PaginationComponent onPageChange={handlePageChange} numberOfItems={numTopics} />
</div>
), [numTopics, topicIds]);
};
export default PaginatedTopicList;

4
packages/concordia-app/src/components/Pagination/PaginatedTopicList/styles.css

@ -0,0 +1,4 @@
#topic-list{
height: auto;
clear: both;
}

23
packages/concordia-app/src/components/Pagination/index.jsx

@ -0,0 +1,23 @@
import React, { useMemo } from 'react';
import { Icon, Pagination } from 'semantic-ui-react';
export const ITEMS_PER_PAGE = 10;
const PaginationComponent = (props) => {
const { numberOfItems, onPageChange } = props;
return useMemo(() => (
<Pagination
defaultActivePage={1}
ellipsisItem={{ content: <Icon name="ellipsis horizontal" />, icon: true }}
firstItem={{ content: <Icon name="angle double left" />, icon: true }}
lastItem={{ content: <Icon name="angle double right" />, icon: true }}
prevItem={{ content: <Icon name="angle left" />, icon: true }}
nextItem={{ content: <Icon name="angle right" />, icon: true }}
totalPages={Math.ceil(numberOfItems / ITEMS_PER_PAGE)}
disabled={numberOfItems <= ITEMS_PER_PAGE}
onPageChange={onPageChange}
/>
), [numberOfItems, onPageChange]);
};
export default PaginationComponent;

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

@ -19,23 +19,15 @@ const TopicList = (props) => {
useEffect(() => { useEffect(() => {
if (drizzleInitialized && !drizzleInitializationFailed) { if (drizzleInitialized && !drizzleInitializationFailed) {
const newTopicsFound = topicIds setGetTopicCallHashes(
.filter((topicId) => !getTopicCallHashes topicIds
.map((getTopicCallHash) => getTopicCallHash.id)
.includes(topicId));
if (newTopicsFound.length > 0) {
setGetTopicCallHashes([
...getTopicCallHashes,
...newTopicsFound
.map((topicId) => ({ .map((topicId) => ({
id: topicId, id: topicId,
hash: getTopicChainData(topicId), hash: getTopicChainData(topicId),
})), })),
]); );
}
} }
}, [drizzleInitializationFailed, drizzleInitialized, getTopicCallHashes, topicIds]); }, [drizzleInitializationFailed, drizzleInitialized, topicIds]);
const topics = useMemo(() => topicIds const topics = useMemo(() => topicIds
.map((topicId) => { .map((topicId) => {

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

@ -2,12 +2,9 @@ import React, { useMemo } from 'react';
import { Button, Header } from 'semantic-ui-react'; import { Button, Header } from 'semantic-ui-react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import _ from 'lodash';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import PaginatedTopicList from '../../../components/Pagination/PaginatedTopicList';
import TopicList from '../../../components/TopicList';
import './styles.css'; import './styles.css';
const Board = (props) => { const Board = (props) => {
@ -33,7 +30,8 @@ const Board = (props) => {
: null} : null}
{/* eslint-disable-next-line no-nested-ternary */} {/* eslint-disable-next-line no-nested-ternary */}
{numberOfTopics > 0 {numberOfTopics > 0
? (<TopicList topicIds={_.rangeRight(0, numberOfTopics)} />) // eslint-disable-next-line react/jsx-no-undef
? (<PaginatedTopicList />)
: (!hasSignedUp : (!hasSignedUp
? ( ? (
<div id="no-topic-message" className="vertical-center-in-parent unselectable"> <div id="no-topic-message" className="vertical-center-in-parent unselectable">

2
packages/concordia-contracts/.solhint.json

@ -1,7 +1,7 @@
{ {
"extends": "solhint:recommended", "extends": "solhint:recommended",
"rules": { "rules": {
"compiler-version": ["error","~0.8.0"], "compiler-version": ["error","~0.8.1"],
"func-visibility": ["warn",{"ignoreConstructors" : true}], "func-visibility": ["warn",{"ignoreConstructors" : true}],
"not-rely-on-time": "off", "not-rely-on-time": "off",
"state-visibility": "off" "state-visibility": "off"

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

@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.0; pragma solidity 0.8.1;
contract Forum { contract Forum {
// Error messages for require() // Error messages for require()
@ -17,6 +17,8 @@ contract Forum {
bool signedUp; // Helper variable for hasUserSignedUp() bool signedUp; // Helper variable for hasUserSignedUp()
} }
uint public numUsers; // Total number of users
mapping(address => User) users; mapping(address => User) users;
mapping(string => address) usernameAddresses; mapping(string => address) usernameAddresses;
address[] userAddresses; address[] userAddresses;
@ -30,6 +32,7 @@ contract Forum {
users[msg.sender] = User(username, new uint[](0), new uint[](0), block.timestamp, true); users[msg.sender] = User(username, new uint[](0), new uint[](0), block.timestamp, true);
usernameAddresses[username] = msg.sender; usernameAddresses[username] = msg.sender;
userAddresses.push(msg.sender); userAddresses.push(msg.sender);
numUsers++;
emit UserSignedUp(username, msg.sender); emit UserSignedUp(username, msg.sender);
return true; return true;
} }

2
packages/concordia-contracts/contracts/Migrations.sol

@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.0; pragma solidity 0.8.1;
contract Migrations { contract Migrations {
address public owner; address public owner;

2
packages/concordia-contracts/contracts/PostVoting.sol

@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.0; pragma solidity 0.8.1;
import "./Forum.sol"; import "./Forum.sol";

2
packages/concordia-contracts/contracts/Voting.sol

@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.0; pragma solidity 0.8.1;
import "./Forum.sol"; import "./Forum.sol";

2
packages/concordia-contracts/package.json

@ -21,7 +21,7 @@
"dependencies": { "dependencies": {
"@openzeppelin/contracts": "~3.3.0", "@openzeppelin/contracts": "~3.3.0",
"concordia-shared": "~0.1.0", "concordia-shared": "~0.1.0",
"truffle": "~5.1.58", "truffle": "5.1.65",
"unirest": "^0.6.0" "unirest": "^0.6.0"
}, },
"devDependencies": { "devDependencies": {

2
packages/concordia-contracts/test/TestVoting.sol

@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.0; pragma solidity 0.8.1;
import "truffle/Assert.sol"; import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol"; import "truffle/DeployedAddresses.sol";

2
packages/concordia-contracts/truffle-config.js

@ -7,7 +7,7 @@ module.exports = {
// to customize your Truffle configuration! // to customize your Truffle configuration!
compilers: { compilers: {
solc: { solc: {
version: '0.8.0', version: '0.8.1',
}, },
}, },
contracts_build_directory: path.join(__dirname, 'build/'), contracts_build_directory: path.join(__dirname, 'build/'),

1147
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save