Chore: Migrate RoomActionsView to Typescript (#3750)

This commit is contained in:
Diego Mello 2022-03-02 11:49:43 -03:00 committed by GitHub
parent 6b3730ce43
commit 6626510f50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 213 additions and 153 deletions

View File

@ -4,7 +4,7 @@ import { ERoomType } from '../definitions/ERoomType';
import { ROOM } from './actionsTypes'; import { ROOM } from './actionsTypes';
// TYPE RETURN RELATED // TYPE RETURN RELATED
type ISelected = Record<string, string>; type ISelected = string[];
export interface ITransferData { export interface ITransferData {
roomId: string; roomId: string;

View File

@ -1,26 +1,26 @@
import { Action } from 'redux'; import { Action } from 'redux';
import { ISettings, TSettings } from '../reducers/settings'; import { TSettingsState, TSupportedSettings, TSettingsValues } from '../reducers/settings';
import { SETTINGS } from './actionsTypes'; import { SETTINGS } from './actionsTypes';
interface IAddSettings extends Action { interface IAddSettings extends Action {
payload: ISettings; payload: TSettingsState;
} }
interface IUpdateSettings extends Action { interface IUpdateSettings extends Action {
payload: { id: string; value: TSettings }; payload: { id: TSupportedSettings; value: TSettingsValues };
} }
export type IActionSettings = IAddSettings & IUpdateSettings; export type IActionSettings = IAddSettings & IUpdateSettings;
export function addSettings(settings: ISettings): IAddSettings { export function addSettings(settings: TSettingsState): IAddSettings {
return { return {
type: SETTINGS.ADD, type: SETTINGS.ADD,
payload: settings payload: settings
}; };
} }
export function updateSettings(id: string, value: TSettings): IUpdateSettings { export function updateSettings(id: TSupportedSettings, value: TSettingsValues): IUpdateSettings {
return { return {
type: SETTINGS.UPDATE, type: SETTINGS.UPDATE,
payload: { id, value } payload: { id, value }

View File

@ -206,4 +206,4 @@ export default {
Canned_Responses_Enable: { Canned_Responses_Enable: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
} }
}; } as const;

View File

@ -12,7 +12,7 @@ export enum SubscriptionType {
DIRECT = 'd', DIRECT = 'd',
CHANNEL = 'c', CHANNEL = 'c',
OMNICHANNEL = 'l', OMNICHANNEL = 'l',
E2E = 'e2e', E2E = 'e2e', // FIXME: this is not a type of subscription
THREAD = 'thread' // FIXME: this is not a type of subscription THREAD = 'thread' // FIXME: this is not a type of subscription
} }
@ -36,7 +36,7 @@ export interface ISubscription {
_updatedAt?: string; // from server _updatedAt?: string; // from server
v?: IVisitor; v?: IVisitor;
f: boolean; f: boolean;
t: SubscriptionType; t: string; // TODO: we need to review this type later
ts: string | Date; ts: string | Date;
ls: Date; ls: Date;
name: string; name: string;
@ -81,6 +81,7 @@ export interface ISubscription {
usernames?: string[]; usernames?: string[];
visitor?: IVisitor; visitor?: IVisitor;
departmentId?: string; departmentId?: string;
status?: string;
servedBy?: IServedBy; servedBy?: IServedBy;
livechatData?: any; livechatData?: any;
tags?: string[]; tags?: string[];

View File

@ -30,6 +30,7 @@ export interface IBaseScreen<T extends Record<string, object | undefined>, S ext
route: RouteProp<T, S>; route: RouteProp<T, S>;
dispatch: Dispatch; dispatch: Dispatch;
theme: string; theme: string;
isMasterDetail: boolean;
} }
export * from './redux'; export * from './redux';

View File

@ -28,15 +28,15 @@ import { IRoles } from '../../reducers/roles';
import { IRoom } from '../../reducers/room'; import { IRoom } from '../../reducers/room';
import { ISelectedUsers } from '../../reducers/selectedUsers'; import { ISelectedUsers } from '../../reducers/selectedUsers';
import { IServer } from '../../reducers/server'; import { IServer } from '../../reducers/server';
import { ISettings } from '../../reducers/settings'; import { TSettingsState } from '../../reducers/settings';
import { IShare } from '../../reducers/share'; import { IShare } from '../../reducers/share';
import { IPermissionsState } from '../../reducers/permissions'; import { IPermissionsState } from '../../reducers/permissions';
import { IEnterpriseModules } from '../../reducers/enterpriseModules'; import { IEnterpriseModules } from '../../reducers/enterpriseModules';
export interface IApplicationState { export interface IApplicationState {
settings: ISettings; settings: TSettingsState;
meteor: IConnect;
login: ILogin; login: ILogin;
meteor: IConnect;
server: IServer; server: IServer;
selectedUsers: ISelectedUsers; selectedUsers: ISelectedUsers;
app: IApp; app: IApp;

View File

@ -10,7 +10,7 @@ export const E2E_BANNER_TYPE = {
REQUEST_PASSWORD: 'REQUEST_PASSWORD', REQUEST_PASSWORD: 'REQUEST_PASSWORD',
SAVE_PASSWORD: 'SAVE_PASSWORD' SAVE_PASSWORD: 'SAVE_PASSWORD'
}; };
export const E2E_ROOM_TYPES = { export const E2E_ROOM_TYPES: Record<string, string> = {
d: 'd', d: 'd',
p: 'p' p: 'p'
}; };

View File

@ -1,4 +1,4 @@
import { IRoom } from '../../definitions'; import { IRoom, SubscriptionType } from '../../definitions';
import { getSubscriptionByRoomId } from '../database/services/Subscription'; import { getSubscriptionByRoomId } from '../database/services/Subscription';
import RocketChat from '../rocketchat'; import RocketChat from '../rocketchat';
@ -10,7 +10,7 @@ const getRoomInfo = async (rid: string): Promise<Pick<IRoom, 'rid' | 'name' | 'f
rid, rid,
name: result.name, name: result.name,
fname: result.fname, fname: result.fname,
t: result.t t: result.t as SubscriptionType
}; };
} }

View File

@ -1,6 +1,6 @@
import { addSettings, clearSettings, updateSettings } from '../actions/settings'; import { addSettings, clearSettings, updateSettings } from '../actions/settings';
import { mockedStore } from './mockedStore'; import { mockedStore } from './mockedStore';
import { initialState } from './settings'; import { initialState, TSettingsState } from './settings';
describe('test settings reducer', () => { describe('test settings reducer', () => {
it('should return initial state', () => { it('should return initial state', () => {
@ -8,7 +8,11 @@ describe('test settings reducer', () => {
expect(state).toEqual(initialState); expect(state).toEqual(initialState);
}); });
const settings = { API_Use_REST_For_DDP_Calls: true, FileUpload_MaxFileSize: 600857600, Jitsi_URL_Room_Prefix: 'RocketChat' }; const settings: TSettingsState = {
API_Use_REST_For_DDP_Calls: true,
FileUpload_MaxFileSize: 600857600,
Jitsi_URL_Room_Prefix: 'RocketChat'
};
it('should return modified store after call addSettings action', () => { it('should return modified store after call addSettings action', () => {
mockedStore.dispatch(addSettings(settings)); mockedStore.dispatch(addSettings(settings));

View File

@ -1,13 +1,17 @@
import { IActionSettings } from '../actions/settings'; import { IActionSettings } from '../actions/settings';
import { SETTINGS } from '../actions/actionsTypes'; import { SETTINGS } from '../actions/actionsTypes';
import settings from '../constants/settings';
export type TSettings = string | number | boolean | string[]; export type TSupportedSettings = keyof typeof settings;
export type TSettingsValues = string | number | boolean | string[];
export type ISettings = Record<string, TSettings>; export type TSettingsState = {
[K in TSupportedSettings]?: TSettingsValues;
};
export const initialState: ISettings = {}; export const initialState: TSettingsState = {};
export default (state = initialState, action: IActionSettings): ISettings => { export default (state = initialState, action: IActionSettings): TSettingsState => {
switch (action.type) { switch (action.type) {
case SETTINGS.ADD: case SETTINGS.ADD:
return { return {

View File

@ -19,35 +19,37 @@ export type ChatsStackParamList = {
NewMessageStackNavigator: any; NewMessageStackNavigator: any;
NewMessageStack: undefined; NewMessageStack: undefined;
RoomsListView: undefined; RoomsListView: undefined;
RoomView?: { RoomView:
rid: string; | {
t: SubscriptionType; rid: string;
tmid?: string; t: SubscriptionType;
message?: object; // TODO: TMessageModel? tmid?: string;
name?: string; message?: object; // TODO: TMessageModel?
fname?: string; name?: string;
prid?: string; fname?: string;
room?: TSubscriptionModel | { rid: string; t: string; name?: string; fname?: string; prid?: string }; prid?: string;
jumpToMessageId?: string; room?: TSubscriptionModel | { rid: string; t: string; name?: string; fname?: string; prid?: string };
jumpToThreadId?: string; jumpToMessageId?: string;
roomUserId?: string | null; jumpToThreadId?: string;
usedCannedResponse?: string; roomUserId?: string | null;
}; usedCannedResponse?: string;
}
| undefined; // Navigates back to RoomView already on stack
RoomActionsView: { RoomActionsView: {
room?: ISubscription; room: TSubscriptionModel;
member: any; member: any;
rid: string; rid: string;
t: SubscriptionType; t: SubscriptionType;
joined: boolean; joined: boolean;
}; };
SelectListView: { SelectListView: {
data: IRoom[]; data?: IRoom[];
title: string; title: string;
infoText: string; infoText?: string;
nextAction: (selected: string[]) => void; nextAction: (selected: string[]) => void;
showAlert: () => void; showAlert?: () => void;
isSearch: boolean; isSearch?: boolean;
onSearch: (text: string) => Partial<IRoom[]>; onSearch?: (text: string) => Promise<Partial<IRoom[]> | any>;
isRadio?: boolean; isRadio?: boolean;
}; };
RoomInfoView: { RoomInfoView: {

View File

@ -1,9 +1,9 @@
import { ChatsStackParamList } from '../stacks/types'; import { ChatsStackParamList } from '../stacks/types';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import { IVisitor, SubscriptionType } from '../definitions/ISubscription'; import { ISubscription, IVisitor, SubscriptionType, TSubscriptionModel } from '../definitions/ISubscription';
export interface IGoRoomItem { interface IGoRoomItem {
search?: boolean; // comes from spotlight search?: boolean; // comes from spotlight
username?: string; username?: string;
t?: SubscriptionType; t?: SubscriptionType;
@ -13,12 +13,14 @@ export interface IGoRoomItem {
visitor?: IVisitor; visitor?: IVisitor;
} }
export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription;
const navigate = ({ const navigate = ({
item, item,
isMasterDetail, isMasterDetail,
...props ...props
}: { }: {
item: IGoRoomItem; item: TGoRoomItem;
isMasterDetail: boolean; isMasterDetail: boolean;
navigationMethod?: () => ChatsStackParamList; navigationMethod?: () => ChatsStackParamList;
}) => { }) => {
@ -45,13 +47,13 @@ export const goRoom = async ({
isMasterDetail = false, isMasterDetail = false,
...props ...props
}: { }: {
item: IGoRoomItem; item: TGoRoomItem;
isMasterDetail: boolean; isMasterDetail: boolean;
navigationMethod?: any; navigationMethod?: any;
jumpToMessageId?: string; jumpToMessageId?: string;
usedCannedResponse?: string; usedCannedResponse?: string;
}): Promise<void> => { }): Promise<void> => {
if (item.t === SubscriptionType.DIRECT && item?.search) { if (!('id' in item) && item.t === SubscriptionType.DIRECT && item?.search) {
// if user is using the search we need first to join/create room // if user is using the search we need first to join/create room
try { try {
const { username } = item; const { username } = item;

View File

@ -115,7 +115,7 @@ const CannedResponseDetail = ({ navigation, route }: ICannedResponseDetailProps)
t: room.t, t: room.t,
fname: name fname: name
}), }),
t: room.t, t: room.t as any,
roomUserId: RocketChat.getUidDirectMessage(room), roomUserId: RocketChat.getUidDirectMessage(room),
usedCannedResponse: item.text usedCannedResponse: item.text
}; };

View File

@ -118,7 +118,7 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
t: room.t, t: room.t,
fname: name fname: name
}), }),
t: room.t, t: room.t as any,
roomUserId: RocketChat.getUidDirectMessage(room), roomUserId: RocketChat.getUidDirectMessage(room),
usedCannedResponse: item.text usedCannedResponse: item.text
}; };

View File

@ -1,38 +1,94 @@
import { Q } from '@nozbe/watermelondb';
import { StackNavigationOptions } from '@react-navigation/stack';
import isEmpty from 'lodash/isEmpty';
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { Share, Switch, Text, View } from 'react-native'; import { Share, Switch, Text, View } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import isEmpty from 'lodash/isEmpty'; import { Observable, Subscription } from 'rxjs';
import { Q } from '@nozbe/watermelondb';
import { compareServerVersion } from '../../lib/utils';
import Touch from '../../utils/touch';
import { setLoading } from '../../actions/selectedUsers';
import { closeRoom, leaveRoom } from '../../actions/room'; import { closeRoom, leaveRoom } from '../../actions/room';
import sharedStyles from '../Styles'; import { setLoading } from '../../actions/selectedUsers';
import Avatar from '../../containers/Avatar';
import Status from '../../containers/Status';
import * as List from '../../containers/List';
import RocketChat from '../../lib/rocketchat';
import log, { events, logEvent } from '../../utils/log';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
import StatusBar from '../../containers/StatusBar';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors'; import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
import { withTheme } from '../../theme'; import Avatar from '../../containers/Avatar';
import * as HeaderButton from '../../containers/HeaderButton'; import * as HeaderButton from '../../containers/HeaderButton';
import * as List from '../../containers/List';
import { MarkdownPreview } from '../../containers/markdown'; import { MarkdownPreview } from '../../containers/markdown';
import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; import RoomTypeIcon from '../../containers/RoomTypeIcon';
import SafeAreaView from '../../containers/SafeAreaView'; import SafeAreaView from '../../containers/SafeAreaView';
import Status from '../../containers/Status';
import StatusBar from '../../containers/StatusBar';
import { IApplicationState, IBaseScreen, IRoom, ISubscription, IUser, TSubscriptionModel } from '../../definitions';
import { withDimensions } from '../../dimensions';
import I18n from '../../i18n';
import database from '../../lib/database';
import { E2E_ROOM_TYPES } from '../../lib/encryption/constants'; import { E2E_ROOM_TYPES } from '../../lib/encryption/constants';
import protectedFunction from '../../lib/methods/helpers/protectedFunction'; import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import database from '../../lib/database'; import RocketChat from '../../lib/rocketchat';
import { withDimensions } from '../../dimensions'; import { compareServerVersion } from '../../lib/utils';
import { getUserSelector } from '../../selectors/login';
import { ChatsStackParamList } from '../../stacks/types';
import { withTheme } from '../../theme';
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
import log, { events, logEvent } from '../../utils/log';
import Touch from '../../utils/touch';
import sharedStyles from '../Styles';
import styles from './styles'; import styles from './styles';
import { ERoomType } from '../../definitions/ERoomType';
class RoomActionsView extends React.Component { interface IRoomActionsViewProps extends IBaseScreen<ChatsStackParamList, 'RoomActionsView'> {
static navigationOptions = ({ navigation, isMasterDetail }) => { userId: string;
const options = { jitsiEnabled: boolean;
jitsiEnableTeams: boolean;
jitsiEnableChannels: boolean;
encryptionEnabled: boolean;
fontScale: number;
serverVersion: string | null;
addUserToJoinedRoomPermission?: string[];
addUserToAnyCRoomPermission?: string[];
addUserToAnyPRoomPermission?: string[];
createInviteLinksPermission?: string[];
editRoomPermission?: string[];
toggleRoomE2EEncryptionPermission?: string[];
viewBroadcastMemberListPermission?: string[];
transferLivechatGuestPermission?: string[];
createTeamPermission?: string[];
addTeamChannelPermission?: string[];
convertTeamPermission?: string[];
viewCannedResponsesPermission?: string[];
}
interface IRoomActionsViewState {
room: TSubscriptionModel;
membersCount: number;
member: Partial<IUser>;
joined: boolean;
canViewMembers: boolean;
canAutoTranslate: boolean;
canAddUser: boolean;
canInviteUser: boolean;
canForwardGuest: boolean;
canReturnQueue: boolean;
canEdit: boolean;
canToggleEncryption: boolean;
canCreateTeam: boolean;
canAddChannelToTeam: boolean;
canConvertTeam: boolean;
canViewCannedResponse: boolean;
}
class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomActionsViewState> {
private mounted: boolean;
private rid: string;
private t: string;
private joined: boolean;
private roomObservable?: Observable<TSubscriptionModel>;
private subscription?: Subscription;
static navigationOptions = ({
navigation,
isMasterDetail
}: Pick<IRoomActionsViewProps, 'navigation' | 'isMasterDetail'>): StackNavigationOptions => {
const options: StackNavigationOptions = {
title: I18n.t('Actions') title: I18n.t('Actions')
}; };
if (isMasterDetail) { if (isMasterDetail) {
@ -41,34 +97,7 @@ class RoomActionsView extends React.Component {
return options; return options;
}; };
static propTypes = { constructor(props: IRoomActionsViewProps) {
navigation: PropTypes.object,
route: PropTypes.object,
leaveRoom: PropTypes.func,
jitsiEnabled: PropTypes.bool,
jitsiEnableTeams: PropTypes.bool,
jitsiEnableChannels: PropTypes.bool,
encryptionEnabled: PropTypes.bool,
setLoadingInvite: PropTypes.func,
closeRoom: PropTypes.func,
theme: PropTypes.string,
fontScale: PropTypes.number,
serverVersion: PropTypes.string,
addUserToJoinedRoomPermission: PropTypes.array,
addUserToAnyCRoomPermission: PropTypes.array,
addUserToAnyPRoomPermission: PropTypes.array,
createInviteLinksPermission: PropTypes.array,
editRoomPermission: PropTypes.array,
toggleRoomE2EEncryptionPermission: PropTypes.array,
viewBroadcastMemberListPermission: PropTypes.array,
transferLivechatGuestPermission: PropTypes.array,
createTeamPermission: PropTypes.array,
addTeamChannelPermission: PropTypes.array,
convertTeamPermission: PropTypes.array,
viewCannedResponsesPermission: PropTypes.array
};
constructor(props) {
super(props); super(props);
this.mounted = false; this.mounted = false;
const room = props.route.params?.room; const room = props.route.params?.room;
@ -77,7 +106,7 @@ class RoomActionsView extends React.Component {
this.t = props.route.params?.t; this.t = props.route.params?.t;
this.joined = props.route.params?.joined; this.joined = props.route.params?.joined;
this.state = { this.state = {
room: room || { rid: this.rid, t: this.t }, room: room || ({ rid: this.rid, t: this.t } as any),
membersCount: 0, membersCount: 0,
member: member || {}, member: member || {},
joined: !!room, joined: !!room,
@ -100,6 +129,7 @@ class RoomActionsView extends React.Component {
if (this.mounted) { if (this.mounted) {
this.setState({ room: changes }); this.setState({ room: changes });
} else { } else {
// @ts-ignore
this.state.room = changes; this.state.room = changes;
} }
}); });
@ -123,7 +153,7 @@ class RoomActionsView extends React.Component {
if (room && room.t !== 'd' && this.canViewMembers()) { if (room && room.t !== 'd' && this.canViewMembers()) {
try { try {
const counters = await RocketChat.getRoomCounters(room.rid, room.t); const counters = await RocketChat.getRoomCounters(room.rid, room.t as any);
if (counters.success) { if (counters.success) {
this.setState({ membersCount: counters.members, joined: counters.joined }); this.setState({ membersCount: counters.members, joined: counters.joined });
} }
@ -177,9 +207,15 @@ class RoomActionsView extends React.Component {
return room.t === 'l' && room.status === 'queued' && !this.joined; return room.t === 'l' && room.status === 'queued' && !this.joined;
} }
onPressTouchable = item => { // TODO: assert params required for navigation
onPressTouchable = (item: { route?: keyof ChatsStackParamList; params?: object; event?: Function }) => {
const { route, event, params } = item; const { route, event, params } = item;
if (route) { if (route) {
/**
* TODO: params can vary too much and ts is going to be happy
* Instead of playing with this, we should think on a better `logEvent` function
*/
// @ts-ignore
logEvent(events[`RA_GO_${route.replace('View', '').toUpperCase()}${params.name ? params.name.toUpperCase() : ''}`]); logEvent(events[`RA_GO_${route.replace('View', '').toUpperCase()}${params.name ? params.name.toUpperCase() : ''}`]);
const { navigation } = this.props; const { navigation } = this.props;
navigation.navigate(route, params); navigation.navigate(route, params);
@ -349,7 +385,7 @@ class RoomActionsView extends React.Component {
onPress: async () => { onPress: async () => {
try { try {
await RocketChat.returnLivechat(rid); await RocketChat.returnLivechat(rid);
} catch (e) { } catch (e: any) {
showErrorAlert(e.reason, I18n.t('Oops')); showErrorAlert(e.reason, I18n.t('Oops'));
} }
} }
@ -364,7 +400,7 @@ class RoomActionsView extends React.Component {
const roomUserId = RocketChat.getUidDirectMessage(room); const roomUserId = RocketChat.getUidDirectMessage(room);
const result = await RocketChat.getUserInfo(roomUserId); const result = await RocketChat.getUserInfo(roomUserId);
if (result.success) { if (result.success) {
this.setState({ member: result.user }); this.setState({ member: result.user as any });
} }
} }
} catch (e) { } catch (e) {
@ -394,7 +430,7 @@ class RoomActionsView extends React.Component {
const { rid, blocker } = room; const { rid, blocker } = room;
const { member } = this.state; const { member } = this.state;
try { try {
await RocketChat.toggleBlockUser(rid, member._id, !blocker); await RocketChat.toggleBlockUser(rid, member._id as string, !blocker);
} catch (e) { } catch (e) {
logEvent(events.RA_TOGGLE_BLOCK_USER_F); logEvent(events.RA_TOGGLE_BLOCK_USER_F);
log(e); log(e);
@ -411,9 +447,9 @@ class RoomActionsView extends React.Component {
const encrypted = !room.encrypted; const encrypted = !room.encrypted;
try { try {
// Instantly feedback to the user // Instantly feedback to the user
await db.action(async () => { await db.write(async () => {
await room.update( await room.update(
protectedFunction(r => { protectedFunction((r: TSubscriptionModel) => {
r.encrypted = encrypted; r.encrypted = encrypted;
}) })
); );
@ -431,9 +467,9 @@ class RoomActionsView extends React.Component {
} }
// If something goes wrong we go back to the previous value // If something goes wrong we go back to the previous value
await db.action(async () => { await db.write(async () => {
await room.update( await room.update(
protectedFunction(r => { protectedFunction((r: TSubscriptionModel) => {
r.encrypted = room.encrypted; r.encrypted = room.encrypted;
}) })
); );
@ -463,28 +499,31 @@ class RoomActionsView extends React.Component {
showConfirmationAlert({ showConfirmationAlert({
message: I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), message: I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }),
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
onPress: () => dispatch(leaveRoom('channel', room)) onPress: () => dispatch(leaveRoom(ERoomType.c, room))
}); });
}; };
convertTeamToChannel = async () => { convertTeamToChannel = async () => {
const { room } = this.state; const { room } = this.state;
const { navigation } = this.props; const { navigation, userId } = this.props;
try { try {
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); if (!room.teamId) {
return;
}
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId });
if (result.rooms?.length) { if (result.rooms?.length) {
const teamChannels = result.rooms.map(r => ({ const teamChannels = result.rooms.map((r: any) => ({
rid: r._id, rid: r._id,
name: r.name, name: r.name,
teamId: r.teamId teamId: r.teamId
})); }));
navigation.navigate('SelectListView', { navigation.navigate('SelectListView', {
title: 'Converting_Team_To_Channel', title: 'Converting_Team_To_Channel',
data: teamChannels, data: teamChannels as any,
infoText: 'Select_Team_Channels_To_Delete', infoText: 'Select_Team_Channels_To_Delete',
nextAction: data => this.convertTeamToChannelConfirmation(data) nextAction: (data: string[]) => this.convertTeamToChannelConfirmation(data)
}); });
} else { } else {
this.convertTeamToChannelConfirmation(); this.convertTeamToChannelConfirmation();
@ -494,12 +533,15 @@ class RoomActionsView extends React.Component {
} }
}; };
handleConvertTeamToChannel = async selected => { handleConvertTeamToChannel = async (selected: string[]) => {
logEvent(events.RA_CONVERT_TEAM_TO_CHANNEL); logEvent(events.RA_CONVERT_TEAM_TO_CHANNEL);
try { try {
const { room } = this.state; const { room } = this.state;
const { navigation } = this.props; const { navigation } = this.props;
if (!room.teamId) {
return;
}
const result = await RocketChat.convertTeamToChannel({ teamId: room.teamId, selected }); const result = await RocketChat.convertTeamToChannel({ teamId: room.teamId, selected });
if (result.success) { if (result.success) {
@ -511,7 +553,7 @@ class RoomActionsView extends React.Component {
} }
}; };
convertTeamToChannelConfirmation = (selected = []) => { convertTeamToChannelConfirmation = (selected: string[] = []) => {
showConfirmationAlert({ showConfirmationAlert({
title: I18n.t('Confirmation'), title: I18n.t('Confirmation'),
message: I18n.t('You_are_converting_the_team'), message: I18n.t('You_are_converting_the_team'),
@ -522,13 +564,16 @@ class RoomActionsView extends React.Component {
leaveTeam = async () => { leaveTeam = async () => {
const { room } = this.state; const { room } = this.state;
const { navigation, dispatch } = this.props; const { navigation, dispatch, userId } = this.props;
try { try {
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); if (!room.teamId) {
return;
}
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId });
if (result.rooms?.length) { if (result.rooms?.length) {
const teamChannels = result.rooms.map(r => ({ const teamChannels = result.rooms.map((r: any) => ({
rid: r._id, rid: r._id,
name: r.name, name: r.name,
teamId: r.teamId, teamId: r.teamId,
@ -538,21 +583,21 @@ class RoomActionsView extends React.Component {
title: 'Leave_Team', title: 'Leave_Team',
data: teamChannels, data: teamChannels,
infoText: 'Select_Team_Channels', infoText: 'Select_Team_Channels',
nextAction: data => dispatch(leaveRoom('team', room, data)), nextAction: data => dispatch(leaveRoom(ERoomType.t, room, data)),
showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave')) showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave'))
}); });
} else { } else {
showConfirmationAlert({ showConfirmationAlert({
message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }),
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
onPress: () => dispatch(leaveRoom('team', room)) onPress: () => dispatch(leaveRoom(ERoomType.t, room))
}); });
} }
} catch (e) { } catch (e) {
showConfirmationAlert({ showConfirmationAlert({
message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }), message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }),
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
onPress: () => dispatch(leaveRoom('team', room)) onPress: () => dispatch(leaveRoom(ERoomType.t, room))
}); });
} }
}; };
@ -562,7 +607,7 @@ class RoomActionsView extends React.Component {
try { try {
const { room } = this.state; const { room } = this.state;
const { navigation } = this.props; const { navigation } = this.props;
const result = await RocketChat.convertChannelToTeam({ rid: room.rid, name: room.name, type: room.t }); const result = await RocketChat.convertChannelToTeam({ rid: room.rid, name: room.name, type: room.t as any });
if (result.success) { if (result.success) {
navigation.navigate('RoomView'); navigation.navigate('RoomView');
@ -582,7 +627,7 @@ class RoomActionsView extends React.Component {
}); });
}; };
handleMoveToTeam = async selected => { handleMoveToTeam = async (selected: string[]) => {
logEvent(events.RA_MOVE_TO_TEAM); logEvent(events.RA_MOVE_TO_TEAM);
try { try {
const { room } = this.state; const { room } = this.state;
@ -603,14 +648,14 @@ class RoomActionsView extends React.Component {
const { navigation } = this.props; const { navigation } = this.props;
const db = database.active; const db = database.active;
const subCollection = db.get('subscriptions'); const subCollection = db.get('subscriptions');
const teamRooms = await subCollection.query(Q.where('team_main', true)); const teamRooms = await subCollection.query(Q.where('team_main', true)).fetch();
if (teamRooms.length) { if (teamRooms.length) {
const data = teamRooms.map(team => ({ const data = teamRooms.map(team => ({
rid: team.teamId, rid: team.teamId,
t: team.t, t: team.t,
name: team.name name: team.name
})); })) as IRoom[]; // TODO: review this usage later
navigation.navigate('SelectListView', { navigation.navigate('SelectListView', {
title: 'Move_to_Team', title: 'Move_to_Team',
infoText: 'Move_Channel_Paragraph', infoText: 'Move_Channel_Paragraph',
@ -637,7 +682,7 @@ class RoomActionsView extends React.Component {
} }
}; };
searchTeam = async onChangeText => { searchTeam = async (onChangeText: string) => {
logEvent(events.RA_SEARCH_TEAM); logEvent(events.RA_SEARCH_TEAM);
try { try {
const { addTeamChannelPermission, createTeamPermission } = this.props; const { addTeamChannelPermission, createTeamPermission } = this.props;
@ -650,9 +695,10 @@ class RoomActionsView extends React.Component {
Q.where('name', Q.like(`%${onChangeText}%`)), Q.where('name', Q.like(`%${onChangeText}%`)),
Q.experimentalTake(QUERY_SIZE), Q.experimentalTake(QUERY_SIZE),
Q.experimentalSortBy('room_updated_at', Q.desc) Q.experimentalSortBy('room_updated_at', Q.desc)
); )
.fetch();
const asyncFilter = async teamArray => { const asyncFilter = async (teamArray: TSubscriptionModel[]) => {
const results = await Promise.all( const results = await Promise.all(
teamArray.map(async team => { teamArray.map(async team => {
const permissions = await RocketChat.hasPermission([addTeamChannelPermission, createTeamPermission], team.rid); const permissions = await RocketChat.hasPermission([addTeamChannelPermission, createTeamPermission], team.rid);
@ -698,7 +744,6 @@ class RoomActionsView extends React.Component {
} }
style={{ backgroundColor: themes[theme].backgroundColor }} style={{ backgroundColor: themes[theme].backgroundColor }}
accessibilityLabel={I18n.t('Room_Info')} accessibilityLabel={I18n.t('Room_Info')}
accessibilityTraits='button'
enabled={!isGroupChat} enabled={!isGroupChat}
testID='room-actions-info' testID='room-actions-info'
theme={theme}> theme={theme}>
@ -708,7 +753,7 @@ class RoomActionsView extends React.Component {
<View style={[sharedStyles.status, { backgroundColor: themes[theme].backgroundColor }]}> <View style={[sharedStyles.status, { backgroundColor: themes[theme].backgroundColor }]}>
<Status size={16} id={member._id} /> <Status size={16} id={member._id} />
</View> </View>
) : null} ) : undefined}
</Avatar> </Avatar>
<View style={styles.roomTitleContainer}> <View style={styles.roomTitleContainer}>
{room.t === 'd' ? ( {room.t === 'd' ? (
@ -782,7 +827,7 @@ class RoomActionsView extends React.Component {
// If this room type can be encrypted // If this room type can be encrypted
// If e2e is enabled // If e2e is enabled
if (E2E_ROOM_TYPES[room?.t] && encryptionEnabled) { if (E2E_ROOM_TYPES[room.t] && encryptionEnabled) {
return ( return (
<List.Section> <List.Section>
<List.Separator /> <List.Separator />
@ -853,7 +898,7 @@ class RoomActionsView extends React.Component {
return null; return null;
}; };
teamChannelActions = (t, room) => { teamChannelActions = (t: string, room: ISubscription) => {
const { canEdit, canCreateTeam, canAddChannelToTeam } = this.state; const { canEdit, canCreateTeam, canAddChannelToTeam } = this.state;
const canConvertToTeam = canEdit && canCreateTeam && !room.teamMain; const canConvertToTeam = canEdit && canCreateTeam && !room.teamMain;
const canMoveToTeam = canEdit && canAddChannelToTeam && !room.teamId; const canMoveToTeam = canEdit && canAddChannelToTeam && !room.teamId;
@ -897,7 +942,7 @@ class RoomActionsView extends React.Component {
); );
}; };
teamToChannelActions = (t, room) => { teamToChannelActions = (t: string, room: ISubscription) => {
const { canEdit, canConvertTeam } = this.state; const { canEdit, canConvertTeam } = this.state;
const canConvertTeamToChannel = canEdit && canConvertTeam && !!room?.teamMain; const canConvertTeamToChannel = canEdit && canConvertTeam && !!room?.teamMain;
@ -952,7 +997,7 @@ class RoomActionsView extends React.Component {
<> <>
<List.Item <List.Item
title='Members' title='Members'
subtitle={membersCount > 0 ? `${membersCount} ${I18n.t('members')}` : null} subtitle={membersCount > 0 ? `${membersCount} ${I18n.t('members')}` : undefined}
onPress={() => this.onPressTouchable({ route: 'RoomMembersView', params: { rid, room } })} onPress={() => this.onPressTouchable({ route: 'RoomMembersView', params: { rid, room } })}
testID='room-actions-members' testID='room-actions-members'
left={() => <List.Icon name='team' />} left={() => <List.Icon name='team' />}
@ -1221,10 +1266,11 @@ class RoomActionsView extends React.Component {
} }
} }
const mapStateToProps = state => ({ const mapStateToProps = (state: IApplicationState) => ({
jitsiEnabled: state.settings.Jitsi_Enabled || false, userId: getUserSelector(state).id,
jitsiEnableTeams: state.settings.Jitsi_Enable_Teams || false, jitsiEnabled: (state.settings.Jitsi_Enabled || false) as boolean,
jitsiEnableChannels: state.settings.Jitsi_Enable_Channels || false, jitsiEnableTeams: (state.settings.Jitsi_Enable_Teams || false) as boolean,
jitsiEnableChannels: (state.settings.Jitsi_Enable_Channels || false) as boolean,
encryptionEnabled: state.encryption.enabled, encryptionEnabled: state.encryption.enabled,
serverVersion: state.server.version, serverVersion: state.server.version,
isMasterDetail: state.app.isMasterDetail, isMasterDetail: state.app.isMasterDetail,

View File

@ -16,7 +16,7 @@ import StatusBar from '../../containers/StatusBar';
import RCTextInput from '../../containers/TextInput'; import RCTextInput from '../../containers/TextInput';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import { MultiSelect } from '../../containers/UIKit/MultiSelect'; import { MultiSelect } from '../../containers/UIKit/MultiSelect';
import { IApplicationState, IBaseScreen, ISubscription, TSubscriptionModel } from '../../definitions'; import { IApplicationState, IBaseScreen, ISubscription, SubscriptionType, TSubscriptionModel } from '../../definitions';
import { ERoomType } from '../../definitions/ERoomType'; import { ERoomType } from '../../definitions/ERoomType';
import I18n from '../../i18n'; import I18n from '../../i18n';
import database from '../../lib/database'; import database from '../../lib/database';
@ -372,7 +372,7 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
title: 'Delete_Team', title: 'Delete_Team',
data: teamChannelOwner, data: teamChannelOwner,
infoText: 'Select_channels_to_delete', infoText: 'Select_channels_to_delete',
nextAction: (selected: Record<string, string>) => { nextAction: (selected: string[]) => {
showConfirmationAlert({ showConfirmationAlert({
message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }), message: I18n.t('You_are_deleting_the_team', { team: RocketChat.getRoomTitle(room) }),
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }), confirmationText: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
@ -437,7 +437,7 @@ class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfo
onPress: async () => { onPress: async () => {
try { try {
logEvent(events.RI_EDIT_TOGGLE_ARCHIVE); logEvent(events.RI_EDIT_TOGGLE_ARCHIVE);
await RocketChat.toggleArchiveRoom(rid, t, !archived); await RocketChat.toggleArchiveRoom(rid, t as SubscriptionType, !archived);
} catch (e) { } catch (e) {
logEvent(events.RI_EDIT_TOGGLE_ARCHIVE_F); logEvent(events.RI_EDIT_TOGGLE_ARCHIVE_F);
log(e); log(e);

View File

@ -24,7 +24,7 @@ import { getUserSelector } from '../../selectors/login';
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types'; import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import EventEmitter from '../../utils/events'; import EventEmitter from '../../utils/events';
import { goRoom, IGoRoomItem } from '../../utils/goRoom'; import { goRoom, TGoRoomItem } from '../../utils/goRoom';
import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
import log from '../../utils/log'; import log from '../../utils/log';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
@ -469,7 +469,7 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
} }
}; };
goRoom = (item: IGoRoomItem) => { goRoom = (item: TGoRoomItem) => {
const { navigation, isMasterDetail } = this.props; const { navigation, isMasterDetail } = this.props;
if (isMasterDetail) { if (isMasterDetail) {
// @ts-ignore // @ts-ignore

View File

@ -52,7 +52,7 @@ import { getHeaderTitlePosition } from '../../containers/Header';
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants'; import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants';
import { takeInquiry } from '../../ee/omnichannel/lib'; import { takeInquiry } from '../../ee/omnichannel/lib';
import Loading from '../../containers/Loading'; import Loading from '../../containers/Loading';
import { goRoom } from '../../utils/goRoom'; import { goRoom, TGoRoomItem } from '../../utils/goRoom';
import getThreadName from '../../lib/methods/getThreadName'; import getThreadName from '../../lib/methods/getThreadName';
import getRoomInfo from '../../lib/methods/getRoomInfo'; import getRoomInfo from '../../lib/methods/getRoomInfo';
import RoomServices from './services'; import RoomServices from './services';
@ -545,7 +545,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
navigation.push('RoomActionsView', { navigation.push('RoomActionsView', {
rid: this.rid, rid: this.rid,
t: this.t as SubscriptionType, t: this.t as SubscriptionType,
room: room as ISubscription, room: room as TSubscriptionModel,
member, member,
joined joined
}); });
@ -1040,7 +1040,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
const { navigation, isMasterDetail } = this.props; const { navigation, isMasterDetail } = this.props;
const roomInfo = await getRoomInfo(message.rid); const roomInfo = await getRoomInfo(message.rid);
return goRoom({ return goRoom({
item: roomInfo as Partial<ISubscription>, item: roomInfo as TGoRoomItem,
isMasterDetail, isMasterDetail,
navigationMethod: navigation.push, navigationMethod: navigation.push,
jumpToMessageId: message.id jumpToMessageId: message.id

View File

@ -29,7 +29,7 @@ const styles = StyleSheet.create({
}); });
interface ISelectListViewState { interface ISelectListViewState {
data: IRoom[]; data?: IRoom[];
dataFiltered?: IRoom[]; dataFiltered?: IRoom[];
isSearching: boolean; isSearching: boolean;
selected: string[]; selected: string[];
@ -53,7 +53,7 @@ class SelectListView extends React.Component<ISelectListViewProps, ISelectListVi
private isSearch: boolean; private isSearch: boolean;
private onSearch: (text: string) => Partial<IRoom[]>; private onSearch?: (text: string) => Promise<Partial<IRoom[]> | any>;
private isRadio?: boolean; private isRadio?: boolean;
@ -61,10 +61,10 @@ class SelectListView extends React.Component<ISelectListViewProps, ISelectListVi
super(props); super(props);
const data = props.route?.params?.data; const data = props.route?.params?.data;
this.title = props.route?.params?.title; this.title = props.route?.params?.title;
this.infoText = props.route?.params?.infoText; this.infoText = props.route?.params?.infoText ?? '';
this.nextAction = props.route?.params?.nextAction; this.nextAction = props.route?.params?.nextAction;
this.showAlert = props.route?.params?.showAlert; this.showAlert = props.route?.params?.showAlert ?? (() => {});
this.isSearch = props.route?.params?.isSearch; this.isSearch = props.route?.params?.isSearch ?? false;
this.onSearch = props.route?.params?.onSearch; this.onSearch = props.route?.params?.onSearch;
this.isRadio = props.route?.params?.isRadio; this.isRadio = props.route?.params?.isRadio;
this.state = { this.state = {
@ -122,7 +122,7 @@ class SelectListView extends React.Component<ISelectListViewProps, ISelectListVi
search = async (text: string) => { search = async (text: string) => {
try { try {
this.setState({ isSearching: true }); this.setState({ isSearching: true });
const result = (await this.onSearch(text)) as IRoom[]; const result = (await this.onSearch?.(text)) as IRoom[];
this.setState({ dataFiltered: result }); this.setState({ dataFiltered: result });
} catch (e) { } catch (e) {
log(e); log(e);