mirror of https://gitlab.com/ecentrics/concordia
Ezerous
4 years ago
25 changed files with 512 additions and 209 deletions
@ -0,0 +1,22 @@ |
|||||
|
import React from 'react'; |
||||
|
|
||||
|
class ErrorBoundary extends React.Component { |
||||
|
constructor(props) { |
||||
|
super(props); |
||||
|
this.state = { hasError: false }; |
||||
|
} |
||||
|
|
||||
|
static getDerivedStateFromError() { |
||||
|
return { hasError: true }; |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { props: { children }, state: { hasError } } = this; |
||||
|
if (hasError) { |
||||
|
return <h1>Something went wrong.</h1>; // TODO: Make a better "Something went wrong" screen |
||||
|
} |
||||
|
return children; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default ErrorBoundary; |
@ -1,4 +0,0 @@ |
|||||
#topic-list{ |
|
||||
height: auto; |
|
||||
clear: both; |
|
||||
} |
|
@ -1,3 +1,7 @@ |
|||||
#post-list{ |
#post-list{ |
||||
height: 100%; |
height: 100%; |
||||
} |
} |
||||
|
|
||||
|
#post-list-pagination{ |
||||
|
padding: 1rem 0; |
||||
|
} |
||||
|
@ -1,7 +1,8 @@ |
|||||
.particles { |
.particles { |
||||
position: fixed; |
position: fixed; |
||||
right: 0; |
top: 0; |
||||
bottom: 0; |
bottom: 0; |
||||
|
right: 0; |
||||
left: 0; |
left: 0; |
||||
background: var(--secondary-color); |
background: var(--secondary-color); |
||||
} |
} |
||||
|
@ -1,67 +0,0 @@ |
|||||
import React, { useMemo } from 'react'; |
|
||||
import { Button, Header } from 'semantic-ui-react'; |
|
||||
import { useSelector } from 'react-redux'; |
|
||||
import { useHistory } from 'react-router'; |
|
||||
import { useTranslation } from 'react-i18next'; |
|
||||
import PropTypes from 'prop-types'; |
|
||||
import PaginatedTopicList from '../../../components/Pagination/PaginatedTopicList'; |
|
||||
import './styles.css'; |
|
||||
|
|
||||
const Board = (props) => { |
|
||||
const { numberOfTopics } = props; |
|
||||
const hasSignedUp = useSelector((state) => state.user.hasSignedUp); |
|
||||
const history = useHistory(); |
|
||||
const { t } = useTranslation(); |
|
||||
|
|
||||
const boardContents = useMemo(() => ( |
|
||||
<> |
|
||||
{hasSignedUp |
|
||||
? ( |
|
||||
<Button |
|
||||
id="new-topic-button" |
|
||||
className="primary-button" |
|
||||
content="New Topic" |
|
||||
icon="plus" |
|
||||
labelPosition="left" |
|
||||
positive |
|
||||
onClick={() => history.push('/topics/new')} |
|
||||
/> |
|
||||
) |
|
||||
: null} |
|
||||
{/* eslint-disable-next-line no-nested-ternary */} |
|
||||
{numberOfTopics > 0 |
|
||||
// eslint-disable-next-line react/jsx-no-undef |
|
||||
? (<PaginatedTopicList />) |
|
||||
: (!hasSignedUp |
|
||||
? ( |
|
||||
<div id="no-topic-message" className="vertical-center-in-parent unselectable"> |
|
||||
<Header textAlign="center" as="h2"> |
|
||||
{t('board.header.no.topics.message')} |
|
||||
</Header> |
|
||||
<Header textAlign="center" as="h3"> |
|
||||
{t('board.sub.header.no.topics.guest')} |
|
||||
</Header> |
|
||||
</div> |
|
||||
) |
|
||||
: ( |
|
||||
<div id="no-topic-message" className="vertical-center-in-parent unselectable"> |
|
||||
<Header textAlign="center" as="h2"> |
|
||||
{t('board.header.no.topics.message')} |
|
||||
</Header> |
|
||||
<Header textAlign="center" as="h3"> |
|
||||
{t('board.sub.header.no.topics.user')} |
|
||||
</Header> |
|
||||
</div> |
|
||||
))} |
|
||||
|
|
||||
</> |
|
||||
), [numberOfTopics, hasSignedUp, t, history]); |
|
||||
|
|
||||
return (boardContents); |
|
||||
}; |
|
||||
|
|
||||
Board.propTypes = { |
|
||||
numberOfTopics: PropTypes.number.isRequired, |
|
||||
}; |
|
||||
|
|
||||
export default Board; |
|
@ -1,15 +0,0 @@ |
|||||
#no-topic-message { |
|
||||
padding-top: 22rem; |
|
||||
clear: both; |
|
||||
} |
|
||||
|
|
||||
#no-topic-message > .header { |
|
||||
color: white; |
|
||||
} |
|
||||
|
|
||||
#new-topic-button{ |
|
||||
float:right; |
|
||||
margin-top: 1px; |
|
||||
margin-bottom: 2em; |
|
||||
margin-right: 0; |
|
||||
} |
|
@ -1,3 +1,19 @@ |
|||||
#home-container { |
#home-container { |
||||
height: 100%; |
height: 100%; |
||||
} |
} |
||||
|
|
||||
|
#no-topic-message { |
||||
|
padding-top: 22rem; |
||||
|
clear: both; |
||||
|
} |
||||
|
|
||||
|
#no-topic-message > .header { |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
#new-topic-button{ |
||||
|
float:right; |
||||
|
margin-top: 1px; |
||||
|
margin-bottom: 2em; |
||||
|
margin-right: 0; |
||||
|
} |
||||
|
@ -0,0 +1,89 @@ |
|||||
|
import React, { |
||||
|
useEffect, useMemo, useState, |
||||
|
} from 'react'; |
||||
|
import { useSelector } from 'react-redux'; |
||||
|
import { useTranslation } from 'react-i18next'; |
||||
|
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; |
||||
|
import { Header } from 'semantic-ui-react'; |
||||
|
import { drizzle } from '../../../redux/store'; |
||||
|
import { ITEMS_PER_PAGE } from '../../../components/PaginationComponent'; |
||||
|
import PostList from '../../../components/PostList'; |
||||
|
|
||||
|
const { |
||||
|
contracts: { |
||||
|
[FORUM_CONTRACT]: { |
||||
|
methods: { |
||||
|
getUserPostCount: { cacheCall: getUserPostCountChainData }, |
||||
|
getUserPosts: { cacheCall: getUserPostsChainData }, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
} = drizzle; |
||||
|
|
||||
|
const ProfilePostList = (props) => { |
||||
|
const { username, profileAddress } = props; |
||||
|
const [pageNumber, setPageNumber] = useState(1); |
||||
|
|
||||
|
const [userPostCount, setUserPostCount] = useState(null); |
||||
|
const [postIds, setPostIds] = useState([]); |
||||
|
|
||||
|
const [getUserPostCountCallHash, setGetUserPostCountCallHash] = useState(null); |
||||
|
const [getUserPostsCallHash, setGetUserPostsCallHash] = useState(null); |
||||
|
|
||||
|
const getUserPostCountResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getUserPostCount[getUserPostCountCallHash]); |
||||
|
const getUserPostsResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getUserPosts[getUserPostsCallHash]); |
||||
|
|
||||
|
const { t } = useTranslation(); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserPostCountCallHash === null) { |
||||
|
setGetUserPostCountCallHash(getUserPostCountChainData(profileAddress)); |
||||
|
} |
||||
|
}, [getUserPostCountCallHash, profileAddress]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (userPostCount !== null && userPostCount !== 0) { |
||||
|
const startIndex = Math.max(userPostCount - ITEMS_PER_PAGE * pageNumber, 0); |
||||
|
const endIndex = userPostCount - ITEMS_PER_PAGE * (pageNumber - 1) - 1; |
||||
|
setGetUserPostsCallHash(getUserPostsChainData(profileAddress, startIndex, endIndex)); |
||||
|
} |
||||
|
}, [pageNumber, profileAddress, userPostCount]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserPostCountResult) { |
||||
|
setUserPostCount(parseInt(getUserPostCountResult.value, 10)); |
||||
|
} |
||||
|
}, [getUserPostCountResult, userPostCount]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserPostsResult) { |
||||
|
setPostIds(getUserPostsResult.value.slice().reverse().map(Number)); |
||||
|
} |
||||
|
}, [getUserPostsResult, userPostCount]); |
||||
|
|
||||
|
const handlePageChange = (event, data) => { |
||||
|
setPageNumber(data.activePage); |
||||
|
}; |
||||
|
|
||||
|
return useMemo(() => { |
||||
|
if (postIds.length && postIds.length !== 0) { |
||||
|
return ( |
||||
|
<PostList |
||||
|
postIds={postIds} |
||||
|
numberOfItems={userPostCount} |
||||
|
onPageChange={handlePageChange} |
||||
|
/> |
||||
|
); |
||||
|
} |
||||
|
if (userPostCount === 0) { |
||||
|
return ( |
||||
|
<Header textAlign="center" as="h2"> |
||||
|
{t('profile.user.has.no.posts.header.message', { user: username })} |
||||
|
</Header> |
||||
|
); |
||||
|
} |
||||
|
return null; |
||||
|
}, [t, postIds, userPostCount, username]); |
||||
|
}; |
||||
|
|
||||
|
export default ProfilePostList; |
@ -0,0 +1,89 @@ |
|||||
|
import React, { |
||||
|
useEffect, useMemo, useState, |
||||
|
} from 'react'; |
||||
|
import { useSelector } from 'react-redux'; |
||||
|
import { useTranslation } from 'react-i18next'; |
||||
|
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; |
||||
|
import { Header } from 'semantic-ui-react'; |
||||
|
import { drizzle } from '../../../redux/store'; |
||||
|
import { ITEMS_PER_PAGE } from '../../../components/PaginationComponent'; |
||||
|
import TopicList from '../../../components/TopicList'; |
||||
|
|
||||
|
const { |
||||
|
contracts: { |
||||
|
[FORUM_CONTRACT]: { |
||||
|
methods: { |
||||
|
getUserTopicCount: { cacheCall: getUserTopicCountChainData }, |
||||
|
getUserTopics: { cacheCall: getUserTopicsChainData }, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
} = drizzle; |
||||
|
|
||||
|
const ProfileTopicList = (props) => { |
||||
|
const { username, profileAddress } = props; |
||||
|
const [pageNumber, setPageNumber] = useState(1); |
||||
|
|
||||
|
const [userTopicCount, setUserTopicCount] = useState(null); |
||||
|
const [topicIds, setTopicIds] = useState([]); |
||||
|
|
||||
|
const [getUserTopicCountCallHash, setGetUserTopicCountCallHash] = useState(null); |
||||
|
const [getUserTopicsCallHash, setGetUserTopicsCallHash] = useState(null); |
||||
|
|
||||
|
const getUserTopicCountResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getUserTopicCount[getUserTopicCountCallHash]); |
||||
|
const getUserTopicsResult = useSelector((state) => state.contracts[FORUM_CONTRACT].getUserTopics[getUserTopicsCallHash]); |
||||
|
|
||||
|
const { t } = useTranslation(); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserTopicCountCallHash === null) { |
||||
|
setGetUserTopicCountCallHash(getUserTopicCountChainData(profileAddress)); |
||||
|
} |
||||
|
}, [getUserTopicCountCallHash, profileAddress]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (userTopicCount !== null && userTopicCount !== 0) { |
||||
|
const startIndex = Math.max(userTopicCount - ITEMS_PER_PAGE * pageNumber, 0); |
||||
|
const endIndex = userTopicCount - ITEMS_PER_PAGE * (pageNumber - 1) - 1; |
||||
|
setGetUserTopicsCallHash(getUserTopicsChainData(profileAddress, startIndex, endIndex)); |
||||
|
} |
||||
|
}, [pageNumber, profileAddress, userTopicCount]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserTopicCountResult) { |
||||
|
setUserTopicCount(parseInt(getUserTopicCountResult.value, 10)); |
||||
|
} |
||||
|
}, [getUserTopicCountResult, userTopicCount]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (getUserTopicsResult) { |
||||
|
setTopicIds(getUserTopicsResult.value.slice().reverse().map(Number)); |
||||
|
} |
||||
|
}, [getUserTopicsResult, userTopicCount]); |
||||
|
|
||||
|
const handlePageChange = (event, data) => { |
||||
|
setPageNumber(data.activePage); |
||||
|
}; |
||||
|
|
||||
|
return useMemo(() => { |
||||
|
if (topicIds.length && topicIds.length !== 0) { |
||||
|
return ( |
||||
|
<TopicList |
||||
|
topicIds={topicIds} |
||||
|
numberOfItems={userTopicCount} |
||||
|
onPageChange={handlePageChange} |
||||
|
/> |
||||
|
); |
||||
|
} |
||||
|
if (userTopicCount === 0) { |
||||
|
return ( |
||||
|
<Header textAlign="center" as="h2"> |
||||
|
{t('profile.user.has.no.topics.header.message', { user: username })} |
||||
|
</Header> |
||||
|
); |
||||
|
} |
||||
|
return null; |
||||
|
}, [t, topicIds, userTopicCount, username]); |
||||
|
}; |
||||
|
|
||||
|
export default ProfileTopicList; |
@ -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 = ITEMS_PER_PAGE * (pageNumber - 1); |
||||
|
const endIndex = Math.min(ITEMS_PER_PAGE * pageNumber - 1, topicPostCount - 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().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; |
Loading…
Reference in new issue