diff --git a/src/actions/actionTypes.js b/src/actions/actionTypes.js
index 5745e33..eb42ca8 100644
--- a/src/actions/actionTypes.js
+++ b/src/actions/actionTypes.js
@@ -1,6 +1,13 @@
export const ADD_POST = 'ADD_POST'
+
export const CREATE_BOARD = 'CREATE_BOARD'
export const CREATING_BOARD = 'CREATING_BOARD'
export const CREATED_BOARD = 'CREATED_BOARD'
-export const BOARD_ERROR = 'BOARD_ERROR'
\ No newline at end of file
+
+export const UPDATE_BOARD = 'UPDATE_BOARD'
+
+export const BOARD_ERROR = 'BOARD_ERROR'
+
+export const ORBITDB_WRITE = 'ORBITDB_WRITE'
+export const ORBITDB_REPLICATED = 'ORBITDB_REPLICATED'
\ No newline at end of file
diff --git a/src/actions/post.js b/src/actions/post.js
index 4bd513c..8cf3f70 100644
--- a/src/actions/post.js
+++ b/src/actions/post.js
@@ -1,8 +1,9 @@
import { ADD_POST } from './actionTypes'
-export function addPost(post) {
+export function addPost(boardId, post) {
return {
type: ADD_POST,
- post
+ post,
+ boardId
}
}
\ No newline at end of file
diff --git a/src/components/Board.js b/src/components/Board.js
index 93b6579..02b5aa8 100644
--- a/src/components/Board.js
+++ b/src/components/Board.js
@@ -1,16 +1,14 @@
import React from 'react'
-import PostEditor from '../containers/PostEditor'
import Post from './Post'
-import { Segment } from 'semantic-ui-react'
+import { Segment, Button } from 'semantic-ui-react'
+import { Link } from 'react-router-dom'
export default function Board({ id, posts }) {
return
{id}
+
-
-
-
- {Object.keys(posts).map(i => )}
+ {Object.keys(posts).map(i => )}
}
\ No newline at end of file
diff --git a/src/components/Post.js b/src/components/Post.js
index 6ece7f7..24371a4 100644
--- a/src/components/Post.js
+++ b/src/components/Post.js
@@ -1,5 +1,5 @@
import React from 'react'
-export default function Post({ title, content }) {
- return {title}: {content}
+export default function Post({ title, multihash}) {
+ return {title}: {multihash}
}
\ No newline at end of file
diff --git a/src/containers/PostEditor.js b/src/containers/PostEditor.js
index 6549246..03cca4f 100644
--- a/src/containers/PostEditor.js
+++ b/src/containers/PostEditor.js
@@ -1,10 +1,14 @@
-import React from 'react'
+import React, { Component } from 'react'
import { connect } from 'react-redux'
import PostForm from '../components/PostForm'
import { addPost } from '../actions/post'
-function PostEditor({ post, addPost }) {
- return
+class PostEditor extends Component {
+ render() {
+ const { post, addPost, match } = this.props
+ const { boardId } = match.params
+ return addPost(boardId, p)} />
+ }
}
function mapStateToProps(state){
@@ -15,7 +19,7 @@ function mapStateToProps(state){
function mapDispatchToProps(dispatch) {
return {
- addPost: post => dispatch(addPost(post))
+ addPost: (boardId, post) => dispatch(addPost(boardId, post))
}
}
diff --git a/src/orbitdb/index.js b/src/orbitdb/index.js
index 1b4d352..78f2480 100644
--- a/src/orbitdb/index.js
+++ b/src/orbitdb/index.js
@@ -48,14 +48,18 @@ export async function open(id, metadata, options = {}) {
} else if (!isValidID(id)) {
throw new Error('invalid address')
}
- const db = await window.orbitDb.open(address, Object.assign(defaultOptions, options))
- await db.load()
- if (metadata && defaultOptions.create) {
- await db.updateMetadata(metadata)
+ try {
+ const db = await window.orbitDb.open(address, Object.assign(defaultOptions, options))
+ await db.load()
+ if (metadata && defaultOptions.create) {
+ await db.updateMetadata(metadata)
+ }
+ if (!window.dbs) window.dbs = {}
+ window.dbs[getBoardIdFromAddress(db.address.toString())] = db
+ return db
+ } catch (error) {
+ console.log(error)
}
- if (!window.dbs) window.dbs = {}
- window.dbs[db.address.toString()] = db
- return db
}
export function connectDb(db, dispatch) {
diff --git a/src/reducers/boards.js b/src/reducers/boards.js
index c89f5e5..5a5c872 100644
--- a/src/reducers/boards.js
+++ b/src/reducers/boards.js
@@ -1,26 +1,30 @@
-import { CREATED_BOARD } from '../actions/actionTypes'
+import { CREATED_BOARD, UPDATE_BOARD } from '../actions/actionTypes'
import { getBoardIdFromAddress } from '../utils/orbitdb'
function getInitialState() {
return {
- boards: []
+ boards: {}
}
}
export default function BoardsReducer(state = getInitialState(), action) {
+ let id, newBoards
switch (action.type) {
case CREATED_BOARD:
- const id = getBoardIdFromAddress(action.board.address)
+ id = getBoardIdFromAddress(action.board.address)
const board = {
id,
- posts: {
- 1: {
- title: 'Example Post',
- content: 'no, this is not real'
- }
- }
+ posts: {}
}
- const newBoards = Object.assign({}, state.boards.boards, { [id]: board })
+ newBoards = Object.assign({}, state.boards, { [id]: board })
+ return Object.assign({}, state, { boards: newBoards })
+ case UPDATE_BOARD:
+ id = action.boardId
+ let { posts } = action
+ console.log(state, action)
+ newBoards = Object.assign({}, state.boards, {
+ [id]: Object.assign({}, state.boards[id], { posts })
+ })
return Object.assign({}, state, { boards: newBoards })
default:
return state;
diff --git a/src/sagas/boards.js b/src/sagas/boards.js
index 5534484..e778c13 100644
--- a/src/sagas/boards.js
+++ b/src/sagas/boards.js
@@ -1,8 +1,20 @@
-import { put, call } from 'redux-saga/effects'
+import { put, call, fork, take } from 'redux-saga/effects'
+import { eventChannel } from 'redux-saga'
import { push } from 'react-router-redux'
import { open, connectDb } from '../orbitdb'
import { creatingBoard, createdBoard, boardError } from '../actions/board'
import { getBoardIdFromAddress } from '../utils/orbitdb'
+import { UPDATE_BOARD } from '../actions/actionTypes'
+
+export function* updateBoard({ id }){
+ const db = window.dbs[id]
+ yield put({
+ type: UPDATE_BOARD,
+ boardId: id,
+ posts: db.posts,
+ metadata: db.metadata
+ })
+}
export function* createBoard({ board }) {
yield put(creatingBoard(board))
@@ -12,15 +24,33 @@ export function* createBoard({ board }) {
title: board.title
})
} catch (error) {
- yield put(boardError, error)
+ yield put(boardError(error))
}
- const address = db.address.toString()
- const dbInfo = {
- id: getBoardIdFromAddress(address),
- address
+ if (db) {
+ const address = db.address.toString()
+ const dbInfo = {
+ id: getBoardIdFromAddress(address),
+ address
+ }
+ const channel = yield call(createDbEventChannel, db)
+ yield fork(watchDb, channel)
+ yield put(createdBoard(Object.assign({}, board, dbInfo)))
+ yield put(push('/b/' + dbInfo.id + '/'))
}
- // TODO: use https://redux-saga.js.org/docs/advanced/Channels.html to handle orbitdb events
- // yield call(connectDb(db, dispatch))
- yield put(createdBoard(Object.assign({}, board, dbInfo)))
- yield put(push('/b/' + dbInfo.id + '/'))
+}
+
+function* watchDb(channel) {
+ // Dispatches action coming from the channel, terminates when ORBITDB_CLOSE arrives
+ let action
+ while(!action || action.type !== 'ORBITDB_CLOSE') {
+ action = yield take(channel)
+ yield put(action)
+ }
+}
+
+function createDbEventChannel(db) {
+ return eventChannel(emitter => {
+ connectDb(db, emitter)
+ return () => db.close()
+ })
}
\ No newline at end of file
diff --git a/src/sagas/index.js b/src/sagas/index.js
index fc29e62..4e42f00 100644
--- a/src/sagas/index.js
+++ b/src/sagas/index.js
@@ -1,7 +1,11 @@
import { takeEvery } from 'redux-saga/effects'
-import { CREATE_BOARD } from '../actions/actionTypes'
-import { createBoard } from './boards'
+import { CREATE_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE } from '../actions/actionTypes'
+import { createBoard, updateBoard } from './boards'
+import { addPost } from './posts'
export default function* saga(){
yield takeEvery(CREATE_BOARD, createBoard)
+ yield takeEvery(ADD_POST, addPost)
+ yield takeEvery(ORBITDB_WRITE, updateBoard)
+ yield takeEvery(ORBITDB_REPLICATED, updateBoard)
}
\ No newline at end of file
diff --git a/src/sagas/posts.js b/src/sagas/posts.js
new file mode 100644
index 0000000..25f57a5
--- /dev/null
+++ b/src/sagas/posts.js
@@ -0,0 +1,9 @@
+import { put, apply, call } from 'redux-saga/effects'
+import { ipfsPut } from '../utils/ipfs'
+
+export function* addPost({ boardId, post }) {
+ const db = window.dbs[boardId]
+ const { title, content } = post
+ const multihash = yield call(ipfsPut, content)
+ yield apply(db, db.addPost, [title, multihash])
+}
\ No newline at end of file
diff --git a/src/utils/ipfs.js b/src/utils/ipfs.js
new file mode 100644
index 0000000..0505cf2
--- /dev/null
+++ b/src/utils/ipfs.js
@@ -0,0 +1,6 @@
+import multihashes from 'multihashes'
+
+export async function ipfsPut(content) {
+ const dagNode = await window.ipfs.object.put(Buffer.from(content))
+ return multihashes.toB58String(dagNode.multihash)
+}
\ No newline at end of file