diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index bc610cd603..99babe714d 100644
--- a/web/react/components/more_direct_channels.jsx
+++ b/web/react/components/more_direct_channels.jsx
@@ -1,133 +1,273 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-var TeamStore = require('../stores/team_store.jsx');
-var Client = require('../utils/client.jsx');
-var Constants = require('../utils/constants.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-var PreferenceStore = require('../stores/preference_store.jsx');
-var utils = require('../utils/utils.jsx');
+const AsyncClient = require('../utils/async_client.jsx');
+const ChannelStore = require('../stores/channel_store.jsx');
+const Constants = require('../utils/constants.jsx');
+const Client = require('../utils/client.jsx');
+const Modal = ReactBootstrap.Modal;
+const PreferenceStore = require('../stores/preference_store.jsx');
+const TeamStore = require('../stores/team_store.jsx');
+const UserStore = require('../stores/user_store.jsx');
+const Utils = require('../utils/utils.jsx');
export default class MoreDirectChannels extends React.Component {
constructor(props) {
super(props);
- this.state = {channels: [], loadingDMChannel: -1};
+ this.handleFilterChange = this.handleFilterChange.bind(this);
+ this.handleHide = this.handleHide.bind(this);
+ this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
+ this.handleUserChange = this.handleUserChange.bind(this);
+
+ this.createRowForUser = this.createRowForUser.bind(this);
+
+ this.state = {
+ users: this.getUsersFromStore(),
+ filter: '',
+ loadingDMChannel: -1
+ };
+ }
+
+ getUsersFromStore() {
+ const currentId = UserStore.getCurrentId();
+ const profiles = UserStore.getProfiles();
+ const users = [];
+
+ for (const id in profiles) {
+ if (id !== currentId) {
+ users.push(profiles[id]);
+ }
+ }
+
+ users.sort((a, b) => a.username.localeCompare(b.username));
+
+ return users;
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', (e) => {
- var button = e.relatedTarget;
- this.setState({channels: $(button).data('channels')}); // eslint-disable-line react/no-did-mount-set-state
- });
+ UserStore.addChangeListener(this.handleUserChange);
}
- handleJoinDirectChannel(channel) {
- const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, channel.teammate_id, 'true');
+ componentWillUnmount() {
+ UserStore.addChangeListener(this.handleUserChange);
+ }
+
+ handleFilterChange() {
+ const filter = React.findDOMNode(this.refs.filter).value;
+
+ if (filter !== this.state.filter) {
+ this.setState({filter});
+ }
+ }
+
+ handleHide() {
+ if (this.props.onModalDismissed) {
+ this.props.onModalDismissed();
+ }
+
+ this.setState({filter: ''});
+ }
+
+ handleShowDirectChannel(teammate, e) {
+ if (this.state.loadingDMChannel !== -1) {
+ return;
+ }
+
+ e.preventDefault();
+
+ const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), teammate.id);
+ let channel = ChannelStore.getByName(channelName);
+
+ const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, teammate.id, 'true');
AsyncClient.savePreferences([preference]);
+
+ if (channel) {
+ Utils.switchChannel(channel);
+
+ this.handleHide();
+ } else {
+ this.setState({loadingDMChannel: teammate.id});
+
+ channel = {
+ name: channelName,
+ last_post_at: 0,
+ total_msg_count: 0,
+ type: 'D',
+ display_name: teammate.username,
+ teammate_id: teammate.id,
+ status: UserStore.getStatus(teammate.id)
+ };
+
+ Client.createDirectChannel(
+ channel,
+ teammate.id,
+ (data) => {
+ this.setState({loadingDMChannel: -1});
+
+ AsyncClient.getChannel(data.id);
+ Utils.switchChannel(data);
+
+ this.handleHide();
+ },
+ () => {
+ this.setState({loadingDMChannel: -1});
+ window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channelName;
+ }
+ );
+ }
+ }
+
+ handleUserChange() {
+ this.setState({users: this.getUsersFromStore()});
+ }
+
+ createRowForUser(user) {
+ const details = [];
+
+ const fullName = Utils.getFullName(user);
+ if (fullName) {
+ details.push(
+
+ {fullName}
+
+ );
+ }
+
+ if (user.nickname) {
+ const separator = fullName ? ' - ' : '';
+ details.push(
+
+ {separator + user.nickname}
+
+ );
+ }
+
+ let joinButton;
+ if (this.state.loadingDMChannel === user.id) {
+ joinButton = (
+
+ );
+ } else {
+ joinButton = (
+
+ );
+ }
+
+ return (
+
+
+

+
+
+
+ {user.username}
+
+
+ {details}
+
+
+
+ {joinButton}
+
+
+ );
}
render() {
- var directMessageItems = this.state.channels.map((channel, index) => {
- var badge = '';
- var titleClass = '';
- var handleClick = null;
+ if (!this.props.show) {
+ return null;
+ }
- if (channel.fake) {
- // It's a direct message channel that doesn't exist yet so let's create it now
- var otherUserId = utils.getUserIdFromChannelName(channel);
+ let users = this.state.users;
+ if (this.state.filter !== '') {
+ users = users.filter((user) => {
+ return user.username.indexOf(this.state.filter) !== -1 ||
+ user.first_name.indexOf(this.state.filter) !== -1 ||
+ user.last_name.indexOf(this.state.filter) !== -1 ||
+ user.nickname.indexOf(this.state.filter) !== -1;
+ });
+ }
- if (this.state.loadingDMChannel === index) {
- badge = (
-
- );
- }
+ const userEntries = users.map(this.createRowForUser);
- if (this.state.loadingDMChannel === -1) {
- handleClick = (e) => {
- e.preventDefault();
- this.setState({loadingDMChannel: index});
- this.handleJoinDirectChannel(channel);
+ if (userEntries.length === 0) {
+ userEntries.push({'No users found :('});
+ }
- Client.createDirectChannel(channel, otherUserId,
- (data) => {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
- this.setState({loadingDMChannel: -1});
- AsyncClient.getChannel(data.id);
- utils.switchChannel(data);
- },
- () => {
- this.setState({loadingDMChannel: -1});
- window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name;
- }
- );
- };
- }
- } else {
- if (channel.unread) {
- badge = {channel.unread};
- titleClass = 'unread-title';
- }
+ let memberString = 'Member';
+ if (users.length !== 1) {
+ memberString += 's';
+ }
- handleClick = (e) => {
- e.preventDefault();
- this.handleJoinDirectChannel(channel);
- utils.switchChannel(channel);
- $(React.findDOMNode(this.refs.modal)).modal('hide');
- };
- }
-
- return (
-
- {badge}{channel.display_name}
-
- );
- });
+ let count;
+ if (users.length === this.state.users.length) {
+ count = `${users.length} ${memberString}`;
+ } else {
+ count = `${users.length} ${memberString} of ${this.state.users.length} Total`;
+ }
return (
-
-
-
-
-
-
{'More Direct Messages'}
-
-
-
-
-
+
+ {'More Direct Messages'}
+
+
+
+
+ {count}
-
-
+
+
+
+
+
+
);
}
}
+
+MoreDirectChannels.propTypes = {
+ show: React.PropTypes.bool.isRequired,
+ onModalDismissed: React.PropTypes.func
+};
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 4911f17ef0..1308165a98 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -8,6 +8,7 @@ const Client = require('../utils/client.jsx');
const Constants = require('../utils/constants.jsx');
const PreferenceStore = require('../stores/preference_store.jsx');
const NewChannelFlow = require('./new_channel_flow.jsx');
+const MoreDirectChannels = require('./more_direct_channels.jsx');
const SearchBox = require('./search_bar.jsx');
const SidebarHeader = require('./sidebar_header.jsx');
const SocketStore = require('../stores/socket_store.jsx');
@@ -33,12 +34,19 @@ export default class Sidebar extends React.Component {
this.onResize = this.onResize.bind(this);
this.updateUnreadIndicators = this.updateUnreadIndicators.bind(this);
this.handleLeaveDirectChannel = this.handleLeaveDirectChannel.bind(this);
+
+ this.showNewChannelModal = this.showNewChannelModal.bind(this);
+ this.hideNewChannelModal = this.hideNewChannelModal.bind(this);
+ this.showMoreDirectChannelsModal = this.showMoreDirectChannelsModal.bind(this);
+ this.hideMoreDirectChannelsModal = this.hideMoreDirectChannelsModal.bind(this);
+
this.createChannelElement = this.createChannelElement.bind(this);
this.isLeaving = new Map();
const state = this.getStateFromStores();
- state.modal = '';
+ state.newChannelModalType = '';
+ state.showMoreDirectChannelsModal = false;
state.loadingDMChannel = -1;
this.state = state;
@@ -47,10 +55,11 @@ export default class Sidebar extends React.Component {
const members = ChannelStore.getAllMembers();
var teamMemberMap = UserStore.getActiveOnlyProfiles();
var currentId = ChannelStore.getCurrentId();
+ const currentUserId = UserStore.getCurrentId();
var teammates = [];
for (var id in teamMemberMap) {
- if (id === UserStore.getCurrentId()) {
+ if (id === currentUserId) {
continue;
}
teammates.push(teamMemberMap[id]);
@@ -58,22 +67,16 @@ export default class Sidebar extends React.Component {
const preferences = PreferenceStore.getPreferences(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
- // Create lists of all read and unread direct channels
var visibleDirectChannels = [];
- var hiddenDirectChannels = [];
+ var hiddenDirectChannelCount = 0;
for (var i = 0; i < teammates.length; i++) {
const teammate = teammates[i];
- if (teammate.id === UserStore.getCurrentId()) {
+ if (teammate.id === currentUserId) {
continue;
}
- var channelName = '';
- if (teammate.id > UserStore.getCurrentId()) {
- channelName = UserStore.getCurrentId() + '__' + teammate.id;
- } else {
- channelName = teammate.id + '__' + UserStore.getCurrentId();
- }
+ const channelName = Utils.getDirectChannelName(currentUserId, teammate.id);
let forceShow = false;
let channel = ChannelStore.getByName(channelName);
@@ -106,19 +109,18 @@ export default class Sidebar extends React.Component {
visibleDirectChannels.push(channel);
} else {
- hiddenDirectChannels.push(channel);
+ hiddenDirectChannelCount += 1;
}
}
visibleDirectChannels.sort(this.sortChannelsByDisplayName);
- hiddenDirectChannels.sort(this.sortChannelsByDisplayName);
return {
activeId: currentId,
channels: ChannelStore.getAll(),
members,
visibleDirectChannels,
- hiddenDirectChannels
+ hiddenDirectChannelCount
};
}
@@ -336,6 +338,20 @@ export default class Sidebar extends React.Component {
return a.display_name.localeCompare(b.display_name);
}
+ showNewChannelModal(type) {
+ this.setState({newChannelModalType: type});
+ }
+ hideNewChannelModal() {
+ this.setState({newChannelModalType: ''});
+ }
+
+ showMoreDirectChannelsModal() {
+ this.setState({showDirectChannelsModal: true});
+ }
+ hideMoreDirectChannelsModal() {
+ this.setState({showDirectChannelsModal: false});
+ }
+
createChannelElement(channel, index, arr, handleClose) {
var members = this.state.members;
var activeId = this.state.activeId;
@@ -532,25 +548,21 @@ export default class Sidebar extends React.Component {
head.appendChild(link);
var directMessageMore = null;
- if (this.state.hiddenDirectChannels.length > 0) {
+ if (this.state.hiddenDirectChannelCount > 0) {
directMessageMore = (
- {'More (' + this.state.hiddenDirectChannels.length + ')'}
+ {'More (' + this.state.hiddenDirectChannelCount + ')'}
);
}
let showChannelModal = false;
- if (this.state.modal !== '') {
+ if (this.state.newChannelModalType !== '') {
showChannelModal = true;
}
@@ -561,9 +573,14 @@ export default class Sidebar extends React.Component {
this.setState({modal: ''})}
+ channelType={this.state.newChannelModalType}
+ onModalDismissed={this.hideNewChannelModal}
/>
+
+
this.setState({modal: 'O'})}
+ onClick={this.showNewChannelModal.bind(this, 'O')}
>
{'+'}
@@ -632,7 +649,7 @@ export default class Sidebar extends React.Component {
this.setState({modal: 'P'})}
+ onClick={this.showNewChannelModal.bind(this, 'P')}
>
{'+'}
diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx
index 4d6d3fd15e..698213eef5 100644
--- a/web/react/pages/channel.jsx
+++ b/web/react/pages/channel.jsx
@@ -24,7 +24,6 @@ var TeamSettingsModal = require('../components/team_settings_modal.jsx');
var ChannelMembersModal = require('../components/channel_members.jsx');
var ChannelInviteModal = require('../components/channel_invite_modal.jsx');
var TeamMembersModal = require('../components/team_members.jsx');
-var DirectChannelModal = require('../components/more_direct_channels.jsx');
var ErrorBar = require('../components/error_bar.jsx');
var ErrorStore = require('../stores/error_store.jsx');
var ChannelLoader = require('../components/channel_loader.jsx');
@@ -155,11 +154,6 @@ function setupChannelPage(props) {
document.getElementById('more_channels_modal')
);
- React.render(
- ,
- document.getElementById('direct_channel_modal')
- );
-
React.render(
,
document.getElementById('post-list')
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 8f697a9c56..f93fe02e4c 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -911,6 +911,18 @@ export function isBrowserEdge() {
return window.naviagtor && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('edge') > -1;
}
+export function getDirectChannelName(id, otherId) {
+ let handle;
+
+ if (otherId > id) {
+ handle = id + '__' + otherId;
+ } else {
+ handle = otherId + '__' + id;
+ }
+
+ return handle;
+}
+
// Used to get the id of the other user from a DM channel
export function getUserIdFromChannelName(channel) {
var ids = channel.name.split('__');
diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss
index 90ea8ce2cd..b942a5a40a 100644
--- a/web/sass-files/sass/partials/_modal.scss
+++ b/web/sass-files/sass/partials/_modal.scss
@@ -329,3 +329,49 @@
}
}
}
+
+.modal-direct-channels {
+ .user-list {
+ list-style-type: none;
+ margin: 15px 0px 0px;
+ max-height: 600px;
+ padding: 0px;
+ overflow: auto;
+
+ li {
+ border-bottom: 1px solid #ddd;
+ height: 60px;
+ padding: 10px 0px;
+
+ .image-div {
+ padding: 0px;
+
+ .profile-image {
+ width: 40px;
+ height: 40px;
+ @include border-radius(20px);
+ }
+ }
+
+ .username {
+ font-weight: bold;
+ }
+
+ .nickname {
+ color: #888;
+ }
+
+ .btn-div {
+ padding: 0px;
+ .btn-message {
+ position: relative;
+ top: 5px;
+ }
+ }
+
+ &:last-child {
+ border-bottom: 0px;
+ }
+ }
+ }
+}