diff --git a/browser/main/HomePage.js b/browser/main/HomePage.js index 015d5d5b..be4d6bfb 100644 --- a/browser/main/HomePage.js +++ b/browser/main/HomePage.js @@ -6,7 +6,7 @@ import ArticleNavigator from './HomePage/ArticleNavigator' import ArticleTopBar from './HomePage/ArticleTopBar' import ArticleList from './HomePage/ArticleList' import ArticleDetail from './HomePage/ArticleDetail' -import { findWhere, pick } from 'lodash' +import { findWhere, findIndex, pick } from 'lodash' import keygen from 'boost/keygen' import { NEW } from './actions' @@ -50,9 +50,20 @@ function remap (state) { let activeUser = findWhere(users, {id: parseInt(status.userId, 10)}) if (activeUser == null) activeUser = users[0] let articles = state.articles['team-' + activeUser.id] - let activeArticle = findWhere(users, {id: status.articleId}) + let activeArticle = findWhere(articles, {id: status.articleId}) if (activeArticle == null) activeArticle = articles[0] + // remove Unsaved new article if user is not CREATE_MODE + if (status.mode !== CREATE_MODE) { + let targetIndex = findIndex(articles, article => article.status === NEW) + + if (targetIndex >= 0) articles.splice(targetIndex, 1) + } + + // switching CREATE_MODE + // restrict + // 1. team have one folder at least + // or Change IDLE MODE if (status.mode === CREATE_MODE && activeUser.Folders.length > 0) { var newArticle = findWhere(articles, {status: 'NEW'}) if (newArticle == null) { @@ -72,10 +83,6 @@ function remap (state) { } else if (status.mode === CREATE_MODE) { status.mode = IDLE_MODE } - if (status.mode !== CREATE_MODE && activeArticle != null && activeArticle.status === NEW) { - articles.splice(articles.indexOf(activeArticle), 1) - activeArticle = articles[0] - } return { users, diff --git a/browser/main/HomePage/ArticleDetail.js b/browser/main/HomePage/ArticleDetail.js index 74e01c1d..677a1c53 100644 --- a/browser/main/HomePage/ArticleDetail.js +++ b/browser/main/HomePage/ArticleDetail.js @@ -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 ( - {tag.name} + {tag.name} ) }) : ( Not tagged yet @@ -50,24 +96,37 @@ export default class ArticleDetail extends React.Component { let folderName = folder != null ? folder.name : '(unknown)' return ( -
-
-
-
- {folderName}  - by {activeArticle.User.profileName}  - Created {moment(activeArticle.createdAt).format('YYYY/MM/DD')}  - Updated {moment(activeArticle.updatedAt).format('YYYY/MM/DD')} +
+ {this.state.openDeleteConfirmMenu + ? ( +
+
+ Are you sure to delete this article? + + +
-
{tags}
-
+ ) + : ( +
+
+
+ {folderName}  + by {activeArticle.User.profileName}  + Created {moment(activeArticle.createdAt).format('YYYY/MM/DD')}  + Updated {moment(activeArticle.updatedAt).format('YYYY/MM/DD')} +
+
{tags}
+
+
+ + + +
+
+ ) + } -
- - - -
-
@@ -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 {
- +