import React, { Component } from 'react'; import { bindActionCreators } from 'redux'; import { push } from 'connected-react-router'; import { connect } from 'react-redux'; import { drizzle } from '../index'; import PostList from '../components/PostList'; import NewPost from '../components/NewPost'; import FloatingButton from '../components/FloatingButton'; import { setNavBarTitle } from '../redux/actions/userInterfaceActions.js'; const contract = 'Forum'; const getTopicMethod = 'getTopic'; class TopicContainer extends Component { constructor(props) { super(props); // Topic ID should be a positive integer if (!/^[0-9]+$/.test(this.props.match.params.topicId)) { this.props.navigateTo('/404'); } this.getBlockchainData = this.getBlockchainData.bind(this); this.fetchTopicSubject = this.fetchTopicSubject.bind(this); this.togglePostingState = this.togglePostingState.bind(this); this.postCreated = this.postCreated.bind(this); this.state = { pageStatus: 'initialized', topicID: parseInt(this.props.match.params.topicId), topicSubject: null, postFocus: this.props.match.params.postId && /^[0-9]+$/.test(this.props.match.params.postId) ? this.props.match.params.postId : null, fetchTopicSubjectStatus: 'pending', posting: false }; } getBlockchainData() { if (this.state.pageStatus === 'initialized' && this.props.drizzleStatus.initialized) { this.dataKey = drizzle.contracts[contract].methods[getTopicMethod].cacheCall( this.state.topicID, ); this.setState({ pageStatus: 'loading' }); } if (this.state.pageStatus === 'loading' && this.props.contracts[contract][getTopicMethod][this.dataKey]) { this.setState({ pageStatus: 'loaded' }); if (this.props.orbitDB.orbitdb !== null) { this.fetchTopicSubject( this.props.contracts[contract][getTopicMethod][this.dataKey].value[0], ); this.setState({ fetchTopicSubjectStatus: 'fetching' }); } } if (this.state.pageStatus === 'loaded' && this.state.fetchTopicSubjectStatus === 'pending' && this.props.orbitDB.orbitdb !== null) { this.fetchTopicSubject( this.props.contracts[contract][getTopicMethod][this.dataKey].value[0], ); this.setState({ fetchTopicSubjectStatus: 'fetching' }); } } async fetchTopicSubject(orbitDBAddress) { let orbitData; if (this.props.contracts[contract][getTopicMethod][this.dataKey].value[1] === this.props.user.address) { orbitData = this.props.orbitDB.topicsDB.get(this.state.topicID); } else { const fullAddress = `/orbitdb/${orbitDBAddress}/topics`; const store = await this.props.orbitDB.orbitdb.keyvalue(fullAddress); await store.load(); const localOrbitData = store.get(this.state.topicID); if (localOrbitData) { orbitData = localOrbitData; } else { // Wait until we have received something from the network store.events.on('replicated', () => { orbitData = store.get(this.state.topicID); }); } } this.props.setNavBarTitle(orbitData.subject); this.setState({ topicSubject: orbitData.subject, fetchTopicSubjectStatus: 'fetched' }); } togglePostingState(event) { if (event) { event.preventDefault(); } this.setState(prevState => ({ posting: !prevState.posting })); } postCreated() { this.setState(prevState => ({ posting: false })); } render() { let topicContents; if (this.state.pageStatus === 'loaded') { topicContents = ( ( <div> <PostList postIDs={this.props.contracts[contract][getTopicMethod][this.dataKey].value[4]} focusOnPost={this.state.postFocus ? this.state.postFocus : null} /> {this.state.posting && ( <NewPost topicID={this.state.topicID} subject={this.state.topicSubject} postIndex={this.props.contracts[contract][getTopicMethod][this.dataKey].value[4].length} onCancelClick={() => { this.togglePostingState(); }} onPostCreated={() => { this.postCreated(); }} /> ) } <div className="posts-list-spacer" /> {this.props.user.hasSignedUp && !this.state.posting && <FloatingButton onClick={this.togglePostingState} /> } </div> ) ); } return ( <div className="fill"> {topicContents} {!this.state.posting && <div className="bottom-overlay-pad" /> } </div> ); } componentDidMount() { this.getBlockchainData(); } componentDidUpdate() { this.getBlockchainData(); } componentWillUnmount() { this.props.setNavBarTitle(''); } } const mapDispatchToProps = dispatch => bindActionCreators({ navigateTo: location => push(location), setNavBarTitle: navBarTitle => setNavBarTitle(navBarTitle) }, dispatch); const mapStateToProps = state => ({ user: state.user, contracts: state.contracts, drizzleStatus: state.drizzleStatus, orbitDB: state.orbit }); export default connect(mapStateToProps, mapDispatchToProps)(TopicContainer);