[NEW] Unify members section (#4399)
* create useUserPermissions hook * create CheckRadioButton component * fix return * create MembersSection component * apply MembersSection and header filter * fix re-render and testID * fix detox tests * rename to RadioButton * move the component closer to the screen * remove useUserPermissions * remove theme prop * migrate to hooks * fix team permissions * remove theme prop from UserItem * remove options prop * fix Member * remove commented test * fixes * fix for room not joined * add room members events * adds empty option * add members filter and pagination * clear RoomMembersView * remove unused styles * Update app/views/RoomMembersView/index.tsx Co-authored-by: Diego Mello <diegolmello@gmail.com> * wip * Temp workaround for SearchBox background color * Rename import * Fix missing params for 5.0 * Fix e2e tests Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
ccbc84f9a8
commit
cbc6892084
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import { RadioButton as RadioButtonUiLib } from 'react-native-ui-lib';
|
||||
|
||||
import { useTheme } from '../../theme';
|
||||
|
||||
export const RadioButton = ({ check, testID, size }: { check: boolean; testID?: string; size?: number }): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<RadioButtonUiLib
|
||||
testID={testID}
|
||||
selected={check}
|
||||
size={size || 20}
|
||||
color={check ? colors.tintActive : colors.auxiliaryTintColor}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -4,9 +4,8 @@ import { Pressable, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-n
|
|||
import Avatar from './Avatar';
|
||||
import { CustomIcon, TIconsName } from './CustomIcon';
|
||||
import sharedStyles from '../views/Styles';
|
||||
import { themes } from '../lib/constants';
|
||||
import { isIOS } from '../lib/methods/helpers';
|
||||
import { TSupportedThemes } from '../theme';
|
||||
import { useTheme } from '../theme';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
|
@ -47,34 +46,36 @@ interface IUserItem {
|
|||
onLongPress?: () => void;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
icon?: TIconsName | null;
|
||||
theme: TSupportedThemes;
|
||||
}
|
||||
|
||||
const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon, theme }: IUserItem) => (
|
||||
<Pressable
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
testID={testID}
|
||||
android_ripple={{
|
||||
color: themes[theme].bannerBackground
|
||||
}}
|
||||
style={({ pressed }: any) => ({
|
||||
backgroundColor: isIOS && pressed ? themes[theme].bannerBackground : 'transparent'
|
||||
})}
|
||||
>
|
||||
<View style={[styles.container, styles.button, style]}>
|
||||
<Avatar text={username} size={30} style={styles.avatar} />
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={[styles.name, { color: themes[theme].titleText }]} numberOfLines={1}>
|
||||
{name}
|
||||
</Text>
|
||||
<Text style={[styles.username, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>
|
||||
@{username}
|
||||
</Text>
|
||||
const UserItem = ({ name, username, onPress, testID, onLongPress, style, icon }: IUserItem): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<Pressable
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
testID={testID}
|
||||
android_ripple={{
|
||||
color: colors.bannerBackground
|
||||
}}
|
||||
style={({ pressed }: any) => ({
|
||||
backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent'
|
||||
})}
|
||||
>
|
||||
<View style={[styles.container, styles.button, style]}>
|
||||
<Avatar text={username} size={30} style={styles.avatar} />
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={[styles.name, { color: colors.titleText }]} numberOfLines={1}>
|
||||
{name}
|
||||
</Text>
|
||||
<Text style={[styles.username, { color: colors.auxiliaryText }]} numberOfLines={1}>
|
||||
@{username}
|
||||
</Text>
|
||||
</View>
|
||||
{icon ? <CustomIcon name={icon} size={22} color={colors.actionTintColor} style={styles.icon} /> : null}
|
||||
</View>
|
||||
{icon ? <CustomIcon name={icon} size={22} color={themes[theme].actionTintColor} style={styles.icon} /> : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserItem;
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"No_mentioned_messages": "No mentioned messages",
|
||||
"No_pinned_messages": "No pinned messages",
|
||||
"No_results_found": "No results found",
|
||||
"No_members_found": "No members found",
|
||||
"No_starred_messages": "No starred messages",
|
||||
"No_thread_messages": "No thread messages",
|
||||
"No_label_provided": "No {{label}} provided.",
|
||||
|
|
|
@ -334,6 +334,7 @@
|
|||
"No_mentioned_messages": "Não há menções",
|
||||
"No_pinned_messages": "Não há mensagens fixadas",
|
||||
"No_results_found": "Nenhum resultado encontrado",
|
||||
"No_members_found": "Nenhum usuário encontrado",
|
||||
"No_starred_messages": "Não há mensagens favoritas",
|
||||
"No_thread_messages": "Não há tópicos",
|
||||
"No_label_provided": "Sem {{label}}.",
|
||||
|
|
|
@ -85,7 +85,7 @@ export function hasRole(role): boolean {
|
|||
return userRoles.indexOf(role) > -1;
|
||||
}
|
||||
|
||||
export async function hasPermission(permissions, rid?: any): boolean[] {
|
||||
export async function hasPermission(permissions, rid?: any): Promise<boolean[]> {
|
||||
let roomRoles = [];
|
||||
if (rid) {
|
||||
const db = database.active;
|
||||
|
|
|
@ -272,6 +272,10 @@ export default {
|
|||
RA_MOVE_TO_TEAM_F: 'ra_move_to_team_f',
|
||||
RA_SEARCH_TEAM: 'ra_search_team',
|
||||
|
||||
// ROOM MEMBERS ACTIONS VIEW
|
||||
RM_GO_SELECTEDUSERS: 'rm_go_selected_users',
|
||||
RM_GO_INVITEUSERS: 'rm_go_invite_users',
|
||||
|
||||
// ROOM INFO VIEW
|
||||
RI_GO_RI_EDIT: 'ri_go_ri_edit',
|
||||
RI_GO_LIVECHAT_EDIT: 'ri_go_livechat_edit',
|
||||
|
|
|
@ -17,10 +17,15 @@ function replace(name: string, params: any) {
|
|||
navigationRef.current?.dispatch(StackActions.replace(name, params));
|
||||
}
|
||||
|
||||
function popToTop() {
|
||||
navigationRef.current?.dispatch(StackActions.popToTop());
|
||||
}
|
||||
|
||||
export default {
|
||||
navigationRef,
|
||||
routeNameRef,
|
||||
navigate,
|
||||
back,
|
||||
replace
|
||||
replace,
|
||||
popToTop
|
||||
};
|
||||
|
|
|
@ -95,7 +95,7 @@ const ChatsStackNavigator = () => {
|
|||
<ChatsStack.Screen name='SelectListView' component={SelectListView} options={SelectListView.navigationOptions} />
|
||||
<ChatsStack.Screen name='RoomInfoView' component={RoomInfoView} options={RoomInfoView.navigationOptions} />
|
||||
<ChatsStack.Screen name='RoomInfoEditView' component={RoomInfoEditView} options={RoomInfoEditView.navigationOptions} />
|
||||
<ChatsStack.Screen name='RoomMembersView' component={RoomMembersView} options={RoomMembersView.navigationOptions} />
|
||||
<ChatsStack.Screen name='RoomMembersView' component={RoomMembersView} />
|
||||
<ChatsStack.Screen name='DiscussionsView' component={DiscussionsView} />
|
||||
<ChatsStack.Screen
|
||||
name='SearchMessagesView'
|
||||
|
|
|
@ -127,7 +127,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
<ModalStack.Screen name='RoomInfoView' component={RoomInfoView} options={RoomInfoView.navigationOptions} />
|
||||
<ModalStack.Screen name='SelectListView' component={SelectListView} />
|
||||
<ModalStack.Screen name='RoomInfoEditView' component={RoomInfoEditView} options={RoomInfoEditView.navigationOptions} />
|
||||
<ModalStack.Screen name='RoomMembersView' component={RoomMembersView} options={RoomMembersView.navigationOptions} />
|
||||
<ModalStack.Screen name='RoomMembersView' component={RoomMembersView} />
|
||||
<ModalStack.Screen
|
||||
name='SearchMessagesView'
|
||||
component={SearchMessagesView}
|
||||
|
|
|
@ -64,6 +64,7 @@ export type ModalStackParamList = {
|
|||
RoomMembersView: {
|
||||
rid: string;
|
||||
room: TSubscriptionModel;
|
||||
joined?: boolean;
|
||||
};
|
||||
DiscussionsView: {
|
||||
rid: string;
|
||||
|
|
|
@ -75,6 +75,7 @@ export type ChatsStackParamList = {
|
|||
RoomMembersView: {
|
||||
rid: string;
|
||||
room: ISubscription;
|
||||
joined?: boolean;
|
||||
};
|
||||
DiscussionsView: {
|
||||
rid: string;
|
||||
|
|
|
@ -331,20 +331,15 @@ class CreateChannelView extends React.Component<ICreateChannelViewProps, ICreate
|
|||
});
|
||||
}
|
||||
|
||||
renderItem = ({ item }: { item: IOtherUser }) => {
|
||||
const { theme } = this.props;
|
||||
|
||||
return (
|
||||
<UserItem
|
||||
name={item.fname}
|
||||
username={item.name}
|
||||
onPress={() => this.removeUser(item)}
|
||||
testID={`create-channel-view-item-${item.name}`}
|
||||
icon='check'
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
renderItem = ({ item }: { item: IOtherUser }) => (
|
||||
<UserItem
|
||||
name={item.fname}
|
||||
username={item.name}
|
||||
onPress={() => this.removeUser(item)}
|
||||
testID={`create-channel-view-item-${item.name}`}
|
||||
icon='check'
|
||||
/>
|
||||
);
|
||||
|
||||
renderInvitedList = () => {
|
||||
const { users, theme } = this.props;
|
||||
|
|
|
@ -290,7 +290,6 @@ class NewMessageView extends React.Component<INewMessageViewProps, INewMessageVi
|
|||
onPress={() => this.goRoom(itemModel)}
|
||||
testID={`new-message-view-item-${item.name}`}
|
||||
style={style}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -64,10 +64,6 @@ interface IRoomActionsViewProps extends IActionSheetProvider, IBaseScreen<ChatsS
|
|||
encryptionEnabled: boolean;
|
||||
fontScale: number;
|
||||
serverVersion: string | null;
|
||||
addUserToJoinedRoomPermission?: string[];
|
||||
addUserToAnyCRoomPermission?: string[];
|
||||
addUserToAnyPRoomPermission?: string[];
|
||||
createInviteLinksPermission?: string[];
|
||||
editRoomPermission?: string[];
|
||||
toggleRoomE2EEncryptionPermission?: string[];
|
||||
viewBroadcastMemberListPermission?: string[];
|
||||
|
@ -94,8 +90,6 @@ interface IRoomActionsViewState {
|
|||
joined: boolean;
|
||||
canViewMembers: boolean;
|
||||
canAutoTranslate: boolean;
|
||||
canAddUser: boolean;
|
||||
canInviteUser: boolean;
|
||||
canEdit: boolean;
|
||||
canToggleEncryption: boolean;
|
||||
canCreateTeam: boolean;
|
||||
|
@ -146,8 +140,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
joined: !!room,
|
||||
canViewMembers: false,
|
||||
canAutoTranslate: false,
|
||||
canAddUser: false,
|
||||
canInviteUser: false,
|
||||
canEdit: false,
|
||||
canToggleEncryption: false,
|
||||
canCreateTeam: false,
|
||||
|
@ -206,8 +198,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
}
|
||||
|
||||
const canAutoTranslate = canAutoTranslateMethod();
|
||||
const canAddUser = await this.canAddUser();
|
||||
const canInviteUser = await this.canInviteUser();
|
||||
const canEdit = await this.canEdit();
|
||||
const canToggleEncryption = await this.canToggleEncryption();
|
||||
const canViewMembers = await this.canViewMembers();
|
||||
|
@ -217,8 +207,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
|
||||
this.setState({
|
||||
canAutoTranslate,
|
||||
canAddUser,
|
||||
canInviteUser,
|
||||
canEdit,
|
||||
canToggleEncryption,
|
||||
canViewMembers,
|
||||
|
@ -261,40 +249,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
}
|
||||
};
|
||||
|
||||
canAddUser = async () => {
|
||||
const { room, joined } = this.state;
|
||||
const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props;
|
||||
const { rid, t } = room;
|
||||
let canAddUser = false;
|
||||
|
||||
const userInRoom = joined;
|
||||
const permissions = await hasPermission(
|
||||
[addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission],
|
||||
rid
|
||||
);
|
||||
|
||||
if (userInRoom && permissions[0]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
if (t === 'c' && permissions[1]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
if (t === 'p' && permissions[2]) {
|
||||
canAddUser = true;
|
||||
}
|
||||
return canAddUser;
|
||||
};
|
||||
|
||||
canInviteUser = async () => {
|
||||
const { room } = this.state;
|
||||
const { createInviteLinksPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await hasPermission([createInviteLinksPermission], rid);
|
||||
|
||||
const canInviteUser = permissions[0];
|
||||
return canInviteUser;
|
||||
};
|
||||
|
||||
canEdit = async () => {
|
||||
const { room } = this.state;
|
||||
const { editRoomPermission } = this.props;
|
||||
|
@ -1135,7 +1089,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
};
|
||||
|
||||
render() {
|
||||
const { room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate } = this.state;
|
||||
const { room, membersCount, canViewMembers, joined, canAutoTranslate } = this.state;
|
||||
const { rid, t, prid } = room;
|
||||
const isGroupChatHandler = isGroupChat(room);
|
||||
|
||||
|
@ -1154,7 +1108,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
<List.Item
|
||||
title='Members'
|
||||
subtitle={membersCount > 0 ? `${membersCount} ${I18n.t('members')}` : undefined}
|
||||
onPress={() => this.onPressTouchable({ route: 'RoomMembersView', params: { rid, room } })}
|
||||
onPress={() => this.onPressTouchable({ route: 'RoomMembersView', params: { rid, room, joined: this.joined } })}
|
||||
testID='room-actions-members'
|
||||
left={() => <List.Icon name='team' />}
|
||||
showActionIndicator
|
||||
|
@ -1164,45 +1118,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
</>
|
||||
) : null}
|
||||
|
||||
{['c', 'p'].includes(t) && canAddUser ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Add_users'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
route: 'SelectedUsersView',
|
||||
params: {
|
||||
title: I18n.t('Add_users'),
|
||||
nextAction: this.addUser
|
||||
}
|
||||
})
|
||||
}
|
||||
testID='room-actions-add-user'
|
||||
left={() => <List.Icon name='add' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['c', 'p'].includes(t) && canInviteUser ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Invite_users'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
route: 'InviteUsersView',
|
||||
params: { rid }
|
||||
})
|
||||
}
|
||||
testID='room-actions-invite-user'
|
||||
left={() => <List.Icon name='user-add' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['c', 'p', 'd'].includes(t) && !prid ? (
|
||||
<>
|
||||
<List.Item
|
||||
|
@ -1384,10 +1299,6 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
encryptionEnabled: state.encryption.enabled,
|
||||
serverVersion: state.server.version,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'],
|
||||
addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'],
|
||||
addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'],
|
||||
createInviteLinksPermission: state.permissions['create-invite-links'],
|
||||
editRoomPermission: state.permissions['edit-room'],
|
||||
toggleRoomE2EEncryptionPermission: state.permissions['toggle-room-e2e-encryption'],
|
||||
viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'],
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
import { CompositeNavigationProp, useNavigation } from '@react-navigation/native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { setLoading } from '../../../actions/selectedUsers';
|
||||
import * as List from '../../../containers/List';
|
||||
import { TSubscriptionModel } from '../../../definitions';
|
||||
import i18n from '../../../i18n';
|
||||
import { usePermissions } from '../../../lib/hooks';
|
||||
import log, { events, logEvent } from '../../../lib/methods/helpers/log';
|
||||
import { Services } from '../../../lib/services';
|
||||
import { MasterDetailInsideStackParamList } from '../../../stacks/MasterDetailStack/types';
|
||||
import { ChatsStackParamList } from '../../../stacks/types';
|
||||
|
||||
type TNavigation = CompositeNavigationProp<
|
||||
StackNavigationProp<ChatsStackParamList, 'RoomActionsView'>,
|
||||
StackNavigationProp<MasterDetailInsideStackParamList>
|
||||
>;
|
||||
|
||||
interface IActionsSection {
|
||||
rid: TSubscriptionModel['rid'];
|
||||
t: TSubscriptionModel['t'];
|
||||
joined: boolean;
|
||||
}
|
||||
|
||||
export default function ActionsSection({ rid, t, joined }: IActionsSection): React.ReactElement {
|
||||
const { navigate, pop } = useNavigation<TNavigation>();
|
||||
const dispatch = useDispatch();
|
||||
const [addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission, createInviteLinksPermission] =
|
||||
usePermissions(['add-user-to-joined-room', 'add-user-to-any-c-room', 'add-user-to-any-p-room', 'create-invite-links'], rid);
|
||||
|
||||
const canAddUser =
|
||||
(joined && addUserToJoinedRoomPermission) ||
|
||||
(t === 'c' && addUserToAnyCRoomPermission) ||
|
||||
(t === 'p' && addUserToAnyPRoomPermission) ||
|
||||
false;
|
||||
|
||||
const canInviteUser = createInviteLinksPermission;
|
||||
|
||||
const handleOnPress = ({
|
||||
route,
|
||||
params
|
||||
}: {
|
||||
route: keyof ChatsStackParamList;
|
||||
params: ChatsStackParamList[keyof ChatsStackParamList];
|
||||
}) => {
|
||||
navigate(route, params);
|
||||
// @ts-ignore
|
||||
logEvent(events[`RM_GO_${route.replace('View', '').toUpperCase()}`]);
|
||||
};
|
||||
|
||||
const addUser = async () => {
|
||||
try {
|
||||
dispatch(setLoading(true));
|
||||
await Services.addUsersToRoom(rid);
|
||||
pop();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
} finally {
|
||||
dispatch(setLoading(false));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ paddingTop: canAddUser || canInviteUser ? 16 : 0, paddingBottom: canAddUser || canInviteUser ? 8 : 0 }}>
|
||||
{['c', 'p'].includes(t) && canAddUser ? (
|
||||
<>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Add_users'
|
||||
onPress={() =>
|
||||
handleOnPress({
|
||||
route: 'SelectedUsersView',
|
||||
params: {
|
||||
title: i18n.t('Add_users'),
|
||||
nextAction: addUser
|
||||
}
|
||||
})
|
||||
}
|
||||
testID='room-actions-add-user'
|
||||
left={() => <List.Icon name='add' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['c', 'p'].includes(t) && canInviteUser ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Invite_users'
|
||||
onPress={() =>
|
||||
handleOnPress({
|
||||
route: 'InviteUsersView',
|
||||
params: { rid }
|
||||
})
|
||||
}
|
||||
testID='room-actions-invite-user'
|
||||
left={() => <List.Icon name='user-add' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import { LISTENER } from '../../containers/Toast';
|
||||
import { IUser, SubscriptionType, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||
import I18n from '../../i18n';
|
||||
import { getRoomTitle, showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers';
|
||||
import EventEmitter from '../../lib/methods/helpers/events';
|
||||
import { goRoom, TGoRoomItem } from '../../lib/methods/helpers/goRoom';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
import appNavigation from '../../lib/navigation/appNavigation';
|
||||
import { Services } from '../../lib/services';
|
||||
import database from '../../lib/database';
|
||||
import { RoomTypes } from '../../lib/methods';
|
||||
|
||||
export type TRoomType = SubscriptionType.CHANNEL | SubscriptionType.GROUP | SubscriptionType.OMNICHANNEL;
|
||||
|
||||
const handleGoRoom = (item: TGoRoomItem, isMasterDetail: boolean): void => {
|
||||
if (isMasterDetail) {
|
||||
appNavigation.navigate('DrawerNavigator');
|
||||
} else {
|
||||
appNavigation.popToTop();
|
||||
}
|
||||
goRoom({ item, isMasterDetail });
|
||||
};
|
||||
|
||||
export const fetchRole = (role: string, selectedUser: TUserModel, roomRoles: any): boolean => {
|
||||
const userRoleResult = roomRoles.find((r: any) => r.u._id === selectedUser._id);
|
||||
return userRoleResult?.roles.includes(role);
|
||||
};
|
||||
|
||||
export const fetchRoomMembersRoles = async (roomType: TRoomType, rid: string, updateState: any): Promise<void> => {
|
||||
try {
|
||||
const type = roomType;
|
||||
const result = await Services.getRoomRoles(rid, type);
|
||||
if (result?.success) {
|
||||
updateState({ roomRoles: result.roles });
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleMute = async (user: TUserModel, rid: string) => {
|
||||
try {
|
||||
await Services.toggleMuteUserInRoom(rid, user?.username, !user?.muted);
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t('User_has_been_key', { key: user?.muted ? I18n.t('unmuted') : I18n.t('muted') })
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleModerator = async (
|
||||
selectedUser: TUserModel,
|
||||
isModerator: boolean,
|
||||
room: TSubscriptionModel,
|
||||
username: string,
|
||||
callback: () => Promise<void>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await Services.toggleRoomModerator({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isModerator
|
||||
});
|
||||
const message = isModerator
|
||||
? 'User__username__is_now_a_moderator_of__room_name_'
|
||||
: 'User__username__removed_from__room_name__moderators';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username,
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
callback();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const navToDirectMessage = async (item: IUser, isMasterDetail: boolean): Promise<void> => {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
const query = await subsCollection.query(Q.where('name', item.username)).fetch();
|
||||
if (query.length) {
|
||||
const [room] = query;
|
||||
handleGoRoom(room, isMasterDetail);
|
||||
} else {
|
||||
const result = await Services.createDirectMessage(item.username);
|
||||
if (result.success) {
|
||||
handleGoRoom({ rid: result.room?._id as string, name: item.username, t: SubscriptionType.DIRECT }, isMasterDetail);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const removeFromTeam = async (
|
||||
selectedUser: IUser,
|
||||
updateState: Function,
|
||||
room: TSubscriptionModel,
|
||||
members: TUserModel[],
|
||||
selected?: any
|
||||
) => {
|
||||
try {
|
||||
const userId = selectedUser._id;
|
||||
const result = await Services.removeTeamMember({
|
||||
teamId: room.teamId,
|
||||
userId,
|
||||
...(selected && { rooms: selected })
|
||||
});
|
||||
if (result.success) {
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
const newMembers = members.filter(member => member._id !== userId);
|
||||
updateState({
|
||||
members: newMembers
|
||||
});
|
||||
}
|
||||
} catch (e: any) {
|
||||
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')
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleRemoveFromTeam = async (
|
||||
selectedUser: TUserModel,
|
||||
updateState: Function,
|
||||
room: TSubscriptionModel,
|
||||
members: TUserModel[]
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const result = await Services.teamListRoomsOfUser({ teamId: room.teamId as string, userId: selectedUser._id });
|
||||
|
||||
if (result.success) {
|
||||
if (result.rooms?.length) {
|
||||
const teamChannels = result.rooms.map((r: any) => ({
|
||||
rid: r._id,
|
||||
name: r.name,
|
||||
teamId: r.teamId,
|
||||
alert: r.isLastOwner
|
||||
}));
|
||||
appNavigation.navigate('SelectListView', {
|
||||
title: 'Remove_Member',
|
||||
infoText: 'Remove_User_Team_Channels',
|
||||
data: teamChannels,
|
||||
nextAction: (selected: any) => removeFromTeam(selectedUser, updateState, room, members, 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: () => removeFromTeam(selectedUser, updateState, room, members)
|
||||
});
|
||||
}
|
||||
}
|
||||
} 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: () => removeFromTeam(selectedUser, updateState, room, members)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const handleLeader = async (
|
||||
selectedUser: TUserModel,
|
||||
isLeader: boolean,
|
||||
room: TSubscriptionModel,
|
||||
username: string,
|
||||
callback: () => Promise<void>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await Services.toggleRoomLeader({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isLeader
|
||||
});
|
||||
const message = isLeader
|
||||
? 'User__username__is_now_a_leader_of__room_name_'
|
||||
: 'User__username__removed_from__room_name__leaders';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username,
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
callback();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleRemoveUserFromRoom = async (
|
||||
selectedUser: TUserModel,
|
||||
room: TSubscriptionModel,
|
||||
callback: Function
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const userId = selectedUser._id;
|
||||
await Services.removeUserFromRoom({ roomId: room.rid, t: room.t as RoomTypes, userId });
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
callback();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleIgnore = async (selectedUser: TUserModel, ignore: boolean, rid: string) => {
|
||||
try {
|
||||
await Services.ignoreUser({
|
||||
rid,
|
||||
userId: selectedUser._id,
|
||||
ignore
|
||||
});
|
||||
const message = I18n.t(ignore ? 'User_has_been_ignored' : 'User_has_been_unignored');
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const handleOwner = async (
|
||||
selectedUser: TUserModel,
|
||||
isOwner: boolean,
|
||||
username: string,
|
||||
room: TSubscriptionModel,
|
||||
callback: Function
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await Services.toggleRoomOwner({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isOwner
|
||||
});
|
||||
const message = isOwner ? 'User__username__is_now_a_owner_of__room_name_' : 'User__username__removed_from__room_name__owners';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username,
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
callback();
|
||||
};
|
|
@ -1,311 +1,202 @@
|
|||
import { Q } from '@nozbe/watermelondb';
|
||||
import React from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { NavigationProp, RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import React, { useEffect, useReducer } from 'react';
|
||||
import { FlatList, Text, View } from 'react-native';
|
||||
|
||||
import { themes } from '../../lib/constants';
|
||||
import { TActionSheetOptions, TActionSheetOptionsItem, withActionSheet } from '../../containers/ActionSheet';
|
||||
import { TActionSheetOptionsItem, useActionSheet } from '../../containers/ActionSheet';
|
||||
import ActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import { CustomIcon } from '../../containers/CustomIcon';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import * as List from '../../containers/List';
|
||||
import { RadioButton } from '../../containers/RadioButton';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import SearchBox from '../../containers/SearchBox';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import { LISTENER } from '../../containers/Toast';
|
||||
import { IApplicationState, IBaseScreen, IUser, SubscriptionType, TSubscriptionModel, TUserModel } from '../../definitions';
|
||||
import I18n from '../../i18n';
|
||||
import database from '../../lib/database';
|
||||
import { CustomIcon } from '../../containers/CustomIcon';
|
||||
import UserItem from '../../containers/UserItem';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import { TSupportedThemes, withTheme } from '../../theme';
|
||||
import EventEmitter from '../../lib/methods/helpers/events';
|
||||
import { goRoom, TGoRoomItem } from '../../lib/methods/helpers/goRoom';
|
||||
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers/info';
|
||||
import { TSubscriptionModel, TUserModel } from '../../definitions';
|
||||
import I18n from '../../i18n';
|
||||
import { useAppSelector, usePermissions } from '../../lib/hooks';
|
||||
import { getRoomTitle, isGroupChat } from '../../lib/methods/helpers';
|
||||
import { showConfirmationAlert } from '../../lib/methods/helpers/info';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
|
||||
import { TSupportedPermissions } from '../../reducers/permissions';
|
||||
import { RoomTypes } from '../../lib/methods';
|
||||
import { compareServerVersion, debounce, getRoomTitle, hasPermission, isGroupChat } from '../../lib/methods/helpers';
|
||||
import styles from './styles';
|
||||
import { Services } from '../../lib/services';
|
||||
import { TSupportedPermissions } from '../../reducers/permissions';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import { useTheme } from '../../theme';
|
||||
import ActionsSection from './components/ActionsSection';
|
||||
import {
|
||||
fetchRole,
|
||||
fetchRoomMembersRoles,
|
||||
handleIgnore,
|
||||
handleLeader,
|
||||
handleModerator,
|
||||
handleMute,
|
||||
handleOwner,
|
||||
handleRemoveFromTeam,
|
||||
handleRemoveUserFromRoom,
|
||||
navToDirectMessage,
|
||||
TRoomType
|
||||
} from './helpers';
|
||||
import styles from './styles';
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
interface IRoomMembersViewProps extends IBaseScreen<ModalStackParamList, 'RoomMembersView'> {
|
||||
rid: string;
|
||||
members: string[];
|
||||
baseUrl: string;
|
||||
room: TSubscriptionModel;
|
||||
user: {
|
||||
id: string;
|
||||
token: string;
|
||||
roles: string[];
|
||||
};
|
||||
showActionSheet: (params: TActionSheetOptions) => {};
|
||||
theme: TSupportedThemes;
|
||||
isMasterDetail: boolean;
|
||||
useRealName: boolean;
|
||||
muteUserPermission: string[];
|
||||
setLeaderPermission: string[];
|
||||
setOwnerPermission: string[];
|
||||
setModeratorPermission: string[];
|
||||
removeUserPermission: string[];
|
||||
editTeamMemberPermission: string[];
|
||||
viewAllTeamChannelsPermission: string[];
|
||||
viewAllTeamsPermission: string[];
|
||||
serverVersion: string;
|
||||
}
|
||||
|
||||
interface IRoomMembersViewState {
|
||||
isLoading: boolean;
|
||||
allUsers: boolean;
|
||||
filtering: string;
|
||||
rid: string;
|
||||
members: TUserModel[];
|
||||
membersFiltered: TUserModel[];
|
||||
room: TSubscriptionModel;
|
||||
end: boolean;
|
||||
roomRoles: any;
|
||||
filter: string;
|
||||
page: number;
|
||||
}
|
||||
|
||||
class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMembersViewState> {
|
||||
private mounted: boolean;
|
||||
private permissions: { [key in TSupportedPermissions]?: boolean };
|
||||
private roomObservable!: Observable<TSubscriptionModel>;
|
||||
private subscription!: Subscription;
|
||||
private roomRoles: any;
|
||||
const RightIcon = ({ check, label }: { check: boolean; label: string }) => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<CustomIcon
|
||||
testID={check ? `action-sheet-set-${label}-checked` : `action-sheet-set-${label}-unchecked`}
|
||||
name={check ? 'checkbox-checked' : 'checkbox-unchecked'}
|
||||
size={20}
|
||||
color={check ? colors.tintActive : colors.auxiliaryTintColor}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
constructor(props: IRoomMembersViewProps) {
|
||||
super(props);
|
||||
this.mounted = false;
|
||||
this.permissions = {};
|
||||
const rid = props.route.params?.rid;
|
||||
const room = props.route.params?.room;
|
||||
this.state = {
|
||||
const RoomMembersView = (): React.ReactElement => {
|
||||
const { showActionSheet } = useActionSheet();
|
||||
const { colors } = useTheme();
|
||||
|
||||
const { params } = useRoute<RouteProp<ModalStackParamList, 'RoomMembersView'>>();
|
||||
const navigation = useNavigation<NavigationProp<ModalStackParamList, 'RoomMembersView'>>();
|
||||
|
||||
const isMasterDetail = useAppSelector(state => state.app.isMasterDetail);
|
||||
|
||||
const useRealName = useAppSelector(state => state.settings.UI_Use_Real_Name);
|
||||
const user = useAppSelector(state => getUserSelector(state));
|
||||
|
||||
const [state, updateState] = useReducer(
|
||||
(state: IRoomMembersViewState, newState: Partial<IRoomMembersViewState>) => ({ ...state, ...newState }),
|
||||
{
|
||||
isLoading: false,
|
||||
allUsers: false,
|
||||
filtering: '',
|
||||
rid,
|
||||
members: [],
|
||||
membersFiltered: [],
|
||||
room: room || ({} as TSubscriptionModel),
|
||||
room: params.room || ({} as TSubscriptionModel),
|
||||
end: false,
|
||||
roomRoles: null,
|
||||
filter: '',
|
||||
page: 0
|
||||
}
|
||||
);
|
||||
|
||||
const teamPermissions: TSupportedPermissions[] = state.room.teamMain
|
||||
? ['edit-team-member', 'view-all-team-channels', 'view-all-teams']
|
||||
: [];
|
||||
|
||||
const [
|
||||
muteUserPermission,
|
||||
setLeaderPermission,
|
||||
setOwnerPermission,
|
||||
setModeratorPermission,
|
||||
removeUserPermission,
|
||||
editTeamMemberPermission,
|
||||
viewAllTeamChannelsPermission,
|
||||
viewAllTeamsPermission
|
||||
] = usePermissions(['mute-user', 'set-leader', 'set-owner', 'set-moderator', 'remove-user', ...teamPermissions], params.rid);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = params?.room?.observe && params.room.observe().subscribe(changes => updateState({ room: changes }));
|
||||
setHeader(true);
|
||||
fetchMembers(true);
|
||||
return () => subscription?.unsubscribe();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchRoles = () => {
|
||||
if (isGroupChat(state.room)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
muteUserPermission ||
|
||||
setLeaderPermission ||
|
||||
setOwnerPermission ||
|
||||
setModeratorPermission ||
|
||||
removeUserPermission ||
|
||||
editTeamMemberPermission ||
|
||||
viewAllTeamChannelsPermission ||
|
||||
viewAllTeamsPermission
|
||||
) {
|
||||
fetchRoomMembersRoles(state.room.t as any, state.room.rid, updateState);
|
||||
}
|
||||
};
|
||||
if (room && room.observe) {
|
||||
this.roomObservable = room.observe();
|
||||
this.subscription = this.roomObservable.subscribe(changes => {
|
||||
if (this.mounted) {
|
||||
this.setState({ room: changes });
|
||||
} else {
|
||||
this.setState({ room: changes });
|
||||
}
|
||||
});
|
||||
fetchRoles();
|
||||
}, [
|
||||
muteUserPermission,
|
||||
setLeaderPermission,
|
||||
setOwnerPermission,
|
||||
setModeratorPermission,
|
||||
removeUserPermission,
|
||||
editTeamMemberPermission,
|
||||
viewAllTeamChannelsPermission,
|
||||
viewAllTeamsPermission
|
||||
]);
|
||||
|
||||
const toggleStatus = (status: boolean) => {
|
||||
try {
|
||||
updateState({ members: [], allUsers: status, end: false });
|
||||
fetchMembers(status);
|
||||
setHeader(status);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
this.setHeader();
|
||||
}
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
const { room } = this.state;
|
||||
this.mounted = true;
|
||||
this.fetchMembers();
|
||||
|
||||
if (isGroupChat(room)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
muteUserPermission,
|
||||
setLeaderPermission,
|
||||
setOwnerPermission,
|
||||
setModeratorPermission,
|
||||
removeUserPermission,
|
||||
editTeamMemberPermission,
|
||||
viewAllTeamChannelsPermission,
|
||||
viewAllTeamsPermission
|
||||
} = this.props;
|
||||
|
||||
const result = await hasPermission(
|
||||
[
|
||||
muteUserPermission,
|
||||
setLeaderPermission,
|
||||
setOwnerPermission,
|
||||
setModeratorPermission,
|
||||
removeUserPermission,
|
||||
...(room.teamMain ? [editTeamMemberPermission, viewAllTeamChannelsPermission, viewAllTeamsPermission] : [])
|
||||
],
|
||||
room.rid
|
||||
);
|
||||
|
||||
this.permissions = {
|
||||
'mute-user': result[0],
|
||||
'set-leader': result[1],
|
||||
'set-owner': result[2],
|
||||
'set-moderator': result[3],
|
||||
'remove-user': result[4],
|
||||
...(room.teamMain
|
||||
? {
|
||||
'edit-team-member': result[5],
|
||||
'view-all-team-channels': result[6],
|
||||
'view-all-teams': result[7]
|
||||
}
|
||||
: {})
|
||||
};
|
||||
|
||||
const hasSinglePermission = Object.values(this.permissions).some(p => !!p);
|
||||
if (hasSinglePermission) {
|
||||
this.fetchRoomMembersRoles();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.subscription && this.subscription.unsubscribe) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { allUsers } = this.state;
|
||||
const { navigation } = this.props;
|
||||
const toggleText = allUsers ? I18n.t('Online') : I18n.t('All');
|
||||
const setHeader = (allUsers: boolean) => {
|
||||
navigation.setOptions({
|
||||
title: I18n.t('Members'),
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item title={toggleText} onPress={this.toggleStatus} testID='room-members-view-toggle-status' />
|
||||
<HeaderButton.Item
|
||||
iconName='filter'
|
||||
onPress={() =>
|
||||
showActionSheet({
|
||||
options: [
|
||||
{
|
||||
title: I18n.t('Online'),
|
||||
onPress: () => toggleStatus(true),
|
||||
right: () => <RadioButton check={allUsers} />,
|
||||
testID: 'room-members-view-toggle-status-online'
|
||||
},
|
||||
{
|
||||
title: I18n.t('All'),
|
||||
onPress: () => toggleStatus(false),
|
||||
right: () => <RadioButton check={!allUsers} />,
|
||||
testID: 'room-members-view-toggle-status-all'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
testID='room-members-view-filter'
|
||||
/>
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
});
|
||||
};
|
||||
|
||||
get isServerVersionLowerThan3_16() {
|
||||
const { serverVersion } = this.props;
|
||||
return compareServerVersion(serverVersion, 'lowerThan', '3.16.0');
|
||||
}
|
||||
const getUserDisplayName = (user: TUserModel) => (useRealName ? user.name : user.username) || user.username;
|
||||
|
||||
onSearchChangeText = debounce((text: string) => {
|
||||
const { members } = this.state;
|
||||
text = text.trim();
|
||||
if (this.isServerVersionLowerThan3_16) {
|
||||
let membersFiltered: TUserModel[] = [];
|
||||
|
||||
if (members && members.length > 0 && text) {
|
||||
membersFiltered = members.filter(
|
||||
m => m.username.toLowerCase().match(text.toLowerCase()) || m.name?.toLowerCase().match(text.toLowerCase())
|
||||
);
|
||||
}
|
||||
return this.setState({ filtering: text, membersFiltered });
|
||||
}
|
||||
|
||||
this.setState({ filtering: text, page: 0, members: [], end: false }, () => {
|
||||
this.fetchMembers();
|
||||
});
|
||||
}, 500);
|
||||
|
||||
navToDirectMessage = async (item: IUser) => {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
const query = await subsCollection.query(Q.where('name', item.username)).fetch();
|
||||
if (query.length) {
|
||||
const [room] = query;
|
||||
this.goRoom(room);
|
||||
} else {
|
||||
const result = await Services.createDirectMessage(item.username);
|
||||
if (result.success) {
|
||||
this.goRoom({ rid: result.room?._id as string, name: item.username, t: SubscriptionType.DIRECT });
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleRemoveFromTeam = async (selectedUser: TUserModel) => {
|
||||
try {
|
||||
const { navigation } = this.props;
|
||||
const { room } = this.state;
|
||||
|
||||
const result = await Services.teamListRoomsOfUser({ teamId: room.teamId as string, userId: selectedUser._id });
|
||||
|
||||
if (result.success) {
|
||||
if (result.rooms?.length) {
|
||||
const teamChannels = result.rooms.map((r: any) => ({
|
||||
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: any) => 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: IUser, selected?: any) => {
|
||||
try {
|
||||
const { members, membersFiltered, room } = this.state;
|
||||
const { navigation } = this.props;
|
||||
|
||||
const userId = selectedUser._id;
|
||||
const result = await Services.removeTeamMember({
|
||||
teamId: room.teamId,
|
||||
userId,
|
||||
...(selected && { rooms: selected })
|
||||
});
|
||||
if (result.success) {
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
const newMembers = members.filter(member => member._id !== userId);
|
||||
const newMembersFiltered = this.isServerVersionLowerThan3_16
|
||||
? membersFiltered.filter(member => member._id !== userId)
|
||||
: [];
|
||||
this.setState({
|
||||
members: newMembers,
|
||||
membersFiltered: newMembersFiltered
|
||||
});
|
||||
// @ts-ignore - This is just to force a reload
|
||||
navigation.navigate('RoomMembersView');
|
||||
}
|
||||
} catch (e: any) {
|
||||
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: TUserModel) => {
|
||||
const { room } = this.state;
|
||||
const { showActionSheet, user, theme } = this.props;
|
||||
const onPressUser = (selectedUser: TUserModel) => {
|
||||
const { room, roomRoles, members } = state;
|
||||
|
||||
const options: TActionSheetOptionsItem[] = [
|
||||
{
|
||||
icon: 'message',
|
||||
title: I18n.t('Direct_message'),
|
||||
onPress: () => this.navToDirectMessage(selectedUser)
|
||||
onPress: () => navToDirectMessage(selectedUser, isMasterDetail)
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -316,12 +207,12 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
options.push({
|
||||
icon: 'ignore',
|
||||
title: I18n.t(isIgnored ? 'Unignore' : 'Ignore'),
|
||||
onPress: () => this.handleIgnore(selectedUser, !isIgnored),
|
||||
onPress: () => handleIgnore(selectedUser, !isIgnored, room.rid),
|
||||
testID: 'action-sheet-ignore-user'
|
||||
});
|
||||
}
|
||||
|
||||
if (this.permissions['mute-user']) {
|
||||
if (muteUserPermission) {
|
||||
const { muted = [] } = room;
|
||||
const userIsMuted = muted.find?.(m => m === selectedUser.username);
|
||||
selectedUser.muted = !!userIsMuted;
|
||||
|
@ -334,7 +225,7 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
roomName: getRoomTitle(room)
|
||||
}),
|
||||
confirmationText: I18n.t(userIsMuted ? 'Unmute' : 'Mute'),
|
||||
onPress: () => this.handleMute(selectedUser)
|
||||
onPress: () => handleMute(selectedUser, room.rid)
|
||||
});
|
||||
},
|
||||
testID: 'action-sheet-mute-user'
|
||||
|
@ -342,78 +233,63 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
}
|
||||
|
||||
// Owner
|
||||
if (this.permissions['set-owner']) {
|
||||
const userRoleResult = this.roomRoles.find((r: any) => r.u._id === selectedUser._id);
|
||||
const isOwner = userRoleResult?.roles.includes('owner');
|
||||
if (setOwnerPermission) {
|
||||
const isOwner = fetchRole('owner', selectedUser, roomRoles);
|
||||
options.push({
|
||||
icon: 'shield-check',
|
||||
title: I18n.t('Owner'),
|
||||
onPress: () => this.handleOwner(selectedUser, !isOwner),
|
||||
right: () => (
|
||||
<CustomIcon
|
||||
testID={isOwner ? 'action-sheet-set-owner-checked' : 'action-sheet-set-owner-unchecked'}
|
||||
name={isOwner ? 'checkbox-checked' : 'checkbox-unchecked'}
|
||||
size={20}
|
||||
color={isOwner ? themes[theme].tintActive : themes[theme].auxiliaryTintColor}
|
||||
/>
|
||||
),
|
||||
onPress: () =>
|
||||
handleOwner(selectedUser, !isOwner, getUserDisplayName(selectedUser), room, () =>
|
||||
fetchRoomMembersRoles(room.t as TRoomType, room.rid, updateState)
|
||||
),
|
||||
right: () => <RightIcon check={isOwner} label='owner' />,
|
||||
testID: 'action-sheet-set-owner'
|
||||
});
|
||||
}
|
||||
|
||||
// Leader
|
||||
if (this.permissions['set-leader']) {
|
||||
const userRoleResult = this.roomRoles.find((r: any) => r.u._id === selectedUser._id);
|
||||
const isLeader = userRoleResult?.roles.includes('leader');
|
||||
if (setLeaderPermission) {
|
||||
const isLeader = fetchRole('leader', selectedUser, roomRoles);
|
||||
options.push({
|
||||
icon: 'shield-alt',
|
||||
title: I18n.t('Leader'),
|
||||
onPress: () => this.handleLeader(selectedUser, !isLeader),
|
||||
right: () => (
|
||||
<CustomIcon
|
||||
testID={isLeader ? 'action-sheet-set-leader-checked' : 'action-sheet-set-leader-unchecked'}
|
||||
name={isLeader ? 'checkbox-checked' : 'checkbox-unchecked'}
|
||||
size={20}
|
||||
color={isLeader ? themes[theme].tintActive : themes[theme].auxiliaryTintColor}
|
||||
/>
|
||||
),
|
||||
onPress: () =>
|
||||
handleLeader(selectedUser, !isLeader, room, getUserDisplayName(selectedUser), () =>
|
||||
fetchRoomMembersRoles(room.t as TRoomType, room.rid, updateState)
|
||||
),
|
||||
right: () => <RightIcon check={isLeader} label='leader' />,
|
||||
testID: 'action-sheet-set-leader'
|
||||
});
|
||||
}
|
||||
|
||||
// Moderator
|
||||
if (this.permissions['set-moderator']) {
|
||||
const userRoleResult = this.roomRoles.find((r: any) => r.u._id === selectedUser._id);
|
||||
const isModerator = userRoleResult?.roles.includes('moderator');
|
||||
if (setModeratorPermission) {
|
||||
const isModerator = fetchRole('moderator', selectedUser, roomRoles);
|
||||
options.push({
|
||||
icon: 'shield',
|
||||
title: I18n.t('Moderator'),
|
||||
onPress: () => this.handleModerator(selectedUser, !isModerator),
|
||||
right: () => (
|
||||
<CustomIcon
|
||||
testID={isModerator ? 'action-sheet-set-moderator-checked' : 'action-sheet-set-moderator-unchecked'}
|
||||
name={isModerator ? 'checkbox-checked' : 'checkbox-unchecked'}
|
||||
size={20}
|
||||
color={isModerator ? themes[theme].tintActive : themes[theme].auxiliaryTintColor}
|
||||
/>
|
||||
),
|
||||
onPress: () =>
|
||||
handleModerator(selectedUser, !isModerator, room, getUserDisplayName(selectedUser), () =>
|
||||
fetchRoomMembersRoles(room.t as TRoomType, room.rid, updateState)
|
||||
),
|
||||
right: () => <RightIcon check={isModerator} label='moderator' />,
|
||||
testID: 'action-sheet-set-moderator'
|
||||
});
|
||||
}
|
||||
|
||||
// Remove from team
|
||||
if (this.permissions['edit-team-member']) {
|
||||
if (editTeamMemberPermission) {
|
||||
options.push({
|
||||
icon: 'logout',
|
||||
danger: true,
|
||||
title: I18n.t('Remove_from_Team'),
|
||||
onPress: () => this.handleRemoveFromTeam(selectedUser),
|
||||
onPress: () => handleRemoveFromTeam(selectedUser, updateState, room, members),
|
||||
testID: 'action-sheet-remove-from-team'
|
||||
});
|
||||
}
|
||||
|
||||
// Remove from room
|
||||
if (this.permissions['remove-user'] && !room.teamMain) {
|
||||
if (removeUserPermission && !room.teamMain) {
|
||||
options.push({
|
||||
icon: 'logout',
|
||||
title: I18n.t('Remove_from_room'),
|
||||
|
@ -422,7 +298,13 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
showConfirmationAlert({
|
||||
message: I18n.t('The_user_will_be_removed_from_s', { s: getRoomTitle(room) }),
|
||||
confirmationText: I18n.t('Yes_remove_user'),
|
||||
onPress: () => this.handleRemoveUserFromRoom(selectedUser)
|
||||
onPress: () => {
|
||||
handleRemoveUserFromRoom(selectedUser, room, () =>
|
||||
updateState({
|
||||
members: members.filter(member => member._id !== selectedUser._id)
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
testID: 'action-sheet-remove-from-room'
|
||||
|
@ -435,256 +317,83 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
});
|
||||
};
|
||||
|
||||
toggleStatus = () => {
|
||||
try {
|
||||
const { allUsers } = this.state;
|
||||
this.setState({ members: [], allUsers: !allUsers, end: false, page: 0 }, () => {
|
||||
this.fetchMembers();
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
fetchRoomMembersRoles = async () => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
const type = room.t as SubscriptionType.CHANNEL | SubscriptionType.GROUP | SubscriptionType.OMNICHANNEL;
|
||||
const result = await Services.getRoomRoles(room.rid, type);
|
||||
if (result?.success) {
|
||||
this.roomRoles = result.roles;
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
fetchMembers = async () => {
|
||||
const { rid, members, isLoading, allUsers, end, room, filtering, page } = this.state;
|
||||
const fetchMembers = async (status: boolean) => {
|
||||
const { members, isLoading, end, room, filter, page } = state;
|
||||
const { t } = room;
|
||||
|
||||
if (isLoading || end) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ isLoading: true });
|
||||
updateState({ isLoading: true });
|
||||
try {
|
||||
const membersResult = await Services.getRoomMembers({
|
||||
rid,
|
||||
rid: room.rid,
|
||||
roomType: t,
|
||||
type: allUsers ? 'all' : 'online',
|
||||
filter: filtering,
|
||||
type: !status ? 'all' : 'online',
|
||||
filter,
|
||||
skip: PAGE_SIZE * page,
|
||||
limit: PAGE_SIZE,
|
||||
allUsers
|
||||
allUsers: !status
|
||||
});
|
||||
const end = membersResult?.length < PAGE_SIZE;
|
||||
const membersResultFiltered = membersResult?.filter((member: TUserModel) => !members.some(m => m._id === member._id));
|
||||
this.setState({
|
||||
members: members.concat(membersResultFiltered || []),
|
||||
updateState({
|
||||
members: [...members, ...membersResultFiltered],
|
||||
isLoading: false,
|
||||
end,
|
||||
page: page + 1
|
||||
});
|
||||
this.setHeader();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
this.setState({ isLoading: false });
|
||||
updateState({ isLoading: false });
|
||||
}
|
||||
};
|
||||
|
||||
goRoom = (item: TGoRoomItem) => {
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
// @ts-ignore
|
||||
navigation.navigate('DrawerNavigator');
|
||||
} else {
|
||||
navigation.popToTop();
|
||||
}
|
||||
goRoom({ item, isMasterDetail });
|
||||
};
|
||||
const filteredMembers =
|
||||
state.members && state.members.length > 0 && state.filter
|
||||
? state.members.filter(
|
||||
m =>
|
||||
m.username.toLowerCase().match(state.filter.toLowerCase()) || m.name?.toLowerCase().match(state.filter.toLowerCase())
|
||||
)
|
||||
: null;
|
||||
|
||||
getUserDisplayName = (user: TUserModel) => {
|
||||
const { useRealName } = this.props;
|
||||
return (useRealName ? user.name : user.username) || user.username;
|
||||
};
|
||||
|
||||
handleMute = async (user: TUserModel) => {
|
||||
const { rid } = this.state;
|
||||
try {
|
||||
await Services.toggleMuteUserInRoom(rid, user?.username, !user?.muted);
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t('User_has_been_key', { key: user?.muted ? I18n.t('unmuted') : I18n.t('muted') })
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleOwner = async (selectedUser: TUserModel, isOwner: boolean) => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
await Services.toggleRoomOwner({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isOwner
|
||||
});
|
||||
const message = isOwner
|
||||
? 'User__username__is_now_a_owner_of__room_name_'
|
||||
: 'User__username__removed_from__room_name__owners';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username: this.getUserDisplayName(selectedUser),
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
this.fetchRoomMembersRoles();
|
||||
};
|
||||
|
||||
handleLeader = async (selectedUser: TUserModel, isLeader: boolean) => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
await Services.toggleRoomLeader({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isLeader
|
||||
});
|
||||
const message = isLeader
|
||||
? 'User__username__is_now_a_leader_of__room_name_'
|
||||
: 'User__username__removed_from__room_name__leaders';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username: this.getUserDisplayName(selectedUser),
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
this.fetchRoomMembersRoles();
|
||||
};
|
||||
|
||||
handleModerator = async (selectedUser: TUserModel, isModerator: boolean) => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
await Services.toggleRoomModerator({
|
||||
roomId: room.rid,
|
||||
t: room.t,
|
||||
userId: selectedUser._id,
|
||||
isModerator
|
||||
});
|
||||
const message = isModerator
|
||||
? 'User__username__is_now_a_moderator_of__room_name_'
|
||||
: 'User__username__removed_from__room_name__moderators';
|
||||
EventEmitter.emit(LISTENER, {
|
||||
message: I18n.t(message, {
|
||||
username: this.getUserDisplayName(selectedUser),
|
||||
room_name: getRoomTitle(room)
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
this.fetchRoomMembersRoles();
|
||||
};
|
||||
|
||||
handleIgnore = async (selectedUser: TUserModel, ignore: boolean) => {
|
||||
try {
|
||||
const { room } = this.state;
|
||||
await Services.ignoreUser({
|
||||
rid: room.rid,
|
||||
userId: selectedUser._id,
|
||||
ignore
|
||||
});
|
||||
const message = I18n.t(ignore ? 'User_has_been_ignored' : 'User_has_been_unignored');
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleRemoveUserFromRoom = async (selectedUser: TUserModel) => {
|
||||
try {
|
||||
const { room, members, membersFiltered } = this.state;
|
||||
const userId = selectedUser._id;
|
||||
// TODO: interface SubscriptionType on IRoom is wrong
|
||||
await Services.removeUserFromRoom({ roomId: room.rid, t: room.t as RoomTypes, userId });
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
this.setState({
|
||||
members: members.filter(member => member._id !== userId),
|
||||
membersFiltered: this.isServerVersionLowerThan3_16 ? membersFiltered.filter(member => member._id !== userId) : []
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
renderSearchBar = () => <SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='room-members-view-search' />;
|
||||
|
||||
renderItem = ({ item }: { item: TUserModel }) => {
|
||||
const { theme } = this.props;
|
||||
|
||||
return (
|
||||
<UserItem
|
||||
name={item.name as string}
|
||||
username={item.username}
|
||||
onPress={() => this.onPressUser(item)}
|
||||
testID={`room-members-view-item-${item.username}`}
|
||||
theme={theme}
|
||||
return (
|
||||
<SafeAreaView testID='room-members-view'>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={filteredMembers || state.members}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ backgroundColor: colors.backgroundColor }}>
|
||||
<UserItem
|
||||
name={item.name as string}
|
||||
username={item.username}
|
||||
onPress={() => onPressUser(item)}
|
||||
testID={`room-members-view-item-${item.username}`}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
style={styles.list}
|
||||
keyExtractor={item => item._id}
|
||||
ItemSeparatorComponent={List.Separator}
|
||||
ListHeaderComponent={
|
||||
<>
|
||||
<ActionsSection joined={params.joined as boolean} rid={state.room.rid} t={state.room.t} />
|
||||
<View style={{ backgroundColor: colors.backgroundColor }}>
|
||||
<SearchBox onChangeText={text => updateState({ filter: text.trim() })} testID='room-members-view-search' />
|
||||
</View>
|
||||
</>
|
||||
}
|
||||
ListFooterComponent={() => (state.isLoading ? <ActivityIndicator /> : null)}
|
||||
onEndReachedThreshold={0.1}
|
||||
onEndReached={() => fetchMembers(state.allUsers)}
|
||||
ListEmptyComponent={() =>
|
||||
state.end ? <Text style={[styles.noResult, { color: colors.titleText }]}>{I18n.t('No_members_found')}</Text> : null
|
||||
}
|
||||
{...scrollPersistTaps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { filtering, members, membersFiltered, isLoading } = this.state;
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<SafeAreaView testID='room-members-view'>
|
||||
<StatusBar />
|
||||
<FlatList
|
||||
data={!!filtering && this.isServerVersionLowerThan3_16 ? membersFiltered : members}
|
||||
renderItem={this.renderItem}
|
||||
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
|
||||
keyExtractor={item => item._id}
|
||||
ItemSeparatorComponent={List.Separator}
|
||||
ListHeaderComponent={this.renderSearchBar}
|
||||
ListFooterComponent={() => {
|
||||
if (isLoading) {
|
||||
return <ActivityIndicator />;
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
onEndReachedThreshold={0.1}
|
||||
onEndReached={this.fetchMembers}
|
||||
maxToRenderPerBatch={5}
|
||||
windowSize={10}
|
||||
{...scrollPersistTaps}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
baseUrl: state.server.server,
|
||||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
muteUserPermission: state.permissions['mute-user'],
|
||||
setLeaderPermission: state.permissions['set-leader'],
|
||||
setOwnerPermission: state.permissions['set-owner'],
|
||||
setModeratorPermission: state.permissions['set-moderator'],
|
||||
removeUserPermission: state.permissions['remove-user'],
|
||||
editTeamMemberPermission: state.permissions['edit-team-member'],
|
||||
viewAllTeamChannelsPermission: state.permissions['view-all-team-channels'],
|
||||
viewAllTeamsPermission: state.permissions['view-all-teams'],
|
||||
serverVersion: state.server.version
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(withActionSheet(RoomMembersView)));
|
||||
export default RoomMembersView;
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import sharedStyles from '../Styles';
|
||||
|
||||
export default StyleSheet.create({
|
||||
list: {
|
||||
flex: 1
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 16,
|
||||
alignItems: 'center'
|
||||
},
|
||||
avatar: {
|
||||
marginRight: 16
|
||||
},
|
||||
separator: {
|
||||
height: StyleSheet.hairlineWidth,
|
||||
marginLeft: 60
|
||||
noResult: {
|
||||
fontSize: 16,
|
||||
paddingVertical: 56,
|
||||
...sharedStyles.textSemibold,
|
||||
...sharedStyles.textAlignCenter
|
||||
}
|
||||
});
|
||||
|
|
|
@ -211,19 +211,15 @@ class SelectedUsersView extends React.Component<ISelectedUsersViewProps, ISelect
|
|||
);
|
||||
};
|
||||
|
||||
renderSelectedItem = ({ item }: { item: ISelectedUser }) => {
|
||||
const { theme } = this.props;
|
||||
return (
|
||||
<UserItem
|
||||
name={item.fname}
|
||||
username={item.name}
|
||||
onPress={() => this._onPressSelectedItem(item)}
|
||||
testID={`selected-user-${item.name}`}
|
||||
style={{ paddingRight: 15 }}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
renderSelectedItem = ({ item }: { item: ISelectedUser }) => (
|
||||
<UserItem
|
||||
name={item.fname}
|
||||
username={item.name}
|
||||
onPress={() => this._onPressSelectedItem(item)}
|
||||
testID={`selected-user-${item.name}`}
|
||||
style={{ paddingRight: 15 }}
|
||||
/>
|
||||
);
|
||||
|
||||
renderItem = ({ item, index }: { item: ISelectedUser; index: number }) => {
|
||||
const { search, chats } = this.state;
|
||||
|
@ -249,7 +245,6 @@ class SelectedUsersView extends React.Component<ISelectedUsersViewProps, ISelect
|
|||
testID={`select-users-view-item-${item.name}`}
|
||||
icon={this.isChecked(username) ? 'check' : null}
|
||||
style={style}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -146,10 +146,6 @@ describe('Room actions screen', () => {
|
|||
await expect(element(by.id('room-actions-members'))).toExist();
|
||||
});
|
||||
|
||||
it('should have add user', async () => {
|
||||
await expect(element(by.id('room-actions-add-user'))).toExist();
|
||||
});
|
||||
|
||||
it('should have files', async () => {
|
||||
await expect(element(by.id('room-actions-files'))).toExist();
|
||||
});
|
||||
|
@ -303,24 +299,12 @@ describe('Room actions screen', () => {
|
|||
.withTimeout(4000);
|
||||
});
|
||||
|
||||
it('should have notification audio option', async () => {
|
||||
await waitFor(element(by.id('notification-preference-view-audio')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
});
|
||||
|
||||
it('should have notification sound option', async () => {
|
||||
await waitFor(element(by.id('notification-preference-view-sound')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
});
|
||||
|
||||
it('should have notification duration option', async () => {
|
||||
await waitFor(element(by.id('notification-preference-view-notification-duration')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
});
|
||||
|
||||
it('should have email alert option', async () => {
|
||||
await waitFor(element(by.id('notification-preference-view-email-alert')))
|
||||
.toExist()
|
||||
|
@ -361,6 +345,14 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
it('should add users to the room', async () => {
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await waitFor(element(by.id('room-members-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
||||
await waitFor(element(by.id('room-actions-add-user')))
|
||||
.toExist()
|
||||
.withTimeout(4000);
|
||||
|
@ -392,19 +384,14 @@ describe('Room actions screen', () => {
|
|||
|
||||
await element(by.id('selected-users-view-submit')).tap();
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await backToActions();
|
||||
});
|
||||
|
||||
describe('Room Members', () => {
|
||||
before(async () => {
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await waitFor(element(by.id('room-members-view')))
|
||||
.toExist()
|
||||
|
@ -442,13 +429,30 @@ describe('Room actions screen', () => {
|
|||
};
|
||||
|
||||
it('should show all users', async () => {
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await waitFor(element(by.id('room-members-view-filter')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('room-members-view-filter')).tap();
|
||||
await waitFor(element(by.id('room-members-view-toggle-status-all')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status-all')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
await tapBack();
|
||||
});
|
||||
|
||||
it('should filter user', async () => {
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await element(by.id('room-members-view-filter')).tap();
|
||||
await waitFor(element(by.id('room-members-view-toggle-status-all')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status-all')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
@ -595,11 +599,21 @@ describe('Room actions screen', () => {
|
|||
await waitFor(element(by.id('room-actions-view')))
|
||||
.toExist()
|
||||
.withTimeout(5000);
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await waitFor(element(by.id('room-members-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await waitFor(element(by.id('room-members-view-filter')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('room-members-view-filter')).tap();
|
||||
await waitFor(element(by.id('room-members-view-toggle-status-all')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status-all')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
@ -625,6 +639,7 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
it('should block/unblock user', async () => {
|
||||
await element(by.id('room-actions-scrollview')).scrollTo('bottom');
|
||||
await waitFor(element(by.id('room-actions-block-user'))).toExist();
|
||||
await element(by.id('room-actions-block-user')).tap();
|
||||
await waitFor(element(by[textMatcher]('Unblock user')))
|
||||
|
|
|
@ -266,6 +266,11 @@ describe('Team', () => {
|
|||
});
|
||||
|
||||
it('should add users to the team', async () => {
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await waitFor(element(by.id('room-members-view')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
|
||||
await waitFor(element(by.id('room-actions-add-user')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
|
@ -296,11 +301,17 @@ describe('Team', () => {
|
|||
|
||||
await element(by.id('selected-users-view-submit')).tap();
|
||||
await sleep(300);
|
||||
await tapBack();
|
||||
await sleep(300);
|
||||
await waitFor(element(by.id('room-actions-members')))
|
||||
.toExist()
|
||||
.withTimeout(10000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await element(by.id('room-members-view-filter')).tap();
|
||||
await waitFor(element(by.id('room-members-view-toggle-status-all')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status-all')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
@ -358,7 +369,11 @@ describe('Team', () => {
|
|||
});
|
||||
|
||||
it('should show all users', async () => {
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await element(by.id('room-members-view-filter')).tap();
|
||||
await waitFor(element(by.id('room-members-view-toggle-status-all')))
|
||||
.toExist()
|
||||
.withTimeout(2000);
|
||||
await element(by.id('room-members-view-toggle-status-all')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${user.username}`)))
|
||||
.toExist()
|
||||
.withTimeout(60000);
|
||||
|
|
Loading…
Reference in New Issue