| 
						
						
						
					 | 
					@ -1,4 +1,4 @@ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					import React, { useEffect, useState } from 'react'; | 
					 | 
					 | 
					import React, { useEffect, useMemo, useState } from 'react'; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					import PropTypes from 'prop-types'; | 
					 | 
					 | 
					import PropTypes from 'prop-types'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { useDispatch, useSelector } from 'react-redux'; | 
					 | 
					 | 
					import { useDispatch, useSelector } from 'react-redux'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { | 
					 | 
					 | 
					import { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -6,19 +6,25 @@ import { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} from 'semantic-ui-react'; | 
					 | 
					 | 
					} from 'semantic-ui-react'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { Link } from 'react-router-dom'; | 
					 | 
					 | 
					import { Link } from 'react-router-dom'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { useHistory } from 'react-router'; | 
					 | 
					 | 
					import { useHistory } from 'react-router'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; | 
					 | 
					 | 
					import { FORUM_CONTRACT, VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases'; | 
					 | 
					 | 
					import { TOPICS_DATABASE, USER_DATABASE } from 'concordia-shared/src/constants/orbit/OrbitDatabases'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import ReactMarkdown from 'react-markdown'; | 
					 | 
					 | 
					import ReactMarkdown from 'react-markdown'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { breeze, drizzle } from '../../../redux/store'; | 
					 | 
					 | 
					import { breeze, drizzle } from '../../../redux/store'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; | 
					 | 
					 | 
					import { FETCH_USER_DATABASE } from '../../../redux/actions/peerDbReplicationActions'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import './styles.css'; | 
					 | 
					 | 
					import './styles.css'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import TopicPostList from './TopicPostList'; | 
					 | 
					 | 
					import TopicPostList from './TopicPostList'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					import PollView from '../../../components/PollView'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import determineKVAddress from '../../../utils/orbitUtils'; | 
					 | 
					 | 
					import determineKVAddress from '../../../utils/orbitUtils'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys'; | 
					 | 
					 | 
					import { TOPIC_SUBJECT } from '../../../constants/orbit/TopicsDatabaseKeys'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import PostCreate from '../../../components/PostCreate'; | 
					 | 
					 | 
					import PostCreate from '../../../components/PostCreate'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import targetBlank from '../../../utils/markdownUtils'; | 
					 | 
					 | 
					import targetBlank from '../../../utils/markdownUtils'; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					const { contracts: { [FORUM_CONTRACT]: { methods: { getTopic: { cacheCall: getTopicChainData } } } } } = drizzle; | 
					 | 
					 | 
					const { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  contracts: { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    [FORUM_CONTRACT]: { methods: { getTopic: { cacheCall: getTopicChainData } } }, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    [VOTING_CONTRACT]: { methods: { pollExists: { cacheCall: pollExistsChainData } } }, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  }, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					} = drizzle; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					const { orbit } = breeze; | 
					 | 
					 | 
					const { orbit } = breeze; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					const TopicView = (props) => { | 
					 | 
					 | 
					const TopicView = (props) => { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -29,15 +35,18 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const userAddress = useSelector((state) => state.user.address); | 
					 | 
					 | 
					  const userAddress = useSelector((state) => state.user.address); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const hasSignedUp = useSelector((state) => state.user.hasSignedUp); | 
					 | 
					 | 
					  const hasSignedUp = useSelector((state) => state.user.hasSignedUp); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const getTopicResults = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopic); | 
					 | 
					 | 
					  const getTopicResults = useSelector((state) => state.contracts[FORUM_CONTRACT].getTopic); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  const pollExistsResults = useSelector((state) => state.contracts[VOTING_CONTRACT].pollExists); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const topics = useSelector((state) => state.orbitData.topics); | 
					 | 
					 | 
					  const topics = useSelector((state) => state.orbitData.topics); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const users = useSelector((state) => state.orbitData.users); | 
					 | 
					 | 
					  const users = useSelector((state) => state.orbitData.users); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					  const [getTopicCallHash, setGetTopicCallHash] = useState([]); | 
					 | 
					 | 
					  const [getTopicCallHash, setGetTopicCallHash] = useState(null); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  const [pollExistsCallHash, setPollExistsCallHash] = useState(null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [topicAuthorAddress, setTopicAuthorAddress] = useState(initialTopicAuthorAddress || null); | 
					 | 
					 | 
					  const [topicAuthorAddress, setTopicAuthorAddress] = useState(initialTopicAuthorAddress || null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [topicAuthor, setTopicAuthor] = useState(initialTopicAuthor || null); | 
					 | 
					 | 
					  const [topicAuthor, setTopicAuthor] = useState(initialTopicAuthor || null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [timestamp, setTimestamp] = useState(initialTimestamp || null); | 
					 | 
					 | 
					  const [timestamp, setTimestamp] = useState(initialTimestamp || null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [postIds, setPostIds] = useState(initialPostIds || null); | 
					 | 
					 | 
					  const [postIds, setPostIds] = useState(initialPostIds || null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [numberOfReplies, setReplyCount] = useState(0); | 
					 | 
					 | 
					  const [numberOfReplies, setReplyCount] = useState(0); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const [topicSubject, setTopicSubject] = useState(null); | 
					 | 
					 | 
					  const [topicSubject, setTopicSubject] = useState(null); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  const [hasPoll, setHasPoll] = useState(false); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const history = useHistory(); | 
					 | 
					 | 
					  const history = useHistory(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const dispatch = useDispatch(); | 
					 | 
					 | 
					  const dispatch = useDispatch(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -52,6 +61,10 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  }, [postIds, timestamp, topicAuthor, topicAuthorAddress, topicId]); | 
					 | 
					 | 
					  }, [postIds, timestamp, topicAuthor, topicAuthorAddress, topicId]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  useEffect(() => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    setPollExistsCallHash(pollExistsChainData(topicId)); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  }, [topicId]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  useEffect(() => { | 
					 | 
					 | 
					  useEffect(() => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if (getTopicCallHash && getTopicResults && getTopicResults[getTopicCallHash]) { | 
					 | 
					 | 
					    if (getTopicCallHash && getTopicResults && getTopicResults[getTopicCallHash]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      if (getTopicResults[getTopicCallHash].value == null) { | 
					 | 
					 | 
					      if (getTopicResults[getTopicCallHash].value == null) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -62,9 +75,9 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      setTopicAuthorAddress(getTopicResults[getTopicCallHash].value[0]); | 
					 | 
					 | 
					      setTopicAuthorAddress(getTopicResults[getTopicCallHash].value[0]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      setTopicAuthor(getTopicResults[getTopicCallHash].value[1]); | 
					 | 
					 | 
					      setTopicAuthor(getTopicResults[getTopicCallHash].value[1]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      setTimestamp(getTopicResults[getTopicCallHash].value[2] * 1000); | 
					 | 
					 | 
					      setTimestamp(getTopicResults[getTopicCallHash].value[2] * 1000); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					      const postIds = getTopicResults[getTopicCallHash].value[3].map((postId) => parseInt(postId, 10)); | 
					 | 
					 | 
					      const fetchedPostIds = getTopicResults[getTopicCallHash].value[3].map((postId) => parseInt(postId, 10)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					      setPostIds(postIds); | 
					 | 
					 | 
					      setPostIds(fetchedPostIds); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					      setReplyCount(postIds.length - 1); | 
					 | 
					 | 
					      setReplyCount(fetchedPostIds.length - 1); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      const topicFound = topics | 
					 | 
					 | 
					      const topicFound = topics | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        .find((topic) => topic.id === topicId); | 
					 | 
					 | 
					        .find((topic) => topic.id === topicId); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -80,6 +93,12 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  }, [dispatch, getTopicCallHash, getTopicResults, history, topicId, topics, userAddress]); | 
					 | 
					 | 
					  }, [dispatch, getTopicCallHash, getTopicResults, history, topicId, topics, userAddress]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  useEffect(() => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    if (pollExistsCallHash && pollExistsResults && pollExistsResults[pollExistsCallHash]) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					      setHasPoll(pollExistsResults[pollExistsCallHash].value); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  }, [pollExistsCallHash, pollExistsResults, topicId]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  useEffect(() => { | 
					 | 
					 | 
					  useEffect(() => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if (topicAuthorAddress !== null) { | 
					 | 
					 | 
					    if (topicAuthorAddress !== null) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      determineKVAddress({ orbit, dbName: USER_DATABASE, userAddress: topicAuthorAddress }) | 
					 | 
					 | 
					      determineKVAddress({ orbit, dbName: USER_DATABASE, userAddress: topicAuthorAddress }) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -111,6 +130,8 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  }, [topicId, topics]); | 
					 | 
					 | 
					  }, [topicId, topics]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					  const poll = useMemo(() => hasPoll && <PollView />, [hasPoll]); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  const stopClickPropagation = (event) => { | 
					 | 
					 | 
					  const stopClickPropagation = (event) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    event.stopPropagation(); | 
					 | 
					 | 
					    event.stopPropagation(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					  }; | 
					 | 
					 | 
					  }; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -147,7 +168,9 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        | 
					 | 
					 | 
					                        | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                          <Icon name="user" fitted /> | 
					 | 
					 | 
					                          <Icon name="user" fitted /> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                      | 
					 | 
					 | 
					                      | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                          <Link to={`/users/${topicAuthorAddress}`} onClick={stopClickPropagation}>{ topicAuthor }</Link> | 
					 | 
					 | 
					                          <Link to={`/users/${topicAuthorAddress}`} onClick={stopClickPropagation}> | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                              {topicAuthor} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          </Link> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        | 
					 | 
					 | 
					                        | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                          <Icon name="reply" fitted /> | 
					 | 
					 | 
					                          <Icon name="reply" fitted /> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                      | 
					 | 
					 | 
					                      | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -155,6 +178,16 @@ const TopicView = (props) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                      </div> | 
					 | 
					 | 
					                      </div> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                  </div> | 
					 | 
					 | 
					                  </div> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                  <Divider /> | 
					 | 
					 | 
					                  <Divider /> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                  { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                  hasPoll && ( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                      <> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          <div id="topic-poll"> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                              {poll} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          </div> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                          <Divider /> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                      </> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                  ) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					              </Dimmer.Dimmable> | 
					 | 
					 | 
					              </Dimmer.Dimmable> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					              <TopicPostList topicId={topicId} loading={postIds === null} focusOnPost={focusOnPost} /> | 
					 | 
					 | 
					              <TopicPostList topicId={topicId} loading={postIds === null} focusOnPost={focusOnPost} /> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					          </Segment> | 
					 | 
					 | 
					          </Segment> | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |