diff --git a/web/react/components/member_list_team.jsx b/web/react/components/member_list_team.jsx
index cb48e5cc59..064330c8de 100644
--- a/web/react/components/member_list_team.jsx
+++ b/web/react/components/member_list_team.jsx
@@ -1,122 +1,27 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-var ChannelStore = require('../stores/channel_store.jsx');
-var UserStore = require('../stores/user_store.jsx');
-var Client = require('../utils/client.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-var utils = require('../utils/utils.jsx');
+const MemberListTeamItem = require('./member_list_team_item.jsx');
-var MemberListTeamItem = React.createClass({
- handleMakeMember: function() {
- var data = {};
- data["user_id"] = this.props.user.id;
- data["new_roles"] = "";
-
- Client.updateRoles(data,
- function(data) {
- AsyncClient.getProfiles();
- }.bind(this),
- function(err) {
- this.setState({ server_error: err.message });
- }.bind(this)
- );
- },
- handleMakeActive: function() {
- Client.updateActive(this.props.user.id, true,
- function(data) {
- AsyncClient.getProfiles();
- }.bind(this),
- function(err) {
- this.setState({ server_error: err.message });
- }.bind(this)
- );
- },
- handleMakeNotActive: function() {
- Client.updateActive(this.props.user.id, false,
- function(data) {
- AsyncClient.getProfiles();
- }.bind(this),
- function(err) {
- this.setState({ server_error: err.message });
- }.bind(this)
- );
- },
- handleMakeAdmin: function() {
- var data = {};
- data["user_id"] = this.props.user.id;
- data["new_roles"] = "admin";
-
- Client.updateRoles(data,
- function(data) {
- AsyncClient.getProfiles();
- }.bind(this),
- function(err) {
- this.setState({ server_error: err.message });
- }.bind(this)
- );
- },
- getInitialState: function() {
- return {};
- },
- render: function() {
- var server_error = this.state.server_error ?
: null;
- var user = this.props.user;
- var currentRoles = "Member";
- var timestamp = UserStore.getCurrentUser().update_at;
-
- if (user.roles.length > 0) {
- currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1);
- }
-
- var email = user.email.length > 0 ? user.email : "";
- var showMakeMember = user.roles == "admin";
- var showMakeAdmin = user.roles == "";
- var showMakeActive = false;
- var showMakeNotActive = true;
-
- if (user.delete_at > 0) {
- currentRoles = "Inactive";
- showMakeMember = false;
- showMakeAdmin = false;
- showMakeActive = true;
- showMakeNotActive = false;
- }
+export default class MemberListTeam extends React.Component {
+ render() {
+ const memberList = this.props.users.map(function makeListItem(user) {
+ return (
+
-
-
{utils.getDisplayName(user)}
-
{email}
-
- { server_error }
+
+ {memberList}
);
}
-});
+}
-
-module.exports = React.createClass({
- render: function() {
- return (
-
- {
- this.props.users.map(function(user) {
- return ;
- }, this)
- }
-
- );
- }
-});
+MemberListTeam.propTypes = {
+ users: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
+};
diff --git a/web/react/components/member_list_team_item.jsx b/web/react/components/member_list_team_item.jsx
new file mode 100644
index 0000000000..b7e81f8431
--- /dev/null
+++ b/web/react/components/member_list_team_item.jsx
@@ -0,0 +1,203 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+const UserStore = require('../stores/user_store.jsx');
+const Client = require('../utils/client.jsx');
+const AsyncClient = require('../utils/async_client.jsx');
+const Utils = require('../utils/utils.jsx');
+
+export default class MemberListTeamItem extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleMakeMember = this.handleMakeMember.bind(this);
+ this.handleMakeActive = this.handleMakeActive.bind(this);
+ this.handleMakeNotActive = this.handleMakeNotActive.bind(this);
+ this.handleMakeAdmin = this.handleMakeAdmin.bind(this);
+
+ this.state = {};
+ }
+ handleMakeMember() {
+ const data = {
+ user_id: this.props.user.id,
+ new_roles: ''
+ };
+
+ Client.updateRoles(data,
+ function handleMakeMemberSuccess() {
+ AsyncClient.getProfiles();
+ },
+ function handleMakeMemberError(err) {
+ this.setState({serverError: err.message});
+ }.bind(this)
+ );
+ }
+ handleMakeActive() {
+ Client.updateActive(this.props.user.id, true,
+ function handleMakeActiveSuccess() {
+ AsyncClient.getProfiles();
+ },
+ function handleMakeActiveError(err) {
+ this.setState({serverError: err.message});
+ }.bind(this)
+ );
+ }
+ handleMakeNotActive() {
+ Client.updateActive(this.props.user.id, false,
+ function handleMakeNotActiveSuccess() {
+ AsyncClient.getProfiles();
+ },
+ function handleMakeNotActiveError(err) {
+ this.setState({serverError: err.message});
+ }.bind(this)
+ );
+ }
+ handleMakeAdmin() {
+ const data = {
+ user_id: this.props.user.id,
+ new_roles: 'admin'
+ };
+
+ Client.updateRoles(data,
+ function handleMakeAdminSuccess() {
+ AsyncClient.getProfiles();
+ },
+ function handleMakeAdmitError(err) {
+ this.setState({serverError: err.message});
+ }.bind(this)
+ );
+ }
+ render() {
+ let serverError = null;
+ if (this.state.serverError) {
+ serverError = (
+
+ {this.state.serverError}
+
+ );
+ }
+
+ const user = this.props.user;
+ let currentRoles = 'Member';
+ const timestamp = UserStore.getCurrentUser().update_at;
+
+ if (user.roles.length > 0) {
+ currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1);
+ }
+
+ const email = user.email;
+ let showMakeMember = user.roles === 'admin';
+ let showMakeAdmin = user.roles === '';
+ let showMakeActive = false;
+ let showMakeNotActive = true;
+
+ if (user.delete_at > 0) {
+ currentRoles = 'Inactive';
+ showMakeMember = false;
+ showMakeAdmin = false;
+ showMakeActive = true;
+ showMakeNotActive = false;
+ }
+
+ let makeAdmin = null;
+ if (showMakeAdmin) {
+ makeAdmin = (
+
+
+ Make Admin
+
+
+ );
+ }
+
+ let makeMember = null;
+ if (showMakeMember) {
+ makeMember = (
+
+
+ Make Member
+
+
+ );
+ }
+
+ let makeActive = null;
+ if (showMakeActive) {
+ makeActive = (
+
+
+ Make Active
+
+
+ );
+ }
+
+ let makeNotActive = null;
+ if (showMakeNotActive) {
+ makeNotActive = (
+
+
+ Make Inactive
+
+
+ );
+ }
+
+ return (
+
+
+
{Utils.getDisplayName(user)}
+
{email}
+
+
+
+ {makeAdmin}
+ {makeMember}
+ {makeActive}
+ {makeNotActive}
+
+
+ {serverError}
+
+ );
+ }
+}
+
+MemberListTeamItem.propTypes = {
+ user: React.PropTypes.object.isRequired
+};
diff --git a/web/react/components/popover_list_members.jsx b/web/react/components/popover_list_members.jsx
new file mode 100644
index 0000000000..fb9522afb7
--- /dev/null
+++ b/web/react/components/popover_list_members.jsx
@@ -0,0 +1,80 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+export default class PopoverListMembers extends React.Component {
+ componentDidMount() {
+ const originalLeave = $.fn.popover.Constructor.prototype.leave;
+ $.fn.popover.Constructor.prototype.leave = function onLeave(obj) {
+ let selfObj;
+ if (obj instanceof this.constructor) {
+ selfObj = obj;
+ } else {
+ selfObj = $(obj.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`);
+ }
+ originalLeave.call(this, obj);
+
+ if (obj.currentTarget && selfObj.$tip) {
+ selfObj.$tip.one('mouseenter', function onMouseEnter() {
+ clearTimeout(selfObj.timeout);
+ selfObj.$tip.one('mouseleave', function onMouseLeave() {
+ $.fn.popover.Constructor.prototype.leave.call(selfObj, selfObj);
+ });
+ });
+ }
+ };
+
+ $('#member_popover').popover({placement: 'bottom', trigger: 'click', html: true});
+ $('body').on('click', function onClick(e) {
+ if ($(e.target.parentNode.parentNode)[0] !== $('#member_popover')[0] && $(e.target).parents('.popover.in').length === 0) {
+ $('#member_popover').popover('hide');
+ }
+ });
+ }
+ render() {
+ let popoverHtml = '';
+ const members = this.props.members;
+ let count;
+ if (members.length > 20) {
+ count = '20+';
+ } else {
+ count = members.length || '-';
+ }
+
+ if (members) {
+ members.sort(function compareByLocal(a, b) {
+ return a.username.localeCompare(b.username);
+ });
+
+ members.forEach(function addMemberElement(m) {
+ popoverHtml += `
${m.username}
`;
+ });
+ }
+
+ return (
+
+ );
+ }
+}
+
+PopoverListMembers.propTypes = {
+ members: React.PropTypes.array.isRequired,
+ channelId: React.PropTypes.string.isRequired
+};
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index e5ab5b624a..88fb9aec82 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -1,95 +1,140 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-var FileAttachmentList = require('./file_attachment_list.jsx');
-var UserStore = require('../stores/user_store.jsx');
-var utils = require('../utils/utils.jsx');
-var Constants = require('../utils/constants.jsx');
+const FileAttachmentList = require('./file_attachment_list.jsx');
+const UserStore = require('../stores/user_store.jsx');
+const Utils = require('../utils/utils.jsx');
+const Constants = require('../utils/constants.jsx');
-module.exports = React.createClass({
- componentWillReceiveProps: function(nextProps) {
- var linkData = utils.extractLinks(nextProps.post.message);
+export default class PostBody extends React.Component {
+ constructor(props) {
+ super(props);
+
+ const linkData = Utils.extractLinks(this.props.post.message);
+ this.state = {links: linkData.links, message: linkData.text};
+ }
+ componentWillReceiveProps(nextProps) {
+ const linkData = Utils.extractLinks(nextProps.post.message);
this.setState({links: linkData.links, message: linkData.text});
- },
- getInitialState: function() {
- var linkData = utils.extractLinks(this.props.post.message);
- return {links: linkData.links, message: linkData.text};
- },
- render: function() {
- var post = this.props.post;
- var filenames = this.props.post.filenames;
- var parentPost = this.props.parentPost;
- var inner = utils.textToJsx(this.state.message);
+ }
+ render() {
+ const post = this.props.post;
+ const filenames = this.props.post.filenames;
+ const parentPost = this.props.parentPost;
+ const inner = Utils.textToJsx(this.state.message);
- var comment = '';
- var reply = '';
- var postClass = '';
+ let comment = '';
+ let postClass = '';
if (parentPost) {
- var profile = UserStore.getProfile(parentPost.user_id);
- var apostrophe = '';
- var name = '...';
+ const profile = UserStore.getProfile(parentPost.user_id);
+
+ let apostrophe = '';
+ let name = '...';
if (profile != null) {
if (profile.username.slice(-1) === 's') {
apostrophe = '\'';
} else {
apostrophe = '\'s';
}
- name =
{profile.username} ;
+ name = (
+
+ {profile.username}
+
+ );
}
- var message = '';
+ let message = '';
if (parentPost.message) {
- message = utils.replaceHtmlEntities(parentPost.message);
+ message = Utils.replaceHtmlEntities(parentPost.message);
} else if (parentPost.filenames.length) {
message = parentPost.filenames[0].split('/').pop();
if (parentPost.filenames.length === 2) {
message += ' plus 1 other file';
} else if (parentPost.filenames.length > 2) {
- message += ' plus ' + (parentPost.filenames.length - 1) + ' other files';
+ message += ` plus ${parentPost.filenames.length - 1} other files`;
}
}
comment = (
- Commented on {name}{apostrophe} message: {message}
+
+ Commented on {name}{apostrophe} message:
+
+ {message}
+
+
);
postClass += ' post-comment';
}
- var loading;
+ let loading;
if (post.state === Constants.POST_FAILED) {
postClass += ' post-fail';
- loading =
Retry ;
+ loading = (
+
+ Retry
+
+ );
} else if (post.state === Constants.POST_LOADING) {
postClass += ' post-waiting';
- loading =
;
+ loading = (
+
+ );
}
- var embed;
+ let embed;
if (filenames.length === 0 && this.state.links) {
- embed = utils.getEmbed(this.state.links[0]);
+ embed = Utils.getEmbed(this.state.links[0]);
}
- var fileAttachmentHolder = '';
+ let fileAttachmentHolder = '';
if (filenames && filenames.length > 0) {
- fileAttachmentHolder = (
);
+ fileAttachmentHolder = (
+
+ );
}
return (
{comment}
-
{loading}{inner}
+
+ {loading}{inner}
+
{fileAttachmentHolder}
{embed}
);
}
-});
+}
+
+PostBody.propTypes = {
+ post: React.PropTypes.object.isRequired,
+ parentPost: React.PropTypes.object,
+ retryPost: React.PropTypes.func.isRequired,
+ handleCommentClick: React.PropTypes.func.isRequired
+};
diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx
index 2fe6dd96b1..37958b649a 100644
--- a/web/react/components/rename_channel_modal.jsx
+++ b/web/react/components/rename_channel_modal.jsx
@@ -1,147 +1,217 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
+const Utils = require('../utils/utils.jsx');
+const Client = require('../utils/client.jsx');
+const AsyncClient = require('../utils/async_client.jsx');
+const ChannelStore = require('../stores/channel_store.jsx');
-var utils = require('../utils/utils.jsx');
-var Client = require('../utils/client.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-var ChannelStore = require('../stores/channel_store.jsx');
-var TeamStore = require('../stores/team_store.jsx');
-var Constants = require('../utils/constants.jsx');
+export default class RenameChannelModal extends React.Component {
+ constructor(props) {
+ super(props);
-module.exports = React.createClass({
- handleSubmit: function(e) {
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.onNameChange = this.onNameChange.bind(this);
+ this.onDisplayNameChange = this.onDisplayNameChange.bind(this);
+ this.displayNameKeyUp = this.displayNameKeyUp.bind(this);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ this.state = {
+ displayName: '',
+ channelName: '',
+ channelId: '',
+ serverError: '',
+ nameError: '',
+ displayNameError: '',
+ invalid: false
+ };
+ }
+ handleSubmit(e) {
e.preventDefault();
- if (this.state.channel_id.length !== 26) return;
+ if (this.state.channelId.length !== 26) {
+ return;
+ }
- var channel = ChannelStore.get(this.state.channel_id);
- var oldName = channel.name
- var oldDisplayName = channel.display_name
- var state = { server_error: "" };
+ let channel = ChannelStore.get(this.state.channelId);
+ const oldName = channel.name;
+ const oldDisplayName = channel.displayName;
+ let state = {serverError: ''};
- channel.display_name = this.state.display_name.trim();
+ channel.display_name = this.state.displayName.trim();
if (!channel.display_name) {
- state.display_name_error = "This field is required";
- state.inValid = true;
- }
- else if (channel.display_name.length > 22) {
- state.display_name_error = "This field must be less than 22 characters";
- state.inValid = true;
- }
- else {
- state.display_name_error = "";
+ state.displayNameError = 'This field is required';
+ state.invalid = true;
+ } else if (channel.display_name.length > 22) {
+ state.displayNameError = 'This field must be less than 22 characters';
+ state.invalid = true;
+ } else {
+ state.displayNameError = '';
}
- channel.name = this.state.channel_name.trim();
+ channel.name = this.state.channelName.trim();
if (!channel.name) {
- state.name_error = "This field is required";
- state.inValid = true;
- }
- else if(channel.name.length > 22){
- state.name_error = "This field must be less than 22 characters";
- state.inValid = true;
- }
- else {
- var cleaned_name = utils.cleanUpUrlable(channel.name);
- if (cleaned_name != channel.name) {
- state.name_error = "Must be lowercase alphanumeric characters";
- state.inValid = true;
- }
- else {
- state.name_error = "";
+ state.nameError = 'This field is required';
+ state.invalid = true;
+ } else if (channel.name.length > 22) {
+ state.nameError = 'This field must be less than 22 characters';
+ state.invalid = true;
+ } else {
+ let cleanedName = Utils.cleanUpUrlable(channel.name);
+ if (cleanedName !== channel.name) {
+ state.nameError = 'Must be lowercase alphanumeric characters';
+ state.invalid = true;
+ } else {
+ state.nameError = '';
}
}
this.setState(state);
- if (state.inValid)
- return;
-
- if (oldName == channel.name && oldDisplayName == channel.display_name)
+ if (state.invalid || (oldName === channel.name && oldDisplayName === channel.display_name)) {
return;
+ }
Client.updateChannel(channel,
- function(data, text, req) {
- $(this.refs.modal.getDOMNode()).modal('hide');
+ function handleUpdateSuccess() {
+ $(React.findDOMNode(this.refs.modal)).modal('hide');
AsyncClient.getChannel(channel.id);
- utils.updateTabTitle(channel.display_name);
- utils.updateAddressBar(channel.name);
+ Utils.updateTabTitle(channel.display_name);
+ Utils.updateAddressBar(channel.name);
- this.refs.display_name.getDOMNode().value = "";
- this.refs.channel_name.getDOMNode().value = "";
+ React.findDOMNode(this.refs.displayName).value = '';
+ React.findDOMNode(this.refs.channelName).value = '';
}.bind(this),
- function(err) {
- state.server_error = err.message;
- state.inValid = true;
+ function handleUpdateError(err) {
+ state.serverError = err.message;
+ state.invalid = true;
this.setState(state);
}.bind(this)
);
- },
- onNameChange: function() {
- this.setState({ channel_name: this.refs.channel_name.getDOMNode().value })
- },
- onDisplayNameChange: function() {
- this.setState({ display_name: this.refs.display_name.getDOMNode().value })
- },
- displayNameKeyUp: function(e) {
- var display_name = this.refs.display_name.getDOMNode().value.trim();
- var channel_name = utils.cleanUpUrlable(display_name);
- this.refs.channel_name.getDOMNode().value = channel_name;
- this.setState({ channel_name: channel_name })
- },
- handleClose: function() {
- this.setState({display_name: "", channel_name: "", display_name_error: "", server_error: "", name_error: ""});
- },
- componentDidMount: function() {
- var self = this;
- $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
- var button = $(e.relatedTarget);
- self.setState({ display_name: button.attr('data-display'), channel_name: button.attr('data-name'), channel_id: button.attr('data-channelid') });
- });
- $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose);
- },
- componentWillUnmount: function() {
- $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose);
- },
- getInitialState: function() {
- return { display_name: "", channel_name: "", channel_id: "" };
- },
- render: function() {
+ }
+ onNameChange() {
+ this.setState({channelName: React.findDOMNode(this.refs.channelName).value});
+ }
+ onDisplayNameChange() {
+ this.setState({displayName: React.findDOMNode(this.refs.displayName).value});
+ }
+ displayNameKeyUp() {
+ const displayName = React.findDOMNode(this.refs.displayName).value.trim();
+ const channelName = Utils.cleanUpUrlable(displayName);
+ React.findDOMNode(this.refs.channelName).value = channelName;
+ this.setState({channelName: channelName});
+ }
+ handleClose() {
+ this.state = {
+ displayName: '',
+ channelName: '',
+ channelId: '',
+ serverError: '',
+ nameError: '',
+ displayNameError: '',
+ invalid: false
+ };
+ }
+ componentDidMount() {
+ $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function handleShow(e) {
+ const button = $(e.relatedTarget);
+ this.setState({displayName: button.attr('data-display'), channelName: button.attr('data-name'), channelId: button.attr('data-channelid')});
+ }.bind(this));
+ $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
+ }
+ componentWillUnmount() {
+ $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
+ }
+ render() {
+ let displayNameError = null;
+ let displayNameClass = 'form-group';
+ if (this.state.displayNameError) {
+ displayNameError =
{this.state.displayNameError} ;
+ displayNameClass += ' has-error';
+ }
- var display_name_error = this.state.display_name_error ?
{ this.state.display_name_error } : null;
- var name_error = this.state.name_error ?
{ this.state.name_error } : null;
- var server_error = this.state.server_error ?
{ this.state.server_error }
: null;
+ let nameError = null;
+ let nameClass = 'form-group';
+ if (this.state.nameError) {
+ nameError =
{this.state.nameError} ;
+ nameClass += ' has-error';
+ }
+
+ let serverError = null;
+ if (this.state.serverError) {
+ serverError =
{this.state.serverError}
;
+ }
return (
-
-
-
-
-
- ×
- Close
+
+
+
+
+
+ ×
+ Close
-
Rename Channel
+ Rename Channel
-