From 50d3b33bc2853fdb008e659f48aeda57998d4b0a Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 25 Jan 2021 20:30:48 +0200 Subject: [PATCH 01/17] Homescreen improvements --- packages/concordia-app/package.json | 2 +- .../public/locales/en/translation.json | 3 +- .../src/components/LoadingScreen.jsx | 5 +- .../TopicList/TopicListRow/index.jsx | 115 +++++++++--------- .../TopicList/TopicListRow/styles.css | 56 ++++++--- .../src/components/TopicList/index.jsx | 24 +++- .../src/components/TopicList/styles.css | 8 ++ .../MainLayout/MainLayoutMenu/index.jsx | 11 -- .../MainLayout/MainLayoutMenu/styles.css | 2 +- yarn.lock | 102 ++++++++-------- 10 files changed, 183 insertions(+), 145 deletions(-) diff --git a/packages/concordia-app/package.json b/packages/concordia-app/package.json index bbe624a..0cc2aeb 100644 --- a/packages/concordia-app/package.json +++ b/packages/concordia-app/package.json @@ -47,7 +47,7 @@ "react-timeago": "~5.2.0", "redux-saga": "~1.1.3", "semantic-ui-css": "~2.4.1", - "semantic-ui-react": "~1.2.1", + "semantic-ui-react": "~2.0.3", "web3": "~1.3.3" }, "devDependencies": { diff --git a/packages/concordia-app/public/locales/en/translation.json b/packages/concordia-app/public/locales/en/translation.json index 33a1c4d..e9c42a5 100644 --- a/packages/concordia-app/public/locales/en/translation.json +++ b/packages/concordia-app/public/locales/en/translation.json @@ -72,11 +72,10 @@ "topic.create.form.post.button": "Post", "topic.create.form.subject.field.label": "Topic subject", "topic.create.form.subject.field.placeholder": "Subject", - "topic.list.row.author": "by {{author}}", "topic.list.row.number.of.replies": "{{numberOfReplies}} replies", "topic.list.row.topic.id": "#{{id}}", "username.selector.error.username.empty.message": "Username is required", "username.selector.error.username.taken.message": "The username {{username}} is already taken.", "username.selector.username.field.label": "Username", "username.selector.username.field.placeholder": "Username" -} \ No newline at end of file +} diff --git a/packages/concordia-app/src/components/LoadingScreen.jsx b/packages/concordia-app/src/components/LoadingScreen.jsx index da719f1..a24d278 100644 --- a/packages/concordia-app/src/components/LoadingScreen.jsx +++ b/packages/concordia-app/src/components/LoadingScreen.jsx @@ -1,9 +1,8 @@ import React from 'react'; +import { Loader } from 'semantic-ui-react'; const LoadingScreen = () => ( -
- Loading -
+ ); export default LoadingScreen; diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx index fd96bf4..e70c0a4 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx @@ -2,12 +2,11 @@ import React, { memo, useEffect, useMemo, useState, } from 'react'; import { - Dimmer, Grid, Image, List, Placeholder, + Dimmer, Grid, Image, Item, List, Placeholder, Segment, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import TimeAgo from 'react-timeago'; -import { useHistory } from 'react-router'; import { useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; @@ -34,7 +33,6 @@ const TopicListRow = (props) => { const topics = useSelector((state) => state.orbitData.topics); const users = useSelector((state) => state.orbitData.users); const dispatch = useDispatch(); - const history = useHistory(); const { t } = useTranslation(); useEffect(() => { @@ -98,7 +96,6 @@ const TopicListRow = (props) => { ? ( ) @@ -124,57 +121,65 @@ const TopicListRow = (props) => { return authorAvatar; }, [authorAvatar, topicAuthorAddress]); - return useMemo(() => { - const handleTopicClick = () => { - history.push(`/topics/${topicId}`); - }; - - return ( - - {authorAvatarLink} - - - - - {topicSubject !== null - ? topicSubject - : } - - - - {t('topic.list.row.topic.id', { id: topicId })} - - - - - - - - {topicAuthor !== null && timeAgo !== null - ? ( -
- {t('topic.list.row.author', { author: topicAuthor })} - ,  - -
- ) - : } -
- - {numberOfReplies !== null - ? ( - - {t('topic.list.row.number.of.replies', { numberOfReplies })} - - ) - : } - -
-
-
-
- ); - }, [authorAvatarLink, history, loading, numberOfReplies, t, timeAgo, topicAuthor, topicId, topicSubject]); + return useMemo(() => ( + + + + + + {authorAvatarLink} + + + + + + + + {topicSubject !== null + ? topicSubject + : } + + + + {t('topic.list.row.topic.id', { id: topicId })} + + + + + + {topicAuthor !== null && timeAgo !== null + ? ( +
+ +  •  + + {topicAuthor} + +
+ ) + : } +
+ + {numberOfReplies !== null + ? ( + + {t('topic.list.row.number.of.replies', { numberOfReplies })} + + ) + : } + +
+
+ + +
+
+ +
+ +
+ + ), [authorAvatarLink, loading, numberOfReplies, t, timeAgo, topicAuthor, topicAuthorAddress, topicId, topicSubject]); }; TopicListRow.defaultProps = { diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css index 6f92675..e520ff8 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css @@ -1,21 +1,49 @@ -.topic-metadata { - font-size: 12px !important; - font-weight: initial; -} - -.list-item { +.topic-row { display: flex !important; text-align: start; } -.profile-picture { - cursor: pointer; - max-width: 36px; - max-height: 36px; - margin: 0; - vertical-align: middle; +.topic-row-segment { + flex-grow: 1; } -.list-content { - flex-grow: 1; +.topic-row-segment:hover { + background-color: rgba(0, 0, 0, 0.03); +} + +.topic-row-segment div { + color: black; +} + +.topic-row-avatar { + margin: auto; + padding-left: 0.75em !important; + padding-right: 0 !important; + font-size: 2em; +} + +.topic-row-avatar i { + text-align: left !important; + margin:0; +} + +.topic-row-content { + padding-left: 2em !important; +} + +.topic-row-subject { + font-size: 1.25em; + font-weight: bold; +} + +.topic-row-metadata { + font-size: 12px !important; + font-weight: initial; +} + +.profile-picture { + border-radius: 50%; + max-width: none !important; + width: 2em; + height: 2em; } diff --git a/packages/concordia-app/src/components/TopicList/index.jsx b/packages/concordia-app/src/components/TopicList/index.jsx index 8a85f4e..ee53b99 100644 --- a/packages/concordia-app/src/components/TopicList/index.jsx +++ b/packages/concordia-app/src/components/TopicList/index.jsx @@ -3,10 +3,12 @@ import React, { } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; -import { List } from 'semantic-ui-react'; +import { useHistory } from 'react-router'; +import { Button, List } from 'semantic-ui-react'; import TopicListRow from './TopicListRow'; import { drizzle } from '../../redux/store'; import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames'; +import './styles.css'; const { contracts: { [FORUM_CONTRACT]: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle; @@ -15,6 +17,8 @@ const TopicList = (props) => { const [getTopicCallHashes, setGetTopicCallHashes] = useState([]); const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized); const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed); + const hasSignedUp = useSelector((state) => state.user.hasSignedUp); + const history = useHistory(); useEffect(() => { if (drizzleInitialized && !drizzleInitializationFailed) { @@ -51,9 +55,21 @@ const TopicList = (props) => { }), [getTopicCallHashes, topicIds]); return ( - - {topics} - +
+ {hasSignedUp && history.location.pathname === '/home' && ( +
); }; diff --git a/packages/concordia-app/src/components/TopicList/styles.css b/packages/concordia-app/src/components/TopicList/styles.css index ac3c53c..3ffc2e8 100644 --- a/packages/concordia-app/src/components/TopicList/styles.css +++ b/packages/concordia-app/src/components/TopicList/styles.css @@ -1,3 +1,11 @@ #topic-list{ height: 100%; + margin-bottom: 4em; + clear: both; +} + +#new-topic-button{ + float:right; + margin-bottom: 2em; + } diff --git a/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx b/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx index b2453f0..012fad6 100644 --- a/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx +++ b/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/index.jsx @@ -42,17 +42,6 @@ const MainLayoutMenu = () => { app_logo - {hasSignedUp && history.location.pathname === '/home' && ( - history.push('/topics/new')} - position="right" - > - {t('topbar.button.create.topic')} - - )} {hasSignedUp ? ( Date: Tue, 26 Jan 2021 12:43:16 +0200 Subject: [PATCH 02/17] TopicView changes, other fixes --- .../public/locales/en/translation.json | 1 - .../concordia-app/src/assets/css/index.css | 1 + .../src/components/PostCreate/index.jsx | 27 +--- .../src/components/PostCreate/styles.css | 12 +- .../components/PostList/PostListRow/index.jsx | 2 +- .../PostList/PostListRow/styles.css | 13 +- .../src/components/PostList/index.jsx | 14 +- .../TopicList/TopicListRow/index.jsx | 128 +++++++++--------- .../TopicList/TopicListRow/styles.css | 25 +++- .../src/components/TopicList/index.jsx | 12 +- .../src/views/Topic/TopicView/index.jsx | 107 ++++++--------- .../src/views/Topic/TopicView/styles.css | 6 + 12 files changed, 174 insertions(+), 174 deletions(-) diff --git a/packages/concordia-app/public/locales/en/translation.json b/packages/concordia-app/public/locales/en/translation.json index e9c42a5..e09a733 100644 --- a/packages/concordia-app/public/locales/en/translation.json +++ b/packages/concordia-app/public/locales/en/translation.json @@ -72,7 +72,6 @@ "topic.create.form.post.button": "Post", "topic.create.form.subject.field.label": "Topic subject", "topic.create.form.subject.field.placeholder": "Subject", - "topic.list.row.number.of.replies": "{{numberOfReplies}} replies", "topic.list.row.topic.id": "#{{id}}", "username.selector.error.username.empty.message": "Username is required", "username.selector.error.username.taken.message": "The username {{username}} is already taken.", diff --git a/packages/concordia-app/src/assets/css/index.css b/packages/concordia-app/src/assets/css/index.css index 31db996..aed14e1 100644 --- a/packages/concordia-app/src/assets/css/index.css +++ b/packages/concordia-app/src/assets/css/index.css @@ -1,6 +1,7 @@ body.app { overflow: auto; margin: 0; + background: #E6E6E6; } div { diff --git a/packages/concordia-app/src/components/PostCreate/index.jsx b/packages/concordia-app/src/components/PostCreate/index.jsx index 27d966a..360d4ae 100644 --- a/packages/concordia-app/src/components/PostCreate/index.jsx +++ b/packages/concordia-app/src/components/PostCreate/index.jsx @@ -2,7 +2,7 @@ import React, { memo, useCallback, useEffect, useState, } from 'react'; import { - Button, Feed, Form, Icon, Image, TextArea, + Button, Feed, Form, Icon, TextArea, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; @@ -10,7 +10,6 @@ import { useDispatch, useSelector } from 'react-redux'; import determineKVAddress from '../../utils/orbitUtils'; import { POSTS_DATABASE, USER_DATABASE } from '../../constants/orbit/OrbitDatabases'; import { FETCH_USER_DATABASE } from '../../redux/actions/peerDbReplicationActions'; -import { USER_PROFILE_PICTURE } from '../../constants/orbit/UserDatabaseKeys'; import { breeze, drizzle } from '../../redux/store'; import './styles.css'; import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../constants/TransactionStatus'; @@ -28,7 +27,6 @@ const PostCreate = (props) => { const transactionStack = useSelector((state) => state.transactionStack); const transactions = useSelector((state) => state.transactions); const [postContent, setPostContent] = useState(''); - const [userProfilePictureUrl, setUserProfilePictureUrl] = useState(); const [createPostCacheSendStackId, setCreatePostCacheSendStackId] = useState(''); const [posting, setPosting] = useState(false); const [storingPost, setStoringPost] = useState(false); @@ -44,9 +42,7 @@ const PostCreate = (props) => { const userFound = users .find((user) => user.id === userOrbitAddress); - if (userFound) { - setUserProfilePictureUrl(userFound[USER_PROFILE_PICTURE]); - } else { + if (!userFound) { dispatch({ type: FETCH_USER_DATABASE, orbit, @@ -122,23 +118,6 @@ const PostCreate = (props) => { return ( - - {userProfilePictureUrl - ? ( - - ) - : ( - - )} -
@@ -152,7 +131,7 @@ const PostCreate = (props) => { />
- + { {authorAvatarLink} - + diff --git a/packages/concordia-app/src/components/PostList/PostListRow/styles.css b/packages/concordia-app/src/components/PostList/PostListRow/styles.css index f6760c2..203f80c 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/styles.css +++ b/packages/concordia-app/src/components/PostList/PostListRow/styles.css @@ -1,5 +1,16 @@ .post-profile-picture { - margin: 5px 0 0 0; + margin-top: 1rem; +} + +.post-profile-picture img { + border-radius: 50%; + width: 2em !important; + height: 2em !important; + margin: 0 !important; +} + +.post-content { + margin-left: 0.5rem !important; } .post-summary-meta-index { diff --git a/packages/concordia-app/src/components/PostList/index.jsx b/packages/concordia-app/src/components/PostList/index.jsx index a967ccd..1070855 100644 --- a/packages/concordia-app/src/components/PostList/index.jsx +++ b/packages/concordia-app/src/components/PostList/index.jsx @@ -3,7 +3,9 @@ import React, { } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; -import { Dimmer, Feed, Loader } from 'semantic-ui-react'; +import { + Dimmer, Feed, Loader, +} from 'semantic-ui-react'; import PostListRow from './PostListRow'; import { drizzle } from '../../redux/store'; import { FORUM_CONTRACT } from '../../constants/contracts/ContractNames'; @@ -58,10 +60,12 @@ const PostList = (props) => { }, [focusOnPost, getPostCallHashes, loading, postIds]); return ( - - - {posts} - + + + + {posts} + + ); }; diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx index e70c0a4..c5e329b 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx @@ -2,11 +2,12 @@ import React, { memo, useEffect, useMemo, useState, } from 'react'; import { - Dimmer, Grid, Image, Item, List, Placeholder, Segment, + Dimmer, Grid, Icon, Image, Item, List, Placeholder, Segment, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import TimeAgo from 'react-timeago'; +import { useHistory } from 'react-router'; import { useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; @@ -33,6 +34,7 @@ const TopicListRow = (props) => { const topics = useSelector((state) => state.orbitData.topics); const users = useSelector((state) => state.orbitData.users); const dispatch = useDispatch(); + const history = useHistory(); const { t } = useTranslation(); useEffect(() => { @@ -40,7 +42,7 @@ const TopicListRow = (props) => { setTopicAuthorAddress(getTopicResults[topicCallHash].value[0]); setTopicAuthor(getTopicResults[topicCallHash].value[1]); setTimeAgo(getTopicResults[topicCallHash].value[2] * 1000); - setNumberOfReplies(getTopicResults[topicCallHash].value[3].length); + setNumberOfReplies(getTopicResults[topicCallHash].value[3].length - 1); } }, [getTopicResults, loading, topicCallHash]); @@ -121,65 +123,69 @@ const TopicListRow = (props) => { return authorAvatar; }, [authorAvatar, topicAuthorAddress]); - return useMemo(() => ( - - - - - - {authorAvatarLink} - - - - - - - - {topicSubject !== null - ? topicSubject - : } - - - - {t('topic.list.row.topic.id', { id: topicId })} - - - - - - {topicAuthor !== null && timeAgo !== null - ? ( -
- -  •  - - {topicAuthor} - -
- ) - : } -
- - {numberOfReplies !== null - ? ( - - {t('topic.list.row.number.of.replies', { numberOfReplies })} - - ) - : } - -
-
- - -
-
- -
- -
- - ), [authorAvatarLink, loading, numberOfReplies, t, timeAgo, topicAuthor, topicAuthorAddress, topicId, topicSubject]); + return useMemo(() => { + const handleTopicClick = () => { + history.push(`/topics/${topicId}`); + }; + return ( + + + + + + {authorAvatarLink} + + + + + + + {topicSubject !== null + ? topicSubject + : } + + + + {t('topic.list.row.topic.id', { id: topicId })} + + + + + + {topicAuthor !== null && timeAgo !== null + ? ( +
+ +  •  + + {topicAuthor} + +
+ ) + : } +
+ + {numberOfReplies !== null + ? ( + + +   + { numberOfReplies } + + ) + : } + +
+
+
+
+ +
+ +
+ + ); + }, [authorAvatarLink, history, loading, numberOfReplies, t, timeAgo, topicAuthor, topicAuthorAddress, topicId, topicSubject]); }; TopicListRow.defaultProps = { diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css index e520ff8..b7a1e9c 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/styles.css @@ -1,6 +1,7 @@ .topic-row { display: flex !important; text-align: start; + cursor: pointer; } .topic-row-segment { @@ -8,18 +9,26 @@ } .topic-row-segment:hover { - background-color: rgba(0, 0, 0, 0.03); + background-color: #F7F7F7; } .topic-row-segment div { color: black; } +.topic-row-segment .placeholder{ + font-size: 0.9rem; +} + +.topic-row-segment .placeholder>.line { + background-color:transparent; +} + .topic-row-avatar { margin: auto; padding-left: 0.75em !important; padding-right: 0 !important; - font-size: 2em; + font-size: 2rem; } .topic-row-avatar i { @@ -28,17 +37,16 @@ } .topic-row-content { - padding-left: 2em !important; + padding-left: 2rem !important; } .topic-row-subject { - font-size: 1.25em; + font-size: 1.4rem; font-weight: bold; } .topic-row-metadata { - font-size: 12px !important; - font-weight: initial; + font-size: 0.9em !important; } .profile-picture { @@ -47,3 +55,8 @@ width: 2em; height: 2em; } + +.replies-placeholder{ + float:right; + width: 6rem; +} diff --git a/packages/concordia-app/src/components/TopicList/index.jsx b/packages/concordia-app/src/components/TopicList/index.jsx index ee53b99..15dde57 100644 --- a/packages/concordia-app/src/components/TopicList/index.jsx +++ b/packages/concordia-app/src/components/TopicList/index.jsx @@ -58,12 +58,12 @@ const TopicList = (props) => {
{hasSignedUp && history.location.pathname === '/home' && (
+ + {topics} + ); }; diff --git a/packages/concordia-app/src/components/TopicList/styles.css b/packages/concordia-app/src/components/TopicList/styles.css index 3ffc2e8..5fae8a7 100644 --- a/packages/concordia-app/src/components/TopicList/styles.css +++ b/packages/concordia-app/src/components/TopicList/styles.css @@ -4,8 +4,3 @@ clear: both; } -#new-topic-button{ - float:right; - margin-bottom: 2em; - -} diff --git a/packages/concordia-app/src/views/Home/Board/index.jsx b/packages/concordia-app/src/views/Home/Board/index.jsx index 7a8b074..f7daaa8 100644 --- a/packages/concordia-app/src/views/Home/Board/index.jsx +++ b/packages/concordia-app/src/views/Home/Board/index.jsx @@ -1,22 +1,43 @@ import React, { useMemo } from 'react'; -import { Header } from 'semantic-ui-react'; +import { Button, Header } from 'semantic-ui-react'; +import { useSelector } from 'react-redux'; +import { useHistory } from 'react-router'; import _ from 'lodash'; import { useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; + import TopicList from '../../../components/TopicList'; +import './styles.css'; + const Board = (props) => { const { numberOfTopics } = props; - const userHasSignedUp = useSelector((state) => state.user.hasSignedUp); + const hasSignedUp = useSelector((state) => state.user.hasSignedUp); + const history = useHistory(); const { t } = useTranslation(); const boardContents = useMemo(() => { if (numberOfTopics > 0) { - return (); - } if (!userHasSignedUp) { return ( -
+ <> + {hasSignedUp + ? ( + diff --git a/packages/concordia-app/src/components/PostCreate/styles.css b/packages/concordia-app/src/components/PostCreate/styles.css index 94d5fc5..8772846 100644 --- a/packages/concordia-app/src/components/PostCreate/styles.css +++ b/packages/concordia-app/src/components/PostCreate/styles.css @@ -8,16 +8,11 @@ color: #fff !important; } -#post-button { +#post-button-div { float: right; - margin: 1rem 0; + margin: 1rem 0 4rem 0; } -#post-button button { +#post-button-div button { margin: 0; - background-color: var(--secondary-color); -} - -#post-button button:hover { - background-color: var(--secondary-color-highlighted); } diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx index 371a218..c1f636b 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx @@ -2,7 +2,7 @@ import React, { memo, useEffect, useMemo, useState, useCallback, } from 'react'; import { - Dimmer, Icon, Image, Feed, Placeholder, Ref, + Dimmer, Feed, Placeholder, Ref, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; @@ -14,7 +14,6 @@ import { breeze } from '../../../redux/store'; import './styles.css'; import { POSTS_DATABASE, USER_DATABASE } from '../../../constants/orbit/OrbitDatabases'; import determineKVAddress from '../../../utils/orbitUtils'; -import { USER_PROFILE_PICTURE } from '../../../constants/orbit/UserDatabaseKeys'; import { POST_CONTENT } from '../../../constants/orbit/PostsDatabaseKeys'; import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames'; import ProfileImage from '../../ProfileImage'; diff --git a/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/styles.css b/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/styles.css index 46bc68f..86cb6a1 100644 --- a/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/styles.css +++ b/packages/concordia-app/src/layouts/MainLayout/MainLayoutMenu/styles.css @@ -5,5 +5,5 @@ .ui.inverted.menu { background: var(--primary-color) !important; border-radius: 0; - margin-bottom: 2em; + margin-bottom: 4rem; } diff --git a/packages/concordia-app/src/views/Home/Board/index.jsx b/packages/concordia-app/src/views/Home/Board/index.jsx index 43e7c23..7b93ea6 100644 --- a/packages/concordia-app/src/views/Home/Board/index.jsx +++ b/packages/concordia-app/src/views/Home/Board/index.jsx @@ -21,11 +21,12 @@ const Board = (props) => { {hasSignedUp ? ( - diff --git a/packages/concordia-app/src/components/PostCreate/index.jsx b/packages/concordia-app/src/components/PostCreate/index.jsx index 17ea739..bf75927 100644 --- a/packages/concordia-app/src/components/PostCreate/index.jsx +++ b/packages/concordia-app/src/components/PostCreate/index.jsx @@ -136,7 +136,7 @@ const PostCreate = (props) => { + ); diff --git a/packages/concordia-app/src/views/Topic/TopicCreate/styles.css b/packages/concordia-app/src/views/Topic/TopicCreate/styles.css index 229f696..5d078ac 100644 --- a/packages/concordia-app/src/views/Topic/TopicCreate/styles.css +++ b/packages/concordia-app/src/views/Topic/TopicCreate/styles.css @@ -9,3 +9,8 @@ border-color: rgb(224, 180, 180) !important; background-color: rgb(255, 246, 246) !important; } + +#create-topic-button { + float: right; + margin: 1rem 0 4rem 0; +} diff --git a/packages/concordia-app/src/views/Topic/TopicView/styles.css b/packages/concordia-app/src/views/Topic/TopicView/styles.css index b592494..75b87b7 100644 --- a/packages/concordia-app/src/views/Topic/TopicView/styles.css +++ b/packages/concordia-app/src/views/Topic/TopicView/styles.css @@ -1,5 +1,5 @@ #topic-container { - height: 100%; + height: auto !important; } #topic-header { From cd1ef7e11b131d4b28b3b754c8d6782012c4a3bd Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 5 Feb 2021 21:35:37 +0200 Subject: [PATCH 09/17] Add post voting buttons --- .../components/PostList/PostListRow/index.jsx | 8 ++++++- .../PostList/PostListRow/styles.css | 21 ++++++++++++++++++- .../src/views/Topic/TopicView/index.jsx | 2 +- .../src/views/Topic/TopicView/styles.css | 3 ++- yarn.lock | 2 +- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx index c1f636b..37026fa 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx @@ -2,7 +2,8 @@ import React, { memo, useEffect, useMemo, useState, useCallback, } from 'react'; import { - Dimmer, Feed, Placeholder, Ref, + Button, + Dimmer, Feed, Placeholder, Ref, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; @@ -138,6 +139,11 @@ const PostListRow = (props) => { ? postContent : } +
+
), [focusRef, loading, postAuthor, postAuthorAddress, postAuthorMeta, postContent, postId, postIndex, t, timeAgo, diff --git a/packages/concordia-app/src/components/PostList/PostListRow/styles.css b/packages/concordia-app/src/components/PostList/PostListRow/styles.css index f8facec..9303195 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/styles.css +++ b/packages/concordia-app/src/components/PostList/PostListRow/styles.css @@ -1,5 +1,5 @@ .post-list-row { - padding: 1rem 0.1rem 1rem 0.6rem !important; + padding: 1.2rem 0.1rem 1.2rem 0.6rem !important; } .post-profile-picture { @@ -14,6 +14,10 @@ font-size: 1rem !important; } +.post-content > div.extra { + padding-right: 1rem !important; +} + .post-content .placeholder { margin: 0.5rem 0 0; font-size: 2rem !important; @@ -25,6 +29,21 @@ .post-summary-meta-index { float: right; + width: 3rem; + text-align: right; font-size: 0.75rem !important; opacity: 0.4; } + +.post-voting { + float: left; + margin-top: 1.2rem; +} + +.post-voting > button{ + margin: 0 !important; +} + +.post-voting > span{ + vertical-align: middle; +} diff --git a/packages/concordia-app/src/views/Topic/TopicView/index.jsx b/packages/concordia-app/src/views/Topic/TopicView/index.jsx index 221c796..5f61fa1 100644 --- a/packages/concordia-app/src/views/Topic/TopicView/index.jsx +++ b/packages/concordia-app/src/views/Topic/TopicView/index.jsx @@ -119,7 +119,7 @@ const TopicView = (props) => { }; return ( - + Date: Sat, 6 Feb 2021 18:55:50 +0200 Subject: [PATCH 10/17] feat: post voting init --- .../components/PostList/PostListRow/index.jsx | 12 +- .../PostList/PostListRow/styles.css | 13 -- .../components/PostList/PostVoting/index.jsx | 134 ++++++++++++++++++ .../components/PostList/PostVoting/styles.css | 12 ++ .../contracts/PostVoting.sol | 6 + yarn.lock | 127 ++++++++++------- 6 files changed, 232 insertions(+), 72 deletions(-) create mode 100644 packages/concordia-app/src/components/PostList/PostVoting/index.jsx create mode 100644 packages/concordia-app/src/components/PostList/PostVoting/styles.css diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx index 37026fa..e6d75fb 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx @@ -1,10 +1,7 @@ import React, { memo, useEffect, useMemo, useState, useCallback, } from 'react'; -import { - Button, - Dimmer, Feed, Placeholder, Ref, -} from 'semantic-ui-react'; +import { Dimmer, Feed, Placeholder, Ref } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import TimeAgo from 'react-timeago'; @@ -18,6 +15,7 @@ import determineKVAddress from '../../../utils/orbitUtils'; import { POST_CONTENT } from '../../../constants/orbit/PostsDatabaseKeys'; import { FORUM_CONTRACT } from '../../../constants/contracts/ContractNames'; import ProfileImage from '../../ProfileImage'; +import PostVoting from '../PostVoting'; const { orbit } = breeze; @@ -139,11 +137,7 @@ const PostListRow = (props) => { ? postContent : } -
-
+
), [focusRef, loading, postAuthor, postAuthorAddress, postAuthorMeta, postContent, postId, postIndex, t, timeAgo, diff --git a/packages/concordia-app/src/components/PostList/PostListRow/styles.css b/packages/concordia-app/src/components/PostList/PostListRow/styles.css index 9303195..d360343 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/styles.css +++ b/packages/concordia-app/src/components/PostList/PostListRow/styles.css @@ -34,16 +34,3 @@ font-size: 0.75rem !important; opacity: 0.4; } - -.post-voting { - float: left; - margin-top: 1.2rem; -} - -.post-voting > button{ - margin: 0 !important; -} - -.post-voting > span{ - vertical-align: middle; -} diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx new file mode 100644 index 0000000..7f84bbc --- /dev/null +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -0,0 +1,134 @@ +import React, { + memo, useCallback, useEffect, useMemo, useState, +} from 'react'; +import { Button } from 'semantic-ui-react'; +import PropTypes from 'prop-types'; + +import './styles.css'; +import { useSelector } from 'react-redux'; +import { POST_VOTING_CONTRACT } from '../../../constants/contracts/ContractNames'; +import { drizzle } from '../../../redux/store'; +import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus'; + +const CHOICE_DEFAULT = '0'; +const CHOICE_UP = '1'; +const CHOICE_DOWN = '2'; + +const { + contracts: { + [POST_VOTING_CONTRACT]: { + methods: { + getVote: { cacheCall: getVoteChainData }, + getTotalVoteCount: { cacheCall: getTotalVoteCountChainData }, + upvote, downvote, unvote, + }, + }, + }, +} = drizzle; + +const PostVoting = (props) => { + const { postId, postAuthorAddress } = props; + const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized); + const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed); + const hasSignedUp = useSelector((state) => state.user.hasSignedUp); + const userAccount = useSelector((state) => state.accounts[0]); + + // Current votes + const getVoteResults = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getVote); + const getTotalVoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getTotalVoteCount); + const [getVoteCallHash, setGetVoteCallHash] = useState([]); + const [getTotalVoteCountCallHash, setGetTotalVoteCountCallHash] = useState([]); + const [ownVote, setOwnVote] = useState(null); + const [totalVoteCount, setTotalVoteCount] = useState(null); + + // Voting + const transactionStack = useSelector((state) => state.transactionStack); + const transactions = useSelector((state) => state.transactions); + const [voting, setVoting] = useState(false); + const [createVoteCacheSendStackId, setVoteCacheSendStackId] = useState(''); + + // Current votes + useEffect(() => { + const shouldGetTotalVoteCountDataFromChain = totalVoteCount === null; + + if (drizzleInitialized && !drizzleInitializationFailed && shouldGetTotalVoteCountDataFromChain && postId !== null) { + setGetTotalVoteCountCallHash(getTotalVoteCountChainData(postId)); + } + }, [drizzleInitializationFailed, drizzleInitialized, postId, totalVoteCount]); + + useEffect(() => { + const shouldGetOwnVoteFromChain = ownVote === null; + + if (drizzleInitialized && !drizzleInitializationFailed && shouldGetOwnVoteFromChain && postId !== null && userAccount !== null) { + setGetVoteCallHash(getVoteChainData(postId, userAccount)); + } + }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, totalVoteCount, userAccount]); + + useEffect(() => { + if (getVoteCallHash && getVoteResults && getVoteResults[getVoteCallHash]) { + setOwnVote(getVoteResults[getVoteCallHash].value); + } + }, [getVoteCallHash, getVoteResults]); + + useEffect(() => { + if (getTotalVoteCountCallHash && getTotalVoteCountResult && getTotalVoteCountResult[getTotalVoteCountCallHash]) { + setTotalVoteCount(getTotalVoteCountResult[getTotalVoteCountCallHash].value); + } + }, [getTotalVoteCountCallHash, getTotalVoteCountResult]); + + // Voting + useEffect(() => { + if (voting && transactionStack && transactionStack[createVoteCacheSendStackId] + && transactions[transactionStack[createVoteCacheSendStackId]]) { + if (transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_SUCCESS || transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_ERROR) { + setVoting(false); + } + } + }, [createVoteCacheSendStackId, transactionStack, transactions, voting]); + + const vote = useCallback((choice) => { + setVoting(true); + if ((ownVote === CHOICE_DEFAULT || ownVote === CHOICE_DOWN) && choice === CHOICE_UP) setVoteCacheSendStackId(upvote.cacheSend(...[postId], { from: userAccount })); + else if ((ownVote === CHOICE_DEFAULT || ownVote === CHOICE_UP) && choice === CHOICE_DOWN) setVoteCacheSendStackId(downvote.cacheSend(...[postId], { from: userAccount })); + else if ((ownVote === CHOICE_UP && choice === CHOICE_UP) || (ownVote === CHOICE_DOWN && choice === CHOICE_DOWN)) setVoteCacheSendStackId(unvote.cacheSend(...[postId], { from: userAccount })); + }, [ownVote, postId, userAccount]); + + const disableVoting = userAccount === null || !hasSignedUp || postAuthorAddress === null || userAccount === postAuthorAddress; + return useMemo(() => ( +
+
+ ), [disableVoting, ownVote, totalVoteCount, vote]); +}; + +PostVoting.defaultProps = { + loading: false, +}; + +PostVoting.propTypes = { + postId: PropTypes.number.isRequired, + postAuthorAddress: PropTypes.string, + totalVoteCount: PropTypes.number, +}; + +export default memo(PostVoting); diff --git a/packages/concordia-app/src/components/PostList/PostVoting/styles.css b/packages/concordia-app/src/components/PostList/PostVoting/styles.css new file mode 100644 index 0000000..0867a5d --- /dev/null +++ b/packages/concordia-app/src/components/PostList/PostVoting/styles.css @@ -0,0 +1,12 @@ +.post-voting { + float: left; + margin-top: 1.2rem; +} + +.post-voting > button{ + margin: 0 !important; +} + +.post-voting > span{ + vertical-align: middle; +} diff --git a/packages/concordia-contracts/contracts/PostVoting.sol b/packages/concordia-contracts/contracts/PostVoting.sol index 1b3374a..c449417 100644 --- a/packages/concordia-contracts/contracts/PostVoting.sol +++ b/packages/concordia-contracts/contracts/PostVoting.sol @@ -40,6 +40,12 @@ contract PostVoting { return (getVoteCount(postID, Option.DOWN)); } + function getTotalVoteCount(uint postID) public view returns (int) { + int upvoteCount = int(getUpvoteCount(postID)); + int downvoteCount = int(getDownvoteCount(postID)); + return upvoteCount - downvoteCount; + } + // Gets voters for a specific option (Option.UP/ Option.DOWN) function getVoters(uint postID, Option option) private view returns (address[] memory) { require(forum.postExists(postID), forum.POST_DOES_NOT_EXIST()); diff --git a/yarn.lock b/yarn.lock index 5123b75..3aef030 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1530,14 +1530,14 @@ level "~6.0.1" orbit-db-identity-provider "~0.3.1" -"@fluentui/react-component-event-listener@~0.51.0": +"@fluentui/react-component-event-listener@~0.51.6": version "0.51.7" resolved "https://registry.yarnpkg.com/@fluentui/react-component-event-listener/-/react-component-event-listener-0.51.7.tgz#158adb970d8bc982c91c57fd1322a0036042d86e" integrity sha512-NjVm+crN0T9A7vITL8alZeHnuV8zi2gos0nezU/2YOxaUAB9E4zKiPxt/6k5U50rJs/gj8Nu45iXxnjO41HbZg== dependencies: "@babel/runtime" "^7.10.4" -"@fluentui/react-component-ref@~0.51.0": +"@fluentui/react-component-ref@~0.51.6": version "0.51.7" resolved "https://registry.yarnpkg.com/@fluentui/react-component-ref/-/react-component-ref-0.51.7.tgz#bfb0312e926c213bed35e53ee5105a68732eea99" integrity sha512-CX27jVJYaFoBCWpuWAizQZ2se137ku1dmDyn8sw+ySNJa+kkQf7LnMydiPW5K7cRdUSqUJW3eS4EjKRvVAx8xA== @@ -2010,6 +2010,11 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.2.0.tgz#3e6b3a7662d8ed64271ade96ef42655db983fd9d" integrity sha512-bUOmkSoPkjnUyMiKo6RYnb0VHBk5D9KKDAgNLzF41aqAM3TeE0yGdFF5dVRcV60pZdJLlyFT/jjXIZCWyyEzAQ== +"@popperjs/core@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.6.0.tgz#f022195afdfc942e088ee2101285a1d31c7d727f" + integrity sha512-cPqjjzuFWNK3BSKLm0abspP0sp/IGOli4p5I5fKFAzdS8fvjdOwDCfZqAaIiXd9lPkOWi3SUUfZof3hEb7J/uw== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -2117,7 +2122,7 @@ redux-thunk "^2.3.0" reselect "^4.0.0" -"@semantic-ui-react/event-stack@^3.1.0": +"@semantic-ui-react/event-stack@^3.1.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@semantic-ui-react/event-stack/-/event-stack-3.1.2.tgz#14fac9796695aa3967962d94ea9733a85325f9c4" integrity sha512-Yd0Qf7lPCIjzJ9bZYfurlNu2RDXT6KKSyubHfYK3WjRauhxCsq6Fk2LMRI9DEvShoEU+AsLSv3NGkqXAcVp0zg== @@ -4191,6 +4196,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -4722,7 +4732,7 @@ core-js@^2.4.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.5.0: +core-js@^3.5.0, core-js@^3.6.1: version "3.8.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.3.tgz#c21906e1f14f3689f93abcc6e26883550dd92dd0" integrity sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q== @@ -4797,14 +4807,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-context@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" - integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - cross-env@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" @@ -4841,6 +4843,11 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + crypto-browserify@3.12.0, crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -5222,7 +5229,7 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" -deep-equal@^1.0.1, deep-equal@^1.1.1: +deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== @@ -7512,11 +7519,6 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - gzip-size@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" @@ -9063,7 +9065,7 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.0.2, is-buffer@^1.1.5: +is-buffer@^1.0.2, is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -9398,6 +9400,11 @@ is-resolvable@^1.0.0: resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== +is-retina@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-retina/-/is-retina-1.0.3.tgz#d7401b286bea2ae37f62477588de504d0b8647e3" + integrity sha1-10AbKGvqKuN/Ykd1iN5QTQuGR+M= + is-retry-allowed@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" @@ -11356,6 +11363,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash-es@^4.17.15: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.20.tgz#29f6332eefc60e849f869c264bc71126ad61e8f7" + integrity sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA== + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -11563,6 +11575,15 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +md5@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + mdast-add-list-metadata@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf" @@ -13623,11 +13644,6 @@ pnp-webpack-plugin@1.6.4: dependencies: ts-pnp "^1.1.6" -popper.js@^1.14.4: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - portfinder@^1.0.26: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -14461,7 +14477,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@~15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@~15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -14743,6 +14759,15 @@ react-app-polyfill@^1.0.6: regenerator-runtime "^0.13.3" whatwg-fetch "^3.0.0" +react-avatar@~3.9.7: + version "3.9.7" + resolved "https://registry.yarnpkg.com/react-avatar/-/react-avatar-3.9.7.tgz#c7eb50d7f827350475ec6041f38fc2dbd249b740" + integrity sha512-UX1prYgo4gS1g2u16tZbx/Vy45M/BxyHHexIoRj6m9hI3ZR0FdHTDt66X5GpTtf6PRYE8KlvwHte1x5n8B0/XQ== + dependencies: + core-js "^3.6.1" + is-retina "^1.0.3" + md5 "^2.0.0" + react-dev-utils@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19" @@ -14788,6 +14813,11 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.8.tgz#474ed11d04fc6bda3af643447d85e9127ed6b5de" integrity sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw== +react-fast-compare@^3.0.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + react-i18next@^11.7.3: version "11.8.5" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.8.5.tgz#a093335822e36252cda6efc0f55facef6253643f" @@ -14801,6 +14831,11 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-i resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.8.6 || ^17.0.0": + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== + react-markdown@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-5.0.3.tgz#41040ea7a9324b564b328fb81dd6c04f2a5373ac" @@ -14825,17 +14860,12 @@ react-particles-js@^3.4.0: lodash "^4.17.11" tsparticles "^1.18.10" -react-popper@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324" - integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww== +react-popper@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.4.tgz#d2ad3d2474ac9f1abf93df3099d408e5aa6a2e22" + integrity sha512-NacOu4zWupdQjVXq02XpTD3yFPSfg5a7fex0wa3uGKVkFK7UN6LvVxgcb+xYr56UCuWiNPMH20tntdVdJRwYew== dependencies: - "@babel/runtime" "^7.1.2" - create-react-context "^0.3.0" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" + react-fast-compare "^3.0.1" warning "^4.0.2" react-redux@~7.2.1: @@ -15654,21 +15684,23 @@ semantic-ui-css@~2.4.1: dependencies: jquery x.* -semantic-ui-react@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-1.2.1.tgz#c58603db072d3628fc2d9b626f6c3b39535deca3" - integrity sha512-p0HKdHg8ZGhnanyNuGOyTp5M6mVGWzTULPY02uBYHxXMzsyRPoRDlUa/tbaU0UdFpg96CmToG4WrvkINqhcZ+Q== +semantic-ui-react@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/semantic-ui-react/-/semantic-ui-react-2.0.3.tgz#39091e24078e28129ff9b1beb7dbfc84ca85544b" + integrity sha512-a0hGN6XXw64sRSKwWqMCKSI/AGLohxNeWuErS39eswvBbUnLjBij8ZoEdiqDiz/PuWpwYIRjgmQVrut+7h3b2g== dependencies: "@babel/runtime" "^7.10.5" - "@fluentui/react-component-event-listener" "~0.51.0" - "@fluentui/react-component-ref" "~0.51.0" - "@semantic-ui-react/event-stack" "^3.1.0" + "@fluentui/react-component-event-listener" "~0.51.6" + "@fluentui/react-component-ref" "~0.51.6" + "@popperjs/core" "^2.6.0" + "@semantic-ui-react/event-stack" "^3.1.2" clsx "^1.1.1" keyboard-key "^1.1.0" lodash "^4.17.19" + lodash-es "^4.17.15" prop-types "^15.7.2" - react-is "^16.8.6" - react-popper "^1.3.7" + react-is "^16.8.6 || ^17.0.0" + react-popper "^2.2.4" shallowequal "^1.1.0" semver-diff@^3.1.1: @@ -17073,11 +17105,6 @@ type@^2.0.0: resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f" integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA== -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - typedarray-to-buffer@^3.1.5, typedarray-to-buffer@~3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -17603,7 +17630,7 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -warning@^4.0.2, warning@^4.0.3: +warning@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== From a32a0f8a243b2d5d3de5bd3c417a4225d9f705d3 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 6 Feb 2021 19:07:42 +0200 Subject: [PATCH 11/17] fix: disallow voting when voting transaction pending --- .../src/components/PostList/PostVoting/index.jsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx index 7f84bbc..6298903 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -59,7 +59,8 @@ const PostVoting = (props) => { useEffect(() => { const shouldGetOwnVoteFromChain = ownVote === null; - if (drizzleInitialized && !drizzleInitializationFailed && shouldGetOwnVoteFromChain && postId !== null && userAccount !== null) { + if (drizzleInitialized && !drizzleInitializationFailed && shouldGetOwnVoteFromChain + && postId !== null && userAccount !== null) { setGetVoteCallHash(getVoteChainData(postId, userAccount)); } }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, totalVoteCount, userAccount]); @@ -87,11 +88,13 @@ const PostVoting = (props) => { }, [createVoteCacheSendStackId, transactionStack, transactions, voting]); const vote = useCallback((choice) => { + if (voting) return; + setVoting(true); if ((ownVote === CHOICE_DEFAULT || ownVote === CHOICE_DOWN) && choice === CHOICE_UP) setVoteCacheSendStackId(upvote.cacheSend(...[postId], { from: userAccount })); else if ((ownVote === CHOICE_DEFAULT || ownVote === CHOICE_UP) && choice === CHOICE_DOWN) setVoteCacheSendStackId(downvote.cacheSend(...[postId], { from: userAccount })); else if ((ownVote === CHOICE_UP && choice === CHOICE_UP) || (ownVote === CHOICE_DOWN && choice === CHOICE_DOWN)) setVoteCacheSendStackId(unvote.cacheSend(...[postId], { from: userAccount })); - }, [ownVote, postId, userAccount]); + }, [ownVote, postId, userAccount, voting]); const disableVoting = userAccount === null || !hasSignedUp || postAuthorAddress === null || userAccount === postAuthorAddress; return useMemo(() => ( @@ -121,10 +124,6 @@ const PostVoting = (props) => { ), [disableVoting, ownVote, totalVoteCount, vote]); }; -PostVoting.defaultProps = { - loading: false, -}; - PostVoting.propTypes = { postId: PropTypes.number.isRequired, postAuthorAddress: PropTypes.string, From 47c8bdb864ec2ae752adab9336c543c476f5dd89 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 6 Feb 2021 20:15:38 +0200 Subject: [PATCH 12/17] fix: make votes unselectable --- packages/concordia-app/src/assets/css/index.css | 9 +++++++++ .../src/components/PostList/PostVoting/index.jsx | 7 +++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/concordia-app/src/assets/css/index.css b/packages/concordia-app/src/assets/css/index.css index 2ecb4f9..cd7fb04 100644 --- a/packages/concordia-app/src/assets/css/index.css +++ b/packages/concordia-app/src/assets/css/index.css @@ -58,3 +58,12 @@ div { color: var(--secondary-color-highlighted) !important; box-shadow: 0 0 0 1px var(--secondary-color-highlighted) inset !important; } + +.unselectable { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx index 6298903..ea3cb0f 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -3,12 +3,11 @@ import React, { } from 'react'; import { Button } from 'semantic-ui-react'; import PropTypes from 'prop-types'; - -import './styles.css'; import { useSelector } from 'react-redux'; import { POST_VOTING_CONTRACT } from '../../../constants/contracts/ContractNames'; import { drizzle } from '../../../redux/store'; import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus'; +import './styles.css'; const CHOICE_DEFAULT = '0'; const CHOICE_UP = '1'; @@ -63,7 +62,7 @@ const PostVoting = (props) => { && postId !== null && userAccount !== null) { setGetVoteCallHash(getVoteChainData(postId, userAccount)); } - }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, totalVoteCount, userAccount]); + }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, userAccount]); useEffect(() => { if (getVoteCallHash && getVoteResults && getVoteResults[getVoteCallHash]) { @@ -107,7 +106,7 @@ const PostVoting = (props) => { disabled={disableVoting} onClick={() => vote(CHOICE_DOWN)} /> - +    {totalVoteCount || 0}    From 0a0c5a4496e8b1c26a00fd9009f1e58fea984041 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 6 Feb 2021 21:55:06 +0200 Subject: [PATCH 13/17] feat: add popup to post votes --- .../components/PostList/PostVoting/index.jsx | 79 +++++++++++++------ .../components/PostList/PostVoting/styles.css | 10 ++- .../contracts/PostVoting.sol | 6 -- 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx index ea3cb0f..022c81f 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -1,13 +1,14 @@ import React, { memo, useCallback, useEffect, useMemo, useState, } from 'react'; -import { Button } from 'semantic-ui-react'; +import { Button, Popup } from 'semantic-ui-react'; import PropTypes from 'prop-types'; + +import './styles.css'; import { useSelector } from 'react-redux'; import { POST_VOTING_CONTRACT } from '../../../constants/contracts/ContractNames'; import { drizzle } from '../../../redux/store'; import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus'; -import './styles.css'; const CHOICE_DEFAULT = '0'; const CHOICE_UP = '1'; @@ -18,7 +19,8 @@ const { [POST_VOTING_CONTRACT]: { methods: { getVote: { cacheCall: getVoteChainData }, - getTotalVoteCount: { cacheCall: getTotalVoteCountChainData }, + getUpvoteCount: { cacheCall: getUpvoteCountChainData }, + getDownvoteCount: { cacheCall: getDownvoteCountChainData }, upvote, downvote, unvote, }, }, @@ -33,12 +35,17 @@ const PostVoting = (props) => { const userAccount = useSelector((state) => state.accounts[0]); // Current votes - const getVoteResults = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getVote); - const getTotalVoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getTotalVoteCount); + const getVoteResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getVote); + const getUpvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getUpvoteCount); + const getDownvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getDownvoteCount); + const [getVoteCallHash, setGetVoteCallHash] = useState([]); - const [getTotalVoteCountCallHash, setGetTotalVoteCountCallHash] = useState([]); + const [getUpvoteCountCallHash, setGetUpvoteCountCallHash] = useState([]); + const [getDownvoteCountCallHash, setGetDownvoteCountCallHash] = useState([]); + const [ownVote, setOwnVote] = useState(null); - const [totalVoteCount, setTotalVoteCount] = useState(null); + const [upvoteCount, setUpvoteCount] = useState(null); + const [downvoteCount, setDownvoteCount] = useState(null); // Voting const transactionStack = useSelector((state) => state.transactionStack); @@ -48,12 +55,12 @@ const PostVoting = (props) => { // Current votes useEffect(() => { - const shouldGetTotalVoteCountDataFromChain = totalVoteCount === null; + if (drizzleInitialized && !drizzleInitializationFailed && postId !== null) { + if (upvoteCount === null) setGetUpvoteCountCallHash(getUpvoteCountChainData(postId)); - if (drizzleInitialized && !drizzleInitializationFailed && shouldGetTotalVoteCountDataFromChain && postId !== null) { - setGetTotalVoteCountCallHash(getTotalVoteCountChainData(postId)); + if (downvoteCount === null) setGetDownvoteCountCallHash(getDownvoteCountChainData(postId)); } - }, [drizzleInitializationFailed, drizzleInitialized, postId, totalVoteCount]); + }, [downvoteCount, drizzleInitializationFailed, drizzleInitialized, postId, upvoteCount, userAccount]); useEffect(() => { const shouldGetOwnVoteFromChain = ownVote === null; @@ -65,16 +72,22 @@ const PostVoting = (props) => { }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, userAccount]); useEffect(() => { - if (getVoteCallHash && getVoteResults && getVoteResults[getVoteCallHash]) { - setOwnVote(getVoteResults[getVoteCallHash].value); + if (getVoteCallHash && getVoteResult && getVoteResult[getVoteCallHash]) { + setOwnVote(getVoteResult[getVoteCallHash].value); } - }, [getVoteCallHash, getVoteResults]); + }, [getVoteCallHash, getVoteResult]); useEffect(() => { - if (getTotalVoteCountCallHash && getTotalVoteCountResult && getTotalVoteCountResult[getTotalVoteCountCallHash]) { - setTotalVoteCount(getTotalVoteCountResult[getTotalVoteCountCallHash].value); + if (getUpvoteCountCallHash && getUpvoteCountResult && getUpvoteCountResult[getUpvoteCountCallHash]) { + setUpvoteCount(getUpvoteCountResult[getUpvoteCountCallHash].value); } - }, [getTotalVoteCountCallHash, getTotalVoteCountResult]); + }, [getUpvoteCountCallHash, getUpvoteCountResult]); + + useEffect(() => { + if (getDownvoteCountCallHash && getDownvoteCountResult && getDownvoteCountResult[getDownvoteCountCallHash]) { + setDownvoteCount(getDownvoteCountResult[getDownvoteCountCallHash].value); + } + }, [getDownvoteCountCallHash, getDownvoteCountResult]); // Voting useEffect(() => { @@ -96,6 +109,7 @@ const PostVoting = (props) => { }, [ownVote, postId, userAccount, voting]); const disableVoting = userAccount === null || !hasSignedUp || postAuthorAddress === null || userAccount === postAuthorAddress; + const totalVoteCount = (upvoteCount !== null && downvoteCount !== null) ? upvoteCount - downvoteCount : null; return useMemo(() => (
- ), [disableVoting, ownVote, totalVoteCount, vote]); + ), [disableVoting, downvoteCount, ownVote, totalVoteCount, upvoteCount, vote]); }; PostVoting.propTypes = { diff --git a/packages/concordia-app/src/components/PostList/PostVoting/styles.css b/packages/concordia-app/src/components/PostList/PostVoting/styles.css index 0867a5d..340e95d 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/styles.css +++ b/packages/concordia-app/src/components/PostList/PostVoting/styles.css @@ -3,10 +3,18 @@ margin-top: 1.2rem; } -.post-voting > button{ +.post-voting > button { margin: 0 !important; } .post-voting > span{ vertical-align: middle; } + +.upvote-count { + color: #21ba45; +} + +.downvote-count { + color: #db2828; +} diff --git a/packages/concordia-contracts/contracts/PostVoting.sol b/packages/concordia-contracts/contracts/PostVoting.sol index c449417..1b3374a 100644 --- a/packages/concordia-contracts/contracts/PostVoting.sol +++ b/packages/concordia-contracts/contracts/PostVoting.sol @@ -40,12 +40,6 @@ contract PostVoting { return (getVoteCount(postID, Option.DOWN)); } - function getTotalVoteCount(uint postID) public view returns (int) { - int upvoteCount = int(getUpvoteCount(postID)); - int downvoteCount = int(getDownvoteCount(postID)); - return upvoteCount - downvoteCount; - } - // Gets voters for a specific option (Option.UP/ Option.DOWN) function getVoters(uint postID, Option option) private view returns (address[] memory) { require(forum.postExists(postID), forum.POST_DOES_NOT_EXIST()); From 8552a9058d7421dd6810918c2f39f29a34f887ec Mon Sep 17 00:00:00 2001 From: apostolof Date: Sun, 7 Feb 2021 16:56:42 +0200 Subject: [PATCH 14/17] fix: resolve merge issues --- .../components/PostList/PostListRow/index.jsx | 4 +++- .../src/components/PostList/PostVoting/index.jsx | 16 ++++++++-------- .../components/TopicList/TopicListRow/index.jsx | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx index f2be072..e2a86b7 100644 --- a/packages/concordia-app/src/components/PostList/PostListRow/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostListRow/index.jsx @@ -1,7 +1,9 @@ import React, { memo, useEffect, useMemo, useState, useCallback, } from 'react'; -import { Dimmer, Feed, Placeholder, Ref } from 'semantic-ui-react'; +import { + Dimmer, Feed, Placeholder, Ref, +} from 'semantic-ui-react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import TimeAgo from 'react-timeago'; diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx index 022c81f..a0f223c 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -3,12 +3,11 @@ import React, { } from 'react'; import { Button, Popup } from 'semantic-ui-react'; import PropTypes from 'prop-types'; - -import './styles.css'; import { useSelector } from 'react-redux'; -import { POST_VOTING_CONTRACT } from '../../../constants/contracts/ContractNames'; +import { POST_VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; import { drizzle } from '../../../redux/store'; import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus'; +import './styles.css'; const CHOICE_DEFAULT = '0'; const CHOICE_UP = '1'; @@ -66,7 +65,7 @@ const PostVoting = (props) => { const shouldGetOwnVoteFromChain = ownVote === null; if (drizzleInitialized && !drizzleInitializationFailed && shouldGetOwnVoteFromChain - && postId !== null && userAccount !== null) { + && postId !== null && userAccount !== null) { setGetVoteCallHash(getVoteChainData(postId, userAccount)); } }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, userAccount]); @@ -92,8 +91,9 @@ const PostVoting = (props) => { // Voting useEffect(() => { if (voting && transactionStack && transactionStack[createVoteCacheSendStackId] - && transactions[transactionStack[createVoteCacheSendStackId]]) { - if (transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_SUCCESS || transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_ERROR) { + && transactions[transactionStack[createVoteCacheSendStackId]]) { + if (transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_SUCCESS + || transactions[transactionStack[createVoteCacheSendStackId]].status === TRANSACTION_ERROR) { setVoting(false); } } @@ -125,7 +125,7 @@ const PostVoting = (props) => {    {totalVoteCount || 0} -    +    )} disabled={(upvoteCount === null && downvoteCount === null) || (upvoteCount === '0' && downvoteCount === '0')} @@ -135,7 +135,7 @@ const PostVoting = (props) => { + {upvoteCount} -    +    ) : null} diff --git a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx index 7e4fb40..6146736 100644 --- a/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx +++ b/packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx @@ -10,9 +10,9 @@ import TimeAgo from 'react-timeago'; import { useHistory } from 'react-router'; import { useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; -import ProfileImage from '../../ProfileImage'; import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases'; +import ProfileImage from '../../ProfileImage'; import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; import { breeze } from '../../../redux/store'; import './styles.css'; From 4e8fc934b9d2f4d8942bf9aa339ac11c8fec3e23 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 7 Feb 2021 20:53:17 +0200 Subject: [PATCH 15/17] Add PostVoting contract to concordia-shared package --- .../InitializationScreen/CustomLoader/index.jsx | 2 +- .../src/redux/actions/contractEventActions.js | 6 ++++++ .../contracts/events/PostVotingContractEvents.js | 10 ++++++++++ .../src/constants/contracts/events/index.js | 6 ++++-- 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 packages/concordia-shared/src/constants/contracts/events/PostVotingContractEvents.js diff --git a/packages/concordia-app/src/components/InitializationScreen/CustomLoader/index.jsx b/packages/concordia-app/src/components/InitializationScreen/CustomLoader/index.jsx index e64aa29..d97d214 100644 --- a/packages/concordia-app/src/components/InitializationScreen/CustomLoader/index.jsx +++ b/packages/concordia-app/src/components/InitializationScreen/CustomLoader/index.jsx @@ -8,7 +8,7 @@ import metamaskLogo from '../../../assets/images/metamask_logo.svg'; import ethereumLogo from '../../../assets/images/ethereum_logo.svg'; import ipfsLogo from '../../../assets/images/ipfs_logo.svg'; import orbitdbLogo from '../../../assets/images/orbitdb_logo.svg'; -import appLogo from '../../../assets/images/app_logo.svg'; +import appLogo from '../../../assets/images/app_logo_circle.svg'; const LoadingComponent = (props) => { useEffect(() => function cleanup() { diff --git a/packages/concordia-app/src/redux/actions/contractEventActions.js b/packages/concordia-app/src/redux/actions/contractEventActions.js index 36a7aea..b736e31 100644 --- a/packages/concordia-app/src/redux/actions/contractEventActions.js +++ b/packages/concordia-app/src/redux/actions/contractEventActions.js @@ -4,17 +4,23 @@ import { USER_SIGNED_UP_EVENT, USERNAME_UPDATED_EVENT, } from 'concordia-shared/src/constants/contracts/events/ForumContractEvents'; +import { + USER_VOTED_POST_EVENT, +} from 'concordia-shared/src/constants/contracts/events/PostVotingContractEvents'; export const FORUM_EVENT_USER_SIGNED_UP = 'FORUM_EVENT_USER_SIGNED_UP'; export const FORUM_EVENT_USERNAME_UPDATED = 'FORUM_EVENT_USERNAME_UPDATED'; export const FORUM_EVENT_TOPIC_CREATED = 'FORUM_EVENT_TOPIC_CREATED'; export const FORUM_EVENT_POST_CREATED = 'FORUM_EVENT_POST_CREATED'; +export const POST_VOTING_USER_VOTED_POST = 'POST_VOTING_USER_VOTED_POST'; + const eventActionMap = { [USER_SIGNED_UP_EVENT]: FORUM_EVENT_USER_SIGNED_UP, [USERNAME_UPDATED_EVENT]: FORUM_EVENT_USERNAME_UPDATED, [TOPIC_CREATED_EVENT]: FORUM_EVENT_TOPIC_CREATED, [POST_CREATED_EVENT]: FORUM_EVENT_POST_CREATED, + [USER_VOTED_POST_EVENT]: POST_VOTING_USER_VOTED_POST, }; export default eventActionMap; diff --git a/packages/concordia-shared/src/constants/contracts/events/PostVotingContractEvents.js b/packages/concordia-shared/src/constants/contracts/events/PostVotingContractEvents.js new file mode 100644 index 0000000..17582ab --- /dev/null +++ b/packages/concordia-shared/src/constants/contracts/events/PostVotingContractEvents.js @@ -0,0 +1,10 @@ +const USER_VOTED_POST_EVENT = 'UserVotedPost'; + +const postVotingContractEvents = Object.freeze([ + USER_VOTED_POST_EVENT, +]); + +module.exports = { + USER_VOTED_POST_EVENT, + postVotingContractEvents, +}; diff --git a/packages/concordia-shared/src/constants/contracts/events/index.js b/packages/concordia-shared/src/constants/contracts/events/index.js index 09e71a3..ddc86bd 100644 --- a/packages/concordia-shared/src/constants/contracts/events/index.js +++ b/packages/concordia-shared/src/constants/contracts/events/index.js @@ -1,8 +1,10 @@ -const forumContractEvents = require('./ForumContractEvents'); -const { FORUM_CONTRACT } = require('../ContractNames'); +const { forumContractEvents } = require('./ForumContractEvents'); +const { postVotingContractEvents } = require('./PostVotingContractEvents'); +const { FORUM_CONTRACT, POST_VOTING_CONTRACT } = require('../ContractNames'); const appEvents = Object.freeze({ [FORUM_CONTRACT]: forumContractEvents, + [POST_VOTING_CONTRACT]: postVotingContractEvents, }); module.exports = appEvents; From 4c9cddffa5643a93cccd0e2897d0b290f1fc4d7e Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 8 Feb 2021 12:46:12 +0200 Subject: [PATCH 16/17] fix: PostVoting total votes refresh --- .../components/PostList/PostVoting/index.jsx | 54 +++++++++++-------- .../contracts/PostVoting.sol | 6 +++ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx index a0f223c..68a6178 100644 --- a/packages/concordia-app/src/components/PostList/PostVoting/index.jsx +++ b/packages/concordia-app/src/components/PostList/PostVoting/index.jsx @@ -18,6 +18,7 @@ const { [POST_VOTING_CONTRACT]: { methods: { getVote: { cacheCall: getVoteChainData }, + getTotalVoteCount: { cacheCall: getTotalVoteCountChainData }, getUpvoteCount: { cacheCall: getUpvoteCountChainData }, getDownvoteCount: { cacheCall: getDownvoteCountChainData }, upvote, downvote, unvote, @@ -34,15 +35,18 @@ const PostVoting = (props) => { const userAccount = useSelector((state) => state.accounts[0]); // Current votes - const getVoteResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getVote); - const getUpvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getUpvoteCount); - const getDownvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getDownvoteCount); + const [getVoteCallHash, setGetVoteCallHash] = useState(null); + const [getTotalVoteCountCallHash, setGetTotalVoteCountCallHash] = useState(null); + const [getUpvoteCountCallHash, setGetUpvoteCountCallHash] = useState(null); + const [getDownvoteCountCallHash, setGetDownvoteCountCallHash] = useState(null); - const [getVoteCallHash, setGetVoteCallHash] = useState([]); - const [getUpvoteCountCallHash, setGetUpvoteCountCallHash] = useState([]); - const [getDownvoteCountCallHash, setGetDownvoteCountCallHash] = useState([]); + const getVoteResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getVote[getVoteCallHash]); + const getTotalVoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getTotalVoteCount[getTotalVoteCountCallHash]); + const getUpvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getUpvoteCount[getUpvoteCountCallHash]); + const getDownvoteCountResult = useSelector((state) => state.contracts[POST_VOTING_CONTRACT].getDownvoteCount[getDownvoteCountCallHash]); const [ownVote, setOwnVote] = useState(null); + const [totalVoteCount, setTotalVoteCount] = useState(null); const [upvoteCount, setUpvoteCount] = useState(null); const [downvoteCount, setDownvoteCount] = useState(null); @@ -55,38 +59,45 @@ const PostVoting = (props) => { // Current votes useEffect(() => { if (drizzleInitialized && !drizzleInitializationFailed && postId !== null) { - if (upvoteCount === null) setGetUpvoteCountCallHash(getUpvoteCountChainData(postId)); - - if (downvoteCount === null) setGetDownvoteCountCallHash(getDownvoteCountChainData(postId)); + if (getTotalVoteCountCallHash === null) setGetTotalVoteCountCallHash(getTotalVoteCountChainData(postId)); + if (getUpvoteCountCallHash === null) setGetUpvoteCountCallHash(getUpvoteCountChainData(postId)); + if (getDownvoteCountCallHash === null) setGetDownvoteCountCallHash(getDownvoteCountChainData(postId)); } - }, [downvoteCount, drizzleInitializationFailed, drizzleInitialized, postId, upvoteCount, userAccount]); + }, [drizzleInitializationFailed, drizzleInitialized, getDownvoteCountCallHash, + getTotalVoteCountCallHash, getUpvoteCountCallHash, postId]); useEffect(() => { const shouldGetOwnVoteFromChain = ownVote === null; if (drizzleInitialized && !drizzleInitializationFailed && shouldGetOwnVoteFromChain - && postId !== null && userAccount !== null) { + && postId !== null && userAccount !== null && getVoteCallHash === null) { setGetVoteCallHash(getVoteChainData(postId, userAccount)); } - }, [drizzleInitializationFailed, drizzleInitialized, ownVote, postId, userAccount]); + }, [drizzleInitializationFailed, drizzleInitialized, getVoteCallHash, ownVote, postId, userAccount]); + + useEffect(() => { + if (getVoteResult) { + setOwnVote(getVoteResult.value); + } + }, [getVoteResult]); useEffect(() => { - if (getVoteCallHash && getVoteResult && getVoteResult[getVoteCallHash]) { - setOwnVote(getVoteResult[getVoteCallHash].value); + if (getTotalVoteCountResult) { + setTotalVoteCount(getTotalVoteCountResult.value); } - }, [getVoteCallHash, getVoteResult]); + }, [getTotalVoteCountResult]); useEffect(() => { - if (getUpvoteCountCallHash && getUpvoteCountResult && getUpvoteCountResult[getUpvoteCountCallHash]) { - setUpvoteCount(getUpvoteCountResult[getUpvoteCountCallHash].value); + if (getUpvoteCountResult) { + setUpvoteCount(getUpvoteCountResult.value); } - }, [getUpvoteCountCallHash, getUpvoteCountResult]); + }, [getUpvoteCountResult]); useEffect(() => { - if (getDownvoteCountCallHash && getDownvoteCountResult && getDownvoteCountResult[getDownvoteCountCallHash]) { - setDownvoteCount(getDownvoteCountResult[getDownvoteCountCallHash].value); + if (getDownvoteCountResult) { + setDownvoteCount(getDownvoteCountResult.value); } - }, [getDownvoteCountCallHash, getDownvoteCountResult]); + }, [getDownvoteCountResult]); // Voting useEffect(() => { @@ -109,7 +120,6 @@ const PostVoting = (props) => { }, [ownVote, postId, userAccount, voting]); const disableVoting = userAccount === null || !hasSignedUp || postAuthorAddress === null || userAccount === postAuthorAddress; - const totalVoteCount = (upvoteCount !== null && downvoteCount !== null) ? upvoteCount - downvoteCount : null; return useMemo(() => (