From 4fea0b452e773631864f557cff910e880eb459c4 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 6 Aug 2015 14:03:45 -0400 Subject: Refactored sidebar in preparation for adding unread indicators --- web/react/components/sidebar.jsx | 145 ++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 78 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 1d39f5f67..0358032ab 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -56,7 +56,6 @@ function getStateFromStores() { var channelMember = members[channel.id]; var msgCount = channel.total_msg_count - channelMember.msg_count; if (msgCount > 0) { - channel.unread = msgCount; showDirectChannels.push(channel); } else if (currentId === channel.id) { showDirectChannels.push(channel); @@ -70,6 +69,7 @@ function getStateFromStores() { tempChannel.display_name = utils.getDisplayName(teammate); tempChannel.status = UserStore.getStatus(teammate.id); tempChannel.last_post_at = 0; + tempChannel.total_msg_count = 0; readDirectChannels.push(tempChannel); } } @@ -240,98 +240,94 @@ module.exports = React.createClass({ }, render: function() { var members = this.state.members; - var newsActive = window.location.pathname === '/' ? 'active' : ''; + var activeId = this.state.active_id; var badgesActive = false; - var self = this; - var channelItems = this.state.channels.map(function(channel) { - if (channel.type != 'O') { - return ''; - } + function createChannelElement(channel) { var channelMember = members[channel.id]; - var active = channel.id === self.state.active_id ? 'active' : ''; + var active = channel.id === activeId ? 'active' : ''; - var msgCount = channel.total_msg_count - channelMember.msg_count; - var titleClass = ''; - if (msgCount > 0 && channelMember.notify_level !== 'quiet') { - titleClass = 'unread-title'; + var unread = false; + if (channelMember) { + var msgCount = channel.total_msg_count - channelMember.msg_count; + unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0; } - var badge = ''; - if (channelMember.mention_count > 0) { - badge = {channelMember.mention_count}; - badgesActive = true; + var titleClass = ''; + if (unread) { titleClass = 'unread-title'; } - return ( -
  • {badge}{channel.display_name}
  • - ); - }); - - var privateChannelItems = this.state.channels.map(function(channel) { - if (channel.type !== 'P') { - return ''; + var badge = null; + 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; + if (msgCount > 0) { + badge = {msgCount}; + badgesActive = true; + } + } else if (channelMember.mention_count > 0) { + // public and private channels only show badges for mentions + badge = {channelMember.mention_count}; + badgesActive = true; + } } - var channelMember = members[channel.id]; - var active = channel.id === self.state.active_id ? 'active' : ''; - - var msgCount = channel.total_msg_count - channelMember.msg_count; - var titleClass = '' - if (msgCount > 0 && channelMember.notify_level !== 'quiet') { - titleClass = 'unread-title' + // set up status icon for direct message channels + var status = null; + if (channel.type === 'D') { + var statusIcon = ''; + if (channel.status === 'online') { + statusIcon = Constants.ONLINE_ICON_SVG; + } else if (channel.status === 'away') { + statusIcon = Constants.ONLINE_ICON_SVG; + } else { + statusIcon = Constants.OFFLINE_ICON_SVG; + } + status = ; } - var badge = ''; - if (channelMember.mention_count > 0) { - badge = {channelMember.mention_count}; - badgesActive = true; - titleClass = 'unread-title'; + // set up click handler to switch channels (or create a new channel for non-existant ones) + var clickHandler = null; + var href; + if (!channel.fake) { + clickHandler = function(e) { + e.preventDefault(); + utils.switchChannel(channel); + }; + href = '#'; + } else { + href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name; } return ( -
  • {badge}{channel.display_name}
  • +
  • + + {status} + {badge} + {channel.display_name} + +
  • ); - }); - - var directMessageItems = this.state.showDirectChannels.map(function(channel) { - var badge = ''; - var titleClass = ''; + }; - var statusIcon = ''; - if (channel.status === 'online') { - statusIcon = Constants.ONLINE_ICON_SVG; - } else if (channel.status === 'away') { - statusIcon = Constants.ONLINE_ICON_SVG; - } else { - statusIcon = Constants.OFFLINE_ICON_SVG; + // create elements for all 3 types of channels + var channelItems = this.state.channels.filter( + function(channel) { + return channel.type === 'O'; } + ).map(createChannelElement); - if (!channel.fake) { - var active = channel.id === self.state.active_id ? 'active' : ''; - - if (channel.unread) { - badge = {channel.unread}; - badgesActive = true; - titleClass = 'unread-title'; - } - - function handleClick(e) { - e.preventDefault(); - utils.switchChannel(channel, channel.teammate_username); - } - - return ( -
  • {badge}{channel.display_name}
  • - ); - } else { - return ( -
  • {badge}{channel.display_name}
  • - ); + var privateChannelItems = this.state.channels.filter( + function(channel) { + return channel.type === 'P'; } - }); + ).map(createChannelElement); + + var directMessageItems = this.state.showDirectChannels.map(createChannelElement); + // update the favicon to show if there are any notifications var link = document.createElement('link'); link.type = 'image/x-icon'; link.rel = 'shortcut icon'; @@ -348,13 +344,6 @@ module.exports = React.createClass({ } head.appendChild(link); - if (channelItems.length == 0) { -
  • Loading...
  • - } - - if (privateChannelItems.length == 0) { -
  • Loading...
  • - } return (
    -- cgit v1.2.3-1-g7c22 From 38e2b69dba76a83a5da25d09b36293dfe2a85630 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 6 Aug 2015 16:28:43 -0400 Subject: Added the ability for the sidebar to determine whether or not there's any unread channels offscreen --- web/react/components/sidebar.jsx | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 0358032ab..abbcd306d 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -132,11 +132,17 @@ module.exports = React.createClass({ $('.nav-pills__container').perfectScrollbar(); this.updateTitle(); + this.updateUnreadIndicators(); + + $('.nav-pills__container').on('scroll', null, this.onScroll); }, componentDidUpdate: function() { this.updateTitle(); + this.updateUnreadIndicators(); }, componentWillUnmount: function() { + $('.nav-pills__container').off('scroll', null, this.onScroll); + ChannelStore.removeChangeListener(this.onChange); UserStore.removeChangeListener(this.onChange); UserStore.removeStatusesChangeListener(this.onChange); @@ -235,6 +241,28 @@ module.exports = React.createClass({ } } }, + onScroll: function(e) { + this.updateUnreadIndicators(); + }, + updateUnreadIndicators: function() { + var container = $(this.refs.container.getDOMNode()); + + if (this.firstUnreadChannel) { + var firstUnreadElement = $(this.refs[this.firstUnreadChannel].getDOMNode()); + + if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) { + console.log("off top"); + } + } + + if (this.lastUnreadChannel) { + var lastUnreadElement = $(this.refs[this.lastUnreadChannel].getDOMNode()); + + if (lastUnreadElement.position().top > container.height()) { + console.log("off bottom"); + } + } + }, getInitialState: function() { return getStateFromStores(); }, @@ -243,6 +271,11 @@ module.exports = React.createClass({ var activeId = this.state.active_id; var badgesActive = false; + // keep track of the first and last unread channels so we can use them to set the unread indicators + var self = this; + this.firstUnreadChannel = null; + this.lastUnreadChannel = null; + function createChannelElement(channel) { var channelMember = members[channel.id]; var active = channel.id === activeId ? 'active' : ''; @@ -256,6 +289,11 @@ module.exports = React.createClass({ var titleClass = ''; if (unread) { titleClass = 'unread-title'; + + if (!self.firstUnreadChannel) { + self.firstUnreadChannel = channel.name; + } + self.lastUnreadChannel = channel.name; } var badge = null; @@ -302,7 +340,7 @@ module.exports = React.createClass({ } return ( -
  • +
  • {status} {badge} @@ -349,7 +387,7 @@ module.exports = React.createClass({ -
    +
    • Channels+

    • {channelItems} -- cgit v1.2.3-1-g7c22 From 34f7451c4ad50fe64cc1c06dbd204c5b6446bca5 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 6 Aug 2015 18:57:57 -0400 Subject: Added indicators for when a channel with unread posts is offscreen --- web/react/components/sidebar.jsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index abbcd306d..d6c22230e 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -134,14 +134,14 @@ module.exports = React.createClass({ this.updateTitle(); this.updateUnreadIndicators(); - $('.nav-pills__container').on('scroll', null, this.onScroll); + $('.nav-pills__container').on('scroll', this.onScroll); }, componentDidUpdate: function() { this.updateTitle(); this.updateUnreadIndicators(); }, componentWillUnmount: function() { - $('.nav-pills__container').off('scroll', null, this.onScroll); + $('.nav-pills__container').off('scroll', this.onScroll); ChannelStore.removeChangeListener(this.onChange); UserStore.removeChangeListener(this.onChange); @@ -251,7 +251,9 @@ module.exports = React.createClass({ var firstUnreadElement = $(this.refs[this.firstUnreadChannel].getDOMNode()); if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) { - console.log("off top"); + $(this.refs.topUnreadIndicator.getDOMNode()).css('display', 'initial'); + } else { + $(this.refs.topUnreadIndicator.getDOMNode()).css('display', 'none'); } } @@ -259,7 +261,10 @@ module.exports = React.createClass({ var lastUnreadElement = $(this.refs[this.lastUnreadChannel].getDOMNode()); if (lastUnreadElement.position().top > container.height()) { - console.log("off bottom"); + $(this.refs.bottomUnreadIndicator.getDOMNode()).css('bottom', '0'); + $(this.refs.bottomUnreadIndicator.getDOMNode()).css('display', 'initial'); + } else { + $(this.refs.bottomUnreadIndicator.getDOMNode()).css('display', 'none'); } } }, @@ -387,6 +392,9 @@ module.exports = React.createClass({ +
      Unread post(s) above
      +
      Unread post(s) below
      +
      • Channels+

      • -- cgit v1.2.3-1-g7c22 From 02eabee792a1bb220c8fac400ac6b80486d1d954 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 6 Aug 2015 19:07:51 -0400 Subject: Removed ternary statements from sidebar --- web/react/components/sidebar.jsx | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index d6c22230e..82a14915c 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -163,7 +163,10 @@ module.exports = React.createClass({ } if (UserStore.getCurrentId() !== msg.user_id) { - var mentions = msg.props.mentions ? JSON.parse(msg.props.mentions) : []; + var mentions = []; + if (msg.props.mentions) { + mentions = JSON.parse(msg.props.mentions); + } var channel = ChannelStore.get(msg.channel_id); var user = UserStore.getCurrentUser(); @@ -181,7 +184,10 @@ module.exports = React.createClass({ username = UserStore.getProfile(msg.user_id).username; } - var title = channel ? channel.display_name : 'Posted'; + var title = 'Posted'; + if (channel) { + title = channel.display_name; + } var repRegex = new RegExp('
        ', 'g'); var post = JSON.parse(msg.props.post); @@ -283,7 +289,11 @@ module.exports = React.createClass({ function createChannelElement(channel) { var channelMember = members[channel.id]; - var active = channel.id === activeId ? 'active' : ''; + + var linkClass = ''; + if (channel.id === self.state.active_id) { + linkClass = 'active'; + } var unread = false; if (channelMember) { @@ -345,7 +355,7 @@ module.exports = React.createClass({ } return ( -
      • +
      • {status} {badge} @@ -387,6 +397,17 @@ module.exports = React.createClass({ } head.appendChild(link); + var directMessageMore = null; + if (this.state.hideDirectChannels.length > 0) { + directMessageMore = ( +
      • + + {'More ('+this.state.hideDirectChannels.length+')'} + +
      • + ); + } + return (
        @@ -409,9 +430,7 @@ module.exports = React.createClass({
      -- cgit v1.2.3-1-g7c22 From 5b831e78a79dba6f8dbea91c0cc2ba0b9253eb15 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 7 Aug 2015 10:54:13 -0400 Subject: Changed sidebar scroll handler to use React's onScroll --- web/react/components/sidebar.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 82a14915c..5ce9e5d02 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -133,16 +133,12 @@ module.exports = React.createClass({ this.updateTitle(); this.updateUnreadIndicators(); - - $('.nav-pills__container').on('scroll', this.onScroll); }, componentDidUpdate: function() { this.updateTitle(); this.updateUnreadIndicators(); }, componentWillUnmount: function() { - $('.nav-pills__container').off('scroll', this.onScroll); - ChannelStore.removeChangeListener(this.onChange); UserStore.removeChangeListener(this.onChange); UserStore.removeStatusesChangeListener(this.onChange); @@ -416,7 +412,7 @@ module.exports = React.createClass({
      Unread post(s) above
      Unread post(s) below
      -
      +
      • Channels+

      • {channelItems} -- cgit v1.2.3-1-g7c22 From 72e5d441ff471d75effe52b4ef0eafe0667aa54e Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 7 Aug 2015 10:58:03 -0400 Subject: Added handlers for the sidebar to update unread message indicators on page resize --- web/react/components/sidebar.jsx | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'web/react/components') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 5ce9e5d02..fe73cbcf7 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -133,12 +133,16 @@ module.exports = React.createClass({ this.updateTitle(); this.updateUnreadIndicators(); + + $(window).on('resize', this.onResize); }, componentDidUpdate: function() { this.updateTitle(); this.updateUnreadIndicators(); }, componentWillUnmount: function() { + $(window).off('resize', this.onResize); + ChannelStore.removeChangeListener(this.onChange); UserStore.removeChangeListener(this.onChange); UserStore.removeStatusesChangeListener(this.onChange); @@ -246,6 +250,9 @@ module.exports = React.createClass({ onScroll: function(e) { this.updateUnreadIndicators(); }, + onResize: function(e) { + this.updateUnreadIndicators(); + }, updateUnreadIndicators: function() { var container = $(this.refs.container.getDOMNode()); -- cgit v1.2.3-1-g7c22