diff --git a/README.md b/README.md index 312dae2..9fd3ac5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Experimental stuff +# IPFS Boards This is a branch with a brand new implementation of boards. Nothing works yet diff --git a/package.json b/package.json index 416f6cc..210df7a 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "dependencies": { "ipfs": "^0.27.7", "orbit-db": "^0.19.4", + "orbit-db-discussion-board": "https://github.com/fazo96/orbit-db-discussion-board.git", "react": "^16.2.0", "react-dom": "^16.2.0", "react-hot-loader": "^3.1.3", diff --git a/src/actions/actionTypes.js b/src/actions/actionTypes.js index 178648e..5745e33 100644 --- a/src/actions/actionTypes.js +++ b/src/actions/actionTypes.js @@ -2,4 +2,5 @@ export const ADD_POST = 'ADD_POST' export const CREATE_BOARD = 'CREATE_BOARD' export const CREATING_BOARD = 'CREATING_BOARD' -export const CREATED_BOARD = 'CREATED_BOARD' \ No newline at end of file +export const CREATED_BOARD = 'CREATED_BOARD' +export const BOARD_ERROR = 'BOARD_ERROR' \ No newline at end of file diff --git a/src/actions/board.js b/src/actions/board.js index 9bdd996..2ca6f14 100644 --- a/src/actions/board.js +++ b/src/actions/board.js @@ -1,7 +1,8 @@ import { CREATE_BOARD, CREATING_BOARD, - CREATED_BOARD + CREATED_BOARD, + BOARD_ERROR } from './actionTypes' export function createBoard(board) { @@ -23,4 +24,11 @@ export function createdBoard(board) { type: CREATED_BOARD, board } +} + +export function boardError(error) { + return { + type: BOARD_ERROR, + error + } } \ No newline at end of file diff --git a/src/components/App.js b/src/components/App.js index 02b4e9b..0b75765 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,19 +1,21 @@ import React, { Component } from 'react'; -import { Switch, Route, withRouter } from 'react-router-dom'; +import { Switch, Route, withRouter } from 'react-router-dom' import Boards from '../containers/Boards' import PostEditor from '../containers/PostEditor' import BoardEditor from '../containers/BoardEditor' +import Board from '../containers/Board' import 'semantic-ui-css/semantic.css' class App extends Component { render() { return ( - + + - ); + ) } } diff --git a/src/components/Board.js b/src/components/Board.js new file mode 100644 index 0000000..daa8447 --- /dev/null +++ b/src/components/Board.js @@ -0,0 +1,5 @@ +import React from 'react' + +export default function Board({ id, address }) { + return
{address}
+} \ No newline at end of file diff --git a/src/components/Boards.js b/src/components/Boards.js index cfac304..8e60479 100644 --- a/src/components/Boards.js +++ b/src/components/Boards.js @@ -5,7 +5,7 @@ import { Button } from 'semantic-ui-react' export default function Boards({ boards, createBoard }) { return - {boards.map(board => )} + {Object.values(boards).map(board => )} } \ No newline at end of file diff --git a/src/components/Feed.js b/src/components/Feed.js index 600db44..15c2a79 100644 --- a/src/components/Feed.js +++ b/src/components/Feed.js @@ -1,5 +1,14 @@ import React from 'react' +import { PostEditor } from '../containers/PostEditor' +import { Section } from 'react-semantic-ui' -export default function Feed({ posts }) { - return +export default function Board({ posts }) { + return
+
+ +
+
+ +
+
} \ No newline at end of file diff --git a/src/containers/Board.js b/src/containers/Board.js index e69de29..361a795 100644 --- a/src/containers/Board.js +++ b/src/containers/Board.js @@ -0,0 +1,43 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { push } from 'react-router-redux' +import BoardComponent from '../components/Board' +import { createBoard } from '../actions/board' + +class Board extends Component { + + componentDidMount() { + const { boards, match } = this.props + if (!boards[match.params.boardId]) { + this.props.openBoard(match.params.boardId) + } + } + + render() { + const { boards, match } = this.props + const id = match.params.boardId + const board = boards[id] + if (board) { + return + } else { + return
Opening this board...
+ } + } +} + +function mapStateToProps(state){ + return { + boards: state.boards.boards + } +} + +function mapDispatchToProps(dispatch){ + return { + openBoard: id => dispatch(createBoard(id)) + } +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(Board) diff --git a/src/orbitdb/index.js b/src/orbitdb/index.js index 3ff1320..65fd9d8 100644 --- a/src/orbitdb/index.js +++ b/src/orbitdb/index.js @@ -1,6 +1,16 @@ import BoardStore from 'orbit-db-discussion-board' +import multihashes from 'multihashes' -export async function open(address, metadata, options = {}) { +export function isValidID(id) { + try { + if (typeof id === 'string' && multihashes.fromB58String(id)) return true + } catch (error) { + return false + } + return false +} + +export async function open(id, metadata, options = {}) { if (!window.ipfs) { const IPFS = await import('ipfs') window.ipfs = new IPFS({ @@ -28,12 +38,13 @@ export async function open(address, metadata, options = {}) { window.orbitDb = new OrbitDB(window.ipfs) } const defaultOptions = { - create: address === undefined, + create: id === undefined, type: BoardStore.type } - if (!address) { + let address + if (!id) { address = 'board-v0' - } else if (!address.indexOf('/orbitdb/') < 0 || address.indexOf('/board-v0') < 0) { + } else if (!isValidID(id)) { throw new Error('invalid address') } const db = await window.orbitDb.open(address, Object.assign(defaultOptions, options)) diff --git a/src/reducers/boards.js b/src/reducers/boards.js index d570e9a..080d6cf 100644 --- a/src/reducers/boards.js +++ b/src/reducers/boards.js @@ -1,4 +1,5 @@ import { CREATED_BOARD } from '../actions/actionTypes' +import { getBoardIdFromAddress } from '../utils/orbitdb' function getInitialState() { return { @@ -9,7 +10,9 @@ function getInitialState() { export default function BoardsReducer(state = getInitialState(), action) { switch (action.type) { case CREATED_BOARD: - return Object.assign({}, state, { boards: state.boards.concat(action.board) }) + const id = getBoardIdFromAddress(action.board.address) + const newBoards = Object.assign({}, state.boards.boards, { [id]: action.board }) + return Object.assign({}, state, { boards: newBoards }) default: return state; } diff --git a/src/reducers/index.js b/src/reducers/index.js index fb0f42b..dc43c42 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,9 +1,11 @@ import { combineReducers } from 'redux' +import { routerReducer } from 'react-router-redux' import postReducer from './post' import boardsReducer from './boards' import boardEditorReducer from './boardEditor' export default combineReducers({ + router: routerReducer, postEditor: postReducer, boards: boardsReducer, boardEditor: boardEditorReducer diff --git a/src/sagas/boards.js b/src/sagas/boards.js index 32a0ad1..4689801 100644 --- a/src/sagas/boards.js +++ b/src/sagas/boards.js @@ -1,13 +1,23 @@ import { put, call } from 'redux-saga/effects' +import { push } from 'react-router-redux' import { open } from '../orbitdb' -import { creatingBoard, createdBoard } from '../actions/board' +import { creatingBoard, createdBoard, boardError } from '../actions/board' +import { getBoardIdFromAddress } from '../utils/orbitdb' export function* createBoard({ board }) { yield put(creatingBoard(board)) - const db = yield call(open, board.address) + let db + try { + db = yield call(open, board.id) + } catch (error) { + yield put(boardError, error) + } + const address = db.address.toString() const dbInfo = { - address: db.address.toString() + id: getBoardIdFromAddress(address), + address } // TODO watch db status yield put(createdBoard(Object.assign({}, board, dbInfo))) + yield put(push('/b/' + dbInfo.id + '/')) } \ No newline at end of file diff --git a/src/utils/orbitdb.js b/src/utils/orbitdb.js new file mode 100644 index 0000000..cfe070a --- /dev/null +++ b/src/utils/orbitdb.js @@ -0,0 +1,6 @@ + +export function getBoardIdFromAddress(address) { + const match = /\/orbitdb\/(.+)\//.exec(address) + if (match[1]) return match[1] + return undefined +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a3a42b6..438cba1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5040,7 +5040,7 @@ level-js@^2.2.4, level-js@~2.2.4: typedarray-to-buffer "~1.0.0" xtend "~2.1.2" -"level-js@github:timkuijsten/level.js#idbunwrapper": +level-js@timkuijsten/level.js#idbunwrapper: version "2.2.3" resolved "https://codeload.github.com/timkuijsten/level.js/tar.gz/18e03adab34c49523be7d3d58fafb0c632f61303" dependencies: @@ -5922,7 +5922,7 @@ multihashing-async@~0.4.6, multihashing-async@~0.4.7: murmurhash3js "^3.0.1" nodeify "^1.0.1" -"multiplex@github:dignifiedquire/multiplex": +multiplex@dignifiedquire/multiplex: version "6.7.0" resolved "https://codeload.github.com/dignifiedquire/multiplex/tar.gz/b5d5edd30454e2c978ee8c52df86f5f4840d2eab" dependencies: @@ -6273,6 +6273,12 @@ orbit-db-counterstore@~1.2.0: crdts "~0.1.2" orbit-db-store "~2.2.0" +"orbit-db-discussion-board@https://github.com/fazo96/orbit-db-discussion-board.git": + version "0.1.0" + resolved "https://github.com/fazo96/orbit-db-discussion-board.git#b71b93f2415a867f8ed29cc76fe7af0e9fb570ce" + dependencies: + orbit-db-store "^2.2.1" + orbit-db-docstore@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/orbit-db-docstore/-/orbit-db-docstore-1.2.0.tgz#c5d7fe291de148db4e1adebdf3bad12422dc44c6" @@ -6313,7 +6319,7 @@ orbit-db-pubsub@~0.3.8: ipfs-pubsub-room "github:haadcode/ipfs-pubsub-room#orbitdb" logplease "~1.2.14" -orbit-db-store@~2.2.0: +orbit-db-store@^2.2.1, orbit-db-store@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/orbit-db-store/-/orbit-db-store-2.2.1.tgz#49ac9c054ae157e3a0052a9a178a73e2e8b7f914" dependencies: