mirror of
https://github.com/fazo96/ipfs-boards
synced 2025-01-09 12:19:49 +01:00
implemented persistence with boards opened before
This commit is contained in:
parent
73eaff3b87
commit
e4b0a16cf0
@ -4,6 +4,7 @@ export const UPDATE_BOARD_METADATA = 'UPDATE_BOARD_METADATA'
|
|||||||
|
|
||||||
export const OPEN_BOARD = 'OPEN_BOARD'
|
export const OPEN_BOARD = 'OPEN_BOARD'
|
||||||
export const OPENED_BOARD = 'OPENED_BOARD'
|
export const OPENED_BOARD = 'OPENED_BOARD'
|
||||||
|
export const CLOSE_BOARD = 'CLOSE_BOARD'
|
||||||
|
|
||||||
export const UPDATE_BOARD = 'UPDATE_BOARD'
|
export const UPDATE_BOARD = 'UPDATE_BOARD'
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
OPEN_BOARD,
|
OPEN_BOARD,
|
||||||
|
CLOSE_BOARD,
|
||||||
OPENED_BOARD,
|
OPENED_BOARD,
|
||||||
UPDATE_BOARD_METADATA
|
UPDATE_BOARD_METADATA
|
||||||
} from './actionTypes'
|
} from './actionTypes'
|
||||||
@ -24,4 +25,11 @@ export function updateBoardMetadata(address, metadata) {
|
|||||||
address,
|
address,
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeBoard(address) {
|
||||||
|
return {
|
||||||
|
type: CLOSE_BOARD,
|
||||||
|
address
|
||||||
|
}
|
||||||
}
|
}
|
@ -37,7 +37,7 @@ export default class BoardEditorForm extends Component {
|
|||||||
onChange={this.updateTitle.bind(this)}
|
onChange={this.updateTitle.bind(this)}
|
||||||
/>
|
/>
|
||||||
</Form.Field>
|
</Form.Field>
|
||||||
<Form.Group fluid widths="equal">
|
<Form.Group widths="equal">
|
||||||
<Form.Field>
|
<Form.Field>
|
||||||
<label>Website</label>
|
<label>Website</label>
|
||||||
<input
|
<input
|
||||||
|
@ -3,7 +3,7 @@ import { List, Icon, Segment, Divider, Grid, Header, Button, Card } from 'semant
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import BoardsItem from './BoardsItem'
|
import BoardsItem from './BoardsItem'
|
||||||
|
|
||||||
export default function Boards({ stats, boards, createBoard }) {
|
export default function Boards({ stats, boards, createBoard, closeBoard }) {
|
||||||
return <Grid container divided colums={2}>
|
return <Grid container divided colums={2}>
|
||||||
<Grid.Column width={8}>
|
<Grid.Column width={8}>
|
||||||
<Header size='large' style={{marginTop:'.5em'}}>
|
<Header size='large' style={{marginTop:'.5em'}}>
|
||||||
@ -65,7 +65,7 @@ export default function Boards({ stats, boards, createBoard }) {
|
|||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
<Grid.Column width={8} style={{paddingTop:'3em'}}>
|
<Grid.Column width={8} style={{paddingTop:'3em'}}>
|
||||||
<Card.Group className="centered">
|
<Card.Group className="centered">
|
||||||
{Object.values(boards).map(board => <BoardsItem key={board.address} {...board} />)}
|
{Object.values(boards).map(board => <BoardsItem key={board.address} closeBoard={closeBoard} {...board} />)}
|
||||||
{Object.keys(boards).length === 0 ? <Segment>No boards opened</Segment> : null}
|
{Object.keys(boards).length === 0 ? <Segment>No boards opened</Segment> : null}
|
||||||
</Card.Group>
|
</Card.Group>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { List, Button, Card } from 'semantic-ui-react'
|
import { Icon, List, Button, Card } from 'semantic-ui-react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { shortenAddress } from '../utils/orbitdb'
|
import { shortenAddress } from '../utils/orbitdb'
|
||||||
|
|
||||||
export default function BoardsItem({ address, metadata, name }) {
|
export default function BoardsItem({ address, metadata, name, closeBoard }) {
|
||||||
return <Card fluid>
|
return <Card fluid>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
@ -29,8 +29,15 @@ export default function BoardsItem({ address, metadata, name }) {
|
|||||||
</List.Item>
|
</List.Item>
|
||||||
</List>
|
</List>
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
<Card.Content extra>
|
<Card.Content>
|
||||||
<Button as={Link} to={shortenAddress(address)} basic fluid>View</Button>
|
<div className="ui two buttons">
|
||||||
|
<Button onClick={() => closeBoard(address)} basic>
|
||||||
|
<Icon name="close"/> Close
|
||||||
|
</Button>
|
||||||
|
<Button as={Link} to={shortenAddress(address)} basic>
|
||||||
|
<Icon name="list"/> View
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card>
|
</Card>
|
||||||
}
|
}
|
@ -43,7 +43,7 @@ export default class OpenBoardForm extends Component {
|
|||||||
<Button as={Link} to={'/'}>
|
<Button as={Link} to={'/'}>
|
||||||
<Icon name="arrow left"/> Back
|
<Icon name="arrow left"/> Back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" onClick={() => openBoard({ address })}>
|
<Button type="submit" onClick={() => openBoard({ address, redirect: true })}>
|
||||||
<Icon name="plus"/> Open
|
<Icon name="plus"/> Open
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,11 +3,16 @@ import { connect } from 'react-redux'
|
|||||||
import { push } from 'react-router-redux'
|
import { push } from 'react-router-redux'
|
||||||
import BoardsComponent from '../components/Boards'
|
import BoardsComponent from '../components/Boards'
|
||||||
import WithStats from './WithStats'
|
import WithStats from './WithStats'
|
||||||
|
import { closeBoard } from '../actions/board'
|
||||||
|
|
||||||
const WrappedComponent = WithStats(BoardsComponent)
|
const WrappedComponent = WithStats(BoardsComponent)
|
||||||
|
|
||||||
function Boards({ boards, createBoard }) {
|
function Boards({ boards, createBoard, closeBoard }) {
|
||||||
return <WrappedComponent boards={boards} createBoard={createBoard} />
|
return <WrappedComponent
|
||||||
|
boards={boards}
|
||||||
|
createBoard={createBoard}
|
||||||
|
closeBoard={closeBoard}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state){
|
function mapStateToProps(state){
|
||||||
@ -18,7 +23,8 @@ function mapStateToProps(state){
|
|||||||
|
|
||||||
function mapDispatchToProps(dispatch){
|
function mapDispatchToProps(dispatch){
|
||||||
return {
|
return {
|
||||||
createBoard: () => dispatch(push('/b/new'))
|
createBoard: () => dispatch(push('/b/new')),
|
||||||
|
closeBoard: address => dispatch(closeBoard(address)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ function mapStateToProps(state){
|
|||||||
|
|
||||||
function mapDispatchToProps(dispatch){
|
function mapDispatchToProps(dispatch){
|
||||||
return {
|
return {
|
||||||
openBoard: address => dispatch(openBoard({ address }))
|
openBoard: address => dispatch(openBoard({ address, redirect: false }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
OPENED_BOARD,
|
OPENED_BOARD,
|
||||||
|
CLOSE_BOARD,
|
||||||
UPDATE_BOARD,
|
UPDATE_BOARD,
|
||||||
ORBITDB_REPLICATE_PROGRESS,
|
ORBITDB_REPLICATE_PROGRESS,
|
||||||
ORBITDB_REPLICATED,
|
ORBITDB_REPLICATED,
|
||||||
@ -18,12 +19,18 @@ function updateBoard(existingBoards, address, value) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteBoard(existingBoards, address) {
|
||||||
|
const boards = Object.assign({}, existingBoards)
|
||||||
|
delete boards[address]
|
||||||
|
return boards
|
||||||
|
}
|
||||||
|
|
||||||
export default function BoardsReducer(state = getInitialState(), action) {
|
export default function BoardsReducer(state = getInitialState(), action) {
|
||||||
let address
|
let address
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case OPENED_BOARD:
|
case OPENED_BOARD:
|
||||||
address = action.board.address
|
address = action.board.address
|
||||||
return Object.assign({}, state, { boards: updateBoard(state.boards, address, action.board) })
|
return Object.assign({}, state, { boards: updateBoard(state.boards, address, Object.assign({}, action.board, { open: true })) })
|
||||||
case UPDATE_BOARD:
|
case UPDATE_BOARD:
|
||||||
address = action.address
|
address = action.address
|
||||||
let { posts, metadata } = action
|
let { posts, metadata } = action
|
||||||
@ -45,6 +52,11 @@ export default function BoardsReducer(state = getInitialState(), action) {
|
|||||||
replicating: false,
|
replicating: false,
|
||||||
lastReplicated: action.time
|
lastReplicated: action.time
|
||||||
})})
|
})})
|
||||||
|
case CLOSE_BOARD:
|
||||||
|
address = action.address
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
boards: deleteBoard(state.boards, address)
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,14 @@ 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 { createdBoard } from '../actions/board'
|
import { createdBoard } from '../actions/board'
|
||||||
import { shortenAddress } from '../utils/orbitdb'
|
import { shortenAddress, closeBoard as closeOrbitDBBoard } from '../utils/orbitdb'
|
||||||
import { UPDATE_BOARD } from '../actions/actionTypes'
|
import { UPDATE_BOARD } from '../actions/actionTypes'
|
||||||
|
import { saveSaga } from './persistence'
|
||||||
|
|
||||||
export function* goToBoard({ board }){
|
export function* goToBoard({ board }){
|
||||||
yield put(push(shortenAddress(board.address)))
|
if (board.redirect) {
|
||||||
|
yield put(push(shortenAddress(board.address)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* updateBoard({ address }){
|
export function* updateBoard({ address }){
|
||||||
@ -20,6 +23,11 @@ export function* updateBoard({ address }){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* closeBoard({ address }){
|
||||||
|
yield call(closeOrbitDBBoard, address)
|
||||||
|
yield saveSaga()
|
||||||
|
}
|
||||||
|
|
||||||
export function* updateBoardMetadata({ address, metadata }){
|
export function* updateBoardMetadata({ address, metadata }){
|
||||||
const db = window.dbs[address]
|
const db = window.dbs[address]
|
||||||
if (db) {
|
if (db) {
|
||||||
@ -47,7 +55,7 @@ export function* openBoard({ board }) {
|
|||||||
try {
|
try {
|
||||||
const channel = yield call(createDbEventChannel, db)
|
const channel = yield call(createDbEventChannel, db)
|
||||||
yield fork(watchDb, channel)
|
yield fork(watchDb, channel)
|
||||||
yield put(createdBoard(Object.assign({}, board, dbInfo)))
|
yield put(createdBoard(Object.assign({ redirect: !!board.redirect }, board, dbInfo)))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
yield put({ type: 'ERROR', error })
|
yield put({ type: 'ERROR', error })
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,29 @@
|
|||||||
import { takeEvery } from 'redux-saga/effects'
|
import { takeEvery, put, call } from 'redux-saga/effects'
|
||||||
import { OPEN_BOARD, OPENED_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE, UPDATE_BOARD_METADATA } from '../actions/actionTypes'
|
import {
|
||||||
import { openBoard, updateBoard, goToBoard, updateBoardMetadata } from './boards'
|
OPEN_BOARD,
|
||||||
|
OPENED_BOARD,
|
||||||
|
CLOSE_BOARD,
|
||||||
|
ADD_POST,
|
||||||
|
ORBITDB_REPLICATED,
|
||||||
|
ORBITDB_WRITE,
|
||||||
|
UPDATE_BOARD_METADATA
|
||||||
|
} from '../actions/actionTypes'
|
||||||
|
import { openBoard, updateBoard, goToBoard, updateBoardMetadata, closeBoard } from './boards'
|
||||||
|
import { openBoard as openBoardAction } from '../actions/board'
|
||||||
import { addPost } from './posts'
|
import { addPost } from './posts'
|
||||||
|
import { openPreviousBoards, saveSaga } from './persistence'
|
||||||
|
|
||||||
export default function* saga(){
|
export default function* saga(){
|
||||||
yield takeEvery(OPEN_BOARD, openBoard)
|
yield takeEvery(OPEN_BOARD, openBoard)
|
||||||
yield takeEvery(OPENED_BOARD, goToBoard)
|
yield takeEvery(OPENED_BOARD, goToBoard)
|
||||||
|
yield takeEvery(OPENED_BOARD, saveSaga)
|
||||||
|
yield takeEvery(CLOSE_BOARD, closeBoard)
|
||||||
|
|
||||||
yield takeEvery(ADD_POST, addPost)
|
yield takeEvery(ADD_POST, addPost)
|
||||||
yield takeEvery(UPDATE_BOARD_METADATA, updateBoardMetadata)
|
yield takeEvery(UPDATE_BOARD_METADATA, updateBoardMetadata)
|
||||||
|
|
||||||
yield takeEvery(ORBITDB_WRITE, updateBoard)
|
yield takeEvery(ORBITDB_WRITE, updateBoard)
|
||||||
yield takeEvery(ORBITDB_REPLICATED, updateBoard)
|
yield takeEvery(ORBITDB_REPLICATED, updateBoard)
|
||||||
|
|
||||||
|
yield openPreviousBoards()
|
||||||
}
|
}
|
16
src/sagas/persistence.js
Normal file
16
src/sagas/persistence.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { call, put } from 'redux-saga/effects'
|
||||||
|
import { openBoard } from '../actions/board'
|
||||||
|
import { save, load } from '../utils/persistence'
|
||||||
|
|
||||||
|
export function* openPreviousBoards() {
|
||||||
|
const data = yield call(load)
|
||||||
|
if (Array.isArray(data.addresses)) {
|
||||||
|
for (const address of data.addresses) {
|
||||||
|
yield put(openBoard({ address, redirect: false }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* saveSaga() {
|
||||||
|
yield call(save)
|
||||||
|
}
|
@ -17,7 +17,7 @@ export async function getStats() {
|
|||||||
const orbitDb = window.orbitDb
|
const orbitDb = window.orbitDb
|
||||||
const dbs = {}
|
const dbs = {}
|
||||||
const stats = {}
|
const stats = {}
|
||||||
if (ipfs) {
|
if (ipfs && ipfs.isOnline()) {
|
||||||
stats.ipfsLoaded = true
|
stats.ipfsLoaded = true
|
||||||
const peers = await ipfs.swarm.peers()
|
const peers = await ipfs.swarm.peers()
|
||||||
const id = await ipfs.id()
|
const id = await ipfs.id()
|
||||||
@ -26,7 +26,7 @@ export async function getStats() {
|
|||||||
} else {
|
} else {
|
||||||
stats.ipfsLoaded = false
|
stats.ipfsLoaded = false
|
||||||
}
|
}
|
||||||
if (orbitDb) {
|
if (stats.ipfsLoaded && orbitDb) {
|
||||||
stats.orbitDbLoaded = true
|
stats.orbitDbLoaded = true
|
||||||
stats.pubKey = await orbitDb.key.getPublic('hex')
|
stats.pubKey = await orbitDb.key.getPublic('hex')
|
||||||
Object.values(window.dbs || {}).forEach(db => {
|
Object.values(window.dbs || {}).forEach(db => {
|
||||||
|
@ -5,4 +5,10 @@ export function getBoardAddress(hash, name) {
|
|||||||
|
|
||||||
export function shortenAddress(address) {
|
export function shortenAddress(address) {
|
||||||
return address.replace(/^\/orbitdb/, '/b')
|
return address.replace(/^\/orbitdb/, '/b')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeBoard(address) {
|
||||||
|
const db = window.dbs[address]
|
||||||
|
delete window.dbs[address]
|
||||||
|
if (db && db.close) db.close()
|
||||||
}
|
}
|
16
src/utils/persistence.js
Normal file
16
src/utils/persistence.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
export function save(){
|
||||||
|
const obj = {
|
||||||
|
addresses: Object.keys(window.dbs || {})
|
||||||
|
}
|
||||||
|
localStorage.setItem('ipfs-boards-v0', JSON.stringify(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function load(){
|
||||||
|
const str = localStorage.getItem('ipfs-boards-v0')
|
||||||
|
try {
|
||||||
|
return JSON.parse(str) || {};
|
||||||
|
} catch (error) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user