diff --git a/browser/finder/text.js b/browser/finder/text.js deleted file mode 100644 index e69de29b..00000000 diff --git a/browser/main/HomePage.js b/browser/main/HomePage.js index be4d6bfb..3cdf401c 100644 --- a/browser/main/HomePage.js +++ b/browser/main/HomePage.js @@ -8,13 +8,27 @@ import ArticleList from './HomePage/ArticleList' import ArticleDetail from './HomePage/ArticleDetail' import { findWhere, findIndex, pick } from 'lodash' import keygen from 'boost/keygen' -import { NEW } from './actions' +import { NEW, refreshArticles } from './actions' +import api from 'boost/api' -class HomeContainer extends React.Component { +class HomePage extends React.Component { componentDidMount () { const { dispatch } = this.props dispatch(switchUser(this.props.params.userId)) + + let currentUser = JSON.parse(localStorage.getItem('currentUser')) + let users = [currentUser].concat(currentUser.Teams) + users.forEach(user => { + api.fetchArticles(user.id) + .then(res => { + dispatch(refreshArticles(user.id, res.body)) + }) + .catch(err => { + if (err.status == null) throw err + console.error(err) + }) + }) } componentWillReceiveProps (nextProps) { @@ -29,7 +43,7 @@ class HomeContainer extends React.Component { const { dispatch, status, users, activeUser, articles, activeArticle } = this.props return ( -
+
@@ -44,13 +58,17 @@ function remap (state) { let status = state.status let currentUser = state.currentUser + if (currentUser == null) return state let teams = Array.isArray(currentUser.Teams) ? currentUser.Teams : [] let users = [currentUser, ...teams] 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(articles, {id: status.articleId}) + if (articles == null) articles = [] + + let activeArticle = findWhere(articles, {key: status.articleKey}) if (activeArticle == null) activeArticle = articles[0] // remove Unsaved new article if user is not CREATE_MODE @@ -68,7 +86,8 @@ function remap (state) { var newArticle = findWhere(articles, {status: 'NEW'}) if (newArticle == null) { newArticle = { - id: keygen(), + id: null, + key: keygen(), title: '', content: '', mode: 'markdown', @@ -84,16 +103,18 @@ function remap (state) { status.mode = IDLE_MODE } - return { + let props = { users, activeUser, status, articles, activeArticle } + console.log(props) + return props } -HomeContainer.propTypes = { +HomePage.propTypes = { users: PropTypes.array, activeUser: PropTypes.object, params: PropTypes.shape({ @@ -108,4 +129,4 @@ HomeContainer.propTypes = { dispatch: PropTypes.func } -export default connect(remap)(HomeContainer) +export default connect(remap)(HomePage) diff --git a/browser/main/HomePage/ArticleDetail.js b/browser/main/HomePage/ArticleDetail.js index 677a1c53..768a3aa9 100644 --- a/browser/main/HomePage/ArticleDetail.js +++ b/browser/main/HomePage/ArticleDetail.js @@ -19,7 +19,7 @@ var modeOptions = aceModes.map(function (mode) { function makeInstantArticle (article) { let instantArticle = Object.assign({}, article) - instantArticle.Tags = instantArticle.Tags.map(tag => tag.name) + instantArticle.Tags = typeof instantArticle.Tags === 'array' ? instantArticle.Tags.map(tag => tag.name) : [] return instantArticle } @@ -102,8 +102,12 @@ export default class ArticleDetail extends React.Component {
Are you sure to delete this article? - - + +
) @@ -133,7 +137,10 @@ export default class ArticleDetail extends React.Component {
{activeArticle.title}
- {activeArticle.mode === 'markdown' ? : } + {activeArticle.mode === 'markdown' + ? + : + }
@@ -147,7 +154,7 @@ export default class ArticleDetail extends React.Component { handleSaveButtonClick (e) { let { activeArticle } = this.props - if (typeof activeArticle.id === 'string') this.saveAsNew() + if (activeArticle.id == null) this.saveAsNew() else this.save() } @@ -254,7 +261,7 @@ export default class ArticleDetail extends React.Component {
this.handleTagsChange(tag, tags)} clearable={false} multi={true} placeholder='add some tags...' allowCreate={true} value={this.state.article.Tags} className='tags'/> +
- {this.state.isSending ? ( -

Logging in...

- ) : null} + {this.state.isSending + ? ( +

Logging in...

+ ) : null} {this.state.error != null ?

{this.state.error.message}

: null} diff --git a/browser/main/SignupPage.js b/browser/main/SignupPage.js index 2a624241..0f3a31e5 100644 --- a/browser/main/SignupPage.js +++ b/browser/main/SignupPage.js @@ -30,23 +30,30 @@ export default class SignupContainer extends React.Component { localStorage.setItem('token', res.body.token) localStorage.setItem('currentUser', JSON.stringify(res.body.user)) - this.props.history.pushState('userHome', {userId: res.body.user.id}) + this.props.history.pushState('home') }) - .catch(function (err) { + .catch(err => { console.error(err) - if (err.response == null) { + if (err.code === 'ECONNREFUSED') { return this.setState({ - error: {name: 'CunnectionRefused', message: 'Can\'t connect to API server.'}, + error: { + name: 'CunnectionRefused', + message: 'Can\'t connect to API server.' + }, isSending: false }) } - - // Connection Failed or Whatever - this.setState({ - error: err.response.body, - isSending: false - }) - }.bind(this)) + else if (err.status != null) { + return this.setState({ + error: { + name: err.response.body.name, + message: err.response.body.message + }, + isSending: false + }) + } + else throw err + }) }) e.preventDefault() @@ -55,7 +62,7 @@ export default class SignupContainer extends React.Component { render () { return (
- + diff --git a/browser/main/index.js b/browser/main/index.js index a3092cb6..2228cd8a 100644 --- a/browser/main/index.js +++ b/browser/main/index.js @@ -13,8 +13,8 @@ require('../styles/main/index.styl') function onlyUser (state, replaceState) { var currentUser = JSON.parse(localStorage.getItem('currentUser')) - if (currentUser == null) replaceState('login', '/login') - if (state.location.pathname === '/') replaceState('user', '/users/' + currentUser.id) + if (currentUser == null) return replaceState('login', '/login') + if (state.location.pathname === '/') return replaceState('user', '/users/' + currentUser.id) } let routes = ( @@ -62,18 +62,6 @@ React.render(( .then(function (res) { let user = res.body store.dispatch(updateUser(user)) - - let users = [user].concat(user.Teams) - users.forEach(user => { - fetchArticles(user.id) - .then(res => { - store.dispatch(refreshArticles(user.id, res.body)) - }) - .catch(err => { - if (err.status == null) throw err - console.error(err) - }) - }) }) .catch(function (err) { console.error(err.message) diff --git a/browser/main/reducer.js b/browser/main/reducer.js index 25de8a13..9fd4600b 100644 --- a/browser/main/reducer.js +++ b/browser/main/reducer.js @@ -2,17 +2,28 @@ import { combineReducers } from 'redux' import { findIndex } from 'lodash' import { SWITCH_USER, SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, USER_UPDATE, ARTICLE_REFRESH, ARTICLE_UPDATE, ARTICLE_DESTROY, IDLE_MODE, CREATE_MODE } from './actions' -const initialCurrentUser = JSON.parse(localStorage.getItem('currentUser')) const initialStatus = { mode: IDLE_MODE } -// init articles -let teams = Array.isArray(initialCurrentUser.Teams) ? initialCurrentUser.Teams : [] -let users = [initialCurrentUser, ...teams] -const initialArticles = users.reduce((res, user) => { - res['team-' + user.id] = JSON.parse(localStorage.getItem('team-' + user.id)) - return res -}, {}) + +function getInitialCurrentUser () { + return JSON.parse(localStorage.getItem('currentUser')) +} + +function getInitialArticles () { + let initialCurrentUser = getInitialCurrentUser() + if (initialCurrentUser == null) return [] + + let teams = Array.isArray(initialCurrentUser.Teams) ? initialCurrentUser.Teams : [] + + let users = [initialCurrentUser, ...teams] + let initialArticles = users.reduce((res, user) => { + res['team-' + user.id] = JSON.parse(localStorage.getItem('team-' + user.id)) + return res + }, {}) + + return initialArticles +} function currentUser (state, action) { switch (action.type) { @@ -21,7 +32,7 @@ function currentUser (state, action) { localStorage.setItem('currentUser', JSON.stringify(user)) return user default: - if (state == null) return initialCurrentUser + if (state == null) return getInitialCurrentUser() return state } } @@ -39,10 +50,10 @@ function status (state, action) { return state case SWITCH_MODE: state.mode = action.data - if (state.mode === CREATE_MODE) state.articleId = null + if (state.mode === CREATE_MODE) state.articleKey = null return state case SWITCH_ARTICLE: - state.articleId = action.data + state.articleKey = action.data state.mode = IDLE_MODE return state default: @@ -94,7 +105,7 @@ function articles (state, action) { } return state default: - if (state == null) return initialArticles + if (state == null) return getInitialArticles() return state } } diff --git a/browser/styles/main/HomeContainer/components/ArticleNavigator.styl b/browser/styles/main/HomeContainer/components/ArticleNavigator.styl index a2f02d45..da74fba6 100644 --- a/browser/styles/main/HomeContainer/components/ArticleNavigator.styl +++ b/browser/styles/main/HomeContainer/components/ArticleNavigator.styl @@ -45,6 +45,9 @@ articleNavBgColor = #353535 width 170px border-radius 5px font-size 20px + transition 0.1s + &:hover + background-color lighten(brandColor, 7%) .folders, .members .header border-bottom 1px solid borderColor diff --git a/browser/styles/main/HomeContainer/index.styl b/browser/styles/main/HomeContainer/index.styl index 6210d6ca..4009c6ed 100644 --- a/browser/styles/main/HomeContainer/index.styl +++ b/browser/styles/main/HomeContainer/index.styl @@ -6,3 +6,4 @@ @require './lib/modal' @require './lib/CreateNewTeam' +@require './lib/CreateNewFolder' diff --git a/browser/styles/main/HomeContainer/lib/CreateNewFolder.styl b/browser/styles/main/HomeContainer/lib/CreateNewFolder.styl new file mode 100644 index 00000000..0da43f58 --- /dev/null +++ b/browser/styles/main/HomeContainer/lib/CreateNewFolder.styl @@ -0,0 +1,75 @@ +tabNavColor = #999999 +iptFocusBorderColor = #369DCD + +.CreateNewFolder.modal + width 600px + height 450px + .closeBtn + position absolute + top 15px + right 15px + width 33px + height 33px + font-size 18px + line-height 33px + padding 0 + text-align center + background-color transparent + border none + color stripBtnColor + &:hover + color stripHoverBtnColor + .title + font-size 32px + text-align center + font-weight bold + margin-top 25px + .ipt + display block + width 330px + font-size 14px + height 44px + line-height 44px + padding 0 15px + border-radius 5px + border solid 1px borderColor + outline none + margin 100px auto 25px + &:focus + border-color iptFocusBorderColor + .public + margin 0 auto + text-align center + button + border none + background-color transparent + font-size 18px + color inactiveTextColor + transition 0.1s + button:hover + font-size 22px + button.active + color brandColor + font-size 22px + .divider + margin 0 5px + .confirmBtn + display block + position absolute + left 180px + bottom 44px + width 240px + font-size 24px + height 44px + line-height 24px + font-weight bold + background-color brandColor + color white + border none + border-radius 5px + margin 0 auto + transition 0.1s + &:hover + transform scale(1.1) + &:disabled + opacity 0.7 diff --git a/browser/styles/main/HomeContainer/lib/CreateNewTeam.styl b/browser/styles/main/HomeContainer/lib/CreateNewTeam.styl index 07b2b399..20dc353e 100644 --- a/browser/styles/main/HomeContainer/lib/CreateNewTeam.styl +++ b/browser/styles/main/HomeContainer/lib/CreateNewTeam.styl @@ -157,7 +157,7 @@ stripBtnColor = lighten(stripHoverBtnColor, 35%) height 44px padding 0 25px clearfix() - &nth-last-child(1) + &:nth-last-child(1) border-bottom-color transparent .userPhoto width 30px diff --git a/browser/styles/mixins/marked.styl b/browser/styles/mixins/marked.styl index 1dcf1947..96f086c4 100644 --- a/browser/styles/mixins/marked.styl +++ b/browser/styles/mixins/marked.styl @@ -46,7 +46,7 @@ marked() margin-bottom 35px li display list-item - margin 15px 0 + line-height 1.8em &>li>ul list-style-type circle &>li>ul @@ -57,7 +57,7 @@ marked() margin-bottom 35px li display list-item - margin 15px 0 + line-height 1.8em code font-family monospace padding 2px 4px diff --git a/lib/api.js b/lib/api.js index e2d1a9ca..1874b71c 100644 --- a/lib/api.js +++ b/lib/api.js @@ -88,6 +88,15 @@ export function deleteMember (teamId, input) { .send(input) } +export function createFolder (input) { + return request + .post(apiUrl + 'folders/') + .set({ + Authorization: 'Bearer ' + localStorage.getItem('token') + }) + .send(input) +} + export function sendEmail (input) { return request .post(apiUrl + 'mail') @@ -109,5 +118,6 @@ export default { searchUser, setMember, deleteMember, + createFolder, sendEmail } diff --git a/lib/components/modal/CreateNewFolder.js b/lib/components/modal/CreateNewFolder.js new file mode 100644 index 00000000..cfdb98e1 --- /dev/null +++ b/lib/components/modal/CreateNewFolder.js @@ -0,0 +1,88 @@ +import React, { PropTypes } from 'react' +import linkState from 'boost/linkState' +import api from 'boost/api' +import { pick } from 'lodash' + +export default class CreateNewFolder extends React.Component { + constructor (props) { + super(props) + + this.state = { + name: '', + public: false + } + } + + handlePublicButtonClick (value) { + console.log(value) + return e => { + this.setState({public: value}) + } + } + + handleConfirmButton (e) { + let { user, close } = this.props + let input = pick(this.state, ['public', 'name']) + input.UserId = user.id + + api.createFolder(input) + .then(res => { + console.log(res) + close() + }) + .catch(err => { + console.log(err) + if (err.code === '') { + let alert = { + type: 'error', + message: 'Can\'t connect to API server.' + } + } + else if (err.status != null) { + let alert = { + type: 'error', + message: err.response.body.message + } + this.setState({alert: alert}) + } + else { + throw err + } + }) + } + + render () { + let alert = this.state.alert + let alertEl = alert != null ? ( +

+ {alert.message} +

+ ) : null + + return ( +
+ + +
Create new folder
+ + + +
+ + / + +
+ {alertEl} + + +
+ ) + } +} + +CreateNewFolder.propTypes = { + user: PropTypes.shape(), + close: PropTypes.func +} + +CreateNewFolder.prototype.linkState = linkState diff --git a/lib/components/modal/CreateNewTeam.js b/lib/components/modal/CreateNewTeam.js index 5ffbb18d..bd1d4211 100644 --- a/lib/components/modal/CreateNewTeam.js +++ b/lib/components/modal/CreateNewTeam.js @@ -144,7 +144,7 @@ export default class CreateNewTeam extends React.Component { role: 'member' } - return function (e) { + return e => { deleteMember(selectState.team.id, input) .then(res => { let selectState = this.state.select @@ -162,7 +162,7 @@ export default class CreateNewTeam extends React.Component { if (err.status != null) throw err else console.error(err) }) - }.bind(this) + } } handleMemberRoleChange (name) {