diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json
index 1648d3bf2..71403821a 100644
--- a/app/i18n/locales/en.json
+++ b/app/i18n/locales/en.json
@@ -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",
diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js
index 1f4bcb9cb..cc1dd46e0 100644
--- a/app/lib/methods/getPermissions.js
+++ b/app/lib/methods/getPermissions.js
@@ -22,6 +22,7 @@ const PERMISSIONS = [
'delete-p',
'edit-message',
'edit-room',
+ 'edit-team-member',
'edit-team-channel',
'force-delete-message',
'mute-user',
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index c1a7655f4..3660b3195 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -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
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index 3256dd0b9..89d34ed07 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -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()
+ });
}
}
diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js
index 9a47b60f7..59d298d94 100644
--- a/app/views/RoomMembersView/index.js
+++ b/app/views/RoomMembersView/index.js
@@ -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: () =>
+ });
+ }
+
+ // 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: () =>
+ });
+ }
+
+ // 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: () =>
+ });
+ }
+
+ // 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)));
diff --git a/app/views/SelectListView.js b/app/views/SelectListView.js
index 9c886da80..bcbb0923f 100644
--- a/app/views/SelectListView.js
+++ b/app/views/SelectListView.js
@@ -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={() => }
right={() => (checked ? : 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'
/>
-
);
}