mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-20 13:11:44 +00:00
CRUD done
This commit is contained in:
@@ -4,10 +4,11 @@ import { findWhere, uniq } from 'lodash'
|
||||
import ModeIcon from 'boost/components/ModeIcon'
|
||||
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
||||
import CodeEditor from 'boost/components/CodeEditor'
|
||||
import { NEW, IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode } from '../actions'
|
||||
import { UNSYNCED, IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, switchArticle, updateArticle, destroyArticle } from '../actions'
|
||||
import aceModes from 'boost/ace-modes'
|
||||
import Select from 'react-select'
|
||||
import linkState from 'boost/linkState'
|
||||
import api from 'boost/api'
|
||||
|
||||
var modeOptions = aceModes.map(function (mode) {
|
||||
return {
|
||||
@@ -16,16 +17,27 @@ var modeOptions = aceModes.map(function (mode) {
|
||||
}
|
||||
})
|
||||
|
||||
function makeInstantArticle (article) {
|
||||
let instantArticle = Object.assign({}, article)
|
||||
instantArticle.Tags = instantArticle.Tags.map(tag => tag.name)
|
||||
return instantArticle
|
||||
}
|
||||
|
||||
export default class ArticleDetail extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
article: Object.assign({}, props.activeArticle)
|
||||
article: makeInstantArticle(props.activeArticle)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
this.setState({article: nextProps.activeArticle})
|
||||
if (nextProps.activeArticle != null && nextProps.activeArticle.id !== this.state.article.id) {
|
||||
this.setState({article: makeInstantArticle(nextProps.activeArticle)}, function () {
|
||||
console.log('receive props')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
renderEmpty () {
|
||||
@@ -36,12 +48,46 @@ export default class ArticleDetail extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
handleEditButtonClick (e) {
|
||||
let { dispatch } = this.props
|
||||
dispatch(switchMode(EDIT_MODE))
|
||||
}
|
||||
|
||||
handleDeleteButtonClick (e) {
|
||||
this.setState({openDeleteConfirmMenu: true})
|
||||
}
|
||||
|
||||
handleDeleteConfirmButtonClick (e) {
|
||||
let { dispatch, activeUser, activeArticle } = this.props
|
||||
|
||||
api.destroyArticle(activeArticle.id)
|
||||
.then(res => {
|
||||
console.log(res.body)
|
||||
})
|
||||
.catch(err => {
|
||||
// connect failed need to queue data
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
return
|
||||
}
|
||||
|
||||
if (err.status != null) throw err
|
||||
else console.log(err)
|
||||
})
|
||||
|
||||
dispatch(destroyArticle(activeUser.id, activeArticle.id))
|
||||
this.setState({openDeleteConfirmMenu: false})
|
||||
}
|
||||
|
||||
handleDeleteCancleButtonClick (e) {
|
||||
this.setState({openDeleteConfirmMenu: false})
|
||||
}
|
||||
|
||||
renderIdle () {
|
||||
let { status, activeArticle, activeUser } = this.props
|
||||
let { activeArticle, activeUser } = this.props
|
||||
|
||||
let tags = activeArticle.Tags.length > 0 ? activeArticle.Tags.map(tag => {
|
||||
return (
|
||||
<a key={tag.id}>{tag.name}</a>
|
||||
<a key={tag.name}>{tag.name}</a>
|
||||
)
|
||||
}) : (
|
||||
<span className='noTags'>Not tagged yet</span>
|
||||
@@ -50,24 +96,37 @@ export default class ArticleDetail extends React.Component {
|
||||
let folderName = folder != null ? folder.name : '(unknown)'
|
||||
|
||||
return (
|
||||
<div className='ArticleDetail show'>
|
||||
<div className='detailInfo'>
|
||||
<div className='left'>
|
||||
<div className='info'>
|
||||
<i className='fa fa-fw fa-square'/> {folderName}
|
||||
by {activeArticle.User.profileName}
|
||||
Created {moment(activeArticle.createdAt).format('YYYY/MM/DD')}
|
||||
Updated {moment(activeArticle.updatedAt).format('YYYY/MM/DD')}
|
||||
<div className='ArticleDetail idle'>
|
||||
{this.state.openDeleteConfirmMenu
|
||||
? (
|
||||
<div className='deleteConfirm'>
|
||||
<div className='right'>
|
||||
Are you sure to delete this article?
|
||||
<button onClick={e => this.handleDeleteConfirmButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Sure</button>
|
||||
<button onClick={e => this.handleDeleteCancleButtonClick(e)}><i className='fa fa-fw fa-times'/> Cancle</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className='detailInfo'>
|
||||
<div className='left'>
|
||||
<div className='info'>
|
||||
<i className='fa fa-fw fa-square'/> {folderName}
|
||||
by {activeArticle.User.profileName}
|
||||
Created {moment(activeArticle.createdAt).format('YYYY/MM/DD')}
|
||||
Updated {moment(activeArticle.updatedAt).format('YYYY/MM/DD')}
|
||||
</div>
|
||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||
</div>
|
||||
<div className='right'>
|
||||
<button onClick={e => this.handleEditButtonClick(e)}><i className='fa fa-fw fa-edit'/></button>
|
||||
<button onClick={e => this.handleDeleteButtonClick(e)}><i className='fa fa-fw fa-trash'/></button>
|
||||
<button><i className='fa fa-fw fa-share-alt'/></button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div className='right'>
|
||||
<button><i className='fa fa-fw fa-edit'/></button>
|
||||
<button><i className='fa fa-fw fa-trash'/></button>
|
||||
<button><i className='fa fa-fw fa-share-alt'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='detailBody'>
|
||||
<div className='detailPanel'>
|
||||
<div className='header'>
|
||||
@@ -86,7 +145,67 @@ export default class ArticleDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
console.log(this.state.article)
|
||||
let { activeArticle } = this.props
|
||||
|
||||
if (typeof activeArticle.id === 'string') this.saveAsNew()
|
||||
else this.save()
|
||||
}
|
||||
|
||||
saveAsNew () {
|
||||
let { dispatch, activeUser } = this.props
|
||||
let article = this.state.article
|
||||
let newArticle = Object.assign({}, article)
|
||||
article.tags = article.Tags
|
||||
|
||||
api.createArticle(article)
|
||||
.then(res => {
|
||||
console.log(res.body)
|
||||
})
|
||||
.catch(err => {
|
||||
// connect failed need to queue data
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
return
|
||||
}
|
||||
|
||||
if (err.status != null) throw err
|
||||
else console.log(err)
|
||||
})
|
||||
|
||||
newArticle.status = UNSYNCED
|
||||
newArticle.Tags = newArticle.Tags.map(tag => { return {name: tag} })
|
||||
|
||||
dispatch(updateArticle(activeUser.id, newArticle))
|
||||
dispatch(switchMode(IDLE_MODE))
|
||||
dispatch(switchArticle(article.id))
|
||||
}
|
||||
|
||||
save () {
|
||||
let { dispatch, activeUser } = this.props
|
||||
let article = this.state.article
|
||||
let newArticle = Object.assign({}, article)
|
||||
|
||||
article.tags = article.Tags
|
||||
|
||||
api.saveArticle(article)
|
||||
.then(res => {
|
||||
console.log(res.body)
|
||||
})
|
||||
.catch(err => {
|
||||
// connect failed need to queue data
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
return
|
||||
}
|
||||
|
||||
if (err.status != null) throw err
|
||||
else console.log(err)
|
||||
})
|
||||
|
||||
newArticle.status = UNSYNCED
|
||||
newArticle.Tags = newArticle.Tags.map(tag => { return {name: tag} })
|
||||
|
||||
dispatch(updateArticle(activeUser.id, newArticle))
|
||||
dispatch(switchMode(IDLE_MODE))
|
||||
dispatch(switchArticle(article.id))
|
||||
}
|
||||
|
||||
handleFolderIdChange (value) {
|
||||
@@ -121,7 +240,7 @@ export default class ArticleDetail extends React.Component {
|
||||
}
|
||||
|
||||
renderEdit () {
|
||||
let { status, activeUser } = this.props
|
||||
let { activeUser } = this.props
|
||||
|
||||
let folderOptions = activeUser.Folders.map(folder => {
|
||||
return {
|
||||
@@ -146,7 +265,7 @@ export default class ArticleDetail extends React.Component {
|
||||
<div className='detailPanel'>
|
||||
<div className='header'>
|
||||
<div className='title'>
|
||||
<input ref='title' valueLink={this.linkState('article.title')}/>
|
||||
<input placeholder='Title' ref='title' valueLink={this.linkState('article.title')}/>
|
||||
</div>
|
||||
<Select ref='mode' onChange={value => this.handleModeChange(value)} clearable={false} options={modeOptions}placeholder='select mode...' value={this.state.article.mode} className='mode'/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user