diff options
Diffstat (limited to 'web/react')
-rw-r--r-- | web/react/components/more_direct_channels.jsx | 93 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 73 | ||||
-rw-r--r-- | web/react/utils/client.jsx | 17 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 15 |
4 files changed, 146 insertions, 52 deletions
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx index 901cd228f..11ddbcbd1 100644 --- a/web/react/components/more_direct_channels.jsx +++ b/web/react/components/more_direct_channels.jsx @@ -3,67 +3,102 @@ var ChannelStore = require('../stores/channel_store.jsx'); var TeamStore = require('../stores/team_store.jsx'); +var Client = require('../utils/client.jsx'); +var AsyncClient = require('../utils/async_client.jsx'); var utils = require('../utils/utils.jsx'); module.exports = React.createClass({ + displayName: 'MoreDirectChannels', componentDidMount: function() { var self = this; - $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { + $(this.refs.modal.getDOMNode()).on('show.bs.modal', function showModal(e) { var button = e.relatedTarget; - self.setState({ channels: $(button).data('channels') }); + self.setState({channels: $(button).data('channels')}); }); }, getInitialState: function() { - return { channels: [] }; + return {channels: [], loadingDMChannel: -1}; }, render: function() { var self = this; - var directMessageItems = this.state.channels.map(function(channel) { - var badge = ""; - var titleClass = "" + var directMessageItems = this.state.channels.map(function mapActivityToChannel(channel, index) { + var badge = ''; + var titleClass = ''; + var active = ''; + var handleClick = null; if (!channel.fake) { - var active = channel.id === ChannelStore.getCurrentId() ? "active" : ""; + if (channel.id === ChannelStore.getCurrentId()) { + active = 'active'; + } if (channel.unread) { - badge = <span className="badge pull-right small">{channel.unread}</span>; - badgesActive = true; - titleClass = "unread-title" + badge = <span className='badge pull-right small'>{channel.unread}</span>; + titleClass = 'unread-title'; } - return ( - <li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href="#" onClick={function(e){e.preventDefault(); utils.switchChannel(channel, channel.teammate_username); $(self.refs.modal.getDOMNode()).modal('hide')}}>{badge}{channel.display_name}</a></li> - ); + + handleClick = function clickHandler(e) { + e.preventDefault(); + utils.switchChannel(channel, channel.teammate_username); + $(self.refs.modal.getDOMNode()).modal('hide'); + }; } else { - return ( - <li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href={TeamStore.getCurrentTeamUrl() + "/channels/"+channel.name}>{badge}{channel.display_name}</a></li> - ); + // It's a direct message channel that doesn't exist yet so let's create it now + var otherUserId = utils.getUserIdFromChannelName(channel); + + if (self.state.loadingDMChannel === index) { + badge = <img className='channel-loading-gif pull-right' src='/static/images/load.gif'/>; + } + + if (self.state.loadingDMChannel === -1) { + handleClick = function clickHandler(e) { + e.preventDefault(); + self.setState({loadingDMChannel: index}); + + Client.createDirectChannel(channel, otherUserId, + function success(data) { + $(self.refs.modal.getDOMNode()).modal('hide'); + self.setState({loadingDMChannel: -1}); + AsyncClient.getChannel(data.id); + utils.switchChannel(data); + }, + function error() { + self.setState({loadingDMChannel: -1}); + window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name; + } + ); + }; + } } + + return ( + <li key={channel.name} className={active}><a className={'sidebar-channel ' + titleClass} href='#' onClick={handleClick}>{badge}{channel.display_name}</a></li> + ); }); return ( - <div className="modal fade" id="more_direct_channels" ref="modal" tabIndex="-1" role="dialog" aria-hidden="true"> - <div className="modal-dialog"> - <div className="modal-content"> - <div className="modal-header"> - <button type="button" className="close" data-dismiss="modal"> - <span aria-hidden="true">×</span> - <span className="sr-only">Close</span> + <div className='modal fade' id='more_direct_channels' ref='modal' tabIndex='-1' role='dialog' aria-hidden='true'> + <div className='modal-dialog'> + <div className='modal-content'> + <div className='modal-header'> + <button type='button' className='close' data-dismiss='modal'> + <span aria-hidden='true'>×</span> + <span className='sr-only'>Close</span> </button> - <h4 className="modal-title">More Private Messages</h4> + <h4 className='modal-title'>More Private Messages</h4> </div> - <div className="modal-body"> - <ul className="nav nav-pills nav-stacked"> + <div className='modal-body'> + <ul className='nav nav-pills nav-stacked'> {directMessageItems} </ul> </div> - <div className="modal-footer"> - <button type="button" className="btn btn-default" data-dismiss="modal">Close</button> + <div className='modal-footer'> + <button type='button' className='btn btn-default' data-dismiss='modal'>Close</button> </div> </div> </div> </div> - ); } }); diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 6735bd6e5..d79505e9e 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -1,8 +1,8 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. -var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var ChannelStore = require('../stores/channel_store.jsx'); +var Client = require('../utils/client.jsx'); var AsyncClient = require('../utils/async_client.jsx'); var SocketStore = require('../stores/socket_store.jsx'); var UserStore = require('../stores/user_store.jsx'); @@ -11,9 +11,7 @@ var BrowserStore = require('../stores/browser_store.jsx'); var utils = require('../utils/utils.jsx'); var SidebarHeader = require('./sidebar_header.jsx'); var SearchBox = require('./search_bar.jsx'); - var Constants = require('../utils/constants.jsx'); -var ActionTypes = Constants.ActionTypes; function getStateFromStores() { var members = ChannelStore.getAllMembers(); @@ -70,13 +68,14 @@ function getStateFromStores() { tempChannel.status = UserStore.getStatus(teammate.id); tempChannel.last_post_at = 0; tempChannel.total_msg_count = 0; + tempChannel.type = 'D'; readDirectChannels.push(tempChannel); } } // If we don't have MAX_DMS unread channels, sort the read list by last_post_at if (showDirectChannels.length < Constants.MAX_DMS) { - readDirectChannels.sort(function(a, b) { + readDirectChannels.sort(function sortByLastPost(a, b) { // sort by last_post_at first if (a.last_post_at > b.last_post_at) { return -1; @@ -124,6 +123,10 @@ function getStateFromStores() { module.exports = React.createClass({ displayName: 'Sidebar', + propTypes: { + teamType: React.PropTypes.string, + teamDisplayName: React.PropTypes.string + }, componentDidMount: function() { ChannelStore.addChangeListener(this.onChange); UserStore.addChangeListener(this.onChange); @@ -244,17 +247,17 @@ module.exports = React.createClass({ var channel = ChannelStore.getCurrent(); if (channel) { if (channel.type === 'D') { - var teammate_username = utils.getDirectTeammate(channel.id).username; - document.title = teammate_username + ' ' + document.title.substring(document.title.lastIndexOf('-')); + var teammateUsername = utils.getDirectTeammate(channel.id).username; + document.title = teammateUsername + ' ' + document.title.substring(document.title.lastIndexOf('-')); } else { document.title = channel.display_name + ' ' + document.title.substring(document.title.lastIndexOf('-')); } } }, - onScroll: function(e) { + onScroll: function() { this.updateUnreadIndicators(); }, - onResize: function(e) { + onResize: function() { this.updateUnreadIndicators(); }, updateUnreadIndicators: function() { @@ -282,7 +285,10 @@ module.exports = React.createClass({ } }, getInitialState: function() { - return getStateFromStores(); + var newState = getStateFromStores(); + newState.loadingDMChannel = -1; + + return newState; }, render: function() { var members = this.state.members; @@ -294,8 +300,9 @@ module.exports = React.createClass({ this.firstUnreadChannel = null; this.lastUnreadChannel = null; - function createChannelElement(channel) { + function createChannelElement(channel, index) { var channelMember = members[channel.id]; + var msgCount; var linkClass = ''; if (channel.id === activeId) { @@ -304,7 +311,7 @@ module.exports = React.createClass({ var unread = false; if (channelMember) { - var msgCount = channel.total_msg_count - channelMember.msg_count; + msgCount = channel.total_msg_count - channelMember.msg_count; unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0; } @@ -322,7 +329,7 @@ module.exports = React.createClass({ if (channelMember) { if (channel.type === 'D') { // direct message channels show badges for any number of unread posts - var msgCount = channel.total_msg_count - channelMember.msg_count; + msgCount = channel.total_msg_count - channelMember.msg_count; if (msgCount > 0) { badge = <span className='badge pull-right small'>{msgCount}</span>; badgesActive = true; @@ -332,6 +339,8 @@ module.exports = React.createClass({ badge = <span className='badge pull-right small'>{channelMember.mention_count}</span>; badgesActive = true; } + } else if (self.state.loadingDMChannel === index && channel.type === 'D') { + badge = <img className='channel-loading-gif pull-right' src='/static/images/load.gif'/>; } // set up status icon for direct message channels @@ -349,39 +358,59 @@ module.exports = React.createClass({ } // set up click handler to switch channels (or create a new channel for non-existant ones) - var clickHandler = null; + var handleClick = null; var href = '#'; var teamURL = TeamStore.getCurrentTeamUrl(); + if (!channel.fake) { - clickHandler = function(e) { + handleClick = function clickHandler(e) { e.preventDefault(); utils.switchChannel(channel); }; - } - if (channel.fake && teamURL){ - href = teamURL + '/channels/' + channel.name; + } else if (channel.fake && teamURL) { + // It's a direct message channel that doesn't exist yet so let's create it now + var otherUserId = utils.getUserIdFromChannelName(channel); + + if (self.state.loadingDMChannel === -1) { + handleClick = function clickHandler(e) { + e.preventDefault(); + self.setState({loadingDMChannel: index}); + + Client.createDirectChannel(channel, otherUserId, + function success(data) { + self.setState({loadingDMChannel: -1}); + AsyncClient.getChannel(data.id); + utils.switchChannel(data); + }, + function error() { + self.setState({loadingDMChannel: -1}); + window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name; + } + ); + }; + } } return ( <li key={channel.name} ref={channel.name} className={linkClass}> - <a className={'sidebar-channel ' + titleClass} href={href} onClick={clickHandler}> + <a className={'sidebar-channel ' + titleClass} href={href} onClick={handleClick}> {status} {channel.display_name} {badge} </a> </li> ); - }; + } // create elements for all 3 types of channels var channelItems = this.state.channels.filter( - function(channel) { + function filterPublicChannels(channel) { return channel.type === 'O'; } ).map(createChannelElement); var privateChannelItems = this.state.channels.filter( - function(channel) { + function filterPrivateChannels(channel) { return channel.type === 'P'; } ).map(createChannelElement); @@ -410,7 +439,7 @@ module.exports = React.createClass({ directMessageMore = ( <li> <a href='#' data-toggle='modal' className='nav-more' data-target='#more_direct_channels' data-channels={JSON.stringify(this.state.hideDirectChannels)}> - {'More ('+this.state.hideDirectChannels.length+')'} + {'More (' + this.state.hideDirectChannels.length + ')'} </a> </li> ); diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index ce044457a..da0b74081 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -438,6 +438,23 @@ module.exports.createChannel = function(channel, success, error) { module.exports.track('api', 'api_channels_create', channel.type, 'name', channel.name); }; +module.exports.createDirectChannel = function(channel, userId, success, error) { + $.ajax({ + url: '/api/v1/channels/create_direct', + dataType: 'json', + contentType: 'application/json', + type: 'POST', + data: JSON.stringify({user_id: userId}), + success: success, + error: function(xhr, status, err) { + var e = handleError('createDirectChannel', xhr, status, err); + error(e); + } + }); + + module.exports.track('api', 'api_channels_create_direct', channel.type, 'name', channel.name); +}; + module.exports.updateChannel = function(channel, success, error) { $.ajax({ url: "/api/v1/channels/update", diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 3f7d204e4..618cc1557 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -968,4 +968,17 @@ module.exports.generateId = function() { module.exports.isBrowserFirefox = function() { return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1; -} +}; + +// Used to get the id of the other user from a DM channel +module.exports.getUserIdFromChannelName = function(channel) { + var ids = channel.name.split('__'); + var otherUserId = ''; + if (ids[0] === UserStore.getCurrentId()) { + otherUserId = ids[1]; + } else { + otherUserId = ids[0]; + } + + return otherUserId; +}; |