PLT-5604 Add/Remove members from pubic channels doesn't match the webapp functionality (#289)

* PLT-5604 Add/Remove members from pubic channels doesn't match the webapp functionality

* Review feedback

* Fix spelling of ChannelMembersTitle

* Use selector to consolidate auth logic for channel member mgmt
This commit is contained in:
Chris Duarte 2017-02-24 18:20:28 -08:00 committed by enahum
parent 80edba14da
commit 9e8fb26f4b
8 changed files with 53 additions and 55 deletions

View file

@ -31,7 +31,6 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
color: theme.centerChannelColor
},
textContainer: {
flex: 1,
flexDirection: 'row',
marginLeft: 5
},
@ -99,7 +98,7 @@ function MemberListRow(props) {
size={40}
/>
<View style={style.textContainer}>
<View style={{flexGrow: 1, flexDirection: 'column'}}>
<View style={{flexDirection: 'column'}}>
<Text style={style.displayName}>
{displayName}
</Text>

View file

@ -44,7 +44,7 @@ class ChannelInfo extends PureComponent {
currentChannelMemberCount: PropTypes.number,
isFavorite: PropTypes.bool.isRequired,
leaveChannelRequest: PropTypes.object.isRequired,
isAdmin: PropTypes.bool.isRequired,
canManageUsers: PropTypes.bool.isRequired,
actions: PropTypes.shape({
getChannelStats: PropTypes.func.isRequired,
goToChannelMembers: PropTypes.func.isRequired,
@ -143,7 +143,7 @@ class ChannelInfo extends PureComponent {
currentChannel,
currentChannelCreatorName,
currentChannelMemberCount,
isAdmin
canManageUsers
} = this.props;
return (
@ -180,15 +180,15 @@ class ChannelInfo extends PureComponent {
</View>
<ChannelInfoRow
action={this.props.actions.goToChannelMembers}
defaultMessage={(isAdmin && currentChannel.type !== Constants.DM_CHANNEL) ? 'Manage Members' : 'View Members'}
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
detail={currentChannelMemberCount}
icon='users'
textId={(isAdmin && currentChannel.type !== Constants.DM_CHANNEL) ? 'channel_header.manageMembers' : 'channel_header.viewMembers'}
textId={canManageUsers ? 'channel_header.manageMembers' : 'channel_header.viewMembers'}
/>
<View style={style.separatorContainer}>
<View style={style.separator}/>
</View>
{isAdmin && this.renderLeaveOrDeleteChannelRow() &&
{canManageUsers && this.renderLeaveOrDeleteChannelRow() &&
<View>
<ChannelInfoRow
action={this.props.actions.goToChannelAddMembers}

View file

@ -8,9 +8,9 @@ import navigationSceneConnect from '../navigationSceneConnect';
import {goToChannelMembers, goToChannelAddMembers, goBack} from 'app/actions/navigation';
import {getChannelStats, deleteChannel} from 'service/actions/channels';
import {markFavorite, unmarkFavorite, leaveChannel} from 'app/actions/views/channel';
import {getCurrentChannel, getCurrentChannelStats, getChannelsByCategory} from 'service/selectors/entities/channels';
import {getCurrentChannel, getCurrentChannelStats, getChannelsByCategory, canManageChannelMembers} from 'service/selectors/entities/channels';
import {getTheme} from 'service/selectors/entities/preferences';
import {getUser, getCurrentUserRoles} from 'service/selectors/entities/users';
import {getUser} from 'service/selectors/entities/users';
import ChannelInfo from './channel_info';
@ -22,8 +22,6 @@ function mapStateToProps(state, ownProps) {
const favoriteChannels = getChannelsByCategory(state).favoriteChannels.map((f) => f.id);
const isFavorite = favoriteChannels.indexOf(currentChannel.id) > -1;
const leaveChannelRequest = state.requests.channels.leaveChannel;
const currentUserRoles = getCurrentUserRoles(state);
const isAdmin = currentUserRoles.includes('_admin');
return {
...ownProps,
@ -34,7 +32,7 @@ function mapStateToProps(state, ownProps) {
isFavorite,
leaveChannelRequest,
theme: getTheme(state),
isAdmin
canManageUsers: canManageChannelMembers(state)
};
}

View file

@ -14,7 +14,6 @@ import MemberList from 'app/components/custom_list';
import {createMembersSections, loadingText} from 'app/utils/member_list';
import MemberListRow from 'app/components/custom_list/member_list_row';
import {displayUsername} from 'service/utils/user_utils';
import {Constants} from 'service/constants';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import ChannelMembersTitle from './channel_members_title';
@ -40,7 +39,7 @@ class ChannelMembers extends PureComponent {
currentTeam: PropTypes.object,
preferences: PropTypes.object,
requestStatus: PropTypes.string,
isAdmin: PropTypes.bool.isRequired,
canManageUsers: PropTypes.bool.isRequired,
subscribeToHeaderEvent: React.PropTypes.func,
unsubscribeFromHeaderEvent: React.PropTypes.func,
actions: PropTypes.shape({
@ -171,8 +170,7 @@ class ChannelMembers extends PureComponent {
}
render() {
const {currentChannel, isAdmin, theme} = this.props;
const canManage = (isAdmin && currentChannel.type !== Constants.DM_CHANNEL && currentChannel.name !== Constants.DEFAULT_CHANNEL);
const {canManageUsers, theme} = this.props;
const style = getStyleFromTheme(theme);
return (
@ -184,7 +182,7 @@ class ChannelMembers extends PureComponent {
preferences={this.props.preferences}
loading={this.props.requestStatus === 'started'}
loadingText={loadingText}
selectable={canManage}
selectable={canManageUsers}
onRowSelect={this.handleRowSelect}
renderRow={this.renderMemberRow}
createSections={createMembersSections}

View file

@ -7,19 +7,16 @@ import navigationSceneConnect from '../navigationSceneConnect';
import {goBack} from 'app/actions/navigation';
import {handleRemoveChannelMembers} from 'app/actions/views/channel_members';
import {getCurrentChannel, getCurrentChannelStats} from 'service/selectors/entities/channels';
import {getCurrentChannel, getCurrentChannelStats, canManageChannelMembers} from 'service/selectors/entities/channels';
import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences';
import {getCurrentTeam} from 'service/selectors/entities/teams';
import {getProfilesInCurrentChannel, getCurrentUserRoles} from 'service/selectors/entities/users';
import {getProfilesInCurrentChannel} from 'service/selectors/entities/users';
import {getProfilesInChannel} from 'service/actions/users';
import ChannelMembers from './channel_members';
function mapStateToProps(state) {
const currentChannelMemberCount = getCurrentChannelStats(state) && getCurrentChannelStats(state).member_count;
const currentUserRoles = getCurrentUserRoles(state);
const isAdmin = currentUserRoles.includes('_admin');
return {
theme: getTheme(state),
@ -30,7 +27,7 @@ function mapStateToProps(state) {
currentTeam: getCurrentTeam(state),
preferences: getMyPreferences(state),
requestStatus: state.requests.users.getProfilesInChannel.status,
isAdmin
canManageUsers: canManageChannelMembers(state)
};
}

View file

@ -3,51 +3,42 @@
import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {
View
} from 'react-native';
import {View} from 'react-native';
import {getCurrentUserRoles} from 'service/selectors/entities/users';
import {getCurrentChannel} from 'service/selectors/entities/channels';
import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels';
import {getTheme} from 'service/selectors/entities/preferences';
import {Constants} from 'service/constants';
import FormattedText from 'app/components/formatted_text';
function ChannelMemberTitle(props) {
const {currentChannel, isAdmin} = props;
const manage = (isAdmin && currentChannel.type !== Constants.DM_CHANNEL && currentChannel.name !== Constants.DEFAULT_CHANNEL);
function ChannelMembersTitle(props) {
const {canManageUsers} = props;
return (
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1, marginHorizontal: 50}}>
<FormattedText
id={manage ? 'channel_header.manageMembers' : 'channel_header.viewMembers'}
defaultMessage={manage ? 'Manage Members' : 'View Members'}
id={canManageUsers ? 'channel_header.manageMembers' : 'channel_header.viewMembers'}
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
style={{color: props.theme.sidebarHeaderTextColor, fontSize: 15, fontWeight: 'bold', textAlign: 'center'}}
/>
</View>
);
}
ChannelMemberTitle.propTypes = {
isAdmin: PropTypes.bool,
ChannelMembersTitle.propTypes = {
canManageUsers: PropTypes.bool.isRequired,
currentChannel: PropTypes.object.isRequired,
theme: PropTypes.object
theme: PropTypes.object.isRequired
};
ChannelMemberTitle.defaultProps = {
ChannelMembersTitle.defaultProps = {
theme: {}
};
function mapStateToProps(state) {
const currentUserRoles = getCurrentUserRoles(state);
const isAdmin = currentUserRoles.includes('_admin');
return {
isAdmin,
canManageUsers: canManageChannelMembers(state),
currentChannel: getCurrentChannel(state),
theme: getTheme(state)
};
}
export default connect(mapStateToProps)(ChannelMemberTitle);
export default connect(mapStateToProps)(ChannelMembersTitle);

View file

@ -10,14 +10,12 @@ import {
import FormattedText from 'app/components/formatted_text';
import {getCurrentUserRoles} from 'service/selectors/entities/users';
import {getCurrentChannel} from 'service/selectors/entities/channels';
import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels';
import {getTheme} from 'service/selectors/entities/preferences';
import {Constants} from 'service/constants';
function RemoveMemberButton(props) {
const {currentChannel, isAdmin} = props;
if (!isAdmin || currentChannel.type === Constants.DM_CHANNEL || currentChannel.name === Constants.DEFAULT_CHANNEL) {
const {canManageUsers} = props;
if (!canManageUsers) {
return null;
}
@ -39,7 +37,7 @@ function RemoveMemberButton(props) {
RemoveMemberButton.propTypes = {
emitter: PropTypes.func.isRequired,
isAdmin: PropTypes.bool.isRequired,
canManageUsers: PropTypes.bool.isRequired,
currentChannel: PropTypes.object.isRequired,
theme: PropTypes.object
};
@ -49,11 +47,8 @@ RemoveMemberButton.defaultProps = {
};
function mapStateToProps(state) {
const currentUserRoles = getCurrentUserRoles(state);
const isAdmin = currentUserRoles.includes('_admin');
return {
isAdmin,
canManageUsers: canManageChannelMembers(state),
currentChannel: getCurrentChannel(state),
theme: getTheme(state)
};

View file

@ -2,7 +2,8 @@
// See License.txt for license information.
import {createSelector} from 'reselect';
import {getCurrentTeamId} from 'service/selectors/entities/teams';
import {getCurrentTeamId, getCurrentTeamMembership} from 'service/selectors/entities/teams';
import {getCurrentUserId, getUsers} from 'service/selectors/entities/users';
import {buildDisplayableChannelList, getNotMemberChannels, completeDirectChannelInfo} from 'service/utils/channel_utils';
import {Constants} from 'service/constants';
@ -150,3 +151,22 @@ export const getAutocompleteChannelWithSections = createSelector(
return channels;
}
);
export const canManageChannelMembers = createSelector(
getCurrentChannel,
getCurrentChannelMembership,
getCurrentTeamMembership,
getUsers,
getCurrentUserId,
(channel, channelMembership, teamMembership, allUsers, currentUserId) => {
const user = allUsers[currentUserId];
const roles = `${channelMembership.roles} ${teamMembership.roles} ${user.roles}`;
if (channel.type === Constants.DM_CHANNEL || channel.name === Constants.DEFAULT_CHANNEL) {
return false;
}
if (channel.type === Constants.OPEN_CHANNEL) {
return true;
}
return roles.includes('_admin');
}
);