summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webapp/actions/channel_actions.jsx3
-rw-r--r--webapp/actions/user_actions.jsx108
-rw-r--r--webapp/client/client.jsx10
-rw-r--r--webapp/components/channel_members_dropdown.jsx180
-rw-r--r--webapp/components/channel_members_modal.jsx153
-rw-r--r--webapp/components/member_list_channel.jsx173
-rw-r--r--webapp/i18n/en.json8
-rw-r--r--webapp/stores/channel_store.jsx49
-rw-r--r--webapp/utils/constants.jsx1
-rw-r--r--webapp/utils/utils.jsx8
10 files changed, 543 insertions, 150 deletions
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx
index 71f5abf84..6cf8449f0 100644
--- a/webapp/actions/channel_actions.jsx
+++ b/webapp/actions/channel_actions.jsx
@@ -108,6 +108,9 @@ export function removeUserFromChannel(channelId, userId, success, error) {
}
UserStore.emitInChannelChange();
+ ChannelStore.removeMemberInChannel(channelId, userId);
+ ChannelStore.emitChange();
+
if (success) {
success(data);
}
diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx
index a5cef65d8..588e77a0d 100644
--- a/webapp/actions/user_actions.jsx
+++ b/webapp/actions/user_actions.jsx
@@ -58,6 +58,34 @@ export function loadProfilesAndTeamMembers(offset, limit, teamId = TeamStore.get
);
}
+export function loadProfilesAndTeamMembersAndChannelMembers(offset, limit, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
+ Client.getProfilesInChannel(
+ channelId,
+ offset,
+ limit,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_PROFILES_IN_CHANNEL,
+ profiles: data,
+ channel_id: channelId,
+ offset,
+ count: Object.keys(data).length
+ });
+
+ loadTeamMembersForProfilesMap(
+ data,
+ teamId,
+ () => {
+ loadChannelMembersForProfilesMap(data, channelId, success, error);
+ loadStatusesForProfilesMap(data);
+ });
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getProfilesInChannel');
+ }
+ );
+}
+
export function loadTeamMembersForProfilesMap(profiles, teamId = TeamStore.getCurrentId(), success, error) {
const membersToLoad = {};
for (const pid in profiles) {
@@ -132,6 +160,86 @@ function loadTeamMembersForProfiles(userIds, teamId, success, error) {
);
}
+export function loadChannelMembersForProfilesMap(profiles, channelId = ChannelStore.getCurrentId(), success, error) {
+ const membersToLoad = {};
+ for (const pid in profiles) {
+ if (!profiles.hasOwnProperty(pid)) {
+ continue;
+ }
+
+ if (!ChannelStore.hasActiveMemberInChannel(channelId, pid)) {
+ membersToLoad[pid] = true;
+ }
+ }
+
+ const list = Object.keys(membersToLoad);
+ if (list.length === 0) {
+ if (success) {
+ success({});
+ }
+ return;
+ }
+
+ loadChannelMembersForProfiles(list, channelId, success, error);
+}
+
+export function loadTeamMembersAndChannelMembersForProfilesList(profiles, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
+ loadTeamMembersForProfilesList(profiles, teamId, () => {
+ loadChannelMembersForProfilesList(profiles, channelId, success, error);
+ }, error);
+}
+
+export function loadChannelMembersForProfilesList(profiles, channelId = ChannelStore.getCurrentId(), success, error) {
+ const membersToLoad = {};
+ for (let i = 0; i < profiles.length; i++) {
+ const pid = profiles[i].id;
+
+ if (!ChannelStore.hasActiveMemberInChannel(channelId, pid)) {
+ membersToLoad[pid] = true;
+ }
+ }
+
+ const list = Object.keys(membersToLoad);
+ if (list.length === 0) {
+ if (success) {
+ success({});
+ }
+ return;
+ }
+
+ loadChannelMembersForProfiles(list, channelId, success, error);
+}
+
+function loadChannelMembersForProfiles(userIds, channelId, success, error) {
+ Client.getChannelMembersByIds(
+ channelId,
+ userIds,
+ (data) => {
+ const memberMap = {};
+ for (let i = 0; i < data.length; i++) {
+ memberMap[data[i].user_id] = data[i];
+ }
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECEIVED_MEMBERS_IN_CHANNEL,
+ channel_id: channelId,
+ channel_members: memberMap
+ });
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ AsyncClient.dispatchError(err, 'getChannelMembersByIds');
+
+ if (error) {
+ error(err);
+ }
+ }
+ );
+}
+
function populateDMChannelsWithProfiles(userIds) {
const currentUserId = UserStore.getCurrentId();
diff --git a/webapp/client/client.jsx b/webapp/client/client.jsx
index ba42d7ae8..5104f34e2 100644
--- a/webapp/client/client.jsx
+++ b/webapp/client/client.jsx
@@ -1496,6 +1496,16 @@ export default class Client {
end(this.handleResponse.bind(this, 'getChannelMember', success, error));
}
+ getChannelMembersByIds(channelId, userIds, success, error) {
+ request.
+ post(`${this.getChannelNeededRoute(channelId)}/members/ids`).
+ set(this.defaultHeaders).
+ type('application/json').
+ accept('application/json').
+ send(userIds).
+ end(this.handleResponse.bind(this, 'getChannelMembersByIds', success, error));
+ }
+
addChannelMember(channelId, userId, success, error) {
request.
post(`${this.getChannelNeededRoute(channelId)}/add`).
diff --git a/webapp/components/channel_members_dropdown.jsx b/webapp/components/channel_members_dropdown.jsx
new file mode 100644
index 000000000..82aaf0612
--- /dev/null
+++ b/webapp/components/channel_members_dropdown.jsx
@@ -0,0 +1,180 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import ChannelStore from 'stores/channel_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+
+import {removeUserFromChannel} from 'actions/channel_actions.jsx';
+
+import * as AsyncClient from 'utils/async_client.jsx';
+import * as Utils from 'utils/utils.jsx';
+
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+
+export default class ChannelMembersDropdown extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleRemoveFromChannel = this.handleRemoveFromChannel.bind(this);
+
+ this.state = {
+ serverError: null,
+ user: null,
+ role: null
+ };
+ }
+
+ handleRemoveFromChannel() {
+ removeUserFromChannel(
+ this.props.channel.id,
+ this.props.user.id,
+ () => {
+ AsyncClient.getChannelStats(this.props.channel.id);
+ },
+ (err) => {
+ this.setState({serverError: err.message});
+ }
+ );
+ }
+
+ // Checks if the user this menu is for is a channel admin or not.
+ isChannelAdmin() {
+ if (Utils.isChannelAdmin(this.props.channelMember.roles)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // Checks if the current user has the power to change the roles of this member.
+ canChangeMemberRoles() {
+ if (UserStore.isSystemAdminForCurrentUser()) {
+ return true;
+ } else if (TeamStore.isTeamAdminForCurrentTeam()) {
+ return true;
+ } else if (ChannelStore.isChannelAdminForCurrentChannel()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // Checks if the current user has the power to remove this member from the channel.
+ canRemoveMember() {
+ // TODO: This will be implemented as part of PLT-5047.
+ return true;
+ }
+
+ render() {
+ let serverError = null;
+ if (this.state.serverError) {
+ serverError = (
+ <div className='has-error'>
+ <label className='has-error control-label'>{this.state.serverError}</label>
+ </div>
+ );
+ }
+
+ if (this.props.user.id === UserStore.getCurrentId()) {
+ return null;
+ }
+
+ if (this.canChangeMemberRoles()) {
+ let role = (
+ <FormattedMessage
+ id='channel_members_dropdown.channel_member'
+ defaultMessage='Channel Member'
+ />
+ );
+
+ if (this.isChannelAdmin()) {
+ role = (
+ <FormattedMessage
+ id='channel_members_dropdown.channel_admin'
+ defaultMessage='Channel Admin'
+ />
+ );
+ }
+
+ let removeFromChannel = null;
+ if (this.canRemoveMember()) {
+ removeFromChannel = (
+ <li role='presentation'>
+ <a
+ role='menuitem'
+ href='#'
+ onClick={this.handleRemoveFromChannel}
+ >
+ <FormattedMessage
+ id='channel_members_dropdown.remove_from_channel'
+ defaultMessage='Remove From Channel'
+ />
+ </a>
+ </li>
+ );
+ }
+
+ return (
+ <div className='dropdown member-drop'>
+ <a
+ href='#'
+ className='dropdown-toggle theme'
+ type='button'
+ data-toggle='dropdown'
+ aria-expanded='true'
+ >
+ <span>{role} </span>
+ <span className='fa fa-chevron-down'/>
+ </a>
+ <ul
+ className='dropdown-menu member-menu'
+ role='menu'
+ >
+ {removeFromChannel}
+ </ul>
+ {serverError}
+ </div>
+ );
+ } else if (this.canRemoveMember()) {
+ return (
+ <button
+ type='button'
+ className='btn btn-danger btn-message'
+ onClick={this.handleRemoveFromChannel}
+ >
+ <FormattedMessage
+ id='channel_members_dropdown.remove_member'
+ defaultMessage='Remove Member'
+ />
+ </button>
+ );
+ } else if (this.isChannelAdmin()) {
+ return (
+ <div>
+ <FormattedMessage
+ id='channel_members_dropdown.channel_admin'
+ defaultMessage='Channel Admin'
+ />
+ </div>
+ );
+ }
+
+ return (
+ <div>
+ <FormattedMessage
+ id='channel_members_dropdown.channel_member'
+ defaultMessage='Channel Member'
+ />
+ </div>
+ );
+ }
+}
+
+ChannelMembersDropdown.propTypes = {
+ channel: React.PropTypes.object.isRequired,
+ user: React.PropTypes.object.isRequired,
+ teamMember: React.PropTypes.object.isRequired,
+ channelMember: React.PropTypes.object.isRequired
+};
diff --git a/webapp/components/channel_members_modal.jsx b/webapp/components/channel_members_modal.jsx
index 351efed96..96d90e5cc 100644
--- a/webapp/components/channel_members_modal.jsx
+++ b/webapp/components/channel_members_modal.jsx
@@ -1,170 +1,29 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import SearchableUserList from './searchable_user_list.jsx';
-import LoadingScreen from './loading_screen.jsx';
-
-import UserStore from 'stores/user_store.jsx';
-import ChannelStore from 'stores/channel_store.jsx';
-import TeamStore from 'stores/team_store.jsx';
-
-import {searchUsers} from 'actions/user_actions.jsx';
-import {removeUserFromChannel} from 'actions/channel_actions.jsx';
-
-import * as AsyncClient from 'utils/async_client.jsx';
-import * as UserAgent from 'utils/user_agent.jsx';
-import Constants from 'utils/constants.jsx';
+import MemberListChannel from './member_list_channel.jsx';
import React from 'react';
import {Modal} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
-const USERS_PER_PAGE = 50;
-
export default class ChannelMembersModal extends React.Component {
constructor(props) {
super(props);
- this.onChange = this.onChange.bind(this);
- this.onStatusChange = this.onStatusChange.bind(this);
this.onHide = this.onHide.bind(this);
- this.handleRemove = this.handleRemove.bind(this);
- this.createRemoveMemberButton = this.createRemoveMemberButton.bind(this);
- this.search = this.search.bind(this);
- this.nextPage = this.nextPage.bind(this);
-
- this.term = '';
- this.searchTimeoutId = 0;
-
- const stats = ChannelStore.getStats(props.channel.id);
this.state = {
- users: [],
- total: stats.member_count,
- show: true,
- search: false,
- statusChange: false
+ channel: this.props.channel,
+ show: true
};
}
- componentDidMount() {
- ChannelStore.addStatsChangeListener(this.onChange);
- UserStore.addInChannelChangeListener(this.onChange);
- UserStore.addStatusesChangeListener(this.onStatusChange);
-
- AsyncClient.getProfilesInChannel(this.props.channel.id, 0);
- }
-
- componentWillUnmount() {
- ChannelStore.removeStatsChangeListener(this.onChange);
- UserStore.removeInChannelChangeListener(this.onChange);
- UserStore.removeStatusesChangeListener(this.onStatusChange);
- }
-
- onChange(force) {
- if (this.state.search && !force) {
- this.search(this.term);
- return;
- }
-
- const stats = ChannelStore.getStats(this.props.channel.id);
- this.setState({
- users: UserStore.getProfileListInChannel(this.props.channel.id),
- total: stats.member_count
- });
- }
-
- onStatusChange() {
- // Initiate a render to pick up on new statuses
- this.setState({
- statusChange: !this.state.statusChange
- });
- }
-
onHide() {
this.setState({show: false});
}
- handleRemove(user) {
- const userId = user.id;
-
- removeUserFromChannel(
- this.props.channel.id,
- userId,
- null,
- (err) => {
- this.setState({inviteError: err.message});
- }
- );
- }
-
- createRemoveMemberButton({user}) {
- if (user.id === UserStore.getCurrentId()) {
- return null;
- }
-
- return (
- <button
- type='button'
- className='btn btn-primary btn-message'
- onClick={this.handleRemove.bind(this, user)}
- >
- <FormattedMessage
- id='channel_members_modal.remove'
- defaultMessage='Remove'
- />
- </button>
- );
- }
-
- nextPage(page) {
- AsyncClient.getProfilesInChannel(this.props.channel.id, (page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
- }
-
- search(term) {
- this.term = term;
-
- if (term === '') {
- this.onChange(true);
- this.setState({search: false});
- return;
- }
-
- clearTimeout(this.searchTimeoutId);
-
- this.searchTimeoutId = setTimeout(
- () => {
- searchUsers(
- term,
- TeamStore.getCurrentId(),
- {in_channel_id: this.props.channel.id},
- (users) => {
- this.setState({search: true, users});
- }
- );
- },
- Constants.SEARCH_TIMEOUT_MILLISECONDS
- );
- }
-
render() {
- let content;
- if (this.state.loading) {
- content = (<LoadingScreen/>);
- } else {
- content = (
- <SearchableUserList
- users={this.state.users}
- usersPerPage={USERS_PER_PAGE}
- total={this.state.total}
- nextPage={this.nextPage}
- search={this.search}
- actions={[this.createRemoveMemberButton]}
- focusOnMount={!UserAgent.isMobile()}
- />
- );
- }
-
return (
<div>
<Modal
@@ -177,7 +36,7 @@ export default class ChannelMembersModal extends React.Component {
<Modal.Title>
<span className='name'>{this.props.channel.display_name}</span>
<FormattedMessage
- id='channel_memebers_modal.members'
+ id='channel_members_modal.members'
defaultMessage=' Members'
/>
</Modal.Title>
@@ -198,7 +57,9 @@ export default class ChannelMembersModal extends React.Component {
<Modal.Body
ref='modalBody'
>
- {content}
+ <MemberListChannel
+ channel={this.props.channel}
+ />
</Modal.Body>
</Modal>
</div>
diff --git a/webapp/components/member_list_channel.jsx b/webapp/components/member_list_channel.jsx
new file mode 100644
index 000000000..75ecd8172
--- /dev/null
+++ b/webapp/components/member_list_channel.jsx
@@ -0,0 +1,173 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import ChannelMembersDropdown from 'components/channel_members_dropdown.jsx';
+import SearchableUserList from 'components/searchable_user_list.jsx';
+
+import ChannelStore from 'stores/channel_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+
+import {searchUsers, loadProfilesAndTeamMembersAndChannelMembers, loadTeamMembersAndChannelMembersForProfilesList} from 'actions/user_actions.jsx';
+import {getChannelStats} from 'utils/async_client.jsx';
+
+import Constants from 'utils/constants.jsx';
+
+import * as UserAgent from 'utils/user_agent.jsx';
+
+import React from 'react';
+
+const USERS_PER_PAGE = 50;
+
+export default class MemberListChannel extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onChange = this.onChange.bind(this);
+ this.onStatsChange = this.onStatsChange.bind(this);
+ this.search = this.search.bind(this);
+ this.loadComplete = this.loadComplete.bind(this);
+
+ this.searchTimeoutId = 0;
+
+ const stats = ChannelStore.getCurrentStats();
+
+ this.state = {
+ users: UserStore.getProfileListInChannel(),
+ teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
+ channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()),
+ total: stats.member_count,
+ search: false,
+ term: '',
+ loading: true
+ };
+ }
+
+ componentDidMount() {
+ UserStore.addInTeamChangeListener(this.onChange);
+ UserStore.addStatusesChangeListener(this.onChange);
+ TeamStore.addChangeListener(this.onChange);
+ ChannelStore.addChangeListener(this.onChange);
+ ChannelStore.addStatsChangeListener(this.onStatsChange);
+
+ loadProfilesAndTeamMembersAndChannelMembers(0, Constants.PROFILE_CHUNK_SIZE, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
+ getChannelStats(ChannelStore.getCurrentId());
+ }
+
+ componentWillUnmount() {
+ UserStore.removeInTeamChangeListener(this.onChange);
+ UserStore.removeStatusesChangeListener(this.onChange);
+ TeamStore.removeChangeListener(this.onChange);
+ ChannelStore.removeChangeListener(this.onChange);
+ ChannelStore.removeStatsChangeListener(this.onStatsChange);
+ }
+
+ loadComplete() {
+ this.setState({loading: false});
+ }
+
+ onChange(force) {
+ if (this.state.search && !force) {
+ return;
+ } else if (this.state.search) {
+ this.search(this.state.term);
+ return;
+ }
+
+ this.setState({
+ users: UserStore.getProfileListInChannel(),
+ teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
+ channelMembers: Object.assign({}, ChannelStore.getMembersInChannel())
+ });
+ }
+
+ onStatsChange() {
+ const stats = ChannelStore.getCurrentStats();
+ this.setState({total: stats.member_count});
+ }
+
+ nextPage(page) {
+ loadProfilesAndTeamMembersAndChannelMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
+ }
+
+ search(term) {
+ if (term === '') {
+ this.setState({
+ search: false,
+ term,
+ users: UserStore.getProfileListInChannel(),
+ teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
+ channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
+ });
+ return;
+ }
+
+ clearTimeout(this.searchTimeoutId);
+
+ this.searchTimeoutId = setTimeout(
+ () => {
+ searchUsers(
+ term,
+ TeamStore.getCurrentId(),
+ {},
+ (users) => {
+ this.setState({
+ loading: true,
+ search: true,
+ users,
+ term,
+ teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
+ channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
+ });
+ loadTeamMembersAndChannelMembersForProfilesList(users, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
+ }
+ );
+ },
+ Constants.SEARCH_TIMEOUT_MILLISECONDS
+ );
+ }
+
+ render() {
+ const teamMembers = this.state.teamMembers;
+ const channelMembers = this.state.channelMembers;
+ const users = this.state.users;
+ const actionUserProps = {};
+
+ let usersToDisplay;
+ if (this.state.loading) {
+ usersToDisplay = null;
+ } else {
+ usersToDisplay = [];
+
+ for (let i = 0; i < users.length; i++) {
+ const user = users[i];
+
+ if (teamMembers[user.id] && channelMembers[user.id]) {
+ usersToDisplay.push(user);
+ actionUserProps[user.id] = {
+ channel: this.props.channel,
+ teamMember: teamMembers[user.id],
+ channelMember: channelMembers[user.id]
+ };
+ }
+ }
+ }
+
+ return (
+ <SearchableUserList
+ users={usersToDisplay}
+ usersPerPage={USERS_PER_PAGE}
+ total={this.state.total}
+ nextPage={this.nextPage}
+ search={this.search}
+ actions={[ChannelMembersDropdown]}
+ actionUserProps={actionUserProps}
+ focusOnMount={!UserAgent.isMobile()}
+ />
+ );
+ }
+}
+
+MemberListChannel.propTypes = {
+ channel: React.PropTypes.object.isRequired
+};
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index 6584c634a..942ab62f3 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -1082,10 +1082,12 @@
"channel_loader.uploadedFile": " uploaded a file",
"channel_loader.uploadedImage": " uploaded an image",
"channel_loader.wrote": " wrote: ",
+ "channel_members_dropdown.channel_admin": "Channel Admin",
+ "channel_members_dropdown.channel_member": "Channel Member",
+ "channel_members_dropdown.remove_from_channel": "Remove From Channel",
+ "channel_members_dropdown.remove_member": "Remove Member",
"channel_members_modal.addNew": " Add New Members",
- "channel_members_modal.close": "Close",
- "channel_members_modal.remove": "Remove",
- "channel_memebers_modal.members": " Members",
+ "channel_members_modal.members": " Members",
"channel_modal.cancel": "Cancel",
"channel_modal.channel": "Channel",
"channel_modal.createNew": "Create New ",
diff --git a/webapp/stores/channel_store.jsx b/webapp/stores/channel_store.jsx
index c93edf7f4..c1922d3a6 100644
--- a/webapp/stores/channel_store.jsx
+++ b/webapp/stores/channel_store.jsx
@@ -5,6 +5,7 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
var Utils;
import {ActionTypes, Constants} from 'utils/constants.jsx';
@@ -25,6 +26,7 @@ class ChannelStoreClass extends EventEmitter {
this.currentId = null;
this.postMode = this.POST_MODE_CHANNEL;
this.channels = [];
+ this.members_in_channel = {};
this.myChannelMembers = {};
this.moreChannels = {};
this.stats = {};
@@ -241,6 +243,29 @@ class ChannelStoreClass extends EventEmitter {
return this.myChannelMembers;
}
+ saveMembersInChannel(channelId = this.getCurrentId(), members) {
+ const oldMembers = this.members_in_channel[channelId] || {};
+ this.members_in_channel[channelId] = Object.assign({}, oldMembers, members);
+ }
+
+ removeMemberInChannel(channelId = this.getCurrentId(), userId) {
+ if (this.members_in_channel[channelId]) {
+ Reflect.deleteProperty(this.members_in_channel[channelId], userId);
+ }
+ }
+
+ getMembersInChannel(channelId = this.getCurrentId()) {
+ return Object.assign({}, this.members_in_channel[channelId]) || {};
+ }
+
+ hasActiveMemberInChannel(channelId = this.getCurrentId(), userId) {
+ if (this.members_in_channel[channelId] && this.members_in_channel[channelId][userId]) {
+ return true;
+ }
+
+ return false;
+ }
+
storeMoreChannels(channels, teamId = TeamStore.getCurrentId()) {
const newChannels = {};
for (let i = 0; i < channels.length; i++) {
@@ -343,6 +368,25 @@ class ChannelStoreClass extends EventEmitter {
return channelNamesMap;
}
+
+ isChannelAdminForCurrentChannel() {
+ return this.isChannelAdmin(UserStore.getCurrentId(), this.getCurrentId());
+ }
+
+ isChannelAdmin(userId, channelId) {
+ if (!Utils) {
+ Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
+ }
+
+ const channelMembers = this.getMembersInChannel(channelId);
+ const channelMember = channelMembers[userId];
+
+ if (channelMember) {
+ return Utils.isChannelAdmin(channelMember.roles);
+ }
+
+ return false;
+ }
}
var ChannelStore = new ChannelStoreClass();
@@ -409,7 +453,10 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
ChannelStore.storeMoreChannels(action.channels);
ChannelStore.emitChange();
break;
-
+ case ActionTypes.RECEIVED_MEMBERS_IN_CHANNEL:
+ ChannelStore.saveMembersInChannel(action.channel_id, action.channel_members);
+ ChannelStore.emitChange();
+ break;
case ActionTypes.RECEIVED_CHANNEL_STATS:
var stats = Object.assign({}, ChannelStore.getStats());
stats[action.stats.channel_id] = action.stats;
diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx
index af099d4a0..c8ac74a82 100644
--- a/webapp/utils/constants.jsx
+++ b/webapp/utils/constants.jsx
@@ -74,6 +74,7 @@ export const ActionTypes = keyMirror({
RECEIVED_MORE_CHANNELS: null,
RECEIVED_CHANNEL_STATS: null,
RECEIVED_MY_CHANNEL_MEMBERS: null,
+ RECEIVED_MEMBERS_IN_CHANNEL: null,
FOCUS_POST: null,
RECEIVED_POSTS: null,
diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx
index e7ed9567b..9654ff605 100644
--- a/webapp/utils/utils.jsx
+++ b/webapp/utils/utils.jsx
@@ -54,6 +54,14 @@ export function isInRole(roles, inRole) {
return false;
}
+export function isChannelAdmin(roles) {
+ if (isInRole(roles, 'channel_admin')) {
+ return true;
+ }
+
+ return false;
+}
+
export function isAdmin(roles) {
if (isInRole(roles, 'team_admin')) {
return true;