From 7483c683a4d6a7c2b6cb2907a9924e8159ab0594 Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Mon, 5 Feb 2018 22:19:54 +0100 Subject: [PATCH] WIP making posts --- src/actions/actionTypes.js | 9 ++++++- src/actions/post.js | 5 ++-- src/components/Board.js | 10 +++----- src/components/Post.js | 4 +-- src/containers/PostEditor.js | 12 ++++++--- src/orbitdb/index.js | 18 ++++++++----- src/reducers/boards.js | 24 +++++++++-------- src/sagas/boards.js | 50 ++++++++++++++++++++++++++++-------- src/sagas/index.js | 8 ++++-- src/sagas/posts.js | 9 +++++++ src/utils/ipfs.js | 6 +++++ 11 files changed, 111 insertions(+), 44 deletions(-) create mode 100644 src/sagas/posts.js create mode 100644 src/utils/ipfs.js 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