[NEW] Remove member from team (#3117)
* Added Create Team * Added actionTypes, actions, ENG strings for Teams and updated NewMessageView * Added createTeam sagas, createTeam reducer, new Team string and update CreateChannelView * Remove unnecessary actionTypes, reducers and sagas, e2e tests and navigation to team view * Minor tweaks * Show TeamChannelsView only if joined the team * Minor tweak * Added AddChannelTeamView * Added permissions, translations strings for teams, deleteTeamRoom and addTeamRooms, AddExistingChannelView, updated CreateChannelView, TeamChannelsView * Refactor touch component and update removeRoom and deleteRoom methods * Minor tweaks * Minor tweaks for removing channels and addExistingChannelView * Added missing events and fixed channels list * Minor tweaks for refactored touch component * Added SelectListView and logic for leaving team * Added addTeamMember and removeTeamMember * Minor tweak * Minor tweak * Minor tweaks * Remove unnecesary changes, update TeamChannelsView, AddExistingChannelView, AddChannelTeamView, createChannel, goRoom and Touchable * Remove unnecesary prop * Add screens to ModalStack, events, autoJoin, update createChannel, addRoomsToTeam and Touchable * Minor tweak * Update loadMessagesForRoom.js * Updated schema, tag component, touch, AddChannelTeamView, AddExistingChannelView, ActionSheet Item * Fix unnecessary changes * Add i18n, update createChannel, AddExistingChannelTeamView, AddChannelTeamView, RightButton and TeamChannelsView * Updated styles, added tag story * Minor tweak * Minor tweaks * Auto-join tweak * Minor tweaks * Minor tweak on search * Minor refactor to ListItem, add SelectListView to ModalStack, update handleLeaveTeam * Minor tweaks * Update SelectListView * Update handleLeaveTeam, remove unnecessary method, add story * Minor tweak * Minor visual tweaks * Update SelectListView.js * Update RoomMembersView * Updated SelectListView, RoomActionsView, leaveTeam method and string translations * Update SelectListVIew * Minor tweak * Update SelectListView * Minor tweak * Minor tweaks * Fix for List.Item subtitles being pushed down by title's flex * Minor tweaks * Update RoomActionsView * Use showConfirmationAlert and showErrorAlert * Remove addTeamMember, update removeTeamMember * Update Alert * Minor tweaks * Minor tweaks * Minor tweak * Update showActionSheet on RoomMembersView * Remove team main from query and move code around * Fetch roles * Update RoomMembersView and SelectListView * Updated leaveTeam and handleRemoveFromTeam * Fix validation * Remove unnecessary function * Added confirmationAlert for missing permissions case Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
17c28e0b1b
commit
6dcb9a51f1
|
@ -683,12 +683,9 @@
|
|||
"No_threads_following": "You are not following any threads",
|
||||
"No_threads_unread": "There are no unread threads",
|
||||
"Messagebox_Send_to_channel": "Send to channel",
|
||||
"Set_as_leader": "Set as leader",
|
||||
"Set_as_moderator": "Set as moderator",
|
||||
"Set_as_owner": "Set as owner",
|
||||
"Remove_as_leader": "Remove as leader",
|
||||
"Remove_as_moderator": "Remove as moderator",
|
||||
"Remove_as_owner": "Remove as owner",
|
||||
"Leader": "Leader",
|
||||
"Moderator": "Moderator",
|
||||
"Owner": "Owner",
|
||||
"Remove_from_room": "Remove from room",
|
||||
"Ignore": "Ignore",
|
||||
"Unignore": "Unignore",
|
||||
|
@ -732,9 +729,14 @@
|
|||
"Leave_Team": "Leave Team",
|
||||
"Select_Team_Channels": "Select the Team's channels you would like to leave.",
|
||||
"Cannot_leave": "Cannot leave",
|
||||
"Cannot_remove": "Cannot remove",
|
||||
"Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.",
|
||||
"last-owner-can-not-be-removed": "Last owner cannot be removed",
|
||||
"Removing_user_from_this_team": "You are removing {{user}} from this team",
|
||||
"Remove_User_Team_Channels": "Select the channels you want the user to be removed from.",
|
||||
"Remove_Member": "Remove Member",
|
||||
"leaving_team": "leaving team",
|
||||
"removing_team": "removing from team",
|
||||
"member-does-not-exist": "Member does not exist",
|
||||
"Load_More": "Load More",
|
||||
"Load_Newer": "Load Newer",
|
||||
|
|
|
@ -22,6 +22,7 @@ const PERMISSIONS = [
|
|||
'delete-p',
|
||||
'edit-message',
|
||||
'edit-room',
|
||||
'edit-team-member',
|
||||
'edit-team-channel',
|
||||
'force-delete-message',
|
||||
'mute-user',
|
||||
|
|
|
@ -778,10 +778,22 @@ const RocketChat = {
|
|||
// RC 3.13.0
|
||||
return this.post('teams.leave', { teamName, rooms });
|
||||
},
|
||||
removeTeamMember({
|
||||
teamId, teamName, userId, rooms
|
||||
}) {
|
||||
// RC 3.13.0
|
||||
return this.post('teams.removeMember', {
|
||||
teamId, teamName, userId, rooms
|
||||
});
|
||||
},
|
||||
updateTeamRoom({ roomId, isDefault }) {
|
||||
// RC 3.13.0
|
||||
return this.post('teams.updateRoom', { roomId, isDefault });
|
||||
},
|
||||
teamListRoomsOfUser({ teamId, userId }) {
|
||||
// RC 3.13.0
|
||||
return this.sdk.get('teams.listRoomsOfUser', { teamId, userId });
|
||||
},
|
||||
joinRoom(roomId, joinCode, type) {
|
||||
// TODO: join code
|
||||
// RC 0.48.0
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { compareServerVersion, methods } from '../../lib/utils';
|
||||
|
||||
import Touch from '../../utils/touch';
|
||||
|
@ -433,14 +432,15 @@ class RoomActionsView extends React.Component {
|
|||
const { navigation } = this.props;
|
||||
|
||||
try {
|
||||
const db = database.active;
|
||||
const subCollection = db.get('subscriptions');
|
||||
const teamChannels = await subCollection.query(
|
||||
Q.where('team_id', room.teamId),
|
||||
Q.where('team_main', null)
|
||||
);
|
||||
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id });
|
||||
|
||||
if (teamChannels.length) {
|
||||
if (result.rooms?.length) {
|
||||
const teamChannels = result.rooms.map(r => ({
|
||||
rid: r._id,
|
||||
name: r.name,
|
||||
teamId: r.teamId,
|
||||
alert: r.isLastOwner
|
||||
}));
|
||||
navigation.navigate('SelectListView', {
|
||||
title: 'Leave_Team',
|
||||
data: teamChannels,
|
||||
|
@ -456,7 +456,11 @@ class RoomActionsView extends React.Component {
|
|||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }),
|
||||
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
|
||||
onPress: () => this.handleLeaveTeam()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@ import { withTheme } from '../../theme';
|
|||
import { themes } from '../../constants/colors';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { withActionSheet } from '../../containers/ActionSheet';
|
||||
import { showConfirmationAlert } from '../../utils/info';
|
||||
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import { goRoom } from '../../utils/goRoom';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
|
@ -34,6 +35,9 @@ const PERMISSION_SET_LEADER = 'set-leader';
|
|||
const PERMISSION_SET_OWNER = 'set-owner';
|
||||
const PERMISSION_SET_MODERATOR = 'set-moderator';
|
||||
const PERMISSION_REMOVE_USER = 'remove-user';
|
||||
const PERMISSION_EDIT_TEAM_MEMBER = 'edit-team-member';
|
||||
const PERMISION_VIEW_ALL_TEAMS = 'view-all-teams';
|
||||
const PERMISSION_VIEW_ALL_TEAM_CHANNELS = 'view-all-team-channels';
|
||||
|
||||
class RoomMembersView extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -55,7 +59,10 @@ class RoomMembersView extends React.Component {
|
|||
setLeaderPermission: PropTypes.array,
|
||||
setOwnerPermission: PropTypes.array,
|
||||
setModeratorPermission: PropTypes.array,
|
||||
removeUserPermission: PropTypes.array
|
||||
removeUserPermission: PropTypes.array,
|
||||
editTeamMemberPermission: PropTypes.array,
|
||||
viewAllTeamChannelsPermission: PropTypes.array,
|
||||
viewAllTeamsPermission: PropTypes.array
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -94,10 +101,11 @@ class RoomMembersView extends React.Component {
|
|||
|
||||
const { room } = this.state;
|
||||
const {
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, editTeamMemberPermission, viewAllTeamChannelsPermission, viewAllTeamsPermission
|
||||
} = this.props;
|
||||
|
||||
const result = await RocketChat.hasPermission([
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission
|
||||
muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission, ...(room.teamMain ? [editTeamMemberPermission, viewAllTeamChannelsPermission, viewAllTeamsPermission] : [])
|
||||
], room.rid);
|
||||
|
||||
this.permissions = {
|
||||
|
@ -105,7 +113,12 @@ class RoomMembersView extends React.Component {
|
|||
[PERMISSION_SET_LEADER]: result[1],
|
||||
[PERMISSION_SET_OWNER]: result[2],
|
||||
[PERMISSION_SET_MODERATOR]: result[3],
|
||||
[PERMISSION_REMOVE_USER]: result[4]
|
||||
[PERMISSION_REMOVE_USER]: result[4],
|
||||
...(room.teamMain ? {
|
||||
[PERMISSION_EDIT_TEAM_MEMBER]: result[5],
|
||||
[PERMISSION_VIEW_ALL_TEAM_CHANNELS]: result[6],
|
||||
[PERMISION_VIEW_ALL_TEAMS]: result[7]
|
||||
} : {})
|
||||
};
|
||||
|
||||
const hasSinglePermission = Object.values(this.permissions).some(p => !!p);
|
||||
|
@ -163,9 +176,80 @@ class RoomMembersView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleRemoveFromTeam = async(selectedUser) => {
|
||||
try {
|
||||
const { navigation } = this.props;
|
||||
const { room } = this.state;
|
||||
|
||||
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: selectedUser._id });
|
||||
|
||||
if (result.rooms?.length) {
|
||||
const teamChannels = result.rooms.map(r => ({
|
||||
rid: r._id,
|
||||
name: r.name,
|
||||
teamId: r.teamId,
|
||||
alert: r.isLastOwner
|
||||
}));
|
||||
navigation.navigate('SelectListView', {
|
||||
title: 'Remove_Member',
|
||||
infoText: 'Remove_User_Team_Channels',
|
||||
data: teamChannels,
|
||||
nextAction: selected => this.removeFromTeam(selectedUser, selected),
|
||||
showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_remove'))
|
||||
});
|
||||
} else {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('Removing_user_from_this_team', { user: selectedUser.username }),
|
||||
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }),
|
||||
onPress: () => this.removeFromTeam(selectedUser)
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('Removing_user_from_this_team', { user: selectedUser.username }),
|
||||
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('remove') }),
|
||||
onPress: () => this.removeFromTeam(selectedUser)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeFromTeam = async(selectedUser, selected) => {
|
||||
try {
|
||||
const { members, membersFiltered, room } = this.state;
|
||||
const { navigation } = this.props;
|
||||
|
||||
const userId = selectedUser._id;
|
||||
const result = await RocketChat.removeTeamMember({
|
||||
teamId: room.teamId,
|
||||
teamName: room.name,
|
||||
userId,
|
||||
...(selected && { rooms: selected })
|
||||
});
|
||||
if (result.success) {
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
const newMembers = members.filter(member => member._id !== userId);
|
||||
const newMembersFiltered = membersFiltered.filter(member => member._id !== userId);
|
||||
this.setState({
|
||||
members: newMembers,
|
||||
membersFiltered: newMembersFiltered
|
||||
});
|
||||
navigation.navigate('RoomMembersView');
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
showErrorAlert(
|
||||
e.data.error
|
||||
? I18n.t(e.data.error)
|
||||
: I18n.t('There_was_an_error_while_action', { action: I18n.t('removing_team') }),
|
||||
I18n.t('Cannot_remove')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onPressUser = (selectedUser) => {
|
||||
const { room } = this.state;
|
||||
const { showActionSheet, user } = this.props;
|
||||
const { showActionSheet, user, theme } = this.props;
|
||||
|
||||
const options = [{
|
||||
icon: 'message',
|
||||
|
@ -173,39 +257,6 @@ class RoomMembersView extends React.Component {
|
|||
onPress: () => this.navToDirectMessage(selectedUser)
|
||||
}];
|
||||
|
||||
// Owner
|
||||
if (this.permissions['set-owner']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isOwner = userRoleResult?.roles.includes('owner');
|
||||
options.push({
|
||||
icon: 'shield-check',
|
||||
title: I18n.t(isOwner ? 'Remove_as_owner' : 'Set_as_owner'),
|
||||
onPress: () => this.handleOwner(selectedUser, !isOwner)
|
||||
});
|
||||
}
|
||||
|
||||
// Leader
|
||||
if (this.permissions['set-leader']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isLeader = userRoleResult?.roles.includes('leader');
|
||||
options.push({
|
||||
icon: 'shield-alt',
|
||||
title: I18n.t(isLeader ? 'Remove_as_leader' : 'Set_as_leader'),
|
||||
onPress: () => this.handleLeader(selectedUser, !isLeader)
|
||||
});
|
||||
}
|
||||
|
||||
// Moderator
|
||||
if (this.permissions['set-moderator']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isModerator = userRoleResult?.roles.includes('moderator');
|
||||
options.push({
|
||||
icon: 'shield',
|
||||
title: I18n.t(isModerator ? 'Remove_as_moderator' : 'Set_as_moderator'),
|
||||
onPress: () => this.handleModerator(selectedUser, !isModerator)
|
||||
});
|
||||
}
|
||||
|
||||
// Ignore
|
||||
if (selectedUser._id !== user.id) {
|
||||
const { ignored } = room;
|
||||
|
@ -236,8 +287,54 @@ class RoomMembersView extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
// Owner
|
||||
if (this.permissions['set-owner']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isOwner = userRoleResult?.roles.includes('owner');
|
||||
options.push({
|
||||
icon: 'shield-check',
|
||||
title: I18n.t('Owner'),
|
||||
onPress: () => this.handleOwner(selectedUser, !isOwner),
|
||||
right: () => <CustomIcon name={isOwner ? 'checkbox-checked' : 'checkbox-unchecked'} size={20} color={isOwner ? themes[theme].tintActive : themes[theme].auxiliaryTintColor} />
|
||||
});
|
||||
}
|
||||
|
||||
// Leader
|
||||
if (this.permissions['set-leader']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isLeader = userRoleResult?.roles.includes('leader');
|
||||
options.push({
|
||||
icon: 'shield-alt',
|
||||
title: I18n.t('Leader'),
|
||||
onPress: () => this.handleLeader(selectedUser, !isLeader),
|
||||
right: () => <CustomIcon name={isLeader ? 'checkbox-checked' : 'checkbox-unchecked'} size={20} color={isLeader ? themes[theme].tintActive : themes[theme].auxiliaryTintColor} />
|
||||
});
|
||||
}
|
||||
|
||||
// Moderator
|
||||
if (this.permissions['set-moderator']) {
|
||||
const userRoleResult = this.roomRoles.find(r => r.u._id === selectedUser._id);
|
||||
const isModerator = userRoleResult?.roles.includes('moderator');
|
||||
options.push({
|
||||
icon: 'shield',
|
||||
title: I18n.t('Moderator'),
|
||||
onPress: () => this.handleModerator(selectedUser, !isModerator),
|
||||
right: () => <CustomIcon name={isModerator ? 'checkbox-checked' : 'checkbox-unchecked'} size={20} color={isModerator ? themes[theme].tintActive : themes[theme].auxiliaryTintColor} />
|
||||
});
|
||||
}
|
||||
|
||||
// Remove from team
|
||||
if (this.permissions['edit-team-member']) {
|
||||
options.push({
|
||||
icon: 'logout',
|
||||
danger: true,
|
||||
title: I18n.t('Remove_from_Team'),
|
||||
onPress: () => this.handleRemoveFromTeam(selectedUser)
|
||||
});
|
||||
}
|
||||
|
||||
// Remove from room
|
||||
if (this.permissions['remove-user']) {
|
||||
if (this.permissions['remove-user'] && !room.teamMain) {
|
||||
options.push({
|
||||
icon: 'logout',
|
||||
title: I18n.t('Remove_from_room'),
|
||||
|
@ -477,7 +574,10 @@ const mapStateToProps = state => ({
|
|||
setLeaderPermission: state.permissions[PERMISSION_SET_LEADER],
|
||||
setOwnerPermission: state.permissions[PERMISSION_SET_OWNER],
|
||||
setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR],
|
||||
removeUserPermission: state.permissions[PERMISSION_REMOVE_USER]
|
||||
removeUserPermission: state.permissions[PERMISSION_REMOVE_USER],
|
||||
editTeamMemberPermission: state.permissions[PERMISSION_EDIT_TEAM_MEMBER],
|
||||
viewAllTeamChannelsPermission: state.permissions[PERMISSION_VIEW_ALL_TEAM_CHANNELS],
|
||||
viewAllTeamsPermission: state.permissions[PERMISION_VIEW_ALL_TEAMS]
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView)));
|
||||
|
|
|
@ -14,7 +14,6 @@ import { themes } from '../constants/colors';
|
|||
import { withTheme } from '../theme';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||
import Loading from '../containers/Loading';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonText: {
|
||||
|
@ -41,8 +40,7 @@ class SelectListView extends React.Component {
|
|||
this.showAlert = props.route?.params?.showAlert;
|
||||
this.state = {
|
||||
data,
|
||||
selected: [],
|
||||
loading: false
|
||||
selected: []
|
||||
};
|
||||
this.setHeader();
|
||||
}
|
||||
|
@ -96,10 +94,8 @@ class SelectListView extends React.Component {
|
|||
|
||||
renderItem = ({ item }) => {
|
||||
const { theme } = this.props;
|
||||
const alert = item.roles.length;
|
||||
|
||||
const icon = item.t === 'p' ? 'channel-private' : 'channel-public';
|
||||
const checked = this.isChecked(item.rid, item.roles) ? 'check' : null;
|
||||
const checked = this.isChecked(item.rid) ? 'check' : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -108,8 +104,8 @@ class SelectListView extends React.Component {
|
|||
title={item.name}
|
||||
translateTitle={false}
|
||||
testID={`select-list-view-item-${ item.name }`}
|
||||
onPress={() => (alert ? this.showAlert() : this.toggleItem(item.rid))}
|
||||
alert={alert}
|
||||
onPress={() => (item.alert ? this.showAlert() : this.toggleItem(item.rid))}
|
||||
alert={item.alert}
|
||||
left={() => <List.Icon name={icon} color={themes[theme].controlText} />}
|
||||
right={() => (checked ? <List.Icon name={checked} color={themes[theme].actionTintColor} /> : null)}
|
||||
/>
|
||||
|
@ -118,7 +114,7 @@ class SelectListView extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { loading, data } = this.state;
|
||||
const { data } = this.state;
|
||||
const { theme } = this.props;
|
||||
|
||||
return (
|
||||
|
@ -133,7 +129,6 @@ class SelectListView extends React.Component {
|
|||
contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }}
|
||||
keyboardShouldPersistTaps='always'
|
||||
/>
|
||||
<Loading visible={loading} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue