summaryrefslogtreecommitdiffstats
path: root/webapp/components/team_sidebar
diff options
context:
space:
mode:
authorenahum <nahumhbl@gmail.com>2016-12-19 10:05:46 -0300
committerJoram Wilander <jwawilander@gmail.com>2016-12-19 08:05:46 -0500
commit999d1553e1ce45adf58f6082b160bc1147dc592b (patch)
tree369a9b7f46dd44d136a79a050469429169433cec /webapp/components/team_sidebar
parent3ce2ce9dc882ed962dc3ce7550bdb07963f376b6 (diff)
downloadchat-999d1553e1ce45adf58f6082b160bc1147dc592b.tar.gz
chat-999d1553e1ce45adf58f6082b160bc1147dc592b.tar.bz2
chat-999d1553e1ce45adf58f6082b160bc1147dc592b.zip
PLT-4167 Team Sidebar (#4569)
* PLT-4167 Team Sidebar * Address feedback from PM * change route from my_members to members * bug fixes * Updating styles for teams sidebar (#4681) * Added PM changes * Fix corner cases * Addressing feedback * use two different endpoints * Bug fixes * Rename model and client functions, using preferences to store last team and channel viewed * Fix mobile notification count and closing the team sidebar * unit test, fixed bad merge and retrieve from cached when available * bug fixes * use id for last channel in preferences, query optimization * Updating multi team css (#4830)
Diffstat (limited to 'webapp/components/team_sidebar')
-rw-r--r--webapp/components/team_sidebar/components/team_button.jsx84
-rw-r--r--webapp/components/team_sidebar/team_sidebar_controller.jsx169
2 files changed, 253 insertions, 0 deletions
diff --git a/webapp/components/team_sidebar/components/team_button.jsx b/webapp/components/team_sidebar/components/team_button.jsx
new file mode 100644
index 000000000..0033ae25a
--- /dev/null
+++ b/webapp/components/team_sidebar/components/team_button.jsx
@@ -0,0 +1,84 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import Constants from 'utils/constants.jsx';
+
+import React from 'react';
+import {Link} from 'react-router/es6';
+import {Tooltip, OverlayTrigger} from 'react-bootstrap';
+
+export default class TeamButton extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleDisabled = this.handleDisabled.bind(this);
+ }
+
+ handleDisabled(e) {
+ e.preventDefault();
+ }
+
+ render() {
+ let teamClass = this.props.active ? 'active' : '';
+ const disabled = this.props.disabled ? 'team-disabled' : '';
+ const handleClick = (this.props.active || this.props.disabled) ? this.handleDisabled : null;
+ let badge;
+
+ if (!teamClass) {
+ teamClass = this.props.unread ? 'unread' : '';
+
+ if (this.props.mentions) {
+ badge = (
+ <span className='badge pull-right small'>{this.props.mentions}</span>
+ );
+ }
+ }
+
+ return (
+ <div
+ className={`team-container ${teamClass}`}
+ >
+ <Link
+ className={disabled}
+ to={this.props.url}
+ onClick={handleClick}
+ >
+ <OverlayTrigger
+ delayShow={Constants.OVERLAY_TIME_DELAY}
+ placement={this.props.placement}
+ overlay={
+ <Tooltip id={`tooltip-${this.props.url}`}>
+ {this.props.tip}
+ </Tooltip>
+ }
+ >
+ <div className='team-btn'>
+ {badge}
+ {this.props.contents}
+ </div>
+ </OverlayTrigger>
+ </Link>
+ </div>
+ );
+ }
+}
+
+TeamButton.defaultProps = {
+ tip: '',
+ placement: 'right',
+ active: false,
+ disabled: false,
+ unread: false,
+ mentions: 0
+};
+
+TeamButton.propTypes = {
+ url: React.PropTypes.string.isRequired,
+ contents: React.PropTypes.node.isRequired,
+ tip: React.PropTypes.node,
+ active: React.PropTypes.bool,
+ disabled: React.PropTypes.bool,
+ unread: React.PropTypes.bool,
+ mentions: React.PropTypes.number,
+ placement: React.PropTypes.oneOf(['left', 'right', 'top', 'bottom'])
+};
diff --git a/webapp/components/team_sidebar/team_sidebar_controller.jsx b/webapp/components/team_sidebar/team_sidebar_controller.jsx
new file mode 100644
index 000000000..f005afeb3
--- /dev/null
+++ b/webapp/components/team_sidebar/team_sidebar_controller.jsx
@@ -0,0 +1,169 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import TeamButton from './components/team_button.jsx';
+
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+
+import * as AsyncClient from 'utils/async_client.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+import $ from 'jquery';
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+
+export default class TeamSidebar extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.getStateFromStores = this.getStateFromStores.bind(this);
+ this.onChange = this.onChange.bind(this);
+ this.handleResize = this.handleResize.bind(this);
+ this.setStyles = this.setStyles.bind(this);
+
+ this.state = this.getStateFromStores();
+ }
+
+ getStateFromStores() {
+ const teamMembers = TeamStore.getMyTeamMembers();
+ const currentTeamId = TeamStore.getCurrentId();
+
+ return {
+ teams: TeamStore.getAll(),
+ teamListings: TeamStore.getTeamListings(),
+ teamMembers,
+ currentTeamId,
+ show: teamMembers && teamMembers.length > 1
+ };
+ }
+
+ componentDidMount() {
+ window.addEventListener('resize', this.handleResize);
+ TeamStore.addChangeListener(this.onChange);
+ TeamStore.addUnreadChangeListener(this.onChange);
+ AsyncClient.getAllTeamListings();
+ this.setStyles();
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.handleResize);
+ TeamStore.removeChangeListener(this.onChange);
+ TeamStore.removeUnreadChangeListener(this.onChange);
+ }
+
+ componentDidUpdate(prevProps, prevState) {
+ $('.team-wrapper').perfectScrollbar();
+
+ // reset the scrollbar upon switching teams
+ if (this.state.currentTeam !== prevState.currentTeam) {
+ this.refs.container.scrollTop = 0;
+ $('.team-wrapper').perfectScrollbar('update');
+ }
+ }
+
+ onChange() {
+ this.setState(this.getStateFromStores());
+ this.setStyles();
+ }
+
+ handleResize() {
+ const teamMembers = this.state.teamMembers;
+ this.setState({show: teamMembers && teamMembers.length > 1});
+ this.setStyles();
+ }
+
+ setStyles() {
+ const root = document.querySelector('#root');
+
+ if (this.state.show) {
+ root.classList.add('multi-teams');
+ } else {
+ root.classList.remove('multi-teams');
+ }
+ }
+
+ render() {
+ if (!this.state.show) {
+ return null;
+ }
+
+ const myTeams = [];
+ const isSystemAdmin = Utils.isSystemAdmin(UserStore.getCurrentUser().roles);
+ const isAlreadyMember = new Map();
+ let moreTeams = false;
+
+ for (const index in this.state.teamMembers) {
+ if (this.state.teamMembers.hasOwnProperty(index)) {
+ const teamMember = this.state.teamMembers[index];
+ const teamId = teamMember.team_id;
+ myTeams.push(Object.assign({
+ unread: teamMember.msg_count > 0,
+ mentions: teamMember.mention_count
+ }, this.state.teams[teamId]));
+ isAlreadyMember[teamId] = true;
+ }
+ }
+
+ for (const id in this.state.teamListings) {
+ if (this.state.teamListings.hasOwnProperty(id) && !isAlreadyMember[id]) {
+ moreTeams = true;
+ break;
+ }
+ }
+
+ const teams = myTeams.
+ sort((a, b) => a.display_name.localeCompare(b.display_name)).
+ map((team) => {
+ return (
+ <TeamButton
+ key={'switch_team_' + team.name}
+ url={`/${team.name}`}
+ tip={team.display_name}
+ active={team.id === this.state.currentTeamId}
+ contents={team.display_name.substring(0, 1).toUpperCase()}
+ unread={team.unread}
+ mentions={team.mentions}
+ />
+ );
+ });
+
+ if (moreTeams) {
+ teams.push(
+ <TeamButton
+ key='more_teams'
+ url='/select_team'
+ tip={
+ <FormattedMessage
+ id='team_sidebar.join'
+ defaultMessage='Other teams you can join.'
+ />
+ }
+ contents={<i className='fa fa-plus'/>}
+ />
+ );
+ } else if (global.window.mm_config.EnableTeamCreation === 'true' || isSystemAdmin) {
+ teams.push(
+ <TeamButton
+ key='more_teams'
+ url='/create_team'
+ tip={
+ <FormattedMessage
+ id='navbar_dropdown.create'
+ defaultMessage='Create a New Team'
+ />
+ }
+ contents={<i className='fa fa-plus'/>}
+ />
+ );
+ }
+
+ return (
+ <div className='team-sidebar'>
+ <div className='team-wrapper'>
+ {teams}
+ </div>
+ </div>
+ );
+ }
+}