Merge branch 'develop' into chore.dehydrate-login-methods-from-rocketchatjs
This commit is contained in:
commit
5a4bfc8f54
|
@ -24,7 +24,7 @@ interface IMultiSelect {
|
||||||
multiselect?: boolean;
|
multiselect?: boolean;
|
||||||
onSearch?: () => void;
|
onSearch?: () => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
inputStyle: object;
|
inputStyle?: object;
|
||||||
value?: any[];
|
value?: any[];
|
||||||
disabled?: boolean | object;
|
disabled?: boolean | object;
|
||||||
theme: string;
|
theme: string;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { MarkdownAST } from '@rocket.chat/message-parser';
|
||||||
|
|
||||||
import { IAttachment } from './IAttachment';
|
import { IAttachment } from './IAttachment';
|
||||||
import { IReaction } from './IReaction';
|
import { IReaction } from './IReaction';
|
||||||
import { IUrl } from './IUrl';
|
import { IUrlFromServer } from './IUrl';
|
||||||
|
|
||||||
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj';
|
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj';
|
||||||
|
|
||||||
|
@ -59,22 +59,61 @@ export interface ILastMessage {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessage {
|
interface IMessageFile {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMessageAttachment {
|
||||||
|
ts: string;
|
||||||
|
title: string;
|
||||||
|
title_link: string;
|
||||||
|
title_link_download: true;
|
||||||
|
image_dimensions: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
image_preview: string;
|
||||||
|
image_url: string;
|
||||||
|
image_type: string;
|
||||||
|
image_size: number;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessageFromServer {
|
||||||
_id: string;
|
_id: string;
|
||||||
rid: string;
|
rid: string;
|
||||||
msg?: string;
|
msg: string;
|
||||||
|
ts: string | Date; // wm date issue
|
||||||
|
u: IUserMessage;
|
||||||
|
_updatedAt: string | Date;
|
||||||
|
urls: IUrlFromServer[];
|
||||||
|
mentions: IUserMention[];
|
||||||
|
channels: IUserChannel[];
|
||||||
|
md: MarkdownAST;
|
||||||
|
file: IMessageFile;
|
||||||
|
files: IMessageFile[];
|
||||||
|
groupable: false;
|
||||||
|
attachments: IMessageAttachment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILoadMoreMessage {
|
||||||
|
_id: string;
|
||||||
|
rid: string;
|
||||||
|
ts: string;
|
||||||
|
t: string;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessage extends IMessageFromServer {
|
||||||
id: string;
|
id: string;
|
||||||
t?: MessageType;
|
t?: MessageType;
|
||||||
ts: string | Date;
|
|
||||||
u: IUserMessage;
|
|
||||||
alias?: string;
|
alias?: string;
|
||||||
parseUrls?: boolean;
|
parseUrls?: boolean;
|
||||||
groupable?: boolean;
|
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
attachments?: IAttachment[];
|
|
||||||
urls?: IUrl[];
|
|
||||||
_updatedAt: string | Date;
|
|
||||||
status?: number;
|
status?: number;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
starred?: boolean;
|
starred?: boolean;
|
||||||
|
@ -88,8 +127,6 @@ export interface IMessage {
|
||||||
tcount?: number;
|
tcount?: number;
|
||||||
tlm?: string | Date;
|
tlm?: string | Date;
|
||||||
replies?: string[];
|
replies?: string[];
|
||||||
mentions?: IUserMention[];
|
|
||||||
channels?: IUserChannel[];
|
|
||||||
unread?: boolean;
|
unread?: boolean;
|
||||||
autoTranslate?: boolean;
|
autoTranslate?: boolean;
|
||||||
translations?: ITranslations[];
|
translations?: ITranslations[];
|
||||||
|
@ -97,8 +134,9 @@ export interface IMessage {
|
||||||
blocks?: any;
|
blocks?: any;
|
||||||
e2e?: string;
|
e2e?: string;
|
||||||
tshow?: boolean;
|
tshow?: boolean;
|
||||||
md?: MarkdownAST;
|
|
||||||
subscription?: { id: string };
|
subscription?: { id: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TMessageModel = IMessage & Model;
|
export type TMessageModel = IMessage & Model;
|
||||||
|
|
||||||
|
export type TTypeMessages = IMessageFromServer | ILoadMoreMessage | IMessage;
|
||||||
|
|
|
@ -30,6 +30,7 @@ export interface IThreadResult {
|
||||||
channels?: IUserChannel[];
|
channels?: IUserChannel[];
|
||||||
replies?: string[];
|
replies?: string[];
|
||||||
tcount?: number;
|
tcount?: number;
|
||||||
|
status?: string;
|
||||||
tlm?: string | Date;
|
tlm?: string | Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
export interface IUrl {
|
|
||||||
_id: number;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
image: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUrlFromServer {
|
export interface IUrlFromServer {
|
||||||
url: string;
|
url: string;
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -47,3 +39,11 @@ export interface IUrlFromServer {
|
||||||
};
|
};
|
||||||
ignoreParse: boolean;
|
ignoreParse: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IUrl extends IUrlFromServer {
|
||||||
|
_id: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
export type ChannelsEndpoints = {
|
export type ChannelsEndpoints = {
|
||||||
'channels.files': {
|
'channels.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; offset: number; count: number; sort: string; query: string }) => {
|
GET: (params: {
|
||||||
|
roomId: IRoom['_id'];
|
||||||
|
offset: number;
|
||||||
|
count: number;
|
||||||
|
sort: string | { uploadedAt: number };
|
||||||
|
query: string;
|
||||||
|
}) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -17,4 +23,9 @@ export type ChannelsEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'channels.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
export type GroupsEndpoints = {
|
export type GroupsEndpoints = {
|
||||||
'groups.files': {
|
'groups.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
|
GET: (params: { roomId: IRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -17,4 +17,9 @@ export type GroupsEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'groups.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export type ImEndpoints = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
'im.files': {
|
'im.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
|
GET: (params: { roomId: IRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -33,4 +33,9 @@ export type ImEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'im.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -179,7 +179,7 @@ export type OmnichannelEndpoints = {
|
||||||
departmentId?: ILivechatAgent['_id'];
|
departmentId?: ILivechatAgent['_id'];
|
||||||
offset: number;
|
offset: number;
|
||||||
count: number;
|
count: number;
|
||||||
sort: string;
|
sort: string | { uploadedAt: number };
|
||||||
}) => {
|
}) => {
|
||||||
queue: {
|
queue: {
|
||||||
chats: number;
|
chats: number;
|
||||||
|
|
|
@ -244,7 +244,7 @@ class Encryption {
|
||||||
const threadMessagesToDecrypt = await threadMessagesCollection.query(...whereClause).fetch();
|
const threadMessagesToDecrypt = await threadMessagesCollection.query(...whereClause).fetch();
|
||||||
|
|
||||||
// Concat messages/threads/threadMessages
|
// Concat messages/threads/threadMessages
|
||||||
let toDecrypt: (TThreadModel | TThreadMessageModel)[] = [
|
let toDecrypt: (TThreadModel | TThreadMessageModel | TMessageModel)[] = [
|
||||||
...messagesToDecrypt,
|
...messagesToDecrypt,
|
||||||
...threadsToDecrypt,
|
...threadsToDecrypt,
|
||||||
...threadMessagesToDecrypt
|
...threadMessagesToDecrypt
|
||||||
|
@ -259,7 +259,7 @@ class Encryption {
|
||||||
newMessage = await this.decryptMessage({
|
newMessage = await this.decryptMessage({
|
||||||
t,
|
t,
|
||||||
rid,
|
rid,
|
||||||
msg,
|
msg: msg as string,
|
||||||
tmsg
|
tmsg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -464,12 +464,13 @@ class Encryption {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rid } = message;
|
const { rid } = message;
|
||||||
const roomE2E = await this.getRoomInstance(rid as string);
|
const roomE2E = await this.getRoomInstance(rid);
|
||||||
return roomE2E.decrypt(message);
|
return roomE2E.decrypt(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Decrypt multiple messages
|
// Decrypt multiple messages
|
||||||
decryptMessages = (messages: IMessage[]) => Promise.all(messages.map((m: IMessage) => this.decryptMessage(m)));
|
decryptMessages = (messages: Partial<IMessage>[]) =>
|
||||||
|
Promise.all(messages.map((m: Partial<IMessage>) => this.decryptMessage(m as IMessage)));
|
||||||
|
|
||||||
// Decrypt multiple subscriptions
|
// Decrypt multiple subscriptions
|
||||||
decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s)));
|
decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s)));
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { getThreadById } from '../database/services/Thread';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import { Encryption } from '../encryption';
|
import { Encryption } from '../encryption';
|
||||||
import getSingleMessage from './getSingleMessage';
|
import getSingleMessage from './getSingleMessage';
|
||||||
import { IThread, TThreadModel } from '../../definitions';
|
import { IMessage, IThread, TThreadModel } from '../../definitions';
|
||||||
|
|
||||||
const buildThreadName = (thread: IThread): string | undefined => thread.msg || thread?.attachments?.[0]?.title;
|
const buildThreadName = (thread: IThread | IMessage): string | undefined => thread.msg || thread?.attachments?.[0]?.title;
|
||||||
|
|
||||||
const getThreadName = async (rid: string, tmid: string, messageId: string): Promise<string | undefined> => {
|
const getThreadName = async (rid: string, tmid: string, messageId: string): Promise<string | undefined> => {
|
||||||
let tmsg: string | undefined;
|
let tmsg: string | undefined;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { IMessage } from '../../../definitions';
|
import { IMessage, IThreadResult } from '../../../definitions';
|
||||||
import messagesStatus from '../../../constants/messagesStatus';
|
import messagesStatus from '../../../constants/messagesStatus';
|
||||||
import normalizeMessage from './normalizeMessage';
|
import normalizeMessage from './normalizeMessage';
|
||||||
|
|
||||||
export default (message: IMessage): IMessage => {
|
export default (message: Partial<IMessage> | IThreadResult): Partial<IMessage> | IThreadResult => {
|
||||||
message.status = messagesStatus.SENT;
|
message.status = messagesStatus.SENT;
|
||||||
return normalizeMessage(message);
|
return normalizeMessage(message);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { MESSAGE_TYPE_LOAD_MORE } from '../../constants/messageTypeLoad';
|
import { IMessage, MessageType, TMessageModel } from '../../definitions';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import { getMessageById } from '../database/services/Message';
|
import { getMessageById } from '../database/services/Message';
|
||||||
|
import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType';
|
||||||
|
import sdk from '../rocketchat/services/sdk';
|
||||||
import { generateLoadMoreId } from '../utils';
|
import { generateLoadMoreId } from '../utils';
|
||||||
import updateMessages from './updateMessages';
|
import updateMessages from './updateMessages';
|
||||||
import { IMessage, TMessageModel } from '../../definitions';
|
|
||||||
import sdk from '../rocketchat/services/sdk';
|
|
||||||
import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType';
|
|
||||||
|
|
||||||
const COUNT = 50;
|
const COUNT = 50;
|
||||||
|
|
||||||
|
@ -23,9 +22,8 @@ async function load({ rid: roomId, latest, t }: { rid: string; latest?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RC 0.48.0
|
// RC 0.48.0
|
||||||
// @ts-ignore
|
const data = await sdk.get(`${apiType}.history`, params);
|
||||||
const data: any = await sdk.get(`${apiType}.history`, params);
|
if (!data.success) {
|
||||||
if (!data || data.status === 'error') {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return data.messages;
|
return data.messages;
|
||||||
|
@ -36,22 +34,22 @@ export default function loadMessagesForRoom(args: {
|
||||||
t: RoomTypes;
|
t: RoomTypes;
|
||||||
latest: string;
|
latest: string;
|
||||||
loaderItem: TMessageModel;
|
loaderItem: TMessageModel;
|
||||||
}): Promise<IMessage[] | []> {
|
}): Promise<Partial<IMessage>[]> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const data = await load(args);
|
const data: Partial<IMessage>[] = await load(args);
|
||||||
if (data?.length) {
|
if (data?.length) {
|
||||||
const lastMessage = data[data.length - 1];
|
const lastMessage = data[data.length - 1];
|
||||||
const lastMessageRecord = await getMessageById(lastMessage._id);
|
const lastMessageRecord = await getMessageById(lastMessage._id as string);
|
||||||
if (!lastMessageRecord && data.length === COUNT) {
|
if (!lastMessageRecord && data.length === COUNT) {
|
||||||
const loadMoreItem = {
|
const loadMoreMessage = {
|
||||||
_id: generateLoadMoreId(lastMessage._id),
|
_id: generateLoadMoreId(lastMessage._id as string),
|
||||||
rid: lastMessage.rid,
|
rid: lastMessage.rid,
|
||||||
ts: moment(lastMessage.ts).subtract(1, 'millisecond'),
|
ts: moment(lastMessage.ts).subtract(1, 'millisecond').toString(),
|
||||||
t: MESSAGE_TYPE_LOAD_MORE,
|
t: 'load_more' as MessageType,
|
||||||
msg: lastMessage.msg
|
msg: lastMessage.msg
|
||||||
};
|
};
|
||||||
data.push(loadMoreItem);
|
data.push(loadMoreMessage);
|
||||||
}
|
}
|
||||||
await updateMessages({ rid: args.rid, update: data, loaderItem: args.loaderItem });
|
await updateMessages({ rid: args.rid, update: data, loaderItem: args.loaderItem });
|
||||||
return resolve(data);
|
return resolve(data);
|
||||||
|
|
|
@ -12,8 +12,8 @@ import { getSubscriptionByRoomId } from '../database/services/Subscription';
|
||||||
|
|
||||||
interface IUpdateMessages {
|
interface IUpdateMessages {
|
||||||
rid: string;
|
rid: string;
|
||||||
update: IMessage[];
|
update: Partial<IMessage>[];
|
||||||
remove?: IMessage[];
|
remove?: Partial<IMessage>[];
|
||||||
loaderItem?: TMessageModel;
|
loaderItem?: TMessageModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export default async function updateMessages({
|
||||||
// Decrypt these messages
|
// Decrypt these messages
|
||||||
update = await Encryption.decryptMessages(update);
|
update = await Encryption.decryptMessages(update);
|
||||||
|
|
||||||
const messagesIds: string[] = [...update.map(m => m._id), ...remove.map(m => m._id)];
|
const messagesIds: string[] = [...update.map(m => m._id as string), ...remove.map(m => m._id as string)];
|
||||||
const msgCollection = db.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadCollection = db.get('threads');
|
const threadCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
|
@ -49,11 +49,11 @@ export default async function updateMessages({
|
||||||
.query(Q.where('subscription_id', rid), Q.where('id', Q.oneOf(messagesIds)))
|
.query(Q.where('subscription_id', rid), Q.where('id', Q.oneOf(messagesIds)))
|
||||||
.fetch();
|
.fetch();
|
||||||
|
|
||||||
update = update.map(m => buildMessage(m));
|
update = update.map(m => buildMessage(m)) as IMessage[];
|
||||||
|
|
||||||
// filter loaders to delete
|
// filter loaders to delete
|
||||||
let loadersToDelete: TMessageModel[] = allMessagesRecords.filter(i1 =>
|
let loadersToDelete: TMessageModel[] = allMessagesRecords.filter(i1 =>
|
||||||
update.find(i2 => i1.id === generateLoadMoreId(i2._id))
|
update.find(i2 => i1.id === generateLoadMoreId(i2._id as string))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
const types = {
|
enum ETypes {
|
||||||
c: 'channels',
|
Channels = 'channels',
|
||||||
d: 'im',
|
Im = 'im',
|
||||||
p: 'groups',
|
Groups = 'groups'
|
||||||
l: 'channels'
|
}
|
||||||
|
|
||||||
|
export const types = {
|
||||||
|
c: ETypes.Channels,
|
||||||
|
d: ETypes.Im,
|
||||||
|
p: ETypes.Groups,
|
||||||
|
l: ETypes.Channels
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: refactor this
|
// TODO: refactor this
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sdk from './sdk';
|
import { SubscriptionType } from '../../../definitions';
|
||||||
import { TEAM_TYPE } from '../../../definitions/ITeam';
|
import { TEAM_TYPE } from '../../../definitions/ITeam';
|
||||||
import roomTypeToApiType, { RoomTypes } from '../methods/roomTypeToApiType';
|
import roomTypeToApiType, { RoomTypes } from '../methods/roomTypeToApiType';
|
||||||
import { SubscriptionType } from '../../../definitions';
|
import sdk from './sdk';
|
||||||
|
|
||||||
export const createChannel = ({
|
export const createChannel = ({
|
||||||
name,
|
name,
|
||||||
|
@ -575,7 +575,7 @@ export const ignoreUser = ({ rid, userId, ignore }: { rid: string; userId: strin
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
sdk.get('chat.ignoreUser', { rid, userId, ignore });
|
sdk.get('chat.ignoreUser', { rid, userId, ignore });
|
||||||
|
|
||||||
export const toggleArchiveRoom = (roomId: string, t: RoomTypes, archive: boolean): any => {
|
export const toggleArchiveRoom = (roomId: string, t: SubscriptionType, archive: boolean): any => {
|
||||||
if (archive) {
|
if (archive) {
|
||||||
// RC 0.48.0
|
// RC 0.48.0
|
||||||
// TODO: missing definitions from server
|
// TODO: missing definitions from server
|
||||||
|
|
|
@ -45,7 +45,7 @@ export type ModalStackParamList = {
|
||||||
title: string;
|
title: string;
|
||||||
infoText: string;
|
infoText: string;
|
||||||
nextAction: Function;
|
nextAction: Function;
|
||||||
showAlert: () => void | boolean;
|
showAlert?: () => void | boolean;
|
||||||
isSearch?: boolean;
|
isSearch?: boolean;
|
||||||
onSearch?: Function;
|
onSearch?: Function;
|
||||||
isRadio?: boolean;
|
isRadio?: boolean;
|
||||||
|
|
|
@ -1,11 +1,24 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Switch, Text, View } from 'react-native';
|
import { Switch, Text, TextStyle, View, ViewStyle } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
|
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
const SwitchContainer = React.memo(
|
interface ISwitchContainer {
|
||||||
|
value: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
leftLabelPrimary: string;
|
||||||
|
leftLabelSecondary: string;
|
||||||
|
rightLabelPrimary?: string;
|
||||||
|
rightLabelSecondary?: string;
|
||||||
|
onValueChange: (value: any) => void;
|
||||||
|
theme: string;
|
||||||
|
testID: string;
|
||||||
|
labelContainerStyle?: ViewStyle;
|
||||||
|
leftLabelStyle?: TextStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SwitchContainer: React.FC<ISwitchContainer> = React.memo(
|
||||||
({
|
({
|
||||||
children,
|
children,
|
||||||
value,
|
value,
|
||||||
|
@ -21,7 +34,7 @@ const SwitchContainer = React.memo(
|
||||||
leftLabelStyle
|
leftLabelStyle
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<View key='switch-container' style={[styles.switchContainer, children && styles.switchMargin]}>
|
<View key='switch-container' style={[styles.switchContainer, !!children && styles.switchMargin]}>
|
||||||
{leftLabelPrimary && (
|
{leftLabelPrimary && (
|
||||||
<View style={[styles.switchLabelContainer, labelContainerStyle]}>
|
<View style={[styles.switchLabelContainer, labelContainerStyle]}>
|
||||||
<Text style={[styles.switchLabelPrimary, { color: themes[theme].titleText }, leftLabelStyle]}>
|
<Text style={[styles.switchLabelPrimary, { color: themes[theme].titleText }, leftLabelStyle]}>
|
||||||
|
@ -57,19 +70,4 @@ const SwitchContainer = React.memo(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
SwitchContainer.propTypes = {
|
|
||||||
value: PropTypes.bool,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
leftLabelPrimary: PropTypes.string,
|
|
||||||
leftLabelSecondary: PropTypes.string,
|
|
||||||
rightLabelPrimary: PropTypes.string,
|
|
||||||
rightLabelSecondary: PropTypes.string,
|
|
||||||
onValueChange: PropTypes.func,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
testID: PropTypes.string,
|
|
||||||
labelContainerStyle: PropTypes.object,
|
|
||||||
leftLabelStyle: PropTypes.object,
|
|
||||||
children: PropTypes.any
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SwitchContainer;
|
export default SwitchContainer;
|
|
@ -1,75 +1,98 @@
|
||||||
import React from 'react';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Alert, Keyboard, ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
|
||||||
import { dequal } from 'dequal';
|
import { dequal } from 'dequal';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import React from 'react';
|
||||||
|
import { Alert, Keyboard, ScrollView, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||||
|
import ImagePicker, { Image } from 'react-native-image-crop-picker';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { compareServerVersion } from '../../lib/utils';
|
import { deleteRoom } from '../../actions/room';
|
||||||
import database from '../../lib/database';
|
|
||||||
import { deleteRoom as deleteRoomAction } from '../../actions/room';
|
|
||||||
import KeyboardView from '../../presentation/KeyboardView';
|
|
||||||
import sharedStyles from '../Styles';
|
|
||||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
|
||||||
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
|
||||||
import { LISTENER } from '../../containers/Toast';
|
|
||||||
import EventEmitter from '../../utils/events';
|
|
||||||
import RocketChat from '../../lib/rocketchat';
|
|
||||||
import RCTextInput from '../../containers/TextInput';
|
|
||||||
import Loading from '../../containers/Loading';
|
|
||||||
import random from '../../utils/random';
|
|
||||||
import log, { events, logEvent } from '../../utils/log';
|
|
||||||
import I18n from '../../i18n';
|
|
||||||
import StatusBar from '../../containers/StatusBar';
|
|
||||||
import { themes } from '../../constants/colors';
|
import { themes } from '../../constants/colors';
|
||||||
import { withTheme } from '../../theme';
|
|
||||||
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
|
|
||||||
import { MessageTypeValues } from '../../utils/messageTypes';
|
|
||||||
import SafeAreaView from '../../containers/SafeAreaView';
|
|
||||||
import Avatar from '../../containers/Avatar';
|
import Avatar from '../../containers/Avatar';
|
||||||
|
import Loading from '../../containers/Loading';
|
||||||
|
import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
|
import StatusBar from '../../containers/StatusBar';
|
||||||
|
import RCTextInput from '../../containers/TextInput';
|
||||||
|
import { LISTENER } from '../../containers/Toast';
|
||||||
|
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
|
||||||
|
import { IApplicationState, IBaseScreen, ISubscription, TSubscriptionModel } from '../../definitions';
|
||||||
|
import { ERoomType } from '../../definitions/ERoomType';
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import database from '../../lib/database';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import SwitchContainer from './SwitchContainer';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
|
import { compareServerVersion } from '../../lib/utils';
|
||||||
|
import KeyboardView from '../../presentation/KeyboardView';
|
||||||
|
import { TSupportedPermissions } from '../../reducers/permissions';
|
||||||
|
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||||
|
import { ChatsStackParamList } from '../../stacks/types';
|
||||||
|
import { withTheme } from '../../theme';
|
||||||
|
import EventEmitter from '../../utils/events';
|
||||||
|
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
||||||
|
import log, { events, logEvent } from '../../utils/log';
|
||||||
|
import { MessageTypeValues } from '../../utils/messageTypes';
|
||||||
|
import random from '../../utils/random';
|
||||||
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
|
import { IAvatar } from '../ProfileView/interfaces';
|
||||||
|
import sharedStyles from '../Styles';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import SwitchContainer from './SwitchContainer';
|
||||||
|
|
||||||
const PERMISSION_SET_READONLY = 'set-readonly';
|
interface IRoomInfoEditViewState {
|
||||||
const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly';
|
room: ISubscription;
|
||||||
const PERMISSION_ARCHIVE = 'archive-room';
|
avatar: IAvatar;
|
||||||
const PERMISSION_UNARCHIVE = 'unarchive-room';
|
permissions: Record<TSupportedPermissions, string>;
|
||||||
const PERMISSION_DELETE_C = 'delete-c';
|
name: string;
|
||||||
const PERMISSION_DELETE_P = 'delete-p';
|
description?: string;
|
||||||
const PERMISSION_DELETE_TEAM = 'delete-team';
|
topic?: string;
|
||||||
|
announcement?: string;
|
||||||
|
joinCode: string;
|
||||||
|
nameError: any;
|
||||||
|
saving: boolean;
|
||||||
|
t: boolean;
|
||||||
|
ro: boolean;
|
||||||
|
reactWhenReadOnly?: boolean;
|
||||||
|
archived: boolean;
|
||||||
|
systemMessages?: boolean | string[];
|
||||||
|
enableSysMes?: boolean | string[];
|
||||||
|
encrypted?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRoomInfoEditViewProps extends IBaseScreen<ChatsStackParamList | ModalStackParamList, 'RoomInfoEditView'> {
|
||||||
|
serverVersion?: string;
|
||||||
|
encryptionEnabled: boolean;
|
||||||
|
theme: string;
|
||||||
|
setReadOnlyPermission: string[];
|
||||||
|
setReactWhenReadOnlyPermission: string[];
|
||||||
|
archiveRoomPermission: string[];
|
||||||
|
unarchiveRoomPermission: string[];
|
||||||
|
deleteCPermission: string[];
|
||||||
|
deletePPermission: string[];
|
||||||
|
deleteTeamPermission: string[];
|
||||||
|
isMasterDetail: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoomInfoEditView extends React.Component<IRoomInfoEditViewProps, IRoomInfoEditViewState> {
|
||||||
|
randomValue = random(15);
|
||||||
|
private querySubscription: any; // Observable dont have unsubscribe prop
|
||||||
|
private room!: TSubscriptionModel;
|
||||||
|
private name!: TextInput | null;
|
||||||
|
private description!: TextInput | null;
|
||||||
|
private topic!: TextInput | null;
|
||||||
|
private announcement!: TextInput | null;
|
||||||
|
private joinCode!: TextInput | null;
|
||||||
|
|
||||||
class RoomInfoEditView extends React.Component {
|
|
||||||
static navigationOptions = () => ({
|
static navigationOptions = () => ({
|
||||||
title: I18n.t('Room_Info_Edit')
|
title: I18n.t('Room_Info_Edit')
|
||||||
});
|
});
|
||||||
|
|
||||||
static propTypes = {
|
constructor(props: IRoomInfoEditViewProps) {
|
||||||
navigation: PropTypes.object,
|
|
||||||
route: PropTypes.object,
|
|
||||||
deleteRoom: PropTypes.func,
|
|
||||||
serverVersion: PropTypes.string,
|
|
||||||
encryptionEnabled: PropTypes.bool,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
setReadOnlyPermission: PropTypes.array,
|
|
||||||
setReactWhenReadOnlyPermission: PropTypes.array,
|
|
||||||
archiveRoomPermission: PropTypes.array,
|
|
||||||
unarchiveRoomPermission: PropTypes.array,
|
|
||||||
deleteCPermission: PropTypes.array,
|
|
||||||
deletePPermission: PropTypes.array,
|
|
||||||
deleteTeamPermission: PropTypes.array,
|
|
||||||
isMasterDetail: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
room: {},
|
room: {} as ISubscription,
|
||||||
avatar: {},
|
avatar: {} as IAvatar,
|
||||||
permissions: {},
|
permissions: {} as Record<TSupportedPermissions, string>,
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
topic: '',
|
topic: '',
|
||||||
|
@ -134,14 +157,15 @@ class RoomInfoEditView extends React.Component {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
// @ts-ignore - Solved by migrating the hasPermission function
|
||||||
permissions: {
|
permissions: {
|
||||||
[PERMISSION_SET_READONLY]: result[0],
|
'set-readonly': result[0],
|
||||||
[PERMISSION_SET_REACT_WHEN_READONLY]: result[1],
|
'set-react-when-readonly': result[1],
|
||||||
[PERMISSION_ARCHIVE]: result[2],
|
'archive-room': result[2],
|
||||||
[PERMISSION_UNARCHIVE]: result[3],
|
'unarchive-room': result[3],
|
||||||
[PERMISSION_DELETE_C]: result[4],
|
'delete-c': result[4],
|
||||||
[PERMISSION_DELETE_P]: result[5],
|
'delete-p': result[5],
|
||||||
...(this.room.teamMain && { [PERMISSION_DELETE_TEAM]: result[6] })
|
...(this.room.teamMain && { 'delete-team': result[6] })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -149,10 +173,10 @@ class RoomInfoEditView extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
init = room => {
|
init = (room: ISubscription) => {
|
||||||
const { description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired, sysMes, encrypted } = room;
|
const { description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired, encrypted } = room;
|
||||||
|
const sysMes = room.sysMes as string[];
|
||||||
// fake password just to user knows about it
|
// fake password just to user knows about it
|
||||||
this.randomValue = random(15);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
room,
|
room,
|
||||||
name: RocketChat.getRoomTitle(room),
|
name: RocketChat.getRoomTitle(room),
|
||||||
|
@ -160,7 +184,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
topic,
|
topic,
|
||||||
announcement,
|
announcement,
|
||||||
t: t === 'p',
|
t: t === 'p',
|
||||||
avatar: {},
|
avatar: {} as IAvatar,
|
||||||
ro,
|
ro,
|
||||||
reactWhenReadOnly,
|
reactWhenReadOnly,
|
||||||
joinCode: joinCodeRequired ? this.randomValue : '',
|
joinCode: joinCodeRequired ? this.randomValue : '',
|
||||||
|
@ -200,6 +224,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
avatar
|
avatar
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { joinCodeRequired } = room;
|
const { joinCodeRequired } = room;
|
||||||
|
const sysMes = room.sysMes as string[];
|
||||||
return !(
|
return !(
|
||||||
room.name === name &&
|
room.name === name &&
|
||||||
room.description === description &&
|
room.description === description &&
|
||||||
|
@ -209,8 +234,8 @@ class RoomInfoEditView extends React.Component {
|
||||||
(room.t === 'p') === t &&
|
(room.t === 'p') === t &&
|
||||||
room.ro === ro &&
|
room.ro === ro &&
|
||||||
room.reactWhenReadOnly === reactWhenReadOnly &&
|
room.reactWhenReadOnly === reactWhenReadOnly &&
|
||||||
dequal(room.sysMes, systemMessages) &&
|
dequal(sysMes, systemMessages) &&
|
||||||
enableSysMes === (room.sysMes && room.sysMes.length > 0) &&
|
enableSysMes === (sysMes && sysMes.length > 0) &&
|
||||||
room.encrypted === encrypted &&
|
room.encrypted === encrypted &&
|
||||||
isEmpty(avatar)
|
isEmpty(avatar)
|
||||||
);
|
);
|
||||||
|
@ -245,7 +270,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
// Clear error objects
|
// Clear error objects
|
||||||
await this.clearErrors();
|
await this.clearErrors();
|
||||||
|
|
||||||
const params = {};
|
const params = {} as any;
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
if (room.name !== name) {
|
if (room.name !== name) {
|
||||||
|
@ -268,7 +293,8 @@ class RoomInfoEditView extends React.Component {
|
||||||
params.roomAnnouncement = announcement;
|
params.roomAnnouncement = announcement;
|
||||||
}
|
}
|
||||||
// Room Type
|
// Room Type
|
||||||
if (room.t !== t) {
|
// This logic is strange to me, since in the code t is boolean, but room.t is string
|
||||||
|
if (!!room.t !== t) {
|
||||||
params.roomType = t ? 'p' : 'c';
|
params.roomType = t ? 'p' : 'c';
|
||||||
}
|
}
|
||||||
// Read Only
|
// Read Only
|
||||||
|
@ -296,7 +322,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await RocketChat.saveRoomSettings(room.rid, params);
|
await RocketChat.saveRoomSettings(room.rid, params);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if (e.error === 'error-invalid-room-name') {
|
if (e.error === 'error-invalid-room-name') {
|
||||||
this.setState({ nameError: e });
|
this.setState({ nameError: e });
|
||||||
}
|
}
|
||||||
|
@ -317,20 +343,26 @@ class RoomInfoEditView extends React.Component {
|
||||||
|
|
||||||
deleteTeam = async () => {
|
deleteTeam = async () => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
const { navigation, deleteCPermission, deletePPermission, deleteRoom } = this.props;
|
const { navigation, deleteCPermission, deletePPermission, dispatch } = this.props;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const teamChannels = await subCollection.query(Q.where('team_id', room.teamId), Q.where('team_main', Q.notEq(true)));
|
const teamChannels = await subCollection.query(
|
||||||
|
Q.where('team_id', room.teamId as string),
|
||||||
|
Q.where('team_main', Q.notEq(true))
|
||||||
|
);
|
||||||
|
|
||||||
const teamChannelOwner = [];
|
const teamChannelOwner = [];
|
||||||
|
// @ts-ignore - wm schema type error dont including array
|
||||||
for (let i = 0; i < teamChannels.length; i += 1) {
|
for (let i = 0; i < teamChannels.length; i += 1) {
|
||||||
|
// @ts-ignore - wm schema type error dont including array
|
||||||
const permissionType = teamChannels[i].t === 'c' ? deleteCPermission : deletePPermission;
|
const permissionType = teamChannels[i].t === 'c' ? deleteCPermission : deletePPermission;
|
||||||
|
// @ts-ignore - wm schema type error dont including array
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const permissions = await RocketChat.hasPermission([permissionType], teamChannels[i].rid);
|
const permissions = await RocketChat.hasPermission([permissionType], teamChannels[i].rid);
|
||||||
|
|
||||||
if (permissions[0]) {
|
if (permissions[0]) {
|
||||||
|
// @ts-ignore - wm schema type error dont including array
|
||||||
teamChannelOwner.push(teamChannels[i]);
|
teamChannelOwner.push(teamChannels[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,11 +372,11 @@ class RoomInfoEditView extends React.Component {
|
||||||
title: 'Delete_Team',
|
title: 'Delete_Team',
|
||||||
data: teamChannelOwner,
|
data: teamChannelOwner,
|
||||||
infoText: 'Select_channels_to_delete',
|
infoText: 'Select_channels_to_delete',
|
||||||
nextAction: selected => {
|
nextAction: (selected: Record<string, 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') }),
|
||||||
onPress: () => deleteRoom('team', room, selected)
|
onPress: () => deleteRoom(ERoomType.t, room, selected)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -352,10 +384,10 @@ class RoomInfoEditView extends React.Component {
|
||||||
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') }),
|
||||||
onPress: () => deleteRoom('team', room)
|
onPress: () => dispatch(deleteRoom(ERoomType.t, room))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log(e);
|
log(e);
|
||||||
showErrorAlert(
|
showErrorAlert(
|
||||||
e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('deleting_team') }),
|
e.data.error ? I18n.t(e.data.error) : I18n.t('There_was_an_error_while_action', { action: I18n.t('deleting_team') }),
|
||||||
|
@ -366,7 +398,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
|
|
||||||
delete = () => {
|
delete = () => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
const { deleteRoom } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
I18n.t('Are_you_sure_question_mark'),
|
I18n.t('Are_you_sure_question_mark'),
|
||||||
|
@ -379,7 +411,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
{
|
{
|
||||||
text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
|
text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
|
||||||
style: 'destructive',
|
style: 'destructive',
|
||||||
onPress: () => deleteRoom('channel', room)
|
onPress: () => dispatch(deleteRoom(ERoomType.c, room))
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
{ cancelable: false }
|
{ cancelable: false }
|
||||||
|
@ -421,14 +453,14 @@ class RoomInfoEditView extends React.Component {
|
||||||
const { room, permissions } = this.state;
|
const { room, permissions } = this.state;
|
||||||
|
|
||||||
if (room.teamMain) {
|
if (room.teamMain) {
|
||||||
return permissions[PERMISSION_DELETE_TEAM];
|
return permissions['delete-team'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room.t === 'p') {
|
if (room.t === 'p') {
|
||||||
return permissions[PERMISSION_DELETE_P];
|
return permissions['delete-p'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return permissions[PERMISSION_DELETE_C];
|
return permissions['delete-c'];
|
||||||
};
|
};
|
||||||
|
|
||||||
renderSystemMessages = () => {
|
renderSystemMessages = () => {
|
||||||
|
@ -445,9 +477,9 @@ class RoomInfoEditView extends React.Component {
|
||||||
value: m.value,
|
value: m.value,
|
||||||
text: { text: I18n.t('Hide_type_messages', { type: I18n.t(m.text) }) }
|
text: { text: I18n.t('Hide_type_messages', { type: I18n.t(m.text) }) }
|
||||||
}))}
|
}))}
|
||||||
onChange={({ value }) => this.setState({ systemMessages: value })}
|
onChange={({ value }: { value: boolean }) => this.setState({ systemMessages: value })}
|
||||||
placeholder={{ text: I18n.t('Hide_System_Messages') }}
|
placeholder={{ text: I18n.t('Hide_System_Messages') }}
|
||||||
value={systemMessages}
|
value={systemMessages as string[]}
|
||||||
context={BLOCK_CONTEXT.FORM}
|
context={BLOCK_CONTEXT.FORM}
|
||||||
multiselect
|
multiselect
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
@ -466,7 +498,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await ImagePicker.openPicker(options);
|
const response: Image = await ImagePicker.openPicker(options);
|
||||||
this.setState({ avatar: { url: response.path, data: `data:image/jpeg;base64,${response.data}`, service: 'upload' } });
|
this.setState({ avatar: { url: response.path, data: `data:image/jpeg;base64,${response.data}`, service: 'upload' } });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -477,27 +509,27 @@ class RoomInfoEditView extends React.Component {
|
||||||
this.setState({ avatar: { data: null } });
|
this.setState({ avatar: { data: null } });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleRoomType = value => {
|
toggleRoomType = (value: boolean) => {
|
||||||
logEvent(events.RI_EDIT_TOGGLE_ROOM_TYPE);
|
logEvent(events.RI_EDIT_TOGGLE_ROOM_TYPE);
|
||||||
this.setState(({ encrypted }) => ({ t: value, encrypted: value && encrypted }));
|
this.setState(({ encrypted }) => ({ t: value, encrypted: value && encrypted }));
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleReadOnly = value => {
|
toggleReadOnly = (value: boolean) => {
|
||||||
logEvent(events.RI_EDIT_TOGGLE_READ_ONLY);
|
logEvent(events.RI_EDIT_TOGGLE_READ_ONLY);
|
||||||
this.setState({ ro: value });
|
this.setState({ ro: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleReactions = value => {
|
toggleReactions = (value: boolean) => {
|
||||||
logEvent(events.RI_EDIT_TOGGLE_REACTIONS);
|
logEvent(events.RI_EDIT_TOGGLE_REACTIONS);
|
||||||
this.setState({ reactWhenReadOnly: value });
|
this.setState({ reactWhenReadOnly: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleHideSystemMessages = value => {
|
toggleHideSystemMessages = (value: boolean) => {
|
||||||
logEvent(events.RI_EDIT_TOGGLE_SYSTEM_MSG);
|
logEvent(events.RI_EDIT_TOGGLE_SYSTEM_MSG);
|
||||||
this.setState(({ systemMessages }) => ({ enableSysMes: value, systemMessages: value ? systemMessages : [] }));
|
this.setState(({ systemMessages }) => ({ enableSysMes: value, systemMessages: value ? systemMessages : [] }));
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleEncrypted = value => {
|
toggleEncrypted = (value: boolean) => {
|
||||||
logEvent(events.RI_EDIT_TOGGLE_ENCRYPTED);
|
logEvent(events.RI_EDIT_TOGGLE_ENCRYPTED);
|
||||||
this.setState({ encrypted: value });
|
this.setState({ encrypted: value });
|
||||||
};
|
};
|
||||||
|
@ -538,15 +570,15 @@ class RoomInfoEditView extends React.Component {
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.avatarContainer}
|
style={styles.avatarContainer}
|
||||||
onPress={this.changeAvatar}
|
onPress={this.changeAvatar}
|
||||||
disabled={compareServerVersion(serverVersion, 'lowerThan', '3.6.0')}>
|
disabled={compareServerVersion(serverVersion || '', 'lowerThan', '3.6.0')}>
|
||||||
<Avatar
|
<Avatar
|
||||||
type={room.t}
|
type={room.t}
|
||||||
text={room.name}
|
text={room.name}
|
||||||
avatar={avatar?.url}
|
avatar={avatar?.url}
|
||||||
isStatic={avatar?.url}
|
isStatic={avatar?.url}
|
||||||
rid={isEmpty(avatar) && room.rid}
|
rid={isEmpty(avatar) ? room.rid : undefined}
|
||||||
size={100}>
|
size={100}>
|
||||||
{compareServerVersion(serverVersion, 'lowerThan', '3.6.0') ? null : (
|
{serverVersion && compareServerVersion(serverVersion, 'lowerThan', '3.6.0') ? undefined : (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.resetButton, { backgroundColor: themes[theme].dangerColor }]}
|
style={[styles.resetButton, { backgroundColor: themes[theme].dangerColor }]}
|
||||||
onPress={this.resetAvatar}>
|
onPress={this.resetAvatar}>
|
||||||
|
@ -563,7 +595,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
value={name}
|
value={name}
|
||||||
onChangeText={value => this.setState({ name: value })}
|
onChangeText={value => this.setState({ name: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.description.focus();
|
this.description?.focus();
|
||||||
}}
|
}}
|
||||||
error={nameError}
|
error={nameError}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
@ -577,7 +609,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
value={description}
|
value={description}
|
||||||
onChangeText={value => this.setState({ description: value })}
|
onChangeText={value => this.setState({ description: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.topic.focus();
|
this.topic?.focus();
|
||||||
}}
|
}}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID='room-info-edit-view-description'
|
testID='room-info-edit-view-description'
|
||||||
|
@ -590,7 +622,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
value={topic}
|
value={topic}
|
||||||
onChangeText={value => this.setState({ topic: value })}
|
onChangeText={value => this.setState({ topic: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.announcement.focus();
|
this.announcement?.focus();
|
||||||
}}
|
}}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID='room-info-edit-view-topic'
|
testID='room-info-edit-view-topic'
|
||||||
|
@ -603,7 +635,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
value={announcement}
|
value={announcement}
|
||||||
onChangeText={value => this.setState({ announcement: value })}
|
onChangeText={value => this.setState({ announcement: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.joinCode.focus();
|
this.joinCode?.focus();
|
||||||
}}
|
}}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID='room-info-edit-view-announcement'
|
testID='room-info-edit-view-announcement'
|
||||||
|
@ -647,19 +679,19 @@ class RoomInfoEditView extends React.Component {
|
||||||
rightLabelPrimary={I18n.t('Read_Only')}
|
rightLabelPrimary={I18n.t('Read_Only')}
|
||||||
rightLabelSecondary={I18n.t('Only_authorized_users_can_write_new_messages')}
|
rightLabelSecondary={I18n.t('Only_authorized_users_can_write_new_messages')}
|
||||||
onValueChange={this.toggleReadOnly}
|
onValueChange={this.toggleReadOnly}
|
||||||
disabled={!permissions[PERMISSION_SET_READONLY] || room.broadcast}
|
disabled={!permissions['set-readonly'] || room.broadcast}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID='room-info-edit-view-ro'
|
testID='room-info-edit-view-ro'
|
||||||
/>
|
/>
|
||||||
{ro && !room.broadcast ? (
|
{ro && !room.broadcast ? (
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={reactWhenReadOnly}
|
value={reactWhenReadOnly as boolean}
|
||||||
leftLabelPrimary={I18n.t('No_Reactions')}
|
leftLabelPrimary={I18n.t('No_Reactions')}
|
||||||
leftLabelSecondary={I18n.t('Reactions_are_disabled')}
|
leftLabelSecondary={I18n.t('Reactions_are_disabled')}
|
||||||
rightLabelPrimary={I18n.t('Allow_Reactions')}
|
rightLabelPrimary={I18n.t('Allow_Reactions')}
|
||||||
rightLabelSecondary={I18n.t('Reactions_are_enabled')}
|
rightLabelSecondary={I18n.t('Reactions_are_enabled')}
|
||||||
onValueChange={this.toggleReactions}
|
onValueChange={this.toggleReactions}
|
||||||
disabled={!permissions[PERMISSION_SET_REACT_WHEN_READONLY]}
|
disabled={!permissions['set-react-when-readonly']}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID='room-info-edit-view-react-when-ro'
|
testID='room-info-edit-view-react-when-ro'
|
||||||
/>
|
/>
|
||||||
|
@ -670,9 +702,9 @@ class RoomInfoEditView extends React.Component {
|
||||||
<View style={[styles.divider, { borderColor: themes[theme].separatorColor }]} />
|
<View style={[styles.divider, { borderColor: themes[theme].separatorColor }]} />
|
||||||
]
|
]
|
||||||
: null}
|
: null}
|
||||||
{!compareServerVersion(serverVersion, 'lowerThan', '3.0.0') ? (
|
{serverVersion && !compareServerVersion(serverVersion, 'lowerThan', '3.0.0') ? (
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={enableSysMes}
|
value={enableSysMes as boolean}
|
||||||
leftLabelPrimary={I18n.t('Hide_System_Messages')}
|
leftLabelPrimary={I18n.t('Hide_System_Messages')}
|
||||||
leftLabelSecondary={
|
leftLabelSecondary={
|
||||||
enableSysMes
|
enableSysMes
|
||||||
|
@ -689,7 +721,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
) : null}
|
) : null}
|
||||||
{encryptionEnabled ? (
|
{encryptionEnabled ? (
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={encrypted}
|
value={encrypted as boolean}
|
||||||
disabled={!t}
|
disabled={!t}
|
||||||
leftLabelPrimary={I18n.t('Encrypted')}
|
leftLabelPrimary={I18n.t('Encrypted')}
|
||||||
leftLabelSecondary={I18n.t('End_to_end_encrypted_room')}
|
leftLabelSecondary={I18n.t('End_to_end_encrypted_room')}
|
||||||
|
@ -735,12 +767,12 @@ class RoomInfoEditView extends React.Component {
|
||||||
styles.buttonInverted,
|
styles.buttonInverted,
|
||||||
styles.buttonContainer_inverted,
|
styles.buttonContainer_inverted,
|
||||||
archived
|
archived
|
||||||
? !permissions[PERMISSION_UNARCHIVE] && sharedStyles.opacity5
|
? !permissions['unarchive-room'] && sharedStyles.opacity5
|
||||||
: !permissions[PERMISSION_ARCHIVE] && sharedStyles.opacity5,
|
: !permissions['archive-room'] && sharedStyles.opacity5,
|
||||||
{ flex: 1, marginLeft: 10, borderColor: dangerColor }
|
{ flex: 1, marginLeft: 10, borderColor: dangerColor }
|
||||||
]}
|
]}
|
||||||
onPress={this.toggleArchive}
|
onPress={this.toggleArchive}
|
||||||
disabled={archived ? !permissions[PERMISSION_UNARCHIVE] : !permissions[PERMISSION_ARCHIVE]}
|
disabled={archived ? !permissions['unarchive-room'] : !permissions['archive-room']}
|
||||||
testID={archived ? 'room-info-edit-view-unarchive' : 'room-info-edit-view-archive'}>
|
testID={archived ? 'room-info-edit-view-unarchive' : 'room-info-edit-view-archive'}>
|
||||||
<Text style={[styles.button, styles.button_inverted, { color: dangerColor }]}>
|
<Text style={[styles.button, styles.button_inverted, { color: dangerColor }]}>
|
||||||
{archived ? I18n.t('UNARCHIVE') : I18n.t('ARCHIVE')}
|
{archived ? I18n.t('UNARCHIVE') : I18n.t('ARCHIVE')}
|
||||||
|
@ -771,21 +803,17 @@ class RoomInfoEditView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = (state: IApplicationState) => ({
|
||||||
serverVersion: state.server.version,
|
serverVersion: state.server.version as string,
|
||||||
encryptionEnabled: state.encryption.enabled,
|
encryptionEnabled: state.encryption.enabled,
|
||||||
setReadOnlyPermission: state.permissions[PERMISSION_SET_READONLY],
|
setReadOnlyPermission: state.permissions['set-readonly'] as string[],
|
||||||
setReactWhenReadOnlyPermission: state.permissions[PERMISSION_SET_REACT_WHEN_READONLY],
|
setReactWhenReadOnlyPermission: state.permissions['set-react-when-readonly'] as string[],
|
||||||
archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE],
|
archiveRoomPermission: state.permissions['archive-room'] as string[],
|
||||||
unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE],
|
unarchiveRoomPermission: state.permissions['unarchive-room'] as string[],
|
||||||
deleteCPermission: state.permissions[PERMISSION_DELETE_C],
|
deleteCPermission: state.permissions['delete-c'] as string[],
|
||||||
deletePPermission: state.permissions[PERMISSION_DELETE_P],
|
deletePPermission: state.permissions['delete-p'] as string[],
|
||||||
deleteTeamPermission: state.permissions[PERMISSION_DELETE_TEAM],
|
deleteTeamPermission: state.permissions['delete-team'] as string[],
|
||||||
isMasterDetail: state.app.isMasterDetail
|
isMasterDetail: state.app.isMasterDetail
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
export default connect(mapStateToProps)(withTheme(RoomInfoEditView));
|
||||||
deleteRoom: (roomType, room, selected) => dispatch(deleteRoomAction(roomType, room, selected))
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RoomInfoEditView));
|
|
|
@ -287,7 +287,7 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update && update.length) {
|
if (update && update.length) {
|
||||||
update = update.map(m => buildMessage(m));
|
update = update.map(m => buildMessage(m)) as IThreadResult[];
|
||||||
// filter threads
|
// filter threads
|
||||||
threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id));
|
threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id));
|
||||||
threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));
|
threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));
|
||||||
|
|
Loading…
Reference in New Issue