Browse Source

Fix NewPost causing PostList re-rendering, Add date of user registration, other minor fixes

develop
Apostolos Fanakis 7 years ago
parent
commit
7d8ba7c6e4
  1. 17
      contracts/Forum.sol
  2. 18
      src/assets/css/App.css
  3. 10
      src/components/FloatingButton.js
  4. 2
      src/components/NewPost.js
  5. 5
      src/components/ProfileInformation.js
  6. 22
      src/components/TopicList.js
  7. 5
      src/containers/BoardContainer.js
  8. 35
      src/containers/ProfileContainer.js
  9. 10
      src/containers/TopicContainer.js
  10. 26
      src/util/orbit.js

17
contracts/Forum.sol

@ -8,6 +8,7 @@ contract Forum {
OrbitDB orbitdb;
uint[] topicIDs; // IDs of the topics the user created
uint[] postIDs; // IDs of the posts the user created
uint timestamp;
bool signedUp; // Helper variable for hasUserSignedUp()
}
@ -20,7 +21,9 @@ contract Forum {
function signUp(string username, string orbitDBId, string orbitTopicsDB, string orbitPostsDB, string orbitPublicKey, string orbitPrivateKey) public returns (bool) {
require (!hasUserSignedUp(msg.sender), "User has already signed up.");
require(!isUserNameTaken(username), "Username is already taken.");
users[msg.sender] = User(username, OrbitDB(orbitDBId, orbitTopicsDB, orbitPostsDB, orbitPublicKey, orbitPrivateKey), new uint[](0), new uint[](0), true);
users[msg.sender] = User(username,
OrbitDB(orbitDBId,orbitTopicsDB, orbitPostsDB, orbitPublicKey, orbitPrivateKey),
new uint[](0), new uint[](0), block.timestamp, true);
userAddresses[username] = msg.sender;
emit UserSignedUp(username, msg.sender);
return true;
@ -56,15 +59,20 @@ contract Forum {
}
function getUserTopics(address userAddress) public view returns (uint[]) {
require (hasUserSignedUp(msg.sender), "User hasn't signed up yet.");
require (hasUserSignedUp(userAddress), "User hasn't signed up yet.");
return users[userAddress].topicIDs;
}
function getUserPosts(address userAddress) public view returns (uint[]) {
require (hasUserSignedUp(msg.sender), "User hasn't signed up yet.");
require (hasUserSignedUp(userAddress), "User hasn't signed up yet.");
return users[userAddress].postIDs;
}
function getUserDateOfRegister(address userAddress) public view returns (uint) {
require (hasUserSignedUp(userAddress), "User hasn't signed up yet.");
return users[userAddress].timestamp;
}
//----------------------------------------OrbitDB----------------------------------------
struct OrbitDB {
string id; // TODO: set an upper bound instead of arbitrary string
@ -136,8 +144,6 @@ contract Forum {
event TopicCreated(uint topicID, uint postID);
event PostCreated(uint postID, uint topicID);
/* event NumberOfTopicsReceived(uint numTopics);
event TopicReceived(string orbitTopicsDB, address author, string username, uint timestamp, uint[] postIDs); */
function createTopic() public returns (uint, uint) {
require(hasUserSignedUp(msg.sender)); // Only registered users can create topics
@ -168,7 +174,6 @@ contract Forum {
}
function getNumberOfTopics() public view returns (uint) {
/* emit NumberOfTopicsReceived(numTopics); */
return numTopics;
}

18
src/assets/css/App.css

@ -184,15 +184,15 @@ body,
/* FLOATING BUTTONS */
.floating-button{
position:fixed;
width:60px;
height:60px;
bottom:40px;
right:40px;
background-color:#0C9;
color:#FFF;
border-radius:50px;
text-align:center;
position: fixed;
width: 60px;
height: 60px;
bottom: 40px;
right: 40px;
background-color: #0C9;
color: #FFF;
border-radius: 50px;
text-align: center;
box-shadow: 2px 2px 3px #999;
}

10
src/components/FloatingButton.js

@ -1,11 +1,19 @@
import React from 'react';
import { Link } from 'react-router';
const FloatingButton = (props) => {
return (
<div className="pure-u-1-1" onClick={props.onClick}>
<div className="pure-u-1-1">
{props.to
?<Link to={props.to}>
<p className="no-margin floating-button" data-fa-transform="down-6">
<i className="fa fa-plus fa-2x"></i>
</p>
</Link>
:<p className="no-margin floating-button" data-fa-transform="down-6" onClick={props.onClick}>
<i className="fa fa-plus fa-2x"></i>
</p>
}
</div>
);
};

2
src/components/NewPost.js

@ -22,7 +22,7 @@ class NewPost extends Component {
this.drizzle = context.drizzle;
this.state = {
postSubjectInput: this.props.subject,
postSubjectInput: this.props.subject ? this.props.subject : "",
postContentInput: '',
postSubjectInputEmptySubmit: false,
postContentInputEmptySubmit: false,

5
src/components/ProfileInformation.js

@ -25,6 +25,11 @@ const ProfileInformation = (props) => {
<p className="no-margin">
<strong>Number of posts:</strong> {props.numberOfPosts}
</p>
{props.dateOfRegister &&
<p className="no-margin">
<strong>Member since:</strong> {props.dateOfRegister}
</p>
}
{props.self && <UsernameFormContainer/>}
</div>
);

22
src/components/TopicList.js

@ -32,17 +32,25 @@ class TopicList extends Component {
}
async fetchSubject(topicIndex) {
/*const fullAddress = this.topicsData[topicID][1];
const store = await this.props.orbitDB.orbitdb.keyvalue(JSON.stringify(fullAddress));
await store.load();
var som = store.get(JSON.stringify(topicID));
this.topicsSubjects[topicID] = som['subject'];
this.topicsSubjectsFetchStatus[topicID] = "fetched";*/
if (this.topicsData[topicIndex][1] === this.props.user.address){
let som =this.props.orbitDB.topicsDB.get(this.props.topicIDs[topicIndex]);
this.topicsSubjects[topicIndex] = som['subject'];
this.topicsSubjectsFetchStatus[topicIndex] = "fetched";
} else {
const fullAddress = "/orbitdb" + this.topicsData[topicIndex][0] + "/topics";
const store = await this.props.orbitDB.orbitdb.keyvalue(fullAddress);
var som =this.props.orbitDB.topicsDB.get(this.props.topicIDs[topicIndex]);
/*store.events.on('replicated', () => {
const result = store.iterator({ limit: -1 }).collect().map(e => e.payload.value)
console.log(result.join('\n'))
})*/
await store.load();
let som = store.get(this.props.topicIDs[topicIndex]);
this.topicsSubjects[topicIndex] = som['subject'];
this.topicsSubjectsFetchStatus[topicIndex] = "fetched";
}
}
render (){
const topics = this.topicsData.map((topic, index) => {

5
src/containers/BoardContainer.js

@ -1,7 +1,6 @@
import { drizzleConnect } from 'drizzle-react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
import TopicList from '../components/TopicList';
import FloatingButton from '../components/FloatingButton';
@ -34,9 +33,7 @@ class Board extends Component {
return (
<div style={{marginBottom: '70px'}}>
{boardContents}
<Link to="/startTopic">
<FloatingButton onClick={this.handleClick}/>
</Link>
<FloatingButton to="/startTopic"/>
</div>
);
}

35
src/containers/ProfileContainer.js

@ -6,9 +6,11 @@ import ProfileInformation from '../components/ProfileInformation';
import TopicList from '../components/TopicList';
import PostList from '../components/PostList';
import LoadingSpinner from '../components/LoadingSpinner';
import epochTimeConverter from '../helpers/EpochTimeConverter';
const contract = "Forum";
const contractMethods = {
getDateOfRegister: "getUserDateOfRegister",
getOrbitDB: "getOrbitDBId",
getUserTopics: "getUserTopics",
getUserPosts: "getUserPosts"
@ -31,8 +33,10 @@ class Profile extends Component {
this.state = {
viewSelected: "topics",
username: this.match.username, // TODO actually get them from match
userAddress: this.match.address, // when router is fixed
userAddress: this.match.userAddress, // when router is fixed
dateOfRegister: null,
orbitDBId: this.match.address === this.props.user.address ? this.props.orbitDB.id : "",
getDateOfRegisterTransactionState: null,
getOrbitDBTransactionState: this.match.address === this.props.user.address ? "SUCCESS" : null,
getTopicsTransactionState: null,
getPostsTransactionState: null,
@ -53,6 +57,7 @@ class Profile extends Component {
orbitAddress={this.state.orbitDBId}
numberOfTopics={this.state.topicIDs.length}
numberOfPosts={this.state.postIDs.length}
dateOfRegister={this.state.dateOfRegister}
self/>
<div className="pure-u-1-1 profile-tabs-header">
<p onClick={() => (this.handleTabClick("topics"))}
@ -83,11 +88,29 @@ class Profile extends Component {
}
componentWillReceiveProps() {
if (this.state.getDateOfRegisterTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
this.dateOfRegisterKey = this.drizzle.contracts[contract]
.methods[contractMethods.getDateOfRegister].cacheCall(this.state.userAddress);
this.setState({'getDateOfRegisterTransactionState': "IN_PROGRESS"});
}
}
if (this.state.getDateOfRegisterTransactionState === "IN_PROGRESS") {
let currentDrizzleState = this.drizzle.store.getState();
let dataFetched = (currentDrizzleState
.contracts[contract][contractMethods.getDateOfRegister])[this.dateOfRegisterKey];
if (dataFetched){
this.setState({
'dateOfRegister': epochTimeConverter(dataFetched.value),
'getDateOfRegisterTransactionState': "SUCCESS"
});
}
}
if (this.state.getOrbitDBTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
//This gets called only once but should be called every time someone posts
this.orbitDBIdKey = this.drizzle.contracts[contract]
.methods[contractMethods.getOrbitDB].cacheCall(this.match.userAddress);
.methods[contractMethods.getOrbitDB].cacheCall(this.state.userAddress);
this.setState({'getOrbitDBTransactionState': "IN_PROGRESS"});
}
}
@ -105,9 +128,8 @@ class Profile extends Component {
if (this.state.getTopicsTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
//This gets called only once but should be called every time someone posts
this.getTopicsKey = this.drizzle.contracts[contract]
.methods[contractMethods.getUserTopics].cacheCall(this.match.userAddress);
.methods[contractMethods.getUserTopics].cacheCall(this.state.userAddress);
this.setState({'getTopicsTransactionState': "IN_PROGRESS"});
}
}
@ -125,9 +147,8 @@ class Profile extends Component {
if (this.state.getPostsTransactionState === null){
if (this.drizzle.contracts[contract]){ //Waits until drizzle is initialized
//This gets called only once but should be called every time someone posts
this.getPostsKey = this.drizzle.contracts[contract]
.methods[contractMethods.getUserPosts].cacheCall(this.match.userAddress);
.methods[contractMethods.getUserPosts].cacheCall(this.state.userAddress);
this.setState({'getPostsTransactionState': "IN_PROGRESS"});
}
}

10
src/containers/TopicContainer.js

@ -63,18 +63,18 @@ class Topic extends Component {
);
} else {
topicContents = (
this.state.posting
?(<div style={{marginBottom: '100px'}}>
(<div style={{marginBottom: '100px'}}>
{this.state.posting &&
<NewPost topicID={1}
subject={this.state.topicSubject}
onCancelClick={() => {this.handleClick()}}
onPostCreated={() => {this.postCreated()}}
/>
}
<PostList postIDs={this.posts}/>
</div>)
:(<div style={{marginBottom: '100px'}}>
<PostList postIDs={this.posts}/>
{!this.state.posting &&
<FloatingButton onClick={this.handleClick}/>
}
</div>)
)
}

26
src/util/orbit.js

@ -12,24 +12,25 @@ const ipfsOptions = {
EXPERIMENTAL: {
pubsub: true
}, config: {
Addresses: {
Swarm: []
}
},
};
/*,
config: {
Addresses: {
Swarm: [
// Use IPFS dev signal server
// Prefer websocket over webrtc
//
// Websocket:
// '/dns4/ws-star-signal-2.servep2p.com/tcp/443//wss/p2p-websocket-star',
// '/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star',
// Local signal server
//'/ip4/127.0.0.1/tcp/4711/ws/p2p-websocket-star'
//
// WebRTC:
// '/dns4/star-signal.cloud.ipfs.team/wss/p2p-webrtc-star',
'/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star',
// Use local signal server
// '/ip4/0.0.0.0/tcp/9090/wss/p2p-webrtc-star',
// Local signal server
// '/ip4/127.0.0.1/tcp/1337/ws/p2p-webrtc-star'
]
}
}*/
},
};
// Create IPFS instance
const ipfs = new IPFS(ipfsOptions);
@ -39,7 +40,6 @@ ipfs.on('ready', async () => {
store.dispatch({type: "IPFS_INITIALIZED"});
});
async function createDatabases() {
orbitdb = new OrbitDB(ipfs);
topicsDB = await orbitdb.keyvalue('topics');

Loading…
Cancel
Save