diff --git a/browser/main/Components/EditProfileModal.jsx b/browser/main/Components/EditProfileModal.jsx index 15cf04cb..dcf9df6d 100644 --- a/browser/main/Components/EditProfileModal.jsx +++ b/browser/main/Components/EditProfileModal.jsx @@ -11,20 +11,20 @@ var UserStore = require('../Stores/UserStore') module.exports = React.createClass({ mixins: [LinkedState], propTypes: { - targetUser: React.PropTypes.shape({ + user: React.PropTypes.shape({ name: React.PropTypes.string, profileName: React.PropTypes.string, email: React.PropTypes.string }) }, getInitialState: function () { - var targetUser = this.props.targetUser + var user = this.props.user return { currentTab: 'userInfo', user: { - name: targetUser.name, - profileName: targetUser.profileName, - email: targetUser.email + name: user.name, + profileName: user.profileName, + email: user.email }, userSubmitStatus: null, password: { @@ -44,7 +44,7 @@ module.exports = React.createClass({ this.setState({ userSubmitStatus: 'sending' }, function () { - Hq.updateUser(this.props.targetUser.name, this.state.user) + Hq.updateUser(this.props.user.name, this.state.user) .then(function (res) { this.setState({userSubmitStatus: 'done'}, function () { localStorage.setItem('currentUser', JSON.stringify(res.body)) @@ -138,7 +138,7 @@ module.exports = React.createClass({ }, renderPasswordTab: function () { return ( -
+
diff --git a/browser/main/Components/HomeNavigator.jsx b/browser/main/Components/HomeNavigator.jsx index 718c79a8..f312c380 100644 --- a/browser/main/Components/HomeNavigator.jsx +++ b/browser/main/Components/HomeNavigator.jsx @@ -27,8 +27,36 @@ module.exports = React.createClass({ onUserChange: function (res) { switch (res.status) { case 'userUpdated': - if (this.state.currentUser.id === res.data.id) { - this.setState({currentUser: res.data}) + var user = res.data + var currentUser = this.state.currentUser + if (currentUser.id === user.id) { + this.setState({currentUser: user}) + return + } + + if (user.userType === 'team') { + var isMyTeam = user.Members.some(function (member) { + if (currentUser.id === member.id) { + return true + } + return false + }) + + if (isMyTeam) { + var isNew = !currentUser.Teams.some(function (team, index) { + if (user.id === team.id) { + currentUser.Teams.splice(index, 1, user) + return true + } + return false + }) + + if (isNew) { + currentUser.Teams.push(user) + } + + this.setState({currentUser: currentUser}) + } } break } @@ -104,7 +132,10 @@ module.exports = React.createClass({
    {planets}
- +
) }, diff --git a/browser/main/Components/PlanetCreateModal.jsx b/browser/main/Components/PlanetCreateModal.jsx index 8e7336b4..974a06a7 100644 --- a/browser/main/Components/PlanetCreateModal.jsx +++ b/browser/main/Components/PlanetCreateModal.jsx @@ -1,30 +1,30 @@ /* global localStorage */ var React = require('react/addons') -var Select = require('react-select') var Hq = require('../Services/Hq') var LinkedState = require('../Mixins/LinkedState') -var UserStore = require('../Stores/UserStore') var PlanetStore = require('../Stores/PlanetStore') module.exports = React.createClass({ mixins: [LinkedState], propTypes: { + ownerName: React.PropTypes.string, transitionTo: React.PropTypes.func, close: React.PropTypes.func }, getInitialState: function () { var currentUser = JSON.parse(localStorage.getItem('currentUser')) + var ownerName = this.props.ownerName != null ? this.props.ownerName : currentUser.name return { user: currentUser, planet: { name: '', public: true }, - ownerName: currentUser.name + ownerName: ownerName } }, componentDidMount: function () { @@ -42,7 +42,10 @@ module.exports = React.createClass({ PlanetStore.Actions.update(planet) - this.props.transitionTo('planetHome', {userName: planet.userName, planetName: planet.name}) + if (this.props.transitionTo != null) { + this.props.transitionTo('planetHome', {userName: planet.userName, planetName: planet.name}) + } + this.props.close() }.bind(this)) .catch(function (err) { @@ -52,7 +55,7 @@ module.exports = React.createClass({ render: function () { var teamOptions = this.state.user.Teams.map(function (team) { return ( - + ) }) return ( diff --git a/browser/main/Components/TeamCreateModal.jsx b/browser/main/Components/TeamCreateModal.jsx index f20b6810..d258cf2c 100644 --- a/browser/main/Components/TeamCreateModal.jsx +++ b/browser/main/Components/TeamCreateModal.jsx @@ -33,7 +33,10 @@ module.exports = React.createClass({ currentUser.Teams.push(team) localStorage.setItem('currentUser', JSON.stringify(currentUser)) UserStore.Actions.update(currentUser) - this.props.transitionTo('userHome', {userName: team.name}) + + if (this.props.transitionTo != null) { + this.props.transitionTo('userHome', {userName: team.name}) + } this.props.close() }.bind(this)) .catch(function (err) { diff --git a/browser/main/Components/TeamSettingsModal.jsx b/browser/main/Components/TeamSettingsModal.jsx new file mode 100644 index 00000000..8853cc5d --- /dev/null +++ b/browser/main/Components/TeamSettingsModal.jsx @@ -0,0 +1,108 @@ +/* global localStorage */ + +var React = require('react/addons') + +var Hq = require('../Services/Hq') + +var LinkedState = require('../Mixins/LinkedState') + +var UserStore = require('../Stores/UserStore') + +module.exports = React.createClass({ + mixins: [LinkedState], + propTypes: { + team: React.PropTypes.shape({ + name: React.PropTypes.string, + profileName: React.PropTypes.string, + email: React.PropTypes.string + }) + }, + getInitialState: function () { + var team = this.props.team + return { + currentTab: 'teamInfo', + team: { + name: team.name, + profileName: team.profileName + }, + userSubmitStatus: null + } + }, + selectTab: function (tabName) { + return function () { + this.setState({currentTab: tabName}) + }.bind(this) + }, + saveUserInfo: function () { + this.setState({ + userSubmitStatus: 'sending' + }, function () { + Hq.updateUser(this.props.team.name, this.state.team) + .then(function (res) { + this.setState({userSubmitStatus: 'done'}, function () { + UserStore.Actions.update(res.body) + }) + }.bind(this)) + .catch(function (err) { + console.error(err) + this.setState({userSubmitStatus: 'error'}) + }.bind(this)) + }) + }, + render: function () { + var content + + switch (this.state.currentTab) { + case 'teamInfo': + content = this.renderTeamInfoTab() + break + case 'members': + content = this.renderMembersTab() + break + } + + return ( +
+
+
Team settings
+
+ + +
+
+
+ {content} +
+
+ ) + }, + renderTeamInfoTab: function () { + return ( +
+
+ + +
+
+ + +
+
+ + +
on Sending...
+ +
Connection failed.. Try again.
+ +
Successfully done!!
+
+
+ ) + }, + renderMembersTab: function () { + return ( +
+
+ ) + } +}) diff --git a/browser/main/Containers/LoginContainer.jsx b/browser/main/Containers/LoginContainer.jsx index 5771ad12..b2cde41f 100644 --- a/browser/main/Containers/LoginContainer.jsx +++ b/browser/main/Containers/LoginContainer.jsx @@ -76,17 +76,6 @@ module.exports = React.createClass({ -
-

Connect with

- - -
- -
-
-
or
-
-
diff --git a/browser/main/Containers/MainContainer.jsx b/browser/main/Containers/MainContainer.jsx index 659f1166..41b8fd1f 100644 --- a/browser/main/Containers/MainContainer.jsx +++ b/browser/main/Containers/MainContainer.jsx @@ -49,13 +49,16 @@ module.exports = React.createClass({ Hq.getUser() .then(function (res) { + console.log(res.body) localStorage.setItem('currentUser', JSON.stringify(res.body)) UserStore.Actions.update(res.body) }) .catch(function (err) { if (err.status === 401) { + console.log('Not logged in yet') localStorage.removeItem('currentUser') this.transitionTo('login') + return } console.error(err) }.bind(this)) diff --git a/browser/main/Containers/SignupContainer.jsx b/browser/main/Containers/SignupContainer.jsx index dd0c1d29..e1ea48b9 100644 --- a/browser/main/Containers/SignupContainer.jsx +++ b/browser/main/Containers/SignupContainer.jsx @@ -30,7 +30,6 @@ module.exports = React.createClass({ }, function () { Hq.signup(this.state.user) .then(function (res) { - console.log(res.body) localStorage.setItem('token', res.body.token) localStorage.setItem('currentUser', JSON.stringify(res.body.user)) @@ -91,11 +90,6 @@ module.exports = React.createClass({ -
-
-
or
-
-
diff --git a/browser/main/Containers/UserContainer.jsx b/browser/main/Containers/UserContainer.jsx index e4f5c82f..74f321d6 100644 --- a/browser/main/Containers/UserContainer.jsx +++ b/browser/main/Containers/UserContainer.jsx @@ -1,21 +1,30 @@ +/* global localStorage */ + var React = require('react/addons') var ReactRouter = require('react-router') +var Navigation = ReactRouter.Navigation +var State = ReactRouter.State var RouteHandler = ReactRouter.RouteHandler var Link = ReactRouter.Link var Reflux = require('reflux') var LinkedState = require('../Mixins/LinkedState') var Modal = require('../Mixins/Modal') +var Helper = require('../Mixins/Helper') var Hq = require('../Services/Hq') var ProfileImage = require('../Components/ProfileImage') var EditProfileModal = require('../Components/EditProfileModal') +var TeamSettingsModal = require('../Components/TeamSettingsModal') +var PlanetCreateModal = require('../Components/PlanetCreateModal') +var TeamCreateModal = require('../Components/TeamCreateModal') var UserStore = require('../Stores/UserStore') +var PlanetStore = require('../Stores/PlanetStore') module.exports = React.createClass({ - mixins: [LinkedState, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange')], + mixins: [LinkedState, State, Navigation, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), Helper], propTypes: { params: React.PropTypes.shape({ userName: React.PropTypes.string, @@ -55,6 +64,67 @@ module.exports = React.createClass({ break } }, + onPlanetChange: function (res) { + if (this.state.user == null) return + + var currentUser, planet, isOwner, team + switch (res.status) { + case 'updated': + // if state.user is currentUser, planet will be fetched by UserStore + currentUser = JSON.parse(localStorage.getItem('currentUser')) + if (currentUser.id === this.state.user.id) return + + planet = res.data + isOwner = planet.Owner.id === this.state.user.id + if (isOwner) { + this.state.user.Planets = this.updateItemToTargetArray(planet, this.state.user.Planets) + this.setState({user: this.state.user}) + return + } + // check if team of user has this planet + team = null + this.state.user.userType !== 'team' && this.state.user.Teams.some(function (_team) { + if (planet.Owner.id === _team.id) { + team = _team + return true + } + return false + }) + if (team != null) { + team.Planets = this.updateItemToTargetArray(planet, team.Planets) + this.setState({user: this.state.user}) + return + } + + break + case 'destroyed': + // if state.user is currentUser, planet will be fetched by UserStore + currentUser = JSON.parse(localStorage.getItem('currentUser')) + if (currentUser.id === this.state.user.id) return + + planet = res.data + isOwner = planet.Owner.id === this.state.user.id + if (isOwner) { + this.state.user.Planets = this.deleteItemFromTargetArray(planet, this.state.user.Planets) + this.setState({user: this.state.user}) + return + } + // check if team of user has this planet + team = null + this.state.user.userType !== 'team' && this.state.user.Teams.some(function (_team) { + if (planet.Owner.id === _team.id) { + team = _team + return true + } + return false + }) + if (team != null) { + team.Planets = this.deleteItemFromTargetArray(planet, team.Planets) + this.setState({user: this.state.user}) + return + } + } + }, fetchUser: function (userName) { if (userName == null) userName = this.props.params.userName @@ -67,11 +137,27 @@ module.exports = React.createClass({ }) }, openEditProfileModal: function () { - this.openModal(EditProfileModal, {targetUser: this.state.user}) + this.openModal(EditProfileModal, {user: this.state.user}) + }, + openTeamSettingsModal: function () { + this.openModal(TeamSettingsModal, {team: this.state.user}) + }, + openAddUserModal: function () { + + }, + openTeamCreateModal: function () { + this.openModal(TeamCreateModal, {user: this.state.user}) + }, + openPlanetCreateModalWithOwnerName: function (name) { + return function () { + this.openModal(PlanetCreateModal, {ownerName: name}) + }.bind(this) }, render: function () { var user = this.state.user + var currentUser = JSON.parse(localStorage.getItem('currentUser')) + if (this.isActive('userHome')) { if (user == null) { return ( @@ -80,9 +166,9 @@ module.exports = React.createClass({
) } else if (user.userType === 'team') { - return this.renderTeamHome() + return this.renderTeamHome(currentUser) } else { - return this.renderUserHome() + return this.renderUserHome(currentUser) } } else { return ( @@ -92,13 +178,16 @@ module.exports = React.createClass({ ) } }, - renderTeamHome: function () { + renderTeamHome: function (currentUser) { var user = this.state.user + var isOwner = true + var userPlanets = user.Planets.map(function (planet) { return (
  • {planet.userName}/{planet.name} +  {!planet.public ? () : null}
  • ) }) @@ -107,6 +196,7 @@ module.exports = React.createClass({ return (
  • {member.profileName} ({member.name}) +
    {member.TeamMember.role}
  • ) }) @@ -119,7 +209,7 @@ module.exports = React.createClass({
    {user.name}
    - +
    {members.length} {members.length > 0 ? 'Members' : 'Member'}
    @@ -132,15 +222,18 @@ module.exports = React.createClass({
      {userPlanets} + {isOwner ? (
    • ) : null}
    ) }, - renderUserHome: function () { + renderUserHome: function (currentUser) { var user = this.state.user + var isOwner = currentUser.id === user.id + var userPlanets = user.Planets.map(function (planet) { return (
  • @@ -159,7 +252,7 @@ module.exports = React.createClass({ }) var teamPlanets = user.Teams == null ? [] : user.Teams.map(function (team) { - var planets = team.Planets.map(function (planet) { + var planets = (team.Planets == null ? [] : team.Planets).map(function (planet) { return (
  • {planet.userName}/{planet.name} @@ -172,10 +265,11 @@ module.exports = React.createClass({
    {team.name}
      {planets} + {isOwner ? (
    • ) : null}
    ) - }) + }.bind(this)) return (
    @@ -186,20 +280,25 @@ module.exports = React.createClass({
    {user.name}
    - + {isOwner ? ( + ) : null}
    {teams.length} {teams.length > 0 ? 'Teams' : 'Team'}
      {teams} + {isOwner ? (
    • ) : null}
    -
    {userPlanets.length} {userPlanets.length > 0 ? 'Planets' : 'Planet'}
    +
    {userPlanets.length + user.Teams.reduce(function (sum, team) { + return sum + (team.Planets != null ? team.Planets.length : 0) + }, 0)} {userPlanets.length > 0 ? 'Planets' : 'Planet'}
    {user.profileName}
      {userPlanets} + {isOwner ? (
    • ) : null}
    {teamPlanets} diff --git a/browser/main/Mixins/Helper.js b/browser/main/Mixins/Helper.js new file mode 100644 index 00000000..fa8ec774 --- /dev/null +++ b/browser/main/Mixins/Helper.js @@ -0,0 +1,30 @@ +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 = { + deleteItemFromTargetArray: deleteItemFromTargetArray, + updateItemToTargetArray: updateItemToTargetArray +} diff --git a/browser/main/Stores/PlanetStore.js b/browser/main/Stores/PlanetStore.js index 7cadc956..f7559876 100644 --- a/browser/main/Stores/PlanetStore.js +++ b/browser/main/Stores/PlanetStore.js @@ -4,6 +4,8 @@ var Reflux = require('reflux') var UserStore = require('./UserStore') +var Helper = require('../Mixins/Helper') + var actions = Reflux.createActions([ 'update', 'destroy', @@ -13,33 +15,8 @@ var actions = Reflux.createActions([ 'destroyNote' ]) -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 = Reflux.createStore({ + mixins: [Helper], listenables: [actions], Actions: actions, onUpdate: function (planet) { @@ -54,7 +31,7 @@ module.exports = Reflux.createStore({ var ownedByCurrentUser = currentUser.id === aPlanet.OwnerId if (ownedByCurrentUser) { - currentUser.Planets = updateItemToTargetArray(aPlanet, currentUser.Planets) + currentUser.Planets = this.updateItemToTargetArray(aPlanet, currentUser.Planets) } if (!ownedByCurrentUser) { @@ -68,7 +45,7 @@ module.exports = Reflux.createStore({ }) if (team) { - team.Planets = updateItemToTargetArray(aPlanet, team.Planets) + team.Planets = this.updateItemToTargetArray(aPlanet, team.Planets) } } @@ -91,7 +68,7 @@ module.exports = Reflux.createStore({ var ownedByCurrentUser = currentUser.id === planet.OwnerId if (ownedByCurrentUser) { - currentUser.Planets = deleteItemFromTargetArray(planet, currentUser.Planets) + currentUser.Planets = this.deleteItemFromTargetArray(planet, currentUser.Planets) } if (!ownedByCurrentUser) { @@ -105,7 +82,7 @@ module.exports = Reflux.createStore({ }) if (team) { - team.Planets = deleteItemFromTargetArray(planet, team.Planets) + team.Planets = this.deleteItemFromTargetArray(planet, team.Planets) } } @@ -126,7 +103,7 @@ module.exports = Reflux.createStore({ var planet = JSON.parse(localStorage.getItem('planet-' + code.PlanetId)) if (planet != null) { - planet.Codes = updateItemToTargetArray(code, planet.Codes) + planet.Codes = this.updateItemToTargetArray(code, planet.Codes) localStorage.setItem('planet-' + code.PlanetId, JSON.stringify(planet)) } @@ -139,7 +116,7 @@ module.exports = Reflux.createStore({ onDestroyCode: function (code) { var planet = JSON.parse(localStorage.getItem('planet-' + code.PlanetId)) if (planet != null) { - planet.Codes = deleteItemFromTargetArray(code, planet.Codes) + planet.Codes = this.deleteItemFromTargetArray(code, planet.Codes) localStorage.setItem('planet-' + code.PlanetId, JSON.stringify(planet)) } @@ -155,7 +132,7 @@ module.exports = Reflux.createStore({ var planet = JSON.parse(localStorage.getItem('planet-' + note.PlanetId)) if (planet != null) { - planet.Notes = updateItemToTargetArray(note, planet.Notes) + planet.Notes = this.updateItemToTargetArray(note, planet.Notes) localStorage.setItem('planet-' + note.PlanetId, JSON.stringify(planet)) } @@ -168,7 +145,7 @@ module.exports = Reflux.createStore({ onDestroyNote: function (note) { var planet = JSON.parse(localStorage.getItem('planet-' + note.PlanetId)) if (planet != null) { - planet.Notes = deleteItemFromTargetArray(note, planet.Notes) + planet.Notes = this.deleteItemFromTargetArray(note, planet.Notes) localStorage.setItem('planet-' + note.PlanetId, JSON.stringify(planet)) } diff --git a/browser/main/Stores/UserStore.js b/browser/main/Stores/UserStore.js index b565716b..1a85440a 100644 --- a/browser/main/Stores/UserStore.js +++ b/browser/main/Stores/UserStore.js @@ -1,3 +1,5 @@ +/* global localStorage */ + var Reflux = require('reflux') var actions = Reflux.createActions([ @@ -8,6 +10,36 @@ var actions = Reflux.createActions([ module.exports = Reflux.createStore({ listenables: [actions], onUpdate: function (user) { + var currentUser = JSON.parse(localStorage.getItem('currentUser')) + + if (currentUser.id === user.id) { + localStorage.setItem('currentUser', JSON.stringify(user)) + } + + if (user.userType === 'team') { + var isMyTeam = user.Members.some(function (member) { + if (currentUser.id === member.id) { + return true + } + return false + }) + + if (isMyTeam) { + var isNew = !currentUser.Teams.some(function (team, index) { + if (user.id === team.id) { + currentUser.Teams.splice(index, 1, user) + return true + } + return false + }) + + if (isNew) { + currentUser.Teams.push(user) + } + localStorage.setItem('currentUser', JSON.stringify(currentUser)) + } + } + this.trigger({ status: 'userUpdated', data: user diff --git a/browser/styles/main/containers/LoginContainer.styl b/browser/styles/main/containers/LoginContainer.styl index 5af8e1f0..c190cf44 100644 --- a/browser/styles/main/containers/LoginContainer.styl +++ b/browser/styles/main/containers/LoginContainer.styl @@ -9,7 +9,7 @@ display block margin 0 auto .authNavigator - margin 15px 0 + margin 15px 0 25px a font-size 1.5em text-decoration none @@ -47,7 +47,8 @@ .dividerLabel text-align center position relative - top -35px + top -27px + font-size 1.3em background-color backgroundColor margin 0 auto width 50px diff --git a/browser/styles/main/containers/UserContainer.styl b/browser/styles/main/containers/UserContainer.styl index 733b8e25..1e5a8e8a 100644 --- a/browser/styles/main/containers/UserContainer.styl +++ b/browser/styles/main/containers/UserContainer.styl @@ -166,6 +166,23 @@ border-color darken(brandBorderColor, 10%) background-color brandColor color white + .newPlanetTooltip + position fixed + z-index 500 + background-color transparentify(invBackgroundColor, 80%) + color invTextColor + padding 10px + line-height 1em + border-radius 5px + margin-top -23px + margin-left 33px + white-space nowrap + font-size 1.1em + opacity 0 + transition 0.1s + pointer-events none + &:hover .newPlanetTooltip + opacity 1 .UserContainer absolute top bottom right left 55px @@ -208,6 +225,13 @@ li margin-bottom 10px font-size 1.1em + .createTeamButton, .addMemberButton + btnStripDefault() + .members .role + margin-left 7px + margin-top 2px + color inactiveTextColor + font-size 0.85em .planetList absolute right bottom top 125px @@ -226,3 +250,5 @@ margin-left 15px li margin-bottom 10px + .createPlanetButton + btnStripDefault() diff --git a/browser/styles/main/containers/UserSettingContainer.styl b/browser/styles/main/containers/UserSettingContainer.styl deleted file mode 100644 index 31014ed9..00000000 --- a/browser/styles/main/containers/UserSettingContainer.styl +++ /dev/null @@ -1,33 +0,0 @@ -.UserSettingContainer - absolute top bottom right - left 50px - .UserSettingNavigation - absolute top bottom left - width 200px - padding 15px - box-sizing border-box - border-right solid 1px borderColor - .userName - font-size 2.0em - margin 10px 0 - color brandColor - a - display block - color textColor - width 100% - padding 15px - margin-bottom 5px - border-radius 10px - box-sizing border-box - cursor pointer - &:hover, &.hover - color brandColor - background-color hoverBackgroundColor - &:active, &.active - color brandColor - - .UserSettingMain - absolute top bottom right - left 200px - padding 10px - box-sizing border-box diff --git a/browser/styles/shared/modal.styl b/browser/styles/shared/modal.styl index 92e601a3..c9bc6325 100644 --- a/browser/styles/shared/modal.styl +++ b/browser/styles/shared/modal.styl @@ -58,7 +58,7 @@ padding 15px .EditProfileModal, .PlanetSettingModal - .userInfoTab, .paswordTab, .planetProfileTab + .userInfoTab, .passwordTab, .planetProfileTab, .userInfoTab, .membersTab padding-top 45px .formField position relative