mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 02:06:29 +00:00
Contact Modal追加
This commit is contained in:
@@ -13,20 +13,20 @@ module.exports = React.createClass({
|
|||||||
var article = this.props.currentArticle
|
var article = this.props.currentArticle
|
||||||
|
|
||||||
if (article != null) {
|
if (article != null) {
|
||||||
if (article.type === 'snippet') {
|
if (article.type === 'code') {
|
||||||
return (
|
return (
|
||||||
<div className='FinderDetail'>
|
<div className='FinderDetail'>
|
||||||
<div className='header'>{article.callSign}</div>
|
<div className='header'><i className='fa fa-code fa-fw'/> {article.description}</div>
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
<CodeViewer code={article.content} mode={article.mode}/>
|
<CodeViewer code={article.content} mode={article.mode}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
} else if (article.type === 'blueprint') {
|
} else if (article.type === 'note') {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='FinderDetail'>
|
<div className='FinderDetail'>
|
||||||
<div className='header'>{article.title}</div>
|
<div className='header'><i className='fa fa-file-text-o fa-fw'/> {article.title}</div>
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
<div className='marked' dangerouslySetInnerHTML={{__html: ' ' + this.markdown(article.content)}}></div>
|
<div className='marked' dangerouslySetInnerHTML={{__html: ' ' + this.markdown(article.content)}}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ module.exports = React.createClass({
|
|||||||
currentArticle: React.PropTypes.shape({
|
currentArticle: React.PropTypes.shape({
|
||||||
id: React.PropTypes.number,
|
id: React.PropTypes.number,
|
||||||
type: React.PropTypes.string
|
type: React.PropTypes.string
|
||||||
})
|
}),
|
||||||
|
selectArticle: React.PropTypes.func
|
||||||
},
|
},
|
||||||
componentDidUpdate: function () {
|
componentDidUpdate: function () {
|
||||||
var index = this.props.articles.indexOf(this.props.currentArticle)
|
var index = this.props.articles.indexOf(this.props.currentArticle)
|
||||||
@@ -26,6 +27,11 @@ module.exports = React.createClass({
|
|||||||
el.scrollTop = li.offsetTop
|
el.scrollTop = li.offsetTop
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
handleArticleClick: function (article) {
|
||||||
|
return function () {
|
||||||
|
this.props.selectArticle(article)
|
||||||
|
}.bind(this)
|
||||||
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var list = this.props.articles.map(function (article) {
|
var list = this.props.articles.map(function (article) {
|
||||||
if (article == null) {
|
if (article == null) {
|
||||||
@@ -38,17 +44,17 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isActive = this.props.currentArticle != null && (article.type === this.props.currentArticle.type && article.id === this.props.currentArticle.id)
|
var isActive = this.props.currentArticle != null && (article.type === this.props.currentArticle.type && article.id === this.props.currentArticle.id)
|
||||||
if (article.type === 'snippet') {
|
if (article.type === 'code') {
|
||||||
return (
|
return (
|
||||||
<li className={isActive ? 'active' : ''}>
|
<li onClick={this.handleArticleClick(article)} className={isActive ? 'active' : ''}>
|
||||||
<div className='articleItem'><i className='fa fa-code fa-fw'/> {article.callSign} / {article.description.substring(0, 10)}</div>
|
<div className='articleItem'><i className='fa fa-code fa-fw'/> {article.description}</div>
|
||||||
<div className='divider'/>
|
<div className='divider'/>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (article.type === 'blueprint') {
|
if (article.type === 'note') {
|
||||||
return (
|
return (
|
||||||
<li className={isActive ? 'active' : ''}>
|
<li onClick={this.handleArticleClick(article)} className={isActive ? 'active' : ''}>
|
||||||
<div className='articleItem'><i className='fa fa-file-text-o fa-fw'/> {article.title}</div>
|
<div className='articleItem'><i className='fa fa-file-text-o fa-fw'/> {article.title}</div>
|
||||||
<div className='divider'/>
|
<div className='divider'/>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -5,79 +5,12 @@ var clipboard = require('clipboard')
|
|||||||
|
|
||||||
var React = require('react/addons')
|
var React = require('react/addons')
|
||||||
|
|
||||||
|
var ArticleFilter = require('../main/Mixins/ArticleFilter')
|
||||||
|
|
||||||
var FinderInput = require('./Components/FinderInput')
|
var FinderInput = require('./Components/FinderInput')
|
||||||
var FinderList = require('./Components/FinderList')
|
var FinderList = require('./Components/FinderList')
|
||||||
var FinderDetail = require('./Components/FinderDetail')
|
var FinderDetail = require('./Components/FinderDetail')
|
||||||
|
|
||||||
// filter start
|
|
||||||
function basicFilter (keyword, articles) {
|
|
||||||
if (keyword === '' || keyword == null) return articles
|
|
||||||
var firstFiltered = articles.filter(function (article) {
|
|
||||||
|
|
||||||
var first = article.type === 'snippet' ? article.callSign : article.title
|
|
||||||
if (first.match(new RegExp(keyword, 'i'))) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
var secondFiltered = articles.filter(function (article) {
|
|
||||||
var second = article.type === 'snippet' ? article.description : article.content
|
|
||||||
if (second.match(new RegExp(keyword, 'i'))) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
var thirdFiltered = articles.filter(function (article) {
|
|
||||||
if (article.type === 'snippet') {
|
|
||||||
if (article.content.match(new RegExp(keyword, 'i'))) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return firstFiltered.concat(secondFiltered, thirdFiltered).filter(function (value, index, self) {
|
|
||||||
return self.indexOf(value) === index
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function snippetFilter (articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.type === 'snippet'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function blueprintFilter (articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.type === 'blueprint'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function tagFilter (keyword, articles) {
|
|
||||||
return articles.filter(function (article) {
|
|
||||||
return article.Tags.some(function (tag) {
|
|
||||||
return tag.name.match(new RegExp('^' + keyword, 'i'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchArticle (search, articles) {
|
|
||||||
var keywords = search.split(' ')
|
|
||||||
|
|
||||||
for (var keyword of keywords) {
|
|
||||||
if (keyword.match(/^\$s/, 'i')) {
|
|
||||||
articles = snippetFilter(articles)
|
|
||||||
continue
|
|
||||||
} else if (keyword.match(/^\$b/, 'i')) {
|
|
||||||
articles = blueprintFilter(articles)
|
|
||||||
continue
|
|
||||||
} else if (keyword.match(/^#[A-Za-z0-9]+/)) {
|
|
||||||
articles = tagFilter(keyword.substring(1, keyword.length), articles)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
articles = basicFilter(keyword, articles)
|
|
||||||
}
|
|
||||||
|
|
||||||
return articles
|
|
||||||
}
|
|
||||||
// Filter end
|
// Filter end
|
||||||
|
|
||||||
function fetchArticles () {
|
function fetchArticles () {
|
||||||
@@ -90,14 +23,20 @@ function fetchArticles () {
|
|||||||
var articles = []
|
var articles = []
|
||||||
user.Planets.forEach(function (planet) {
|
user.Planets.forEach(function (planet) {
|
||||||
var _planet = JSON.parse(localStorage.getItem('planet-' + planet.id))
|
var _planet = JSON.parse(localStorage.getItem('planet-' + planet.id))
|
||||||
articles = articles.concat(_planet.Snippets, _planet.Blueprints)
|
articles = articles.concat(_planet.Codes, _planet.Notes)
|
||||||
|
})
|
||||||
|
user.Teams.forEach(function (team) {
|
||||||
|
team.Planets.forEach(function (planet) {
|
||||||
|
var _planet = JSON.parse(localStorage.getItem('planet-' + planet.id))
|
||||||
|
articles = articles.concat(_planet.Codes, _planet.Notes)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
console.log(articles.length + ' articles')
|
|
||||||
|
|
||||||
return articles
|
return articles
|
||||||
}
|
}
|
||||||
|
|
||||||
var Finder = React.createClass({
|
var Finder = React.createClass({
|
||||||
|
mixins: [ArticleFilter],
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
var articles = fetchArticles()
|
var articles = fetchArticles()
|
||||||
return {
|
return {
|
||||||
@@ -122,8 +61,14 @@ var Finder = React.createClass({
|
|||||||
var articles = fetchArticles()
|
var articles = fetchArticles()
|
||||||
this.setState({
|
this.setState({
|
||||||
articles: articles,
|
articles: articles,
|
||||||
currentArticle: articles[0],
|
|
||||||
search: ''
|
search: ''
|
||||||
|
}, function () {
|
||||||
|
var firstArticle = this.refs.finderList.props.articles[0]
|
||||||
|
if (firstArticle) {
|
||||||
|
this.setState({
|
||||||
|
currentArticle: firstArticle
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleKeyDown: function (e) {
|
handleKeyDown: function (e) {
|
||||||
@@ -139,11 +84,9 @@ var Finder = React.createClass({
|
|||||||
|
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
var article = this.state.currentArticle
|
var article = this.state.currentArticle
|
||||||
if (article.type === 'snippet') {
|
clipboard.writeText(article.content)
|
||||||
clipboard.writeText(article.content)
|
hideFinder()
|
||||||
hideFinder()
|
e.preventDefault()
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
hideFinder()
|
hideFinder()
|
||||||
@@ -168,17 +111,20 @@ var Finder = React.createClass({
|
|||||||
this.setState({currentArticle: this.refs.finderList.props.articles[index + 1]})
|
this.setState({currentArticle: this.refs.finderList.props.articles[index + 1]})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectArticle: function (article) {
|
||||||
|
this.setState({currentArticle: article})
|
||||||
|
},
|
||||||
handleChange: function (e) {
|
handleChange: function (e) {
|
||||||
this.setState({search: e.target.value}, function () {
|
this.setState({search: e.target.value}, function () {
|
||||||
this.setState({currentArticle: this.refs.finderList.props.articles[0]})
|
this.setState({currentArticle: this.refs.finderList.props.articles[0]})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var articles = searchArticle(this.state.search, this.state.articles)
|
var articles = this.searchArticle(this.state.search, this.state.articles)
|
||||||
return (
|
return (
|
||||||
<div className='Finder'>
|
<div className='Finder'>
|
||||||
<FinderInput ref='finderInput' onChange={this.handleChange} search={this.state.search}/>
|
<FinderInput ref='finderInput' onChange={this.handleChange} search={this.state.search}/>
|
||||||
<FinderList ref='finderList' currentArticle={this.state.currentArticle} articles={articles}/>
|
<FinderList ref='finderList' currentArticle={this.state.currentArticle} articles={articles} selectArticle={this.selectArticle}/>
|
||||||
<FinderDetail currentArticle={this.state.currentArticle}/>
|
<FinderDetail currentArticle={this.state.currentArticle}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module.exports = React.createClass({
|
|||||||
<div className='AboutModal modal'>
|
<div className='AboutModal modal'>
|
||||||
<div className='about1'>
|
<div className='about1'>
|
||||||
<img className='logo' src='resources/favicon-230x230.png'/>
|
<img className='logo' src='resources/favicon-230x230.png'/>
|
||||||
<div className='appInfo'>Boost {version == null ? 'DEV version' : 'v' + version}</div>
|
<div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='about2'>
|
<div className='about2'>
|
||||||
|
|||||||
83
browser/main/Components/AddMemberModal.jsx
Normal file
83
browser/main/Components/AddMemberModal.jsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
var React = require('react/addons')
|
||||||
|
var Select = require('react-select')
|
||||||
|
|
||||||
|
var LinkedState = require('../Mixins/LinkedState')
|
||||||
|
|
||||||
|
var Hq = require('../Services/Hq')
|
||||||
|
|
||||||
|
var UserStore = require('../Stores/UserStore')
|
||||||
|
|
||||||
|
var getOptions = function (input, callback) {
|
||||||
|
Hq.searchUser(input)
|
||||||
|
.then(function (res) {
|
||||||
|
callback(null, {
|
||||||
|
options: res.body.map(function (user) {
|
||||||
|
return {
|
||||||
|
label: user.name,
|
||||||
|
value: user.name
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
complete: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
mixins: [LinkedState],
|
||||||
|
propTypes: {
|
||||||
|
team: React.PropTypes.object,
|
||||||
|
close: React.PropTypes.func
|
||||||
|
},
|
||||||
|
getInitialState: function () {
|
||||||
|
return {
|
||||||
|
userName: '',
|
||||||
|
role: 'member'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSubmit: function () {
|
||||||
|
Hq
|
||||||
|
.addMember(this.props.team.name, {
|
||||||
|
userName: this.state.userName,
|
||||||
|
role: this.state.role
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
console.log(res.body)
|
||||||
|
UserStore.Actions.addMember(res.body)
|
||||||
|
this.props.close()
|
||||||
|
}.bind(this))
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleChange: function (value) {
|
||||||
|
this.setState({userName: value})
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
return (
|
||||||
|
<div className='AddMemberModal modal'>
|
||||||
|
<Select
|
||||||
|
name='userName'
|
||||||
|
value={this.state.userName}
|
||||||
|
placeholder='Username to add'
|
||||||
|
asyncOptions={getOptions}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
className='userNameSelect'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className='formField'>
|
||||||
|
Add member as
|
||||||
|
<select valueLink={this.linkState('role')}>
|
||||||
|
<option value={'member'}>Member</option>
|
||||||
|
<option value={'owner'}>Owner</option>
|
||||||
|
</select>
|
||||||
|
role
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onClick={this.handleSubmit} className='submitButton'><i className='fa fa-check'/></button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
62
browser/main/Components/ContactModal.jsx
Normal file
62
browser/main/Components/ContactModal.jsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
var React = require('react')
|
||||||
|
|
||||||
|
var LinkedState = require('../Mixins/LinkedState')
|
||||||
|
|
||||||
|
var Hq = require('../Services/Hq')
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
mixins: [LinkedState],
|
||||||
|
propTypes: {
|
||||||
|
close: React.PropTypes.func
|
||||||
|
},
|
||||||
|
getInitialState: function () {
|
||||||
|
return {
|
||||||
|
isSent: false,
|
||||||
|
mail: {
|
||||||
|
title: '',
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sendEmail: function () {
|
||||||
|
Hq.sendEmail(this.state.mail)
|
||||||
|
.then(function (res) {
|
||||||
|
this.setState({isSent: !this.state.isSent})
|
||||||
|
}.bind(this))
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
return (
|
||||||
|
<div className='ContactModal modal'>
|
||||||
|
<div className='modal-header'><h1>Contact form</h1></div>
|
||||||
|
|
||||||
|
{!this.state.isSent ? (
|
||||||
|
<div className='contactForm'>
|
||||||
|
<div className='modal-body'>
|
||||||
|
<div className='formField'>
|
||||||
|
<input valueLink={this.linkState('mail.title')} placeholder='Title'/>
|
||||||
|
</div>
|
||||||
|
<div className='formField'>
|
||||||
|
<textarea valueLink={this.linkState('mail.content')} placeholder='Content'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='modal-footer'>
|
||||||
|
<div className='formControl'>
|
||||||
|
<button onClick={this.sendEmail} className='sendButton'>Send</button>
|
||||||
|
<button onClick={this.props.close}>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='confirmation'>
|
||||||
|
<div className='confirmationMessage'>Thanks for sharing your opinion!</div>
|
||||||
|
<button className='doneButton' onClick={this.props.close}>Done</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -22,7 +22,6 @@ module.exports = React.createClass({
|
|||||||
return {
|
return {
|
||||||
currentTab: 'userInfo',
|
currentTab: 'userInfo',
|
||||||
user: {
|
user: {
|
||||||
name: user.name,
|
|
||||||
profileName: user.profileName,
|
profileName: user.profileName,
|
||||||
email: user.email
|
email: user.email
|
||||||
},
|
},
|
||||||
@@ -116,10 +115,6 @@ module.exports = React.createClass({
|
|||||||
<label>Profile Name</label>
|
<label>Profile Name</label>
|
||||||
<input valueLink={this.linkState('user.profileName')}/>
|
<input valueLink={this.linkState('user.profileName')}/>
|
||||||
</div>
|
</div>
|
||||||
<div className='formField'>
|
|
||||||
<label>Name</label>
|
|
||||||
<input valueLink={this.linkState('user.name')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formField'>
|
<div className='formField'>
|
||||||
<label>E-mail</label>
|
<label>E-mail</label>
|
||||||
<input valueLink={this.linkState('user.email')}/>
|
<input valueLink={this.linkState('user.email')}/>
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
var React = require('react/addons')
|
|
||||||
var ReactRouter = require('react-router')
|
|
||||||
var Select = require('react-select')
|
|
||||||
var request = require('superagent')
|
|
||||||
|
|
||||||
var Catalyst = require('../Mixins/Catalyst')
|
|
||||||
|
|
||||||
var PlanetActions = require('../Actions/PlanetActions')
|
|
||||||
|
|
||||||
var apiUrl = require('../../../config').apiUrl
|
|
||||||
|
|
||||||
var getOptions = function (input, callback) {
|
|
||||||
request
|
|
||||||
.get(apiUrl + 'users/search')
|
|
||||||
.query({name: input})
|
|
||||||
.send()
|
|
||||||
.end(function (err, res) {
|
|
||||||
if (err) {
|
|
||||||
callback(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
callback(null, {
|
|
||||||
options: res.body.map(function (user) {
|
|
||||||
return {
|
|
||||||
label: user.name,
|
|
||||||
value: user.name
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
complete: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
mixins: [Catalyst.LinkedStateMixin, ReactRouter.State],
|
|
||||||
propTypes: {
|
|
||||||
close: React.PropTypes.func
|
|
||||||
},
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
userName: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
|
||||||
window.ns = React.findDOMNode(this).querySelector('.Select')
|
|
||||||
},
|
|
||||||
handleSubmit: function () {
|
|
||||||
var userName = this.state.userName
|
|
||||||
var params = this.getParams()
|
|
||||||
var ownerName = params.userName
|
|
||||||
var planetName = params.planetName
|
|
||||||
|
|
||||||
PlanetActions.addUser(ownerName + '/' + planetName, userName)
|
|
||||||
},
|
|
||||||
handleChange: function (value) {
|
|
||||||
this.setState({userName: value})
|
|
||||||
},
|
|
||||||
stopPropagation: function (e) {
|
|
||||||
e.stopPropagation()
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div onClick={this.stopPropagation} className='PlanetAddUserModal modal'>
|
|
||||||
<Select
|
|
||||||
name='userName'
|
|
||||||
value={this.state.userName}
|
|
||||||
placeholder='Username'
|
|
||||||
asyncOptions={getOptions}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
className='userNameSelect'
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button onClick={this.handleSubmit} className='submitButton'><i className='fa fa-check'/></button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,20 +1,43 @@
|
|||||||
/* global localStorage */
|
/* global localStorage */
|
||||||
|
|
||||||
var React = require('react/addons')
|
var React = require('react/addons')
|
||||||
|
var Reflux = require('reflux')
|
||||||
|
var Select = require('react-select')
|
||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
var Hq = require('../Services/Hq')
|
||||||
|
|
||||||
var LinkedState = require('../Mixins/LinkedState')
|
var LinkedState = require('../Mixins/LinkedState')
|
||||||
|
var Helper = require('../Mixins/Helper')
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
var UserStore = require('../Stores/UserStore')
|
||||||
|
|
||||||
|
var getOptions = function (input, callback) {
|
||||||
|
Hq.searchUser(input)
|
||||||
|
.then(function (res) {
|
||||||
|
callback(null, {
|
||||||
|
options: res.body.map(function (user) {
|
||||||
|
return {
|
||||||
|
label: user.name,
|
||||||
|
value: user.name
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
complete: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
mixins: [LinkedState],
|
mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper],
|
||||||
propTypes: {
|
propTypes: {
|
||||||
team: React.PropTypes.shape({
|
team: React.PropTypes.shape({
|
||||||
|
id: React.PropTypes.number,
|
||||||
name: React.PropTypes.string,
|
name: React.PropTypes.string,
|
||||||
profileName: React.PropTypes.string,
|
profileName: React.PropTypes.string,
|
||||||
email: React.PropTypes.string
|
email: React.PropTypes.string,
|
||||||
|
Members: React.PropTypes.array
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
@@ -22,10 +45,31 @@ module.exports = React.createClass({
|
|||||||
return {
|
return {
|
||||||
currentTab: 'teamInfo',
|
currentTab: 'teamInfo',
|
||||||
team: {
|
team: {
|
||||||
name: team.name,
|
|
||||||
profileName: team.profileName
|
profileName: team.profileName
|
||||||
},
|
},
|
||||||
userSubmitStatus: null
|
userSubmitStatus: null,
|
||||||
|
member: {
|
||||||
|
name: '',
|
||||||
|
role: 'member'
|
||||||
|
},
|
||||||
|
updatingMember: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUserChange: function (res) {
|
||||||
|
var member
|
||||||
|
switch (res.status) {
|
||||||
|
case 'memberAdded':
|
||||||
|
member = res.data
|
||||||
|
if (member.TeamMember.TeamId === this.props.team.id) {
|
||||||
|
this.forceUpdate()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'memberRemoved':
|
||||||
|
member = res.data
|
||||||
|
if (member.TeamMember.TeamId === this.props.team.id) {
|
||||||
|
this.forceUpdate()
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectTab: function (tabName) {
|
selectTab: function (tabName) {
|
||||||
@@ -41,6 +85,7 @@ module.exports = React.createClass({
|
|||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
this.setState({userSubmitStatus: 'done'}, function () {
|
this.setState({userSubmitStatus: 'done'}, function () {
|
||||||
UserStore.Actions.update(res.body)
|
UserStore.Actions.update(res.body)
|
||||||
|
this.forceUpdate()
|
||||||
})
|
})
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
@@ -49,6 +94,66 @@ module.exports = React.createClass({
|
|||||||
}.bind(this))
|
}.bind(this))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
handleMemberNameChange: function (value) {
|
||||||
|
var member = this.state.member
|
||||||
|
member.name = value
|
||||||
|
this.setState({member: member})
|
||||||
|
},
|
||||||
|
addMember: function () {
|
||||||
|
this.setState({updatingMember: true}, function () {
|
||||||
|
Hq
|
||||||
|
.addMember(this.props.team.name, {
|
||||||
|
userName: this.state.member.name,
|
||||||
|
role: this.state.member.role
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
UserStore.Actions.addMember(res.body)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
roleChange: function (memberName) {
|
||||||
|
return function (e) {
|
||||||
|
var role = e.target.value
|
||||||
|
this.setState({updatingMember: true}, function () {
|
||||||
|
Hq
|
||||||
|
.addMember(this.props.team.name, {
|
||||||
|
userName: memberName,
|
||||||
|
role: role
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
UserStore.Actions.addMember(res.body)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
})
|
||||||
|
}.bind(this)
|
||||||
|
},
|
||||||
|
removeMember: function (memberName) {
|
||||||
|
return function () {
|
||||||
|
this.setState({updatingMember: true}, function () {
|
||||||
|
Hq
|
||||||
|
.removeMember(this.props.team.name, {
|
||||||
|
userName: memberName
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
UserStore.Actions.removeMember(res.body)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
.catch(function (err) {
|
||||||
|
console.error(err)
|
||||||
|
this.setState({updatingMember: false})
|
||||||
|
}.bind(this))
|
||||||
|
})
|
||||||
|
}.bind(this)
|
||||||
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var content
|
var content
|
||||||
|
|
||||||
@@ -62,7 +167,7 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='EditProfileModal modal tabModal'>
|
<div className='TeamSettingsModal modal tabModal'>
|
||||||
<div className='leftPane'>
|
<div className='leftPane'>
|
||||||
<div className='tabLabel'>Team settings</div>
|
<div className='tabLabel'>Team settings</div>
|
||||||
<div className='tabList'>
|
<div className='tabList'>
|
||||||
@@ -83,10 +188,6 @@ module.exports = React.createClass({
|
|||||||
<label>Profile Name</label>
|
<label>Profile Name</label>
|
||||||
<input valueLink={this.linkState('team.profileName')}/>
|
<input valueLink={this.linkState('team.profileName')}/>
|
||||||
</div>
|
</div>
|
||||||
<div className='formField'>
|
|
||||||
<label>Name</label>
|
|
||||||
<input valueLink={this.linkState('team.name')}/>
|
|
||||||
</div>
|
|
||||||
<div className='formConfirm'>
|
<div className='formConfirm'>
|
||||||
<button disabled={this.state.userSubmitStatus === 'sending'} onClick={this.saveUserInfo}>Save</button>
|
<button disabled={this.state.userSubmitStatus === 'sending'} onClick={this.saveUserInfo}>Save</button>
|
||||||
|
|
||||||
@@ -100,8 +201,72 @@ module.exports = React.createClass({
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
renderMembersTab: function () {
|
renderMembersTab: function () {
|
||||||
|
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
|
||||||
|
|
||||||
|
var members = this.props.team.Members.map(function (member) {
|
||||||
|
var isCurrentUser = currentUser.id === member.id
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{member.profileName}({member.name})</td>
|
||||||
|
<td>
|
||||||
|
{isCurrentUser ? (
|
||||||
|
'Owner'
|
||||||
|
) : (
|
||||||
|
<select disabled={this.state.updatingMember} onChange={this.roleChange(member.name)} className='roleSelect' value={member.TeamMember.role}>
|
||||||
|
<option value='owner'>Owner</option>
|
||||||
|
<option value='member'>Member</option>
|
||||||
|
</select>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{isCurrentUser ? '-' : (
|
||||||
|
<button disabled={this.state.updatingMember} onClick={this.removeMember(member.name)}><i className='fa fa-close fa-fw'/></button>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
|
var belowLimit = members.length < 5
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='membersTab'>
|
<div className='membersTab'>
|
||||||
|
<table className='memberTable'>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Control</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{members}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{belowLimit ? (
|
||||||
|
<div className='addMemberForm'>
|
||||||
|
<div className='formLabel'>Add Member</div>
|
||||||
|
<div className='formGroup'>
|
||||||
|
<Select
|
||||||
|
name='userName'
|
||||||
|
value={this.state.member.name}
|
||||||
|
placeholder='Username to add'
|
||||||
|
asyncOptions={getOptions}
|
||||||
|
onChange={this.handleMemberNameChange}
|
||||||
|
className='userNameSelect'
|
||||||
|
/>
|
||||||
|
<select valueLink={this.linkState('member.role')} className='roleSelect'>
|
||||||
|
<option value={'member'}>Member</option>
|
||||||
|
<option value={'owner'}>Owner</option>
|
||||||
|
</select>
|
||||||
|
<button disabled={this.state.updatingMember} onClick={this.addMember} className='confirmButton'>Add Member</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
Maximum numbr of members is 5 on Beta version. Please contact us if you want futher use.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/* global localStorage */
|
/* global localStorage */
|
||||||
|
|
||||||
|
var ipc = require('ipc')
|
||||||
|
|
||||||
var React = require('react/addons')
|
var React = require('react/addons')
|
||||||
var ReactRouter = require('react-router')
|
var ReactRouter = require('react-router')
|
||||||
var RouteHandler = ReactRouter.RouteHandler
|
var RouteHandler = ReactRouter.RouteHandler
|
||||||
@@ -8,35 +10,45 @@ var State = ReactRouter.State
|
|||||||
|
|
||||||
var Hq = require('../Services/Hq')
|
var Hq = require('../Services/Hq')
|
||||||
|
|
||||||
|
var Modal = require('../Mixins/Modal')
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
var UserStore = require('../Stores/UserStore')
|
||||||
|
|
||||||
// function fetchPlanet (planet) {
|
var ContactModal = require('../Components/ContactModal')
|
||||||
// return Hq.fetchPlanet(planet.userName, planet.name)
|
|
||||||
// .then(function (res) {
|
function fetchPlanet (userName, planetName) {
|
||||||
// var _planet = res.body
|
Hq.fetchPlanet(userName, planetName)
|
||||||
// _planet.userName = planet.userName
|
.then(function (res) {
|
||||||
//
|
var planet = res.body
|
||||||
// _planet.Snippets = _planet.Snippets.map(function (snippet) {
|
|
||||||
// snippet.type = 'snippet'
|
planet.Codes.forEach(function (code) {
|
||||||
// return snippet
|
code.type = 'code'
|
||||||
// })
|
})
|
||||||
//
|
|
||||||
// _planet.Blueprints = _planet.Blueprints.map(function (blueprint) {
|
planet.Notes.forEach(function (note) {
|
||||||
// blueprint.type = 'blueprint'
|
note.type = 'note'
|
||||||
// return blueprint
|
})
|
||||||
// })
|
|
||||||
//
|
console.log('planet-' + planet.id + ' fetched!')
|
||||||
// localStorage.setItem('planet-' + _planet.id, JSON.stringify(_planet))
|
localStorage.setItem('planet-' + planet.id, JSON.stringify(planet))
|
||||||
// console.log('planet-' + _planet.id + ' fetched')
|
})
|
||||||
// })
|
.catch(function (err) {
|
||||||
// .catch(function (err) {
|
console.error(err)
|
||||||
// console.error(err)
|
})
|
||||||
// })
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
mixins: [State, Navigation],
|
mixins: [State, Navigation, Modal],
|
||||||
|
getInitialState: function () {
|
||||||
|
return {
|
||||||
|
updateAvailable: false
|
||||||
|
}
|
||||||
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
|
ipc.on('update-available', function (message) {
|
||||||
|
this.setState({updateAvailable: true})
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
if (this.isActive('root')) {
|
if (this.isActive('root')) {
|
||||||
if (localStorage.getItem('currentUser') == null) {
|
if (localStorage.getItem('currentUser') == null) {
|
||||||
this.transitionTo('login')
|
this.transitionTo('login')
|
||||||
@@ -49,9 +61,19 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
Hq.getUser()
|
Hq.getUser()
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
console.log(res.body)
|
var user = res.body
|
||||||
localStorage.setItem('currentUser', JSON.stringify(res.body))
|
localStorage.setItem('currentUser', JSON.stringify(user))
|
||||||
UserStore.Actions.update(res.body)
|
UserStore.Actions.update(user)
|
||||||
|
|
||||||
|
user.Planets.forEach(function (planet) {
|
||||||
|
fetchPlanet(planet.userName, planet.name)
|
||||||
|
})
|
||||||
|
user.Teams.forEach(function (team) {
|
||||||
|
team.Planets.forEach(function (planet) {
|
||||||
|
fetchPlanet(planet.userName, planet.name)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
if (err.status === 401) {
|
if (err.status === 401) {
|
||||||
@@ -63,9 +85,19 @@ module.exports = React.createClass({
|
|||||||
console.error(err)
|
console.error(err)
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
},
|
},
|
||||||
|
updateApp: function () {
|
||||||
|
ipc.send('update-app', 'Deal with it.')
|
||||||
|
},
|
||||||
|
openContactModal: function () {
|
||||||
|
this.openModal(ContactModal)
|
||||||
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
return (
|
return (
|
||||||
<div className='Main'>
|
<div className='Main'>
|
||||||
|
{this.state.updateAvailable ? (
|
||||||
|
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
|
||||||
|
) : null}
|
||||||
|
<button onClick={this.openContactModal} className='contactButton'><i className='fa fa-paper-plane-o'/></button>
|
||||||
<RouteHandler/>
|
<RouteHandler/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,42 +9,17 @@ var PlanetNavigator = require('../Components/PlanetNavigator')
|
|||||||
var PlanetArticleList = require('../Components/PlanetArticleList')
|
var PlanetArticleList = require('../Components/PlanetArticleList')
|
||||||
var PlanetArticleDetail = require('../Components/PlanetArticleDetail')
|
var PlanetArticleDetail = require('../Components/PlanetArticleDetail')
|
||||||
|
|
||||||
|
var Hq = require('../Services/Hq')
|
||||||
|
|
||||||
var Modal = require('../Mixins/Modal')
|
var Modal = require('../Mixins/Modal')
|
||||||
var ArticleFilter = require('../Mixins/ArticleFilter')
|
var ArticleFilter = require('../Mixins/ArticleFilter')
|
||||||
|
var Helper = require('../Mixins/Helper')
|
||||||
var Hq = require('../Services/Hq')
|
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
var UserStore = require('../Stores/UserStore')
|
||||||
var PlanetStore = require('../Stores/PlanetStore')
|
var PlanetStore = require('../Stores/PlanetStore')
|
||||||
|
|
||||||
function deleteItemFromTargetArray (item, targetArray) {
|
|
||||||
targetArray.some(function (_item, index) {
|
|
||||||
if (_item.id === item.id) {
|
|
||||||
targetArray.splice(index, 1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return targetArray
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateItemToTargetArray (item, targetArray) {
|
|
||||||
var isNew = !targetArray.some(function (_item, index) {
|
|
||||||
if (_item.id === item.id) {
|
|
||||||
targetArray.splice(index, 1, item)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isNew) targetArray.push(item)
|
|
||||||
|
|
||||||
return targetArray
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter],
|
mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper],
|
||||||
propTypes: {
|
propTypes: {
|
||||||
params: React.PropTypes.object,
|
params: React.PropTypes.object,
|
||||||
planetName: React.PropTypes.string
|
planetName: React.PropTypes.string
|
||||||
@@ -111,7 +86,7 @@ module.exports = React.createClass({
|
|||||||
case 'codeUpdated':
|
case 'codeUpdated':
|
||||||
code = res.data
|
code = res.data
|
||||||
if (code.PlanetId === this.state.planet.id) {
|
if (code.PlanetId === this.state.planet.id) {
|
||||||
this.state.planet.Codes = updateItemToTargetArray(code, this.state.planet.Codes)
|
this.state.planet.Codes = this.updateItemToTargetArray(code, this.state.planet.Codes)
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
this.setState({planet: this.state.planet})
|
||||||
}
|
}
|
||||||
@@ -119,7 +94,7 @@ module.exports = React.createClass({
|
|||||||
case 'noteUpdated':
|
case 'noteUpdated':
|
||||||
note = res.data
|
note = res.data
|
||||||
if (note.PlanetId === this.state.planet.id) {
|
if (note.PlanetId === this.state.planet.id) {
|
||||||
this.state.planet.Notes = updateItemToTargetArray(note, this.state.planet.Notes)
|
this.state.planet.Notes = this.updateItemToTargetArray(note, this.state.planet.Notes)
|
||||||
|
|
||||||
this.setState({planet: this.state.planet})
|
this.setState({planet: this.state.planet})
|
||||||
}
|
}
|
||||||
@@ -127,7 +102,7 @@ module.exports = React.createClass({
|
|||||||
case 'codeDestroyed':
|
case 'codeDestroyed':
|
||||||
code = res.data
|
code = res.data
|
||||||
if (code.PlanetId === this.state.planet.id) {
|
if (code.PlanetId === this.state.planet.id) {
|
||||||
this.state.planet.Codes = deleteItemFromTargetArray(code, this.state.planet.Codes)
|
this.state.planet.Codes = this.deleteItemFromTargetArray(code, this.state.planet.Codes)
|
||||||
|
|
||||||
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === code.type && this.refs.detail.props.article.localId === code.localId) {
|
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === code.type && this.refs.detail.props.article.localId === code.localId) {
|
||||||
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
||||||
@@ -151,7 +126,7 @@ module.exports = React.createClass({
|
|||||||
case 'noteDestroyed':
|
case 'noteDestroyed':
|
||||||
note = res.data
|
note = res.data
|
||||||
if (note.PlanetId === this.state.planet.id) {
|
if (note.PlanetId === this.state.planet.id) {
|
||||||
this.state.planet.Notes = deleteItemFromTargetArray(note, this.state.planet.Notes)
|
this.state.planet.Notes = this.deleteItemFromTargetArray(note, this.state.planet.Notes)
|
||||||
|
|
||||||
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === note.type && this.refs.detail.props.article.localId === note.localId) {
|
if (this.refs.detail.props.article != null && this.refs.detail.props.article.type === note.type && this.refs.detail.props.article.localId === note.localId) {
|
||||||
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
articleIndex = this.getFilteredIndexOfCurrentArticle()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ var ProfileImage = require('../Components/ProfileImage')
|
|||||||
var EditProfileModal = require('../Components/EditProfileModal')
|
var EditProfileModal = require('../Components/EditProfileModal')
|
||||||
var TeamSettingsModal = require('../Components/TeamSettingsModal')
|
var TeamSettingsModal = require('../Components/TeamSettingsModal')
|
||||||
var PlanetCreateModal = require('../Components/PlanetCreateModal')
|
var PlanetCreateModal = require('../Components/PlanetCreateModal')
|
||||||
|
var AddMemberModal = require('../Components/AddMemberModal')
|
||||||
var TeamCreateModal = require('../Components/TeamCreateModal')
|
var TeamCreateModal = require('../Components/TeamCreateModal')
|
||||||
|
|
||||||
var UserStore = require('../Stores/UserStore')
|
var UserStore = require('../Stores/UserStore')
|
||||||
@@ -56,12 +57,29 @@ module.exports = React.createClass({
|
|||||||
onUserChange: function (res) {
|
onUserChange: function (res) {
|
||||||
if (this.state.user == null) return
|
if (this.state.user == null) return
|
||||||
|
|
||||||
|
var member
|
||||||
switch (res.status) {
|
switch (res.status) {
|
||||||
case 'userUpdated':
|
case 'userUpdated':
|
||||||
if (this.state.user.id === res.data.id) {
|
if (this.state.user.id === res.data.id) {
|
||||||
this.setState({user: res.data})
|
this.setState({user: res.data})
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'memberAdded':
|
||||||
|
member = res.data
|
||||||
|
if (this.state.user.userType === 'team' && member.TeamMember.TeamId === this.state.user.id) {
|
||||||
|
this.state.user.Members = this.updateItemToTargetArray(member, this.state.user.Members)
|
||||||
|
|
||||||
|
this.setState({user: this.state.user})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'memberRemoved':
|
||||||
|
member = res.data
|
||||||
|
if (this.state.user.userType === 'team' && member.TeamMember.TeamId === this.state.user.id) {
|
||||||
|
this.state.user.Members = this.deleteItemFromTargetArray(member, this.state.user.Members)
|
||||||
|
|
||||||
|
this.setState({user: this.state.user})
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPlanetChange: function (res) {
|
onPlanetChange: function (res) {
|
||||||
@@ -123,6 +141,7 @@ module.exports = React.createClass({
|
|||||||
this.setState({user: this.state.user})
|
this.setState({user: this.state.user})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchUser: function (userName) {
|
fetchUser: function (userName) {
|
||||||
@@ -143,7 +162,7 @@ module.exports = React.createClass({
|
|||||||
this.openModal(TeamSettingsModal, {team: this.state.user})
|
this.openModal(TeamSettingsModal, {team: this.state.user})
|
||||||
},
|
},
|
||||||
openAddUserModal: function () {
|
openAddUserModal: function () {
|
||||||
|
this.openModal(AddMemberModal, {team: this.state.user})
|
||||||
},
|
},
|
||||||
openTeamCreateModal: function () {
|
openTeamCreateModal: function () {
|
||||||
this.openModal(TeamCreateModal, {user: this.state.user})
|
this.openModal(TeamCreateModal, {user: this.state.user})
|
||||||
@@ -212,9 +231,10 @@ module.exports = React.createClass({
|
|||||||
<button onClick={this.openTeamSettingsModal} className='editProfileButton'>Team settings</button>
|
<button onClick={this.openTeamSettingsModal} className='editProfileButton'>Team settings</button>
|
||||||
</div>
|
</div>
|
||||||
<div className='memberList'>
|
<div className='memberList'>
|
||||||
<div className='memberLabel'>{members.length} {members.length > 0 ? 'Members' : 'Member'}</div>
|
<div className='memberLabel'>{members.length} {members.length > 1 ? 'Members' : 'Member'}</div>
|
||||||
<ul className='members'>
|
<ul className='members'>
|
||||||
{members}
|
{members}
|
||||||
|
{isOwner ? (<li><button onClick={this.openAddUserModal} className='addMemberButton'><i className='fa fa-plus-square-o'/> add Member</button></li>) : null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='planetList'>
|
<div className='planetList'>
|
||||||
@@ -271,6 +291,10 @@ module.exports = React.createClass({
|
|||||||
)
|
)
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
|
|
||||||
|
var planetCount = userPlanets.length + user.Teams.reduce(function (sum, team) {
|
||||||
|
return sum + (team.Planets != null ? team.Planets.length : 0)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='UserContainer'>
|
<div className='UserContainer'>
|
||||||
<div className='userProfile'>
|
<div className='userProfile'>
|
||||||
@@ -284,16 +308,14 @@ module.exports = React.createClass({
|
|||||||
<button onClick={this.openEditProfileModal} className='editProfileButton'>Edit profile</button>) : null}
|
<button onClick={this.openEditProfileModal} className='editProfileButton'>Edit profile</button>) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='teamList'>
|
<div className='teamList'>
|
||||||
<div className='teamLabel'>{teams.length} {teams.length > 0 ? 'Teams' : 'Team'}</div>
|
<div className='teamLabel'>{teams.length} {teams.length > 1 ? 'Teams' : 'Team'}</div>
|
||||||
<ul className='teams'>
|
<ul className='teams'>
|
||||||
{teams}
|
{teams}
|
||||||
{isOwner ? (<li><button onClick={this.openTeamCreateModal} className='createTeamButton'><i className='fa fa-plus-square-o'/> Create new team</button></li>) : null}
|
{isOwner ? (<li><button onClick={this.openTeamCreateModal} className='createTeamButton'><i className='fa fa-plus-square-o'/> Create new team</button></li>) : null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='planetList'>
|
<div className='planetList'>
|
||||||
<div className='planetLabel'>{userPlanets.length + user.Teams.reduce(function (sum, team) {
|
<div className='planetLabel'>{planetCount} {planetCount > 1 ? 'Planets' : 'Planet'}</div>
|
||||||
return sum + (team.Planets != null ? team.Planets.length : 0)
|
|
||||||
}, 0)} {userPlanets.length > 0 ? 'Planets' : 'Planet'}</div>
|
|
||||||
<div className='planetGroup'>
|
<div className='planetGroup'>
|
||||||
<div className='planetGroupLabel'>{user.profileName}</div>
|
<div className='planetGroupLabel'>{user.profileName}</div>
|
||||||
<ul className='planets'>
|
<ul className='planets'>
|
||||||
|
|||||||
@@ -52,6 +52,22 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
.send(input)
|
.send(input)
|
||||||
},
|
},
|
||||||
|
addMember: function (userName, input) {
|
||||||
|
return request
|
||||||
|
.post(apiUrl + 'resources/' + userName + '/members')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
.send(input)
|
||||||
|
},
|
||||||
|
removeMember: function (userName, input) {
|
||||||
|
return request
|
||||||
|
.del(apiUrl + 'resources/' + userName + '/members')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
.send(input)
|
||||||
|
},
|
||||||
createPlanet: function (userName, input) {
|
createPlanet: function (userName, input) {
|
||||||
return request
|
return request
|
||||||
.post(apiUrl + 'resources/' + userName + '/planets')
|
.post(apiUrl + 'resources/' + userName + '/planets')
|
||||||
@@ -131,5 +147,20 @@ module.exports = {
|
|||||||
return request
|
return request
|
||||||
.get(apiUrl + 'search/tags')
|
.get(apiUrl + 'search/tags')
|
||||||
.query({name: tagName})
|
.query({name: tagName})
|
||||||
|
},
|
||||||
|
searchUser: function (userName) {
|
||||||
|
return request
|
||||||
|
.get(apiUrl + 'search/users')
|
||||||
|
.query({name: userName})
|
||||||
|
},
|
||||||
|
|
||||||
|
// Mail
|
||||||
|
sendEmail: function (input) {
|
||||||
|
return request
|
||||||
|
.post(apiUrl + 'mail')
|
||||||
|
.set({
|
||||||
|
Authorization: 'Bearer ' + localStorage.getItem('token')
|
||||||
|
})
|
||||||
|
.send(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ var Reflux = require('reflux')
|
|||||||
|
|
||||||
var actions = Reflux.createActions([
|
var actions = Reflux.createActions([
|
||||||
'update',
|
'update',
|
||||||
'destroy'
|
'destroy',
|
||||||
|
'addMember',
|
||||||
|
'removeMember'
|
||||||
])
|
])
|
||||||
|
|
||||||
module.exports = Reflux.createStore({
|
module.exports = Reflux.createStore({
|
||||||
@@ -51,5 +53,17 @@ module.exports = Reflux.createStore({
|
|||||||
data: user
|
data: user
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
onAddMember: function (member) {
|
||||||
|
this.trigger({
|
||||||
|
status: 'memberAdded',
|
||||||
|
data: member
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRemoveMember: function (member) {
|
||||||
|
this.trigger({
|
||||||
|
status: 'memberRemoved',
|
||||||
|
data: member
|
||||||
|
})
|
||||||
|
},
|
||||||
Actions: actions
|
Actions: actions
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>CodeXen v0.2.1</title>
|
<script>
|
||||||
|
var version = require('remote').getGlobal('version')
|
||||||
|
document.title = 'Boost ' + ((version == null || version.length === 0) ? 'DEV version' : 'v' + version)
|
||||||
|
</script>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ body
|
|||||||
padding 10px
|
padding 10px
|
||||||
border solid 2px transparent
|
border solid 2px transparent
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
|
cursor pointer
|
||||||
.divider
|
.divider
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
border-bottom solid 1px borderColor
|
border-bottom solid 1px borderColor
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
.DashboardContainer
|
|
||||||
fullsize()
|
|
||||||
box-sizing border-box
|
|
||||||
overflow-y auto
|
|
||||||
padding 10px
|
|
||||||
.jumbotron
|
|
||||||
background-color brandColor
|
|
||||||
color white
|
|
||||||
padding 65px 20px
|
|
||||||
font-size 3.5em
|
|
||||||
margin-bottom 25px
|
|
||||||
h2, h3
|
|
||||||
margin-bottom 15px
|
|
||||||
p
|
|
||||||
margin-bottom 25px
|
|
||||||
@@ -222,6 +222,7 @@
|
|||||||
font-size 1.2em
|
font-size 1.2em
|
||||||
margin-bottom 15px
|
margin-bottom 15px
|
||||||
.teams, .members
|
.teams, .members
|
||||||
|
margin-left 10px
|
||||||
li
|
li
|
||||||
margin-bottom 10px
|
margin-bottom 10px
|
||||||
font-size 1.1em
|
font-size 1.1em
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ body
|
|||||||
font-size fontSize
|
font-size fontSize
|
||||||
font-weight 400
|
font-weight 400
|
||||||
|
|
||||||
div, span, a, button, input
|
div, span, a, button, input, textarea
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
|
|
||||||
h1
|
h1
|
||||||
@@ -98,3 +98,21 @@ textarea.block-input
|
|||||||
|
|
||||||
#content
|
#content
|
||||||
fullsize()
|
fullsize()
|
||||||
|
|
||||||
|
.Main
|
||||||
|
.appUpdateButton
|
||||||
|
position fixed
|
||||||
|
z-index 2000
|
||||||
|
bottom 5px
|
||||||
|
right 53px
|
||||||
|
btnDefault()
|
||||||
|
padding 10px 15px
|
||||||
|
border-radius 5px
|
||||||
|
.contactButton
|
||||||
|
position fixed
|
||||||
|
z-index 2000
|
||||||
|
bottom 5px
|
||||||
|
right 5px
|
||||||
|
btnDefault()
|
||||||
|
padding 10px 15px
|
||||||
|
border-radius 5px
|
||||||
|
|||||||
@@ -56,8 +56,9 @@
|
|||||||
absolute top bottom right
|
absolute top bottom right
|
||||||
left 175px
|
left 175px
|
||||||
padding 15px
|
padding 15px
|
||||||
|
overflow-y auto
|
||||||
|
|
||||||
.EditProfileModal, .PlanetSettingModal
|
.EditProfileModal, .PlanetSettingModal, .TeamSettingsModal
|
||||||
.userInfoTab, .passwordTab, .planetProfileTab, .userInfoTab, .membersTab
|
.userInfoTab, .passwordTab, .planetProfileTab, .userInfoTab, .membersTab
|
||||||
padding-top 45px
|
padding-top 45px
|
||||||
.formField
|
.formField
|
||||||
@@ -75,7 +76,7 @@
|
|||||||
borderInput()
|
borderInput()
|
||||||
height 33px
|
height 33px
|
||||||
font-size 1em
|
font-size 1em
|
||||||
border-radius 10px
|
border-radius 5px
|
||||||
float left
|
float left
|
||||||
.formRadioField
|
.formRadioField
|
||||||
margin-bottom 15px
|
margin-bottom 15px
|
||||||
@@ -152,6 +153,48 @@
|
|||||||
alertSuccess()
|
alertSuccess()
|
||||||
.alertError
|
.alertError
|
||||||
alertError()
|
alertError()
|
||||||
|
.membersTab
|
||||||
|
.memberTable
|
||||||
|
width 100%
|
||||||
|
margin-bottom 25px
|
||||||
|
th
|
||||||
|
border-bottom solid 2px borderColor
|
||||||
|
td
|
||||||
|
border-bottom solid 1px borderColor
|
||||||
|
height 38px
|
||||||
|
button
|
||||||
|
btnDefault()
|
||||||
|
padding 5px
|
||||||
|
border-radius 5px
|
||||||
|
.roleSelect
|
||||||
|
height 33px
|
||||||
|
border solid 1px borderColor
|
||||||
|
background-color backgroundColor
|
||||||
|
th, td
|
||||||
|
padding 5px 0
|
||||||
|
.addMemberForm
|
||||||
|
.formLabel
|
||||||
|
margin-bottom 5px
|
||||||
|
.formGroup
|
||||||
|
clearfix()
|
||||||
|
.userNameSelect
|
||||||
|
display block
|
||||||
|
width 200px
|
||||||
|
margin-right 5px
|
||||||
|
float left
|
||||||
|
.roleSelect
|
||||||
|
display block
|
||||||
|
height 33px
|
||||||
|
border solid 1px borderColor
|
||||||
|
background-color backgroundColor
|
||||||
|
float left
|
||||||
|
margin-right 5px
|
||||||
|
.confirmButton
|
||||||
|
display block
|
||||||
|
height 33px
|
||||||
|
btnDefault()
|
||||||
|
border-radius 5px
|
||||||
|
float left
|
||||||
|
|
||||||
|
|
||||||
.LaunchModal
|
.LaunchModal
|
||||||
@@ -240,8 +283,7 @@
|
|||||||
li
|
li
|
||||||
margin-bottom 15px
|
margin-bottom 15px
|
||||||
|
|
||||||
|
.PlanetCreateModal.modal, .TeamCreateModal.modal, .AddMemberModal.modal
|
||||||
.PlanetCreateModal.modal, .TeamCreateModal.modal
|
|
||||||
padding 60px 0
|
padding 60px 0
|
||||||
.nameInput
|
.nameInput
|
||||||
width 80%
|
width 80%
|
||||||
@@ -264,7 +306,6 @@
|
|||||||
background-color white
|
background-color white
|
||||||
padding 0 10px
|
padding 0 10px
|
||||||
margin 0 15px
|
margin 0 15px
|
||||||
|
|
||||||
.submitButton
|
.submitButton
|
||||||
display block
|
display block
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
@@ -273,3 +314,44 @@
|
|||||||
height 55px
|
height 55px
|
||||||
circle()
|
circle()
|
||||||
btnPrimary()
|
btnPrimary()
|
||||||
|
|
||||||
|
.ContactModal
|
||||||
|
padding 15px
|
||||||
|
.contactForm
|
||||||
|
.formField
|
||||||
|
width 100%
|
||||||
|
margin-bottom 10px
|
||||||
|
input, textarea
|
||||||
|
display block
|
||||||
|
width 100%
|
||||||
|
borderInput()
|
||||||
|
border-radius 5px
|
||||||
|
input
|
||||||
|
height 33px
|
||||||
|
font-size 1em
|
||||||
|
textarea
|
||||||
|
height 175px
|
||||||
|
font-size 1em
|
||||||
|
.formControl
|
||||||
|
clearfix()
|
||||||
|
button
|
||||||
|
float right
|
||||||
|
btnDefault()
|
||||||
|
height 44px
|
||||||
|
padding 0 15px
|
||||||
|
border-radius 5px
|
||||||
|
margin-left 5px
|
||||||
|
button.sendButton
|
||||||
|
btnPrimary()
|
||||||
|
.confirmation
|
||||||
|
.confirmationMessage
|
||||||
|
padding 35px 0
|
||||||
|
text-align center
|
||||||
|
font-size 1.1em
|
||||||
|
.doneButton
|
||||||
|
btnDefault()
|
||||||
|
height 44px
|
||||||
|
padding 0 35px
|
||||||
|
border-radius 5px
|
||||||
|
display block
|
||||||
|
margin 0 auto 25px
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
// apiUrl: 'http://codexen-server-dex2-ezebi636yb.elasticbeanstalk.com/'
|
apiUrl: 'http://codexen-server-dev2.elasticbeanstalk.com/'
|
||||||
apiUrl: 'http://localhost:8000/'
|
// apiUrl: 'http://localhost:8000/'
|
||||||
}
|
}
|
||||||
|
|||||||
35
main.js
35
main.js
@@ -3,6 +3,7 @@ var BrowserWindow = require('browser-window')
|
|||||||
var Menu = require('menu')
|
var Menu = require('menu')
|
||||||
var MenuItem = require('menu-item')
|
var MenuItem = require('menu-item')
|
||||||
var Tray = require('tray')
|
var Tray = require('tray')
|
||||||
|
var ipc = require('ipc')
|
||||||
|
|
||||||
require('crash-reporter').start()
|
require('crash-reporter').start()
|
||||||
|
|
||||||
@@ -19,49 +20,66 @@ var update = null
|
|||||||
|
|
||||||
var version = app.getVersion()
|
var version = app.getVersion()
|
||||||
global.version = version
|
global.version = version
|
||||||
|
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
||||||
var nn = require('node-notifier')
|
var nn = require('node-notifier')
|
||||||
var autoUpdater = require('auto-updater')
|
var autoUpdater = require('auto-updater')
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
autoUpdater
|
autoUpdater
|
||||||
.on('error', function (err, message) {
|
.on('error', function (err, message) {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Error! Ver.' + version,
|
title: 'Error! ' + versionText,
|
||||||
|
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
||||||
message: message
|
message: message
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('checking-for-update', function () {
|
.on('checking-for-update', function () {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Boost launched!! Ver. ' + version,
|
title: 'Boost launched!! ' + versionText,
|
||||||
|
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
||||||
message: 'Checking update is available....'
|
message: 'Checking update is available....'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('update-available', function () {
|
.on('update-available', function () {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Update is available!! Ver. ' + version,
|
title: 'Update is available!! ' + versionText,
|
||||||
|
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
||||||
message: 'Download started.. wait for the update ready.'
|
message: 'Download started.. wait for the update ready.'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('update-not-available', function () {
|
.on('update-not-available', function () {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Latest Build!! Ver. ' + version,
|
title: 'Latest Build!! ' + versionText,
|
||||||
|
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
||||||
message: 'Hope you to enjoy our app :D'
|
message: 'Hope you to enjoy our app :D'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Ready to Update!! v' + version,
|
title: 'Ready to Update!! ' + versionText,
|
||||||
|
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
||||||
message: 'Click tray icon to update app: ' + releaseName
|
message: 'Click tray icon to update app: ' + releaseName
|
||||||
})
|
})
|
||||||
update = quitAndUpdate
|
update = quitAndUpdate
|
||||||
|
|
||||||
|
if (mainWindow != null && !mainWindow.webContents.isLoading()) {
|
||||||
|
mainWindow.webContents.send('update-available', 'Update available!')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('ready', function () {
|
app.on('ready', function () {
|
||||||
console.log('Version ' + version)
|
console.log('Version ' + version)
|
||||||
autoUpdater.setFeedUrl('http://localhost:8000/testcat/test/latest?version=' + version)
|
autoUpdater.setFeedUrl('http://orbital.b00st.io/rokt33r/boost/latest?version=' + version)
|
||||||
autoUpdater.checkForUpdates()
|
autoUpdater.checkForUpdates()
|
||||||
// menu start
|
// menu start
|
||||||
var template = require('./modules/menu-template')
|
var template = require('./modules/menu-template')
|
||||||
|
|
||||||
|
ipc.on('update-app', function (event, msg) {
|
||||||
|
if (update != null) {
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
menu = Menu.buildFromTemplate(template)
|
menu = Menu.buildFromTemplate(template)
|
||||||
|
|
||||||
Menu.setApplicationMenu(menu)
|
Menu.setApplicationMenu(menu)
|
||||||
@@ -152,6 +170,11 @@ function makeNewMainWindow () {
|
|||||||
'overlay-scrollbars': true
|
'overlay-scrollbars': true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (update != null) {
|
||||||
|
mainWindow.webContents.on('did-finish-load', function () {
|
||||||
|
mainWindow.webContents.send('update-available', 'whoooooooh!')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
mainWindow.loadUrl('file://' + __dirname + '/browser/main/index.electron.html')
|
mainWindow.loadUrl('file://' + __dirname + '/browser/main/index.electron.html')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user