mirror of https://gitlab.com/ecentrics/concordia
Apostolos Fanakis
4 years ago
6 changed files with 191 additions and 3 deletions
@ -0,0 +1,103 @@ |
|||||
|
import React, { |
||||
|
memo, useEffect, useMemo, useState, |
||||
|
} from 'react'; |
||||
|
import { |
||||
|
Dimmer, Grid, List, Loader, Placeholder, |
||||
|
} from 'semantic-ui-react'; |
||||
|
import PropTypes from 'prop-types'; |
||||
|
import { useTranslation } from 'react-i18next'; |
||||
|
import moment from 'moment'; |
||||
|
import { useHistory } from 'react-router'; |
||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||
|
import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; |
||||
|
import { breeze } from '../../../redux/store'; |
||||
|
import './styles.css'; |
||||
|
|
||||
|
const { orbit } = breeze; |
||||
|
|
||||
|
const PostListRow = (props) => { |
||||
|
const { id: postId, postCallHash, loading } = props; |
||||
|
const getPostResults = useSelector((state) => state.contracts.Forum.getPost); |
||||
|
const [postAuthorAddress, setPostAuthorAddress] = useState(null); |
||||
|
const [postAuthor, setPostAuthor] = useState(null); |
||||
|
const [timeAgo, setTimeAgo] = useState(null); |
||||
|
const [postSubject, setPostSubject] = useState(null); |
||||
|
const [postMessage, setPostMessage] = useState(null); |
||||
|
const userAddress = useSelector((state) => state.user.address); |
||||
|
const posts = useSelector((state) => state.orbitData.posts); |
||||
|
const dispatch = useDispatch(); |
||||
|
const history = useHistory(); |
||||
|
const { t } = useTranslation(); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (!loading && postCallHash && getPostResults[postCallHash] !== undefined) { |
||||
|
setPostAuthorAddress(getPostResults[postCallHash].value[0]); |
||||
|
setPostAuthor(getPostResults[postCallHash].value[1]); |
||||
|
setTimeAgo(moment(getPostResults[postCallHash].value[2] * 1000).fromNow()); |
||||
|
} |
||||
|
}, [getPostResults, loading, postCallHash]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (postAuthorAddress && userAddress !== postAuthorAddress) { |
||||
|
dispatch({ |
||||
|
type: FETCH_USER_DATABASE, |
||||
|
orbit, |
||||
|
dbName: 'posts', |
||||
|
userAddress: postAuthorAddress, |
||||
|
}); |
||||
|
} |
||||
|
}, [dispatch, postAuthorAddress, userAddress]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
const postFound = posts |
||||
|
.find((post) => post.id === postId); |
||||
|
|
||||
|
if (postFound) { |
||||
|
setPostSubject(postFound.subject); |
||||
|
setPostMessage(postFound.message); |
||||
|
} |
||||
|
}, [postId, posts]); |
||||
|
|
||||
|
return useMemo(() => ( |
||||
|
<Dimmer.Dimmable as={List.Item} blurring dimmed={loading} className="list-item"> |
||||
|
<List.Icon name="user circle" size="big" inverted color="black" verticalAlign="middle" /> |
||||
|
<List.Content> |
||||
|
<List.Header> |
||||
|
<Grid> |
||||
|
<Grid.Column floated="left" width={14}> |
||||
|
{postSubject !== null |
||||
|
? postSubject |
||||
|
: <Placeholder><Placeholder.Line length="very long" /></Placeholder>} |
||||
|
</Grid.Column> |
||||
|
<Grid.Column floated="right" width={2} textAlign="right"> |
||||
|
<span className="post-metadata"> |
||||
|
{t('post.list.row.post.id', { id: postId })} |
||||
|
</span> |
||||
|
</Grid.Column> |
||||
|
</Grid> |
||||
|
</List.Header> |
||||
|
<List.Description> |
||||
|
<Grid verticalAlign="middle"> |
||||
|
<Grid.Column floated="left" width={14}> |
||||
|
{postAuthor !== null && timeAgo !== null |
||||
|
? t('post.list.row.author.date', { author: postAuthor, timeAgo }) |
||||
|
: <Placeholder><Placeholder.Line length="long" /></Placeholder>} |
||||
|
</Grid.Column> |
||||
|
</Grid> |
||||
|
</List.Description> |
||||
|
</List.Content> |
||||
|
</Dimmer.Dimmable> |
||||
|
), [loading, postAuthor, postId, postSubject, t, timeAgo]); |
||||
|
}; |
||||
|
|
||||
|
PostListRow.defaultProps = { |
||||
|
loading: false, |
||||
|
}; |
||||
|
|
||||
|
PostListRow.propTypes = { |
||||
|
id: PropTypes.number.isRequired, |
||||
|
postCallHash: PropTypes.string, |
||||
|
loading: PropTypes.bool, |
||||
|
}; |
||||
|
|
||||
|
export default memo(PostListRow); |
@ -0,0 +1,8 @@ |
|||||
|
.post-metadata { |
||||
|
font-size: 12px !important; |
||||
|
font-weight: initial; |
||||
|
} |
||||
|
|
||||
|
.list-item { |
||||
|
text-align: start; |
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
import React, { |
||||
|
useEffect, useMemo, useState, |
||||
|
} from 'react'; |
||||
|
import PropTypes from 'prop-types'; |
||||
|
import { useSelector } from 'react-redux'; |
||||
|
import { Dimmer, List, Loader } from 'semantic-ui-react'; |
||||
|
import PostListRow from './PostListRow'; |
||||
|
import { drizzle } from '../../redux/store'; |
||||
|
|
||||
|
const { contracts: { Forum: { methods: { getPost: { cacheCall: getPostChainData } } } } } = drizzle; |
||||
|
|
||||
|
const PostList = (props) => { |
||||
|
const { postIds, loading } = props; |
||||
|
const [getPostCallHashes, setGetPostCallHashes] = useState([]); |
||||
|
const drizzleInitialized = useSelector((state) => state.drizzleStatus.initialized); |
||||
|
const drizzleInitializationFailed = useSelector((state) => state.drizzleStatus.failed); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (drizzleInitialized && !drizzleInitializationFailed && !loading) { |
||||
|
const newPostsFound = postIds |
||||
|
.filter((postId) => !getPostCallHashes |
||||
|
.map((getPostCallHash) => getPostCallHash.id) |
||||
|
.includes(postId)); |
||||
|
|
||||
|
if (newPostsFound.length > 0) { |
||||
|
setGetPostCallHashes([ |
||||
|
...getPostCallHashes, |
||||
|
...newPostsFound |
||||
|
.map((postId) => ({ |
||||
|
id: postId, |
||||
|
hash: getPostChainData(postId), |
||||
|
})), |
||||
|
]); |
||||
|
} |
||||
|
} |
||||
|
}, [drizzleInitializationFailed, drizzleInitialized, getPostCallHashes, loading, postIds]); |
||||
|
|
||||
|
const posts = useMemo(() => { |
||||
|
if (loading) { |
||||
|
return null; |
||||
|
} |
||||
|
return postIds |
||||
|
.map((postId) => { |
||||
|
const postHash = getPostCallHashes.find((getPostCallHash) => getPostCallHash.id === postId); |
||||
|
|
||||
|
return ( |
||||
|
<PostListRow |
||||
|
id={postId} |
||||
|
key={postId} |
||||
|
postCallHash={postHash && postHash.hash} |
||||
|
loading={postHash === undefined} |
||||
|
/> |
||||
|
); |
||||
|
}); |
||||
|
}, [getPostCallHashes, loading, postIds]); |
||||
|
|
||||
|
return ( |
||||
|
<Dimmer.Dimmable as={List} blurring dimmed={loading} selection divided id="post-list" size="big"> |
||||
|
<Loader active={loading} /> |
||||
|
{posts} |
||||
|
</Dimmer.Dimmable> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
PostList.propTypes = { |
||||
|
postIds: PropTypes.arrayOf(PropTypes.number).isRequired, |
||||
|
loading: PropTypes.bool, |
||||
|
}; |
||||
|
|
||||
|
export default PostList; |
@ -0,0 +1,3 @@ |
|||||
|
#post-list{ |
||||
|
height: 100%; |
||||
|
} |
Loading…
Reference in new issue