1
0
mirror of https://github.com/fazo96/ipfs-boards synced 2025-01-10 12:24:20 +01:00

WIP making posts

This commit is contained in:
Enrico Fasoli 2018-02-05 22:19:54 +01:00
parent c9218d94e6
commit 7483c683a4
No known key found for this signature in database
GPG Key ID: 1238873C5F27DB4D
11 changed files with 111 additions and 44 deletions

View File

@ -1,6 +1,13 @@
export const ADD_POST = 'ADD_POST' export const ADD_POST = 'ADD_POST'
export const CREATE_BOARD = 'CREATE_BOARD' export const CREATE_BOARD = 'CREATE_BOARD'
export const CREATING_BOARD = 'CREATING_BOARD' export const CREATING_BOARD = 'CREATING_BOARD'
export const CREATED_BOARD = 'CREATED_BOARD' export const CREATED_BOARD = 'CREATED_BOARD'
export const UPDATE_BOARD = 'UPDATE_BOARD'
export const BOARD_ERROR = 'BOARD_ERROR' export const BOARD_ERROR = 'BOARD_ERROR'
export const ORBITDB_WRITE = 'ORBITDB_WRITE'
export const ORBITDB_REPLICATED = 'ORBITDB_REPLICATED'

View File

@ -1,8 +1,9 @@
import { ADD_POST } from './actionTypes' import { ADD_POST } from './actionTypes'
export function addPost(post) { export function addPost(boardId, post) {
return { return {
type: ADD_POST, type: ADD_POST,
post post,
boardId
} }
} }

View File

@ -1,16 +1,14 @@
import React from 'react' import React from 'react'
import PostEditor from '../containers/PostEditor'
import Post from './Post' 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 }) { export default function Board({ id, posts }) {
return <div> return <div>
<Segment>{id}</Segment> <Segment>{id}</Segment>
<Segment><Button as={Link} to={'p/new'}>New Post</Button></Segment>
<Segment> <Segment>
<PostEditor /> <ul>{Object.keys(posts).map(i => <Post key={posts[i].multihash} {...posts[i]}/>)}</ul>
</Segment>
<Segment>
<ul>{Object.keys(posts).map(i => <Post key={posts[i]} {...posts[i]}/>)}</ul>
</Segment> </Segment>
</div> </div>
} }

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
export default function Post({ title, content }) { export default function Post({ title, multihash}) {
return <li>{title}: {content}</li> return <li>{title}: {multihash}</li>
} }

View File

@ -1,10 +1,14 @@
import React from 'react' import React, { Component } from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import PostForm from '../components/PostForm' import PostForm from '../components/PostForm'
import { addPost } from '../actions/post' import { addPost } from '../actions/post'
function PostEditor({ post, addPost }) { class PostEditor extends Component {
return <PostForm post={post} onSave={addPost} /> render() {
const { post, addPost, match } = this.props
const { boardId } = match.params
return <PostForm post={post} onSave={p => addPost(boardId, p)} />
}
} }
function mapStateToProps(state){ function mapStateToProps(state){
@ -15,7 +19,7 @@ function mapStateToProps(state){
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {
return { return {
addPost: post => dispatch(addPost(post)) addPost: (boardId, post) => dispatch(addPost(boardId, post))
} }
} }

View File

@ -48,14 +48,18 @@ export async function open(id, metadata, options = {}) {
} else if (!isValidID(id)) { } else if (!isValidID(id)) {
throw new Error('invalid address') throw new Error('invalid address')
} }
try {
const db = await window.orbitDb.open(address, Object.assign(defaultOptions, options)) const db = await window.orbitDb.open(address, Object.assign(defaultOptions, options))
await db.load() await db.load()
if (metadata && defaultOptions.create) { if (metadata && defaultOptions.create) {
await db.updateMetadata(metadata) await db.updateMetadata(metadata)
} }
if (!window.dbs) window.dbs = {} if (!window.dbs) window.dbs = {}
window.dbs[db.address.toString()] = db window.dbs[getBoardIdFromAddress(db.address.toString())] = db
return db return db
} catch (error) {
console.log(error)
}
} }
export function connectDb(db, dispatch) { export function connectDb(db, dispatch) {

View File

@ -1,26 +1,30 @@
import { CREATED_BOARD } from '../actions/actionTypes' import { CREATED_BOARD, UPDATE_BOARD } from '../actions/actionTypes'
import { getBoardIdFromAddress } from '../utils/orbitdb' import { getBoardIdFromAddress } from '../utils/orbitdb'
function getInitialState() { function getInitialState() {
return { return {
boards: [] boards: {}
} }
} }
export default function BoardsReducer(state = getInitialState(), action) { export default function BoardsReducer(state = getInitialState(), action) {
let id, newBoards
switch (action.type) { switch (action.type) {
case CREATED_BOARD: case CREATED_BOARD:
const id = getBoardIdFromAddress(action.board.address) id = getBoardIdFromAddress(action.board.address)
const board = { const board = {
id, id,
posts: { posts: {}
1: {
title: 'Example Post',
content: 'no, this is not real'
} }
} newBoards = Object.assign({}, state.boards, { [id]: board })
} return Object.assign({}, state, { boards: newBoards })
const newBoards = Object.assign({}, state.boards.boards, { [id]: board }) 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 }) return Object.assign({}, state, { boards: newBoards })
default: default:
return state; return state;

View File

@ -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 { push } from 'react-router-redux'
import { open, connectDb } from '../orbitdb' import { open, connectDb } from '../orbitdb'
import { creatingBoard, createdBoard, boardError } from '../actions/board' import { creatingBoard, createdBoard, boardError } from '../actions/board'
import { getBoardIdFromAddress } from '../utils/orbitdb' 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 }) { export function* createBoard({ board }) {
yield put(creatingBoard(board)) yield put(creatingBoard(board))
@ -12,15 +24,33 @@ export function* createBoard({ board }) {
title: board.title title: board.title
}) })
} catch (error) { } catch (error) {
yield put(boardError, error) yield put(boardError(error))
} }
if (db) {
const address = db.address.toString() const address = db.address.toString()
const dbInfo = { const dbInfo = {
id: getBoardIdFromAddress(address), id: getBoardIdFromAddress(address),
address address
} }
// TODO: use https://redux-saga.js.org/docs/advanced/Channels.html to handle orbitdb events const channel = yield call(createDbEventChannel, db)
// yield call(connectDb(db, dispatch)) yield fork(watchDb, channel)
yield put(createdBoard(Object.assign({}, board, dbInfo))) yield put(createdBoard(Object.assign({}, board, dbInfo)))
yield put(push('/b/' + dbInfo.id + '/')) 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()
})
}

View File

@ -1,7 +1,11 @@
import { takeEvery } from 'redux-saga/effects' import { takeEvery } from 'redux-saga/effects'
import { CREATE_BOARD } from '../actions/actionTypes' import { CREATE_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE } from '../actions/actionTypes'
import { createBoard } from './boards' import { createBoard, updateBoard } from './boards'
import { addPost } from './posts'
export default function* saga(){ export default function* saga(){
yield takeEvery(CREATE_BOARD, createBoard) yield takeEvery(CREATE_BOARD, createBoard)
yield takeEvery(ADD_POST, addPost)
yield takeEvery(ORBITDB_WRITE, updateBoard)
yield takeEvery(ORBITDB_REPLICATED, updateBoard)
} }

9
src/sagas/posts.js Normal file
View File

@ -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])
}

6
src/utils/ipfs.js Normal file
View File

@ -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)
}