Merge branch 'develop' into chore.dehydrate-login-methods-from-rocketchatjs
This commit is contained in:
commit
ff44417b32
|
@ -1,59 +0,0 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function loginRequest(credentials, logoutOnError, isFromWebView) {
|
||||
return {
|
||||
type: types.LOGIN.REQUEST,
|
||||
credentials,
|
||||
logoutOnError,
|
||||
isFromWebView
|
||||
};
|
||||
}
|
||||
|
||||
export function loginSuccess(user) {
|
||||
return {
|
||||
type: types.LOGIN.SUCCESS,
|
||||
user
|
||||
};
|
||||
}
|
||||
|
||||
export function loginFailure(err) {
|
||||
return {
|
||||
type: types.LOGIN.FAILURE,
|
||||
err
|
||||
};
|
||||
}
|
||||
|
||||
export function logout(forcedByServer = false) {
|
||||
return {
|
||||
type: types.LOGOUT,
|
||||
forcedByServer
|
||||
};
|
||||
}
|
||||
|
||||
export function setUser(user) {
|
||||
return {
|
||||
type: types.USER.SET,
|
||||
user
|
||||
};
|
||||
}
|
||||
|
||||
export function setLoginServices(data) {
|
||||
return {
|
||||
type: types.LOGIN.SET_SERVICES,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
export function setPreference(preference) {
|
||||
return {
|
||||
type: types.LOGIN.SET_PREFERENCE,
|
||||
preference
|
||||
};
|
||||
}
|
||||
|
||||
export function setLocalAuthenticated(isLocalAuthenticated) {
|
||||
return {
|
||||
type: types.LOGIN.SET_LOCAL_AUTHENTICATED,
|
||||
isLocalAuthenticated
|
||||
};
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { IUser } from '../definitions';
|
||||
import * as types from './actionsTypes';
|
||||
|
||||
interface ICredentials {
|
||||
resume: string;
|
||||
user: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
interface ILoginRequest extends Action {
|
||||
credentials: any;
|
||||
logoutOnError?: boolean;
|
||||
isFromWebView?: boolean;
|
||||
}
|
||||
|
||||
interface ILoginSuccess extends Action {
|
||||
user: Partial<IUser>;
|
||||
}
|
||||
|
||||
interface ILoginFailure extends Action {
|
||||
err: Partial<IUser>;
|
||||
}
|
||||
|
||||
interface ILogout extends Action {
|
||||
forcedByServer: boolean;
|
||||
}
|
||||
|
||||
interface ISetUser extends Action {
|
||||
user: Partial<IUser>;
|
||||
}
|
||||
|
||||
interface ISetServices extends Action {
|
||||
data: Record<string, string>;
|
||||
}
|
||||
|
||||
interface ISetPreference extends Action {
|
||||
preference: Record<string, any>;
|
||||
}
|
||||
|
||||
interface ISetLocalAuthenticated extends Action {
|
||||
isLocalAuthenticated: boolean;
|
||||
}
|
||||
|
||||
export type TActionsLogin = ILoginRequest &
|
||||
ILoginSuccess &
|
||||
ILoginFailure &
|
||||
ILogout &
|
||||
ISetUser &
|
||||
ISetServices &
|
||||
ISetPreference &
|
||||
ISetLocalAuthenticated;
|
||||
|
||||
export function loginRequest(
|
||||
credentials: Partial<ICredentials>,
|
||||
logoutOnError?: boolean,
|
||||
isFromWebView?: boolean
|
||||
): ILoginRequest {
|
||||
return {
|
||||
type: types.LOGIN.REQUEST,
|
||||
credentials,
|
||||
logoutOnError,
|
||||
isFromWebView
|
||||
};
|
||||
}
|
||||
|
||||
export function loginSuccess(user: Partial<IUser>): ILoginSuccess {
|
||||
return {
|
||||
type: types.LOGIN.SUCCESS,
|
||||
user
|
||||
};
|
||||
}
|
||||
|
||||
export function loginFailure(err: Record<string, any>): ILoginFailure {
|
||||
return {
|
||||
type: types.LOGIN.FAILURE,
|
||||
err
|
||||
};
|
||||
}
|
||||
|
||||
export function logout(forcedByServer = false): ILogout {
|
||||
return {
|
||||
type: types.LOGOUT,
|
||||
forcedByServer
|
||||
};
|
||||
}
|
||||
|
||||
export function setUser(user: Partial<IUser>): ISetUser {
|
||||
return {
|
||||
type: types.USER.SET,
|
||||
user
|
||||
};
|
||||
}
|
||||
|
||||
export function setLoginServices(data: Record<string, any>): ISetServices {
|
||||
return {
|
||||
type: types.LOGIN.SET_SERVICES,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
export function setPreference(preference: Record<string, any>): ISetPreference {
|
||||
return {
|
||||
type: types.LOGIN.SET_PREFERENCE,
|
||||
preference
|
||||
};
|
||||
}
|
||||
|
||||
export function setLocalAuthenticated(isLocalAuthenticated: boolean): ISetLocalAuthenticated {
|
||||
return {
|
||||
type: types.LOGIN.SET_LOCAL_AUTHENTICATED,
|
||||
isLocalAuthenticated
|
||||
};
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
import * as types from './actionsTypes';
|
||||
|
||||
export function subscribeRoom(rid) {
|
||||
return {
|
||||
type: types.ROOM.SUBSCRIBE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function unsubscribeRoom(rid) {
|
||||
return {
|
||||
type: types.ROOM.UNSUBSCRIBE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function leaveRoom(roomType, room, selected) {
|
||||
return {
|
||||
type: types.ROOM.LEAVE,
|
||||
room,
|
||||
roomType,
|
||||
selected
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRoom(roomType, room, selected) {
|
||||
return {
|
||||
type: types.ROOM.DELETE,
|
||||
room,
|
||||
roomType,
|
||||
selected
|
||||
};
|
||||
}
|
||||
|
||||
export function closeRoom(rid) {
|
||||
return {
|
||||
type: types.ROOM.CLOSE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function forwardRoom(rid, transferData) {
|
||||
return {
|
||||
type: types.ROOM.FORWARD,
|
||||
transferData,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function removedRoom() {
|
||||
return {
|
||||
type: types.ROOM.REMOVED
|
||||
};
|
||||
}
|
||||
|
||||
export function userTyping(rid, status = true) {
|
||||
return {
|
||||
type: types.ROOM.USER_TYPING,
|
||||
rid,
|
||||
status
|
||||
};
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { ERoomType } from '../definitions/ERoomType';
|
||||
import { ROOM } from './actionsTypes';
|
||||
|
||||
// TYPE RETURN RELATED
|
||||
type ISelected = Record<string, string>;
|
||||
|
||||
export interface ITransferData {
|
||||
roomId: string;
|
||||
userId?: string;
|
||||
departmentId?: string;
|
||||
}
|
||||
|
||||
// ACTION RETURN RELATED
|
||||
interface IBaseReturn extends Action {
|
||||
rid: string;
|
||||
}
|
||||
|
||||
type TSubscribeRoom = IBaseReturn;
|
||||
type TUnsubscribeRoom = IBaseReturn;
|
||||
type TCloseRoom = IBaseReturn;
|
||||
|
||||
type TRoom = Record<string, any>;
|
||||
|
||||
interface ILeaveRoom extends Action {
|
||||
roomType: ERoomType;
|
||||
room: TRoom;
|
||||
selected?: ISelected;
|
||||
}
|
||||
|
||||
interface IDeleteRoom extends Action {
|
||||
roomType: ERoomType;
|
||||
room: TRoom;
|
||||
selected?: ISelected;
|
||||
}
|
||||
|
||||
interface IForwardRoom extends Action {
|
||||
transferData: ITransferData;
|
||||
rid: string;
|
||||
}
|
||||
|
||||
interface IUserTyping extends Action {
|
||||
rid: string;
|
||||
status: boolean;
|
||||
}
|
||||
|
||||
export type TActionsRoom = TSubscribeRoom & TUnsubscribeRoom & TCloseRoom & ILeaveRoom & IDeleteRoom & IForwardRoom & IUserTyping;
|
||||
|
||||
export function subscribeRoom(rid: string): TSubscribeRoom {
|
||||
return {
|
||||
type: ROOM.SUBSCRIBE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function unsubscribeRoom(rid: string): TUnsubscribeRoom {
|
||||
return {
|
||||
type: ROOM.UNSUBSCRIBE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function leaveRoom(roomType: ERoomType, room: TRoom, selected?: ISelected): ILeaveRoom {
|
||||
return {
|
||||
type: ROOM.LEAVE,
|
||||
room,
|
||||
roomType,
|
||||
selected
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRoom(roomType: ERoomType, room: TRoom, selected?: ISelected): IDeleteRoom {
|
||||
return {
|
||||
type: ROOM.DELETE,
|
||||
room,
|
||||
roomType,
|
||||
selected
|
||||
};
|
||||
}
|
||||
|
||||
export function closeRoom(rid: string): TCloseRoom {
|
||||
return {
|
||||
type: ROOM.CLOSE,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function forwardRoom(rid: string, transferData: ITransferData): IForwardRoom {
|
||||
return {
|
||||
type: ROOM.FORWARD,
|
||||
transferData,
|
||||
rid
|
||||
};
|
||||
}
|
||||
|
||||
export function removedRoom(): Action {
|
||||
return {
|
||||
type: ROOM.REMOVED
|
||||
};
|
||||
}
|
||||
|
||||
export function userTyping(rid: string, status = true): IUserTyping {
|
||||
return {
|
||||
type: ROOM.USER_TYPING,
|
||||
rid,
|
||||
status
|
||||
};
|
||||
}
|
|
@ -82,6 +82,7 @@ interface IMessageBoxProps {
|
|||
isFocused(): boolean;
|
||||
user: {
|
||||
id: string;
|
||||
_id: string;
|
||||
username: string;
|
||||
token: string;
|
||||
};
|
||||
|
@ -1184,5 +1185,5 @@ const mapStateToProps = (state: any) => ({
|
|||
const dispatchToProps = {
|
||||
typing: (rid: any, status: any) => userTypingAction(rid, status)
|
||||
};
|
||||
// @ts-ignore
|
||||
|
||||
export default connect(mapStateToProps, dispatchToProps, null, { forwardRef: true })(withActionSheet(MessageBox)) as any;
|
||||
|
|
|
@ -45,7 +45,14 @@ export const SYSTEM_MESSAGES = [
|
|||
'message_snippeted',
|
||||
'thread-created',
|
||||
'room_e2e_enabled',
|
||||
'room_e2e_disabled'
|
||||
'room_e2e_disabled',
|
||||
'removed-user-from-team',
|
||||
'added-user-to-team',
|
||||
'user-added-room-to-team',
|
||||
'user-converted-to-team',
|
||||
'user-converted-to-channel',
|
||||
'user-deleted-room-from-team',
|
||||
'user-removed-room-from-team'
|
||||
];
|
||||
|
||||
export const SYSTEM_MESSAGE_TYPES = {
|
||||
|
@ -56,7 +63,14 @@ export const SYSTEM_MESSAGE_TYPES = {
|
|||
USER_JOINED_TEAM: 'ujt',
|
||||
USER_JOINED_DISCUSSION: 'ut',
|
||||
USER_LEFT_CHANNEL: 'ul',
|
||||
USER_LEFT_TEAM: 'ult'
|
||||
USER_LEFT_TEAM: 'ult',
|
||||
REMOVED_USER_FROM_TEAM: 'removed-user-from-team',
|
||||
ADDED_USER_TO_TEAM: 'added-user-to-team',
|
||||
ADDED_ROOM_TO_TEAM: 'user-added-room-to-team',
|
||||
CONVERTED_TO_TEAM: 'user-converted-to-team',
|
||||
CONVERTED_TO_CHANNEL: 'user-converted-to-channel',
|
||||
DELETED_ROOM_FROM_TEAM: 'user-deleted-room-from-team',
|
||||
REMOVED_ROOM_FROM_TEAM: 'user-removed-room-from-team'
|
||||
};
|
||||
|
||||
export const SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME = [
|
||||
|
@ -67,7 +81,14 @@ export const SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME = [
|
|||
SYSTEM_MESSAGE_TYPES.USER_JOINED_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.USER_JOINED_DISCUSSION,
|
||||
SYSTEM_MESSAGE_TYPES.USER_LEFT_CHANNEL,
|
||||
SYSTEM_MESSAGE_TYPES.USER_LEFT_TEAM
|
||||
SYSTEM_MESSAGE_TYPES.USER_LEFT_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.REMOVED_USER_FROM_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.ADDED_USER_TO_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.ADDED_ROOM_TO_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.CONVERTED_TO_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.CONVERTED_TO_CHANNEL,
|
||||
SYSTEM_MESSAGE_TYPES.DELETED_ROOM_FROM_TEAM,
|
||||
SYSTEM_MESSAGE_TYPES.REMOVED_ROOM_FROM_TEAM
|
||||
];
|
||||
|
||||
type TInfoMessage = {
|
||||
|
@ -76,6 +97,7 @@ type TInfoMessage = {
|
|||
msg: string;
|
||||
author: { username: string };
|
||||
};
|
||||
|
||||
export const getInfoMessage = ({ type, role, msg, author }: TInfoMessage): string => {
|
||||
const { username } = author;
|
||||
if (type === 'rm') {
|
||||
|
@ -147,6 +169,27 @@ export const getInfoMessage = ({ type, role, msg, author }: TInfoMessage): strin
|
|||
if (type === 'room_e2e_enabled') {
|
||||
return I18n.t('This_room_encryption_has_been_enabled_by__username_', { username });
|
||||
}
|
||||
if (type === 'removed-user-from-team') {
|
||||
return I18n.t('Removed__username__from_team', { user_removed: username });
|
||||
}
|
||||
if (type === 'added-user-to-team') {
|
||||
return I18n.t('Added__username__to_team', { user_added: username });
|
||||
}
|
||||
if (type === 'user-added-room-to-team') {
|
||||
return I18n.t('added__roomName__to_team', { roomName: msg });
|
||||
}
|
||||
if (type === 'user-converted-to-team') {
|
||||
return I18n.t('Converted__roomName__to_team', { roomName: msg });
|
||||
}
|
||||
if (type === 'user-converted-to-channel') {
|
||||
return I18n.t('Converted__roomName__to_channel', { roomName: msg });
|
||||
}
|
||||
if (type === 'user-deleted-room-from-team') {
|
||||
return I18n.t('Deleted__roomName__', { roomName: msg });
|
||||
}
|
||||
if (type === 'user-removed-room-from-team') {
|
||||
return I18n.t('Removed__roomName__from_this_team', { roomName: msg });
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export enum ERoomType {
|
||||
p = 'group',
|
||||
c = 'channel',
|
||||
d = 'direct',
|
||||
t = 'team',
|
||||
l = 'omnichannel'
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
export interface IAttachment {
|
||||
ts: Date;
|
||||
ts: string | Date;
|
||||
title: string;
|
||||
type: string;
|
||||
description: string;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
export interface ICustomEmoji {
|
||||
_id: string;
|
||||
name?: string;
|
||||
aliases?: string;
|
||||
aliases?: string[];
|
||||
extension: string;
|
||||
_updatedAt: Date;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ export interface IMessage {
|
|||
_id: string;
|
||||
rid: string;
|
||||
msg?: string;
|
||||
id?: string;
|
||||
id: string;
|
||||
t?: MessageType;
|
||||
ts: string | Date;
|
||||
u: IUserMessage;
|
||||
|
@ -74,7 +74,7 @@ export interface IMessage {
|
|||
emoji?: string;
|
||||
attachments?: IAttachment[];
|
||||
urls?: IUrl[];
|
||||
_updatedAt: Date;
|
||||
_updatedAt: string | Date;
|
||||
status?: number;
|
||||
pinned?: boolean;
|
||||
starred?: boolean;
|
||||
|
@ -83,10 +83,10 @@ export interface IMessage {
|
|||
role?: string;
|
||||
drid?: string;
|
||||
dcount?: number;
|
||||
dlm?: Date;
|
||||
dlm?: string | Date;
|
||||
tmid?: string;
|
||||
tcount?: number;
|
||||
tlm?: Date;
|
||||
tlm?: string | Date;
|
||||
replies?: string[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export interface IRocketChatRecord {
|
||||
_id: string;
|
||||
_updatedAt: Date;
|
||||
_id?: string;
|
||||
_updatedAt?: Date;
|
||||
}
|
||||
|
||||
export type RocketChatRecordDeleted<T> = T &
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Model from '@nozbe/watermelondb/Model';
|
||||
import { MarkdownAST } from '@rocket.chat/message-parser';
|
||||
|
||||
import { IAttachment } from './IAttachment';
|
||||
import { IMessage } from './IMessage';
|
||||
import { IServedBy } from './IServedBy';
|
||||
import { SubscriptionType } from './ISubscription';
|
||||
|
@ -37,6 +39,7 @@ export interface IRoom {
|
|||
tags?: string[];
|
||||
e2eKeyId?: string;
|
||||
avatarETag?: string;
|
||||
latest?: string;
|
||||
default?: true;
|
||||
featured?: true;
|
||||
}
|
||||
|
@ -100,3 +103,52 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
|
|||
}
|
||||
|
||||
export type TRoomModel = IRoom & Model;
|
||||
|
||||
export interface IServerRoomItem {
|
||||
_id: string;
|
||||
name: string;
|
||||
fname: string;
|
||||
t: SubscriptionType;
|
||||
u: {
|
||||
_id: string;
|
||||
username: string;
|
||||
};
|
||||
customFields: {};
|
||||
ts: string;
|
||||
ro: boolean;
|
||||
_updatedAt: string;
|
||||
lm: string;
|
||||
lastMessage: {
|
||||
alias: string;
|
||||
msg: string;
|
||||
attachments: IAttachment[];
|
||||
parseUrls: boolean;
|
||||
bot: {
|
||||
i: string;
|
||||
};
|
||||
groupable: boolean;
|
||||
avatar: string;
|
||||
ts: string;
|
||||
u: IUser;
|
||||
rid: string;
|
||||
_id: string;
|
||||
_updatedAt: string;
|
||||
mentions: [];
|
||||
channels: [];
|
||||
md: MarkdownAST;
|
||||
};
|
||||
topic: string;
|
||||
joinCodeRequired: boolean;
|
||||
description: string;
|
||||
jitsiTimeout: string;
|
||||
usersCount: number;
|
||||
e2eKeyId: string;
|
||||
avatarETag: string;
|
||||
encrypted: boolean;
|
||||
}
|
||||
|
||||
export interface IServerRoom {
|
||||
update: IServerRoomItem[];
|
||||
remove: IServerRoomItem[];
|
||||
success: boolean;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import { IEnterpriseModules } from '../reducers/enterpriseModules';
|
||||
|
||||
export interface IServer {
|
||||
name: string;
|
||||
iconURL: string;
|
||||
|
@ -13,7 +15,7 @@ export interface IServer {
|
|||
autoLockTime?: number;
|
||||
biometry?: boolean;
|
||||
uniqueID: string;
|
||||
enterpriseModules: string;
|
||||
enterpriseModules: IEnterpriseModules;
|
||||
E2E_Enable: boolean;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,4 +9,22 @@ export interface ISettings {
|
|||
_updatedAt?: Date;
|
||||
}
|
||||
|
||||
export interface IPreparedSettings {
|
||||
_id: string;
|
||||
value: string;
|
||||
enterprise: boolean;
|
||||
valueAsString?: string;
|
||||
valueAsBoolean?: boolean;
|
||||
valueAsNumber?: number;
|
||||
}
|
||||
|
||||
export interface ISettingsIcon {
|
||||
_id: string;
|
||||
value: {
|
||||
defaultUrl: string;
|
||||
url?: string;
|
||||
};
|
||||
enterprise: boolean;
|
||||
}
|
||||
|
||||
export type TSettingsModel = ISettings & Model;
|
||||
|
|
|
@ -9,4 +9,8 @@ export interface ISlashCommand {
|
|||
appId?: string;
|
||||
}
|
||||
|
||||
export interface ISlashCommandResult extends ISlashCommand {
|
||||
command: string;
|
||||
}
|
||||
|
||||
export type TSlashCommandModel = ISlashCommand & Model;
|
||||
|
|
|
@ -24,12 +24,20 @@ export interface IVisitor {
|
|||
lastMessageTs: Date;
|
||||
}
|
||||
|
||||
export enum ERoomTypes {
|
||||
DIRECT = 'direct',
|
||||
GROUP = 'group',
|
||||
CHANNEL = 'channel'
|
||||
}
|
||||
|
||||
export interface ISubscription {
|
||||
_id: string; // _id belongs watermelonDB
|
||||
id: string; // id from server
|
||||
_updatedAt?: string; // from server
|
||||
v?: IVisitor;
|
||||
f: boolean;
|
||||
t: SubscriptionType;
|
||||
ts: Date;
|
||||
ts: string | Date;
|
||||
ls: Date;
|
||||
name: string;
|
||||
fname?: string;
|
||||
|
@ -38,12 +46,14 @@ export interface ISubscription {
|
|||
alert: boolean;
|
||||
roles?: string[];
|
||||
unread: number;
|
||||
lm: string;
|
||||
lr: string;
|
||||
userMentions: number;
|
||||
groupMentions: number;
|
||||
tunread?: string[];
|
||||
tunreadUser?: string[];
|
||||
tunreadGroup?: string[];
|
||||
roomUpdatedAt: Date;
|
||||
roomUpdatedAt: Date | number;
|
||||
ro: boolean;
|
||||
lastOpen?: Date;
|
||||
description?: string;
|
||||
|
@ -59,7 +69,7 @@ export interface ISubscription {
|
|||
ignored?: string[];
|
||||
broadcast?: boolean;
|
||||
prid?: string;
|
||||
draftMessage?: string;
|
||||
draftMessage?: string | null;
|
||||
lastThreadSync?: Date;
|
||||
jitsiTimeout?: number;
|
||||
autoTranslate?: boolean;
|
||||
|
@ -88,3 +98,30 @@ export interface ISubscription {
|
|||
}
|
||||
|
||||
export type TSubscriptionModel = ISubscription & Model;
|
||||
|
||||
export interface IServerSubscriptionItem {
|
||||
_id: string;
|
||||
rid: string;
|
||||
u: {
|
||||
_id: string;
|
||||
username: string;
|
||||
};
|
||||
_updatedAt: string;
|
||||
alert: boolean;
|
||||
fname: string;
|
||||
groupMentions: number;
|
||||
name: string;
|
||||
open: boolean;
|
||||
t: string;
|
||||
unread: number;
|
||||
userMentions: number;
|
||||
ls: string;
|
||||
lr: string;
|
||||
tunread: number[] | [];
|
||||
}
|
||||
|
||||
export interface IServerSubscription {
|
||||
update: IServerSubscriptionItem[];
|
||||
remove: IServerSubscriptionItem[];
|
||||
success: boolean;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ interface IFileThread {
|
|||
}
|
||||
|
||||
export interface IThreadResult {
|
||||
id: string;
|
||||
_id: string;
|
||||
rid: string;
|
||||
ts: string | Date;
|
||||
|
@ -23,13 +24,13 @@ export interface IThreadResult {
|
|||
attachments?: IAttachment[];
|
||||
md?: MarkdownAST;
|
||||
u: IUserMessage;
|
||||
_updatedAt: Date;
|
||||
_updatedAt: string | Date;
|
||||
urls?: IUrl[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
replies?: string[];
|
||||
tcount?: number;
|
||||
tlm?: Date;
|
||||
tlm?: string | Date;
|
||||
}
|
||||
|
||||
export interface IThread {
|
||||
|
@ -38,8 +39,8 @@ export interface IThread {
|
|||
msg?: string;
|
||||
t?: MessageType;
|
||||
rid: string;
|
||||
_updatedAt?: Date;
|
||||
ts?: Date;
|
||||
_updatedAt?: string | Date;
|
||||
ts?: string | Date;
|
||||
u?: IUserMessage;
|
||||
alias?: string;
|
||||
parseUrls?: boolean;
|
||||
|
@ -56,10 +57,10 @@ export interface IThread {
|
|||
role?: string;
|
||||
drid?: string;
|
||||
dcount?: number | string;
|
||||
dlm?: number;
|
||||
dlm?: string | Date;
|
||||
tmid?: string;
|
||||
tcount?: number | string;
|
||||
tlm?: string;
|
||||
tlm?: string | Date;
|
||||
replies?: string[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
|
@ -67,7 +68,7 @@ export interface IThread {
|
|||
autoTranslate?: boolean;
|
||||
translations?: any;
|
||||
e2e?: string;
|
||||
subscription: { id: string };
|
||||
subscription?: { id: string };
|
||||
}
|
||||
|
||||
export type TThreadModel = IThread & Model;
|
||||
|
|
|
@ -6,6 +6,7 @@ import { IReaction } from './IReaction';
|
|||
import { IUrl } from './IUrl';
|
||||
|
||||
export interface IThreadMessage {
|
||||
id: string;
|
||||
_id: string;
|
||||
tmsg?: string;
|
||||
msg?: string;
|
||||
|
@ -20,7 +21,7 @@ export interface IThreadMessage {
|
|||
emoji?: string;
|
||||
attachments?: IAttachment[];
|
||||
urls?: IUrl[];
|
||||
_updatedAt?: Date;
|
||||
_updatedAt?: string | Date;
|
||||
status?: number;
|
||||
pinned?: boolean;
|
||||
starred?: boolean;
|
||||
|
@ -29,10 +30,10 @@ export interface IThreadMessage {
|
|||
role?: string;
|
||||
drid?: string;
|
||||
dcount?: number;
|
||||
dlm?: Date;
|
||||
dlm?: string | Date;
|
||||
tmid?: string;
|
||||
tcount?: number;
|
||||
tlm?: Date;
|
||||
tlm?: string | Date;
|
||||
replies?: string[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
export interface IUpload {
|
||||
id: string;
|
||||
path?: string;
|
||||
id?: string;
|
||||
rid?: string;
|
||||
path: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
size: number;
|
||||
type?: string;
|
||||
store?: string;
|
||||
progress: number;
|
||||
error: boolean;
|
||||
subscription: { id: string };
|
||||
progress?: number;
|
||||
error?: boolean;
|
||||
subscription?: { id: string };
|
||||
}
|
||||
|
||||
export type TUploadModel = IUpload & Model;
|
||||
|
|
|
@ -2,6 +2,7 @@ import Model from '@nozbe/watermelondb/Model';
|
|||
|
||||
import { UserStatus } from './UserStatus';
|
||||
import { IRocketChatRecord } from './IRocketChatRecord';
|
||||
import { ILoggedUser } from './ILoggedUser';
|
||||
|
||||
export interface ILoginToken {
|
||||
hashedToken: string;
|
||||
|
@ -93,14 +94,16 @@ export interface IUserSettings {
|
|||
};
|
||||
}
|
||||
|
||||
export interface IUser extends IRocketChatRecord {
|
||||
export interface IUser extends IRocketChatRecord, Omit<ILoggedUser, 'username' | 'name' | 'status'> {
|
||||
_id: string;
|
||||
createdAt: Date;
|
||||
roles: string[];
|
||||
type: string;
|
||||
active: boolean;
|
||||
name?: string;
|
||||
id: string;
|
||||
token: string;
|
||||
createdAt?: Date;
|
||||
roles?: string[];
|
||||
type?: string;
|
||||
active?: boolean;
|
||||
username: string;
|
||||
name?: string;
|
||||
services?: IUserServices;
|
||||
emails?: IUserEmail[];
|
||||
status?: UserStatus;
|
||||
|
@ -115,7 +118,6 @@ export interface IUser extends IRocketChatRecord {
|
|||
oauth?: {
|
||||
authorizedClients: string[];
|
||||
};
|
||||
_updatedAt: Date;
|
||||
statusLivechat?: string;
|
||||
e2e?: {
|
||||
private_key: string;
|
||||
|
|
|
@ -23,7 +23,9 @@ import { ICreateChannel } from '../../reducers/createChannel';
|
|||
import { ICreateDiscussion } from '../../reducers/createDiscussion';
|
||||
import { IEncryption } from '../../reducers/encryption';
|
||||
import { IInviteLinks } from '../../reducers/inviteLinks';
|
||||
import { ILogin } from '../../reducers/login';
|
||||
import { IRoles } from '../../reducers/roles';
|
||||
import { IRoom } from '../../reducers/room';
|
||||
import { ISelectedUsers } from '../../reducers/selectedUsers';
|
||||
import { IServer } from '../../reducers/server';
|
||||
import { ISettings } from '../../reducers/settings';
|
||||
|
@ -33,13 +35,13 @@ import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
|||
|
||||
export interface IApplicationState {
|
||||
settings: ISettings;
|
||||
login: any;
|
||||
meteor: IConnect;
|
||||
login: ILogin;
|
||||
server: IServer;
|
||||
selectedUsers: ISelectedUsers;
|
||||
app: IApp;
|
||||
createChannel: ICreateChannel;
|
||||
room: any;
|
||||
room: IRoom;
|
||||
rooms: any;
|
||||
sortPreferences: any;
|
||||
share: IShare;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export type E2eEndpoints = {
|
||||
'e2e.setUserPublicAndPrivateKeys': {
|
||||
POST: (params: { public_key: string; private_key: string }) => void;
|
||||
};
|
||||
};
|
|
@ -9,7 +9,7 @@ export type EmojiCustomEndpoints = {
|
|||
} & PaginatedResult;
|
||||
};
|
||||
'emoji-custom.list': {
|
||||
GET: (params: { query: string }) => {
|
||||
GET: (params: { updatedSince: string }) => {
|
||||
emojis?: {
|
||||
update: ICustomEmojiDescriptor[];
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import { OauthCustomConfiguration } from './settings';
|
|||
import { UserEndpoints } from './user';
|
||||
import { UsersEndpoints } from './users';
|
||||
import { TeamsEndpoints } from './teams';
|
||||
import { E2eEndpoints } from './e2e';
|
||||
|
||||
export type Endpoints = ChannelsEndpoints &
|
||||
ChatEndpoints &
|
||||
|
@ -30,4 +31,5 @@ export type Endpoints = ChannelsEndpoints &
|
|||
OauthCustomConfiguration &
|
||||
UserEndpoints &
|
||||
UsersEndpoints &
|
||||
TeamsEndpoints;
|
||||
TeamsEndpoints &
|
||||
E2eEndpoints;
|
||||
|
|
|
@ -788,5 +788,24 @@
|
|||
"Enable_Message_Parser": "Enable Message Parser",
|
||||
"Unsupported_format": "Unsupported format",
|
||||
"Downloaded_file": "Downloaded file",
|
||||
"Error_Download_file": "Error while downloading file"
|
||||
"Error_Download_file": "Error while downloading file",
|
||||
"added__roomName__to_team": "added #{{roomName}} to this Team",
|
||||
"Added__username__to_team": "added @{{user_added}} to this Team",
|
||||
"Converted__roomName__to_team": "converted #{{roomName}} to a Team",
|
||||
"Converted__roomName__to_channel": "converted #{{roomName}} to a Channel",
|
||||
"Converting_team_to_channel": "Converting Team to Channel",
|
||||
"Deleted__roomName__": "deleted #{{roomName}}",
|
||||
"Message_HideType_added_user_to_team": "Hide \"User Added to Team\" messages",
|
||||
"Message_HideType_removed_user_from_team": "Hide \"User Removed from Team\" messages",
|
||||
"Message_HideType_ujt": "Hide \"User Joined Team\" messages",
|
||||
"Message_HideType_ult": "Hide \"User Left Team\" messages",
|
||||
"Message_HideType_user_added_room_to_team": "Hide \"User Added Room to Team\" messages",
|
||||
"Message_HideType_user_converted_to_channel": "Hide \"User converted team to a Channel\" messages",
|
||||
"Message_HideType_user_converted_to_team": "Hide \"User converted channel to a Team\" messages",
|
||||
"Message_HideType_user_deleted_room_from_team": "Hide \"User deleted room from Team\" messages",
|
||||
"Message_HideType_user_removed_room_from_team": "Hide \"User removed room from Team\" messages",
|
||||
"Removed__roomName__from_this_team": "removed #{{roomName}} from this Team",
|
||||
"Removed__username__from_team": "removed @{{user_removed}} from this Team",
|
||||
"User_joined_team": "joined this Team",
|
||||
"User_left_team": "left this Team"
|
||||
}
|
|
@ -443,7 +443,7 @@ class Encryption {
|
|||
};
|
||||
|
||||
// Decrypt a message
|
||||
decryptMessage = async (message: Partial<IMessage>) => {
|
||||
decryptMessage = async (message: Pick<IMessage, 't' | 'e2e' | 'rid' | 'msg' | 'tmsg'>) => {
|
||||
const { t, e2e } = message;
|
||||
|
||||
// Prevent create a new instance if this room was encrypted sometime ago
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { store as reduxStore } from '../auxStore';
|
||||
import Navigation from '../Navigation';
|
||||
import { ISubscription } from '../../definitions';
|
||||
import { events, logEvent } from '../../utils/log';
|
||||
import { store } from '../auxStore';
|
||||
import Navigation from '../Navigation';
|
||||
import sdk from '../rocketchat';
|
||||
|
||||
async function jitsiURL({ room }) {
|
||||
const { settings } = reduxStore.getState();
|
||||
async function jitsiURL({ room }: { room: ISubscription }) {
|
||||
const { settings } = store.getState();
|
||||
const { Jitsi_Enabled } = settings;
|
||||
|
||||
if (!Jitsi_Enabled) {
|
||||
|
@ -19,7 +21,7 @@ async function jitsiURL({ room }) {
|
|||
let queryString = '';
|
||||
if (Jitsi_Enabled_TokenAuth) {
|
||||
try {
|
||||
const accessToken = await this.methodCallWrapper('jitsi:generateAccessToken', room?.rid);
|
||||
const accessToken = await sdk.methodCallWrapper('jitsi:generateAccessToken', room?.rid);
|
||||
queryString = `?jwt=${accessToken}`;
|
||||
} catch {
|
||||
logEvent(events.RA_JITSI_F);
|
||||
|
@ -30,23 +32,23 @@ async function jitsiURL({ room }) {
|
|||
if (Jitsi_URL_Room_Hash) {
|
||||
rname = uniqueID + room?.rid;
|
||||
} else {
|
||||
rname = encodeURIComponent(room.t === 'd' ? room?.usernames?.join?.(' x ') : room?.name);
|
||||
rname = encodeURIComponent(room.t === 'd' ? (room?.usernames?.join?.(' x ') as string) : room?.name);
|
||||
}
|
||||
|
||||
return `${protocol}${domain}${prefix}${rname}${queryString}`;
|
||||
}
|
||||
|
||||
export function callJitsiWithoutServer(path) {
|
||||
export function callJitsiWithoutServer(path: string): void {
|
||||
logEvent(events.RA_JITSI_VIDEO);
|
||||
const { Jitsi_SSL } = reduxStore.getState().settings;
|
||||
const { Jitsi_SSL } = store.getState().settings;
|
||||
const protocol = Jitsi_SSL ? 'https://' : 'http://';
|
||||
const url = `${protocol}${path}`;
|
||||
Navigation.navigate('JitsiMeetView', { url, onlyAudio: false });
|
||||
}
|
||||
|
||||
async function callJitsi(room, onlyAudio = false) {
|
||||
async function callJitsi(room: ISubscription, onlyAudio = false): Promise<void> {
|
||||
logEvent(onlyAudio ? events.RA_JITSI_AUDIO : events.RA_JITSI_VIDEO);
|
||||
const url = await jitsiURL.call(this, { room });
|
||||
const url = await jitsiURL({ room });
|
||||
Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid: room?.rid });
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
import database from '../database';
|
||||
import { ERoomTypes } from '../../definitions';
|
||||
import { store } from '../auxStore';
|
||||
import database from '../database';
|
||||
import RocketChat from '../rocketchat';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
const restTypes = {
|
||||
channel: 'channels',
|
||||
|
@ -7,27 +10,28 @@ const restTypes = {
|
|||
group: 'groups'
|
||||
};
|
||||
|
||||
async function open({ type, rid, name }) {
|
||||
async function open({ type, rid, name }: { type: ERoomTypes; rid: string; name: string }) {
|
||||
try {
|
||||
const params = rid ? { roomId: rid } : { roomName: name };
|
||||
|
||||
// if it's a direct link without rid we'll create a new dm
|
||||
// if the dm already exists it'll return the existent
|
||||
if (type === 'direct' && !rid) {
|
||||
const result = await this.createDirectMessage(name);
|
||||
if (type === ERoomTypes.DIRECT && !rid) {
|
||||
const result = await RocketChat.createDirectMessage(name);
|
||||
if (result.success) {
|
||||
const { room } = result;
|
||||
room.rid = room._id;
|
||||
room.rid = room._id as string;
|
||||
return room;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a group we need to check if you can open
|
||||
if (type === 'group') {
|
||||
if (type === ERoomTypes.GROUP) {
|
||||
try {
|
||||
// RC 0.61.0
|
||||
await this.sdk.post(`${restTypes[type]}.open`, params);
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
await sdk.post(`${restTypes[type]}.open`, params);
|
||||
} catch (e: any) {
|
||||
if (!(e.data && /is already open/.test(e.data.error))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -36,9 +40,10 @@ async function open({ type, rid, name }) {
|
|||
|
||||
// if it's a channel or group and the link don't have rid
|
||||
// we'll get info from the room
|
||||
if ((type === 'channel' || type === 'group') && !rid) {
|
||||
if ((type === ERoomTypes.CHANNEL || type === ERoomTypes.GROUP) && !rid) {
|
||||
// RC 0.72.0
|
||||
const result = await this.sdk.get(`${restTypes[type]}.info`, params);
|
||||
// @ts-ignore
|
||||
const result: any = await sdk.get(`channel.info`, params);
|
||||
if (result.success) {
|
||||
const room = result[type];
|
||||
room.rid = room._id;
|
||||
|
@ -56,7 +61,7 @@ async function open({ type, rid, name }) {
|
|||
}
|
||||
}
|
||||
|
||||
export default async function canOpenRoom({ rid, path, isCall }) {
|
||||
export default async function canOpenRoom({ rid, path, isCall }: { rid: string; isCall: boolean; path: string }): Promise<any> {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
|
@ -86,8 +91,9 @@ export default async function canOpenRoom({ rid, path, isCall }) {
|
|||
}
|
||||
|
||||
const [type, name] = path.split('/');
|
||||
const t = type as ERoomTypes;
|
||||
try {
|
||||
const result = await open.call(this, { type, rid, name });
|
||||
const result = await open({ type: t, rid, name });
|
||||
return result;
|
||||
} catch (e) {
|
||||
return false;
|
|
@ -1,11 +1,12 @@
|
|||
import sdk from '../rocketchat/services/sdk';
|
||||
import { compareServerVersion } from '../utils';
|
||||
import { store as reduxStore } from '../auxStore';
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import { clearEnterpriseModules, setEnterpriseModules as setEnterpriseModulesAction } from '../../actions/enterpriseModules';
|
||||
|
||||
export const LICENSE_OMNICHANNEL_MOBILE_ENTERPRISE = 'omnichannel-mobile-enterprise';
|
||||
export const LICENSE_LIVECHAT_ENTERPRISE = 'livechat-enterprise';
|
||||
const LICENSE_OMNICHANNEL_MOBILE_ENTERPRISE = 'omnichannel-mobile-enterprise';
|
||||
const LICENSE_LIVECHAT_ENTERPRISE = 'livechat-enterprise';
|
||||
|
||||
export async function setEnterpriseModules() {
|
||||
try {
|
||||
|
@ -29,17 +30,17 @@ export async function setEnterpriseModules() {
|
|||
}
|
||||
|
||||
export function getEnterpriseModules() {
|
||||
return new Promise(async resolve => {
|
||||
return new Promise<void>(async resolve => {
|
||||
try {
|
||||
const { version: serverVersion, server: serverId } = reduxStore.getState().server;
|
||||
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '3.1.0')) {
|
||||
// RC 3.1.0
|
||||
const enterpriseModules = await this.methodCallWrapper('license:getModules');
|
||||
const enterpriseModules = await sdk.methodCallWrapper('license:getModules');
|
||||
if (enterpriseModules) {
|
||||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
const server = await serversCollection.find(serverId);
|
||||
await serversDB.action(async () => {
|
||||
await serversDB.write(async () => {
|
||||
await server.update(s => {
|
||||
s.enterpriseModules = enterpriseModules.join(',');
|
||||
});
|
||||
|
@ -56,7 +57,7 @@ export function getEnterpriseModules() {
|
|||
});
|
||||
}
|
||||
|
||||
export function hasLicense(module) {
|
||||
export function hasLicense(module: string) {
|
||||
const { enterpriseModules } = reduxStore.getState();
|
||||
return enterpriseModules.includes(module);
|
||||
}
|
|
@ -1,13 +1,22 @@
|
|||
import orderBy from 'lodash/orderBy';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
|
||||
import { ICustomEmojis } from '../../reducers/customEmojis';
|
||||
import { compareServerVersion } from '../utils';
|
||||
import { store as reduxStore } from '../auxStore';
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import { setCustomEmojis as setCustomEmojisAction } from '../../actions/customEmojis';
|
||||
import { ICustomEmoji, TCustomEmojiModel } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
const getUpdatedSince = allEmojis => {
|
||||
interface IUpdateEmojis {
|
||||
update: TCustomEmojiModel[];
|
||||
remove?: TCustomEmojiModel[];
|
||||
allRecords: TCustomEmojiModel[];
|
||||
}
|
||||
|
||||
const getUpdatedSince = (allEmojis: ICustomEmoji[]) => {
|
||||
if (!allEmojis.length) {
|
||||
return null;
|
||||
}
|
||||
|
@ -19,27 +28,27 @@ const getUpdatedSince = allEmojis => {
|
|||
return ordered && ordered[0]._updatedAt.toISOString();
|
||||
};
|
||||
|
||||
const updateEmojis = async ({ update = [], remove = [], allRecords }) => {
|
||||
const updateEmojis = async ({ update = [], remove = [], allRecords }: IUpdateEmojis) => {
|
||||
if (!((update && update.length) || (remove && remove.length))) {
|
||||
return;
|
||||
}
|
||||
const db = database.active;
|
||||
const emojisCollection = db.get('custom_emojis');
|
||||
let emojisToCreate = [];
|
||||
let emojisToUpdate = [];
|
||||
let emojisToDelete = [];
|
||||
let emojisToCreate: TCustomEmojiModel[] = [];
|
||||
let emojisToUpdate: TCustomEmojiModel[] = [];
|
||||
let emojisToDelete: TCustomEmojiModel[] = [];
|
||||
|
||||
// Create or update
|
||||
if (update && update.length) {
|
||||
emojisToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
|
||||
emojisToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
|
||||
emojisToCreate = emojisToCreate.map(emoji =>
|
||||
const filterEmojisToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
|
||||
const filterEmojisToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
|
||||
emojisToCreate = filterEmojisToCreate.map(emoji =>
|
||||
emojisCollection.prepareCreate(e => {
|
||||
e._raw = sanitizedRaw({ id: emoji._id }, emojisCollection.schema);
|
||||
Object.assign(e, emoji);
|
||||
})
|
||||
);
|
||||
emojisToUpdate = emojisToUpdate.map(emoji => {
|
||||
emojisToUpdate = filterEmojisToUpdate.map(emoji => {
|
||||
const newEmoji = update.find(e => e._id === emoji.id);
|
||||
return emoji.prepareUpdate(e => {
|
||||
Object.assign(e, newEmoji);
|
||||
|
@ -48,12 +57,12 @@ const updateEmojis = async ({ update = [], remove = [], allRecords }) => {
|
|||
}
|
||||
|
||||
if (remove && remove.length) {
|
||||
emojisToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
|
||||
emojisToDelete = emojisToDelete.map(emoji => emoji.prepareDestroyPermanently());
|
||||
const filterEmojisToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
|
||||
emojisToDelete = filterEmojisToDelete.map(emoji => emoji.prepareDestroyPermanently());
|
||||
}
|
||||
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await db.batch(...emojisToCreate, ...emojisToUpdate, ...emojisToDelete);
|
||||
});
|
||||
return true;
|
||||
|
@ -66,26 +75,34 @@ export async function setCustomEmojis() {
|
|||
const db = database.active;
|
||||
const emojisCollection = db.get('custom_emojis');
|
||||
const allEmojis = await emojisCollection.query().fetch();
|
||||
const parsed = allEmojis.reduce((ret, item) => {
|
||||
ret[item.name] = {
|
||||
name: item.name,
|
||||
extension: item.extension
|
||||
};
|
||||
item.aliases.forEach(alias => {
|
||||
ret[alias] = {
|
||||
const parsed = allEmojis.reduce((ret: ICustomEmojis, item) => {
|
||||
if (item.name) {
|
||||
ret[item.name] = {
|
||||
name: item.name,
|
||||
extension: item.extension
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (item.aliases) {
|
||||
item.aliases.forEach(alias => {
|
||||
if (item.name) {
|
||||
ret[alias] = {
|
||||
name: item.name,
|
||||
extension: item.extension
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}, {});
|
||||
reduxStore.dispatch(setCustomEmojisAction(parsed));
|
||||
}
|
||||
|
||||
export function getCustomEmojis() {
|
||||
return new Promise(async resolve => {
|
||||
return new Promise<void>(async resolve => {
|
||||
try {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
const serverVersion = reduxStore.getState().server.version as string;
|
||||
const db = database.active;
|
||||
const emojisCollection = db.get('custom_emojis');
|
||||
const allRecords = await emojisCollection.query().fetch();
|
||||
|
@ -94,10 +111,11 @@ export function getCustomEmojis() {
|
|||
// if server version is lower than 0.75.0, fetches from old api
|
||||
if (compareServerVersion(serverVersion, 'lowerThan', '0.75.0')) {
|
||||
// RC 0.61.0
|
||||
const result = await this.sdk.get('emoji-custom');
|
||||
|
||||
// @ts-ignore
|
||||
const result = await sdk.get('emoji-custom');
|
||||
// @ts-ignore
|
||||
let { emojis } = result;
|
||||
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
|
||||
emojis = emojis.filter((emoji: TCustomEmojiModel) => !updatedSince || emoji._updatedAt.toISOString() > updatedSince);
|
||||
const changedEmojis = await updateEmojis({ update: emojis, allRecords });
|
||||
|
||||
// `setCustomEmojis` is fired on selectServer
|
||||
|
@ -106,28 +124,28 @@ export function getCustomEmojis() {
|
|||
setCustomEmojis();
|
||||
}
|
||||
return resolve();
|
||||
} else {
|
||||
const params = {};
|
||||
if (updatedSince) {
|
||||
params.updatedSince = updatedSince;
|
||||
}
|
||||
}
|
||||
const params: { updatedSince: string } = { updatedSince: '' };
|
||||
if (updatedSince) {
|
||||
params.updatedSince = updatedSince;
|
||||
}
|
||||
|
||||
// RC 0.75.0
|
||||
const result = await this.sdk.get('emoji-custom.list', params);
|
||||
// RC 0.75.0
|
||||
const result = await sdk.get('emoji-custom.list', params);
|
||||
|
||||
if (!result.success) {
|
||||
return resolve();
|
||||
}
|
||||
if (!result.success) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
const { emojis } = result;
|
||||
const { update, remove } = emojis;
|
||||
const changedEmojis = await updateEmojis({ update, remove, allRecords });
|
||||
const { emojis } = result;
|
||||
// @ts-ignore
|
||||
const { update, remove } = emojis;
|
||||
const changedEmojis = await updateEmojis({ update, remove, allRecords });
|
||||
|
||||
// `setCustomEmojis` is fired on selectServer
|
||||
// We run it again only if emojis were changed
|
||||
if (changedEmojis) {
|
||||
setCustomEmojis();
|
||||
}
|
||||
// `setCustomEmojis` is fired on selectServer
|
||||
// We run it again only if emojis were changed
|
||||
if (changedEmojis) {
|
||||
setCustomEmojis();
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
|
@ -1,4 +1,5 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import database from '../database';
|
||||
import { getRoleById } from '../database/services/Role';
|
||||
|
@ -6,8 +7,10 @@ import log from '../../utils/log';
|
|||
import { store as reduxStore } from '../auxStore';
|
||||
import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../actions/roles';
|
||||
import protectedFunction from './helpers/protectedFunction';
|
||||
import { TRoleModel } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
export async function setRoles() {
|
||||
export async function setRoles(): Promise<void> {
|
||||
const db = database.active;
|
||||
const rolesCollection = db.get('roles');
|
||||
const allRoles = await rolesCollection.query().fetch();
|
||||
|
@ -15,7 +18,17 @@ export async function setRoles() {
|
|||
reduxStore.dispatch(setRolesAction(parsed));
|
||||
}
|
||||
|
||||
export async function onRolesChanged(ddpMessage) {
|
||||
interface IRolesChanged {
|
||||
fields: {
|
||||
args: {
|
||||
type: string;
|
||||
_id: string;
|
||||
description: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export async function onRolesChanged(ddpMessage: IRolesChanged): Promise<void> {
|
||||
const { type, _id, description } = ddpMessage.fields.args[0];
|
||||
if (/changed/.test(type)) {
|
||||
const db = database.active;
|
||||
|
@ -42,7 +55,6 @@ export async function onRolesChanged(ddpMessage) {
|
|||
}
|
||||
if (/removed/.test(type)) {
|
||||
const db = database.active;
|
||||
const rolesCollection = db.get('roles');
|
||||
try {
|
||||
const roleRecord = await getRoleById(_id);
|
||||
if (roleRecord) {
|
||||
|
@ -57,12 +69,12 @@ export async function onRolesChanged(ddpMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
export function getRoles() {
|
||||
export function getRoles(): Promise<void> {
|
||||
const db = database.active;
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
// RC 0.70.0
|
||||
const result = await this.sdk.get('roles.list');
|
||||
const result = await sdk.get('roles.list');
|
||||
|
||||
if (!result.success) {
|
||||
return resolve();
|
||||
|
@ -71,18 +83,18 @@ export function getRoles() {
|
|||
const { roles } = result;
|
||||
|
||||
if (roles && roles.length) {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
const rolesCollections = db.get('roles');
|
||||
const allRolesRecords = await rolesCollections.query().fetch();
|
||||
|
||||
// filter roles
|
||||
let rolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id));
|
||||
let rolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id));
|
||||
const filteredRolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id));
|
||||
const filteredRolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id));
|
||||
|
||||
// Create
|
||||
rolesToCreate = rolesToCreate.map(role =>
|
||||
const rolesToCreate = filteredRolesToCreate.map(role =>
|
||||
rolesCollections.prepareCreate(
|
||||
protectedFunction(r => {
|
||||
protectedFunction((r: TRoleModel) => {
|
||||
r._raw = sanitizedRaw({ id: role._id }, rolesCollections.schema);
|
||||
Object.assign(r, role);
|
||||
})
|
||||
|
@ -90,16 +102,16 @@ export function getRoles() {
|
|||
);
|
||||
|
||||
// Update
|
||||
rolesToUpdate = rolesToUpdate.map(role => {
|
||||
const rolesToUpdate = filteredRolesToUpdate.map(role => {
|
||||
const newRole = roles.find(r => r._id === role.id);
|
||||
return role.prepareUpdate(
|
||||
protectedFunction(r => {
|
||||
protectedFunction((r: TRoleModel) => {
|
||||
Object.assign(r, newRole);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const allRecords = [...rolesToCreate, ...rolesToUpdate];
|
||||
const allRecords: Model[] = [...rolesToCreate, ...rolesToUpdate];
|
||||
|
||||
try {
|
||||
await db.batch(...allRecords);
|
|
@ -1,7 +1,8 @@
|
|||
import { IRoom } from '../../definitions';
|
||||
import { getSubscriptionByRoomId } from '../database/services/Subscription';
|
||||
import RocketChat from '../rocketchat';
|
||||
|
||||
const getRoomInfo = async rid => {
|
||||
const getRoomInfo = async (rid: string): Promise<Pick<IRoom, 'rid' | 'name' | 'fname' | 't'> | null> => {
|
||||
let result;
|
||||
result = await getSubscriptionByRoomId(rid);
|
||||
if (result) {
|
|
@ -6,8 +6,12 @@ export default function (updatedSince: Date) {
|
|||
if (updatedSince) {
|
||||
const updatedDate = updatedSince.toISOString();
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return Promise.all([sdk.get('subscriptions.get', { updatedDate }), sdk.get('rooms.get', { updatedDate })]);
|
||||
return Promise.all([
|
||||
// @ts-ignore
|
||||
sdk.get('subscriptions.get', { updatedSince: updatedDate }),
|
||||
// @ts-ignore
|
||||
sdk.get('rooms.get', { updatedSince: updatedDate })
|
||||
]);
|
||||
}
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
|
||||
import { addSettings, clearSettings } from '../../actions/settings';
|
||||
import RocketChat from '../rocketchat';
|
||||
import { store as reduxStore } from '../auxStore';
|
||||
import settings from '../../constants/settings';
|
||||
import log from '../../utils/log';
|
||||
import database from '../database';
|
||||
import fetch from '../../utils/fetch';
|
||||
import { DEFAULT_AUTO_LOCK } from '../../constants/localAuthentication';
|
||||
import settings from '../../constants/settings';
|
||||
import { IPreparedSettings, ISettingsIcon } from '../../definitions';
|
||||
import fetch from '../../utils/fetch';
|
||||
import log from '../../utils/log';
|
||||
import { store as reduxStore } from '../auxStore';
|
||||
import database from '../database';
|
||||
import RocketChat from '../rocketchat';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
import protectedFunction from './helpers/protectedFunction';
|
||||
|
||||
const serverInfoKeys = [
|
||||
|
@ -41,7 +43,7 @@ const loginSettings = [
|
|||
'Accounts_Iframe_api_method'
|
||||
];
|
||||
|
||||
const serverInfoUpdate = async (serverInfo, iconSetting) => {
|
||||
const serverInfoUpdate = async (serverInfo: IPreparedSettings[], iconSetting: ISettingsIcon) => {
|
||||
const serversDB = database.servers;
|
||||
const serverId = reduxStore.getState().server.server;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
|
@ -73,7 +75,7 @@ const serverInfoUpdate = async (serverInfo, iconSetting) => {
|
|||
return { ...allSettings, autoLockTime: DEFAULT_AUTO_LOCK };
|
||||
}
|
||||
// if Force_Screen_Lock_After > 0 and forceScreenLock is enabled, use it
|
||||
if (setting.valueAsNumber > 0 && forceScreenLock) {
|
||||
if (setting.valueAsNumber && setting.valueAsNumber > 0 && forceScreenLock) {
|
||||
return { ...allSettings, autoLockTime: setting.valueAsNumber };
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +93,7 @@ const serverInfoUpdate = async (serverInfo, iconSetting) => {
|
|||
info = { ...info, iconURL };
|
||||
}
|
||||
|
||||
await serversDB.action(async () => {
|
||||
await serversDB.write(async () => {
|
||||
try {
|
||||
await server.update(record => {
|
||||
Object.assign(record, info);
|
||||
|
@ -102,7 +104,7 @@ const serverInfoUpdate = async (serverInfo, iconSetting) => {
|
|||
});
|
||||
};
|
||||
|
||||
export async function getLoginSettings({ server }) {
|
||||
export async function getLoginSettings({ server }: { server: string }): Promise<void> {
|
||||
try {
|
||||
const settingsParams = JSON.stringify(loginSettings);
|
||||
const result = await fetch(`${server}/api/v1/settings.public?query={"_id":{"$in":${settingsParams}}}`).then(response =>
|
||||
|
@ -111,14 +113,14 @@ export async function getLoginSettings({ server }) {
|
|||
|
||||
if (result.success && result.settings.length) {
|
||||
reduxStore.dispatch(clearSettings());
|
||||
reduxStore.dispatch(addSettings(this.parseSettings(this._prepareSettings(result.settings))));
|
||||
reduxStore.dispatch(addSettings(RocketChat.parseSettings(RocketChat._prepareSettings(result.settings))));
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function setSettings() {
|
||||
export async function setSettings(): Promise<void> {
|
||||
const db = database.active;
|
||||
const settingsCollection = db.get('settings');
|
||||
const settingsRecords = await settingsCollection.query().fetch();
|
||||
|
@ -133,17 +135,19 @@ export async function setSettings() {
|
|||
reduxStore.dispatch(addSettings(RocketChat.parseSettings(parsed.slice(0, parsed.length))));
|
||||
}
|
||||
|
||||
export function subscribeSettings() {
|
||||
export function subscribeSettings(): void {
|
||||
return RocketChat.subscribe('stream-notify-all', 'public-settings-changed');
|
||||
}
|
||||
|
||||
export default async function () {
|
||||
type IData = ISettingsIcon | IPreparedSettings;
|
||||
|
||||
export default async function (): Promise<void> {
|
||||
try {
|
||||
const db = database.active;
|
||||
const settingsParams = Object.keys(settings).filter(key => !loginSettings.includes(key));
|
||||
// RC 0.60.0
|
||||
const result = await fetch(
|
||||
`${this.sdk.client.host}/api/v1/settings.public?query={"_id":{"$in":${JSON.stringify(settingsParams)}}}&count=${
|
||||
`${sdk.current.client.host}/api/v1/settings.public?query={"_id":{"$in":${JSON.stringify(settingsParams)}}}&count=${
|
||||
settingsParams.length
|
||||
}`
|
||||
).then(response => response.json());
|
||||
|
@ -151,33 +155,32 @@ export default async function () {
|
|||
if (!result.success) {
|
||||
return;
|
||||
}
|
||||
const data = result.settings || [];
|
||||
const filteredSettings = this._prepareSettings(data);
|
||||
const data: IData[] = result.settings || [];
|
||||
const filteredSettings: IPreparedSettings[] = RocketChat._prepareSettings(data);
|
||||
const filteredSettingsIds = filteredSettings.map(s => s._id);
|
||||
|
||||
reduxStore.dispatch(addSettings(this.parseSettings(filteredSettings)));
|
||||
reduxStore.dispatch(addSettings(RocketChat.parseSettings(filteredSettings)));
|
||||
|
||||
// filter server info
|
||||
const serverInfo = filteredSettings.filter(i1 => serverInfoKeys.includes(i1._id));
|
||||
const iconSetting = data.find(item => item._id === 'Assets_favicon_512');
|
||||
const iconSetting = data.find(icon => icon._id === 'Assets_favicon_512');
|
||||
try {
|
||||
await serverInfoUpdate(serverInfo, iconSetting);
|
||||
await serverInfoUpdate(serverInfo, iconSetting as ISettingsIcon);
|
||||
} catch {
|
||||
// Server not found
|
||||
}
|
||||
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
const settingsCollection = db.get('settings');
|
||||
const allSettingsRecords = await settingsCollection.query(Q.where('id', Q.oneOf(filteredSettingsIds))).fetch();
|
||||
|
||||
// filter settings
|
||||
let settingsToCreate = filteredSettings.filter(i1 => !allSettingsRecords.find(i2 => i1._id === i2.id));
|
||||
let settingsToUpdate = allSettingsRecords.filter(i1 => filteredSettings.find(i2 => i1.id === i2._id));
|
||||
|
||||
const settingsToCreate = filteredSettings.filter(i1 => !allSettingsRecords.find(i2 => i1._id === i2.id));
|
||||
const settingsToUpdate = allSettingsRecords.filter(i1 => filteredSettings.find(i2 => i1.id === i2._id));
|
||||
// Create
|
||||
settingsToCreate = settingsToCreate.map(setting =>
|
||||
const settingsToCreateMapped = settingsToCreate.map(setting =>
|
||||
settingsCollection.prepareCreate(
|
||||
protectedFunction(s => {
|
||||
protectedFunction((s: any) => {
|
||||
s._raw = sanitizedRaw({ id: setting._id }, settingsCollection.schema);
|
||||
Object.assign(s, setting);
|
||||
})
|
||||
|
@ -185,16 +188,16 @@ export default async function () {
|
|||
);
|
||||
|
||||
// Update
|
||||
settingsToUpdate = settingsToUpdate.map(setting => {
|
||||
const settingsToUpdateMapped = settingsToUpdate.map(setting => {
|
||||
const newSetting = filteredSettings.find(s => s._id === setting.id);
|
||||
return setting.prepareUpdate(
|
||||
protectedFunction(s => {
|
||||
protectedFunction((s: any) => {
|
||||
Object.assign(s, newSetting);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const allRecords = [...settingsToCreate, ...settingsToUpdate];
|
||||
const allRecords = [...settingsToCreateMapped, ...settingsToUpdateMapped];
|
||||
|
||||
try {
|
||||
await db.batch(...allRecords);
|
|
@ -1,6 +1,7 @@
|
|||
import RocketChat from '../rocketchat';
|
||||
import { IMessage } from '../../definitions';
|
||||
|
||||
const getSingleMessage = (messageId: string) =>
|
||||
const getSingleMessage = (messageId: string): Promise<IMessage> =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const result = await RocketChat.getSingleMessage(messageId);
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import protectedFunction from './helpers/protectedFunction';
|
||||
|
||||
export default function () {
|
||||
const db = database.active;
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
// RC 0.60.2
|
||||
const result = await this.sdk.get('commands.list');
|
||||
|
||||
if (!result.success) {
|
||||
console.log(result);
|
||||
return resolve();
|
||||
}
|
||||
|
||||
const { commands } = result;
|
||||
|
||||
if (commands && commands.length) {
|
||||
await db.action(async () => {
|
||||
const slashCommandsCollection = db.get('slash_commands');
|
||||
const allSlashCommandsRecords = await slashCommandsCollection.query().fetch();
|
||||
|
||||
// filter slash commands
|
||||
let slashCommandsToCreate = commands.filter(i1 => !allSlashCommandsRecords.find(i2 => i1.command === i2.id));
|
||||
let slashCommandsToUpdate = allSlashCommandsRecords.filter(i1 => commands.find(i2 => i1.id === i2.command));
|
||||
let slashCommandsToDelete = allSlashCommandsRecords.filter(
|
||||
i1 => !slashCommandsToCreate.find(i2 => i2.command === i1.id) && !slashCommandsToUpdate.find(i2 => i2.id === i1.id)
|
||||
);
|
||||
|
||||
// Create
|
||||
slashCommandsToCreate = slashCommandsToCreate.map(command =>
|
||||
slashCommandsCollection.prepareCreate(
|
||||
protectedFunction(s => {
|
||||
s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema);
|
||||
Object.assign(s, command);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// Update
|
||||
slashCommandsToUpdate = slashCommandsToUpdate.map(command => {
|
||||
const newCommand = commands.find(s => s.command === command.id);
|
||||
return command.prepareUpdate(
|
||||
protectedFunction(s => {
|
||||
Object.assign(s, newCommand);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Delete
|
||||
slashCommandsToDelete = slashCommandsToDelete.map(command => command.prepareDestroyPermanently());
|
||||
|
||||
const allRecords = [...slashCommandsToCreate, ...slashCommandsToUpdate, ...slashCommandsToDelete];
|
||||
|
||||
try {
|
||||
await db.batch(...allRecords);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
return allRecords.length;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
return resolve();
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import protectedFunction from './helpers/protectedFunction';
|
||||
import { ISlashCommandResult, TSlashCommandModel } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
export default function getSlashCommands() {
|
||||
const db = database.active;
|
||||
return new Promise<void>(async resolve => {
|
||||
try {
|
||||
// RC 0.60.2
|
||||
// @ts-ignore
|
||||
const result = await sdk.get('commands.list');
|
||||
|
||||
if (!result.success) {
|
||||
return resolve();
|
||||
}
|
||||
// @ts-ignore
|
||||
const { commands } = result;
|
||||
if (commands && commands.length) {
|
||||
await db.write(async () => {
|
||||
const slashCommandsCollection = db.get('slash_commands');
|
||||
const allSlashCommandsRecords = await slashCommandsCollection.query().fetch();
|
||||
|
||||
// filter slash commands
|
||||
const filteredSlashCommandsToCreate = commands.filter(
|
||||
(i1: ISlashCommandResult) => !allSlashCommandsRecords.find(i2 => i1.command === i2.id)
|
||||
);
|
||||
const filteredSlashCommandsToUpdate = allSlashCommandsRecords.filter(i1 =>
|
||||
commands.find((i2: ISlashCommandResult) => i1.id === i2.command)
|
||||
);
|
||||
const filteredSlashCommandsToDelete = allSlashCommandsRecords.filter(
|
||||
i1 =>
|
||||
!filteredSlashCommandsToCreate.find((i2: ISlashCommandResult) => i2.command === i1.id) &&
|
||||
!filteredSlashCommandsToUpdate.find(i2 => i2.id === i1.id)
|
||||
);
|
||||
|
||||
// Create
|
||||
const slashCommandsToCreate = filteredSlashCommandsToCreate.map((command: ISlashCommandResult) =>
|
||||
slashCommandsCollection.prepareCreate(
|
||||
protectedFunction((s: TSlashCommandModel) => {
|
||||
s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema);
|
||||
Object.assign(s, command);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// Update
|
||||
const slashCommandsToUpdate = filteredSlashCommandsToUpdate.map(command => {
|
||||
const newCommand = commands.find((s: ISlashCommandResult) => s.command === command.id);
|
||||
return command.prepareUpdate(
|
||||
protectedFunction((s: TSlashCommandModel) => {
|
||||
Object.assign(s, newCommand);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Delete
|
||||
const slashCommandsToDelete = filteredSlashCommandsToDelete.map(command => command.prepareDestroyPermanently());
|
||||
|
||||
const allRecords = [...slashCommandsToCreate, ...slashCommandsToUpdate, ...slashCommandsToDelete];
|
||||
|
||||
try {
|
||||
await db.batch(...allRecords);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
return allRecords.length;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
return resolve();
|
||||
}
|
||||
});
|
||||
}
|
|
@ -6,11 +6,12 @@ import { getThreadById } from '../database/services/Thread';
|
|||
import log from '../../utils/log';
|
||||
import { Encryption } from '../encryption';
|
||||
import getSingleMessage from './getSingleMessage';
|
||||
import { IThread, TThreadModel } from '../../definitions';
|
||||
|
||||
const buildThreadName = thread => thread.msg || thread?.attachments?.[0]?.title;
|
||||
const buildThreadName = (thread: IThread): string | undefined => thread.msg || thread?.attachments?.[0]?.title;
|
||||
|
||||
const getThreadName = async (rid, tmid, messageId) => {
|
||||
let tmsg;
|
||||
const getThreadName = async (rid: string, tmid: string, messageId: string): Promise<string | undefined> => {
|
||||
let tmsg: string | undefined;
|
||||
try {
|
||||
const db = database.active;
|
||||
const threadCollection = db.get('threads');
|
||||
|
@ -18,7 +19,7 @@ const getThreadName = async (rid, tmid, messageId) => {
|
|||
const threadRecord = await getThreadById(tmid);
|
||||
if (threadRecord) {
|
||||
tmsg = buildThreadName(threadRecord);
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await messageRecord?.update(m => {
|
||||
m.tmsg = tmsg;
|
||||
});
|
||||
|
@ -27,11 +28,11 @@ const getThreadName = async (rid, tmid, messageId) => {
|
|||
let thread = await getSingleMessage(tmid);
|
||||
thread = await Encryption.decryptMessage(thread);
|
||||
tmsg = buildThreadName(thread);
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await db.batch(
|
||||
threadCollection?.prepareCreate(t => {
|
||||
threadCollection?.prepareCreate((t: TThreadModel) => {
|
||||
t._raw = sanitizedRaw({ id: thread._id }, threadCollection.schema);
|
||||
t.subscription.id = rid;
|
||||
if (t.subscription) t.subscription.id = rid;
|
||||
Object.assign(t, thread);
|
||||
}),
|
||||
messageRecord?.prepareUpdate(m => {
|
|
@ -1,14 +1,17 @@
|
|||
import { InteractionManager } from 'react-native';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
|
||||
import { IActiveUsers } from '../../reducers/activeUsers';
|
||||
import { compareServerVersion } from '../utils';
|
||||
import { store as reduxStore } from '../auxStore';
|
||||
import { setActiveUsers } from '../../actions/activeUsers';
|
||||
import { setUser } from '../../actions/login';
|
||||
import database from '../database';
|
||||
import { IRocketChat, IUser } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
export function subscribeUsersPresence() {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
export function subscribeUsersPresence(this: IRocketChat) {
|
||||
const serverVersion = reduxStore.getState().server.version as string;
|
||||
|
||||
// if server is lower than 1.1.0
|
||||
if (compareServerVersion(serverVersion, 'lowerThan', '1.1.0')) {
|
||||
|
@ -17,22 +20,22 @@ export function subscribeUsersPresence() {
|
|||
this.activeUsersSubTimeout = false;
|
||||
}
|
||||
this.activeUsersSubTimeout = setTimeout(() => {
|
||||
this.sdk.subscribe('activeUsers');
|
||||
sdk.subscribe('activeUsers');
|
||||
}, 5000);
|
||||
} else if (compareServerVersion(serverVersion, 'lowerThan', '4.1.0')) {
|
||||
this.sdk.subscribe('stream-notify-logged', 'user-status');
|
||||
sdk.subscribe('stream-notify-logged', 'user-status');
|
||||
}
|
||||
|
||||
// RC 0.49.1
|
||||
this.sdk.subscribe('stream-notify-logged', 'updateAvatar');
|
||||
sdk.subscribe('stream-notify-logged', 'updateAvatar');
|
||||
// RC 0.58.0
|
||||
this.sdk.subscribe('stream-notify-logged', 'Users:NameChanged');
|
||||
sdk.subscribe('stream-notify-logged', 'Users:NameChanged');
|
||||
}
|
||||
|
||||
let ids = [];
|
||||
let ids: string[] = [];
|
||||
|
||||
export default async function getUsersPresence() {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
const serverVersion = reduxStore.getState().server.version as string;
|
||||
const { user: loggedUser } = reduxStore.getState().login;
|
||||
|
||||
// if server is greather than or equal 1.1.0
|
||||
|
@ -51,17 +54,17 @@ export default async function getUsersPresence() {
|
|||
|
||||
try {
|
||||
// RC 1.1.0
|
||||
const result = await this.sdk.get('users.presence', params);
|
||||
const result = (await sdk.get('users.presence' as any, params as any)) as any;
|
||||
|
||||
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '4.1.0')) {
|
||||
this.sdk.subscribeRaw('stream-user-presence', ['', { added: ids }]);
|
||||
sdk.subscribeRaw('stream-user-presence', ['', { added: ids }]);
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
const { users } = result;
|
||||
|
||||
const activeUsers = ids.reduce((ret, id) => {
|
||||
const user = users.find(u => u._id === id) ?? { _id: id, status: 'offline' };
|
||||
const activeUsers = ids.reduce((ret: IActiveUsers, id) => {
|
||||
const user = users.find((u: IUser) => u._id === id) ?? { _id: id, status: 'offline' };
|
||||
const { _id, status, statusText } = user;
|
||||
|
||||
if (loggedUser && loggedUser.id === _id) {
|
||||
|
@ -78,17 +81,17 @@ export default async function getUsersPresence() {
|
|||
|
||||
const db = database.active;
|
||||
const userCollection = db.get('users');
|
||||
users.forEach(async user => {
|
||||
users.forEach(async (user: IUser) => {
|
||||
try {
|
||||
const userRecord = await userCollection.find(user._id);
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await userRecord.update(u => {
|
||||
Object.assign(u, user);
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
// User not found
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await userCollection.create(u => {
|
||||
u._raw = sanitizedRaw({ id: user._id }, userCollection.schema);
|
||||
Object.assign(u, user);
|
||||
|
@ -103,11 +106,11 @@ export default async function getUsersPresence() {
|
|||
}
|
||||
}
|
||||
|
||||
let usersTimer = null;
|
||||
export function getUserPresence(uid) {
|
||||
let usersTimer: number | null = null;
|
||||
export function getUserPresence(uid: string) {
|
||||
if (!usersTimer) {
|
||||
usersTimer = setTimeout(() => {
|
||||
getUsersPresence.call(this);
|
||||
getUsersPresence();
|
||||
usersTimer = null;
|
||||
}, 2000);
|
||||
}
|
|
@ -1,15 +1,18 @@
|
|||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import { IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
|
||||
import database from '../../database';
|
||||
|
||||
export default async (subscriptions = [], rooms = []) => {
|
||||
export default async (subscriptions: IServerSubscriptionItem[], rooms: IServerRoomItem[]) => {
|
||||
let sub = subscriptions;
|
||||
let room = rooms;
|
||||
try {
|
||||
const db = database.active;
|
||||
const subCollection = db.get('subscriptions');
|
||||
|
||||
const roomIds = rooms.filter(r => !subscriptions.find(s => s.rid === r._id)).map(r => r._id);
|
||||
let existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch();
|
||||
existingSubs = existingSubs.map(s => ({
|
||||
const existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch();
|
||||
const mappedExistingSubs = existingSubs.map(s => ({
|
||||
_id: s._id,
|
||||
f: s.f,
|
||||
t: s.t,
|
||||
|
@ -55,11 +58,12 @@ export default async (subscriptions = [], rooms = []) => {
|
|||
E2EKey: s.E2EKey,
|
||||
avatarETag: s.avatarETag
|
||||
}));
|
||||
subscriptions = subscriptions.concat(existingSubs);
|
||||
// Assign
|
||||
sub = subscriptions.concat(mappedExistingSubs as unknown as IServerSubscriptionItem);
|
||||
|
||||
const subsIds = subscriptions.filter(s => !rooms.find(r => s.rid === r._id)).map(s => s._id);
|
||||
let existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch();
|
||||
existingRooms = existingRooms.map(r => ({
|
||||
const existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch();
|
||||
const mappedExistingRooms = existingRooms.map(r => ({
|
||||
_updatedAt: r._updatedAt,
|
||||
lastMessage: r.lastMessage,
|
||||
description: r.description,
|
||||
|
@ -84,13 +88,14 @@ export default async (subscriptions = [], rooms = []) => {
|
|||
e2eKeyId: r.e2eKeyId,
|
||||
avatarETag: r.avatarETag
|
||||
}));
|
||||
rooms = rooms.concat(existingRooms);
|
||||
// Assign
|
||||
room = rooms.concat(mappedExistingRooms as unknown as IServerRoomItem);
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return {
|
||||
subscriptions,
|
||||
rooms
|
||||
subscriptions: sub,
|
||||
rooms: room
|
||||
};
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
export default function (message) {
|
||||
export default function (message: { type: string; url: string }) {
|
||||
if (/image/.test(message.type)) {
|
||||
return { image_url: message.url };
|
||||
}
|
|
@ -5,17 +5,18 @@ import { store as reduxStore } from '../../auxStore';
|
|||
import { compareServerVersion } from '../../utils';
|
||||
import findSubscriptionsRooms from './findSubscriptionsRooms';
|
||||
import normalizeMessage from './normalizeMessage';
|
||||
import { ISubscription, IServerRoom, IServerSubscription, IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
|
||||
// TODO: delete and update
|
||||
|
||||
export const merge = (subscription, room) => {
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
subscription = EJSON.fromJSONValue(subscription);
|
||||
room = EJSON.fromJSONValue(room);
|
||||
export const merge = (
|
||||
subscription: ISubscription | IServerSubscriptionItem,
|
||||
room?: ISubscription | IServerRoomItem
|
||||
): ISubscription => {
|
||||
const serverVersion = reduxStore.getState().server.version as string;
|
||||
subscription = EJSON.fromJSONValue(subscription) as ISubscription;
|
||||
|
||||
if (!subscription) {
|
||||
return;
|
||||
}
|
||||
if (room) {
|
||||
room = EJSON.fromJSONValue(room) as ISubscription;
|
||||
if (room._updatedAt) {
|
||||
subscription.lastMessage = normalizeMessage(room.lastMessage);
|
||||
subscription.description = room.description;
|
||||
|
@ -28,15 +29,21 @@ export const merge = (subscription, room) => {
|
|||
subscription.usernames = room.usernames;
|
||||
subscription.uids = room.uids;
|
||||
}
|
||||
|
||||
if (compareServerVersion(serverVersion, 'lowerThan', '3.7.0')) {
|
||||
const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null;
|
||||
const lastMessageTs = subscription?.lastMessage?.ts ? new Date(subscription.lastMessage.ts) : null;
|
||||
// @ts-ignore
|
||||
// If all parameters are null it will return zero, if only one is null it will return its timestamp only.
|
||||
// "It works", but it's not the best solution. It does not accept "Date" as a parameter, but it works.
|
||||
subscription.roomUpdatedAt = Math.max(updatedAt, lastMessageTs);
|
||||
} else {
|
||||
// https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180
|
||||
const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt;
|
||||
// @ts-ignore Same as above scenario
|
||||
subscription.roomUpdatedAt = subscription.lr
|
||||
? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate))
|
||||
? // @ts-ignore Same as above scenario
|
||||
Math.max(new Date(subscription.lr), new Date(lastRoomUpdate))
|
||||
: lastRoomUpdate;
|
||||
}
|
||||
subscription.ro = room.ro;
|
||||
|
@ -76,7 +83,7 @@ export const merge = (subscription, room) => {
|
|||
}
|
||||
|
||||
if (!subscription.name) {
|
||||
subscription.name = subscription.fname;
|
||||
subscription.name = subscription.fname as string;
|
||||
}
|
||||
|
||||
if (!subscription.autoTranslate) {
|
||||
|
@ -88,29 +95,24 @@ export const merge = (subscription, room) => {
|
|||
return subscription;
|
||||
};
|
||||
|
||||
export default async (subscriptions = [], rooms = []) => {
|
||||
if (subscriptions.update) {
|
||||
subscriptions = subscriptions.update;
|
||||
rooms = rooms.update;
|
||||
}
|
||||
export default async (serverSubscriptions: IServerSubscription, serverRooms: IServerRoom): Promise<ISubscription[]> => {
|
||||
const subscriptions = serverSubscriptions.update;
|
||||
const rooms = serverRooms.update;
|
||||
|
||||
// Find missing rooms/subscriptions on local database
|
||||
({ subscriptions, rooms } = await findSubscriptionsRooms(subscriptions, rooms));
|
||||
const findData = await findSubscriptionsRooms(subscriptions, rooms);
|
||||
// Merge each subscription into a room
|
||||
subscriptions = subscriptions.map(s => {
|
||||
const index = rooms.findIndex(({ _id }) => _id === s.rid);
|
||||
const mergedSubscriptions = findData.subscriptions.map(subscription => {
|
||||
const index = rooms.findIndex(({ _id }) => _id === subscription.rid);
|
||||
// Room not found
|
||||
if (index < 0) {
|
||||
return merge(s);
|
||||
return merge(subscription);
|
||||
}
|
||||
const [room] = rooms.splice(index, 1);
|
||||
return merge(s, room);
|
||||
return merge(subscription, room);
|
||||
});
|
||||
// Decrypt all subscriptions missing decryption
|
||||
subscriptions = await Encryption.decryptSubscriptions(subscriptions);
|
||||
const decryptedSubscriptions = (await Encryption.decryptSubscriptions(mergedSubscriptions)) as ISubscription[];
|
||||
|
||||
return {
|
||||
subscriptions,
|
||||
rooms
|
||||
};
|
||||
return decryptedSubscriptions;
|
||||
};
|
|
@ -5,32 +5,41 @@ import log from '../../utils/log';
|
|||
import { getMessageById } from '../database/services/Message';
|
||||
import { generateLoadMoreId } from '../utils';
|
||||
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;
|
||||
|
||||
async function load({ rid: roomId, latest, t }) {
|
||||
let params = { roomId, count: COUNT };
|
||||
async function load({ rid: roomId, latest, t }: { rid: string; latest?: string; t: RoomTypes }) {
|
||||
let params = { roomId, count: COUNT } as { roomId: string; count: number; latest?: string };
|
||||
if (latest) {
|
||||
params = { ...params, latest: new Date(latest).toISOString() };
|
||||
}
|
||||
|
||||
const apiType = this.roomTypeToApiType(t);
|
||||
const apiType = roomTypeToApiType(t);
|
||||
if (!apiType) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// RC 0.48.0
|
||||
const data = await this.sdk.get(`${apiType}.history`, params);
|
||||
// @ts-ignore
|
||||
const data: any = await sdk.get(`${apiType}.history`, params);
|
||||
if (!data || data.status === 'error') {
|
||||
return [];
|
||||
}
|
||||
return data.messages;
|
||||
}
|
||||
|
||||
export default function loadMessagesForRoom(args) {
|
||||
export default function loadMessagesForRoom(args: {
|
||||
rid: string;
|
||||
t: RoomTypes;
|
||||
latest: string;
|
||||
loaderItem: TMessageModel;
|
||||
}): Promise<IMessage[] | []> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const data = await load.call(this, args);
|
||||
const data = await load(args);
|
||||
if (data?.length) {
|
||||
const lastMessage = data[data.length - 1];
|
||||
const lastMessageRecord = await getMessageById(lastMessage._id);
|
||||
|
@ -46,9 +55,8 @@ export default function loadMessagesForRoom(args) {
|
|||
}
|
||||
await updateMessages({ rid: args.rid, update: data, loaderItem: args.loaderItem });
|
||||
return resolve(data);
|
||||
} else {
|
||||
return resolve([]);
|
||||
}
|
||||
return resolve([]);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
reject(e);
|
|
@ -1,44 +0,0 @@
|
|||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import updateMessages from './updateMessages';
|
||||
|
||||
const getLastUpdate = async rid => {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
const sub = await subsCollection.find(rid);
|
||||
return sub.lastOpen.toISOString();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
async function load({ rid: roomId, lastOpen }) {
|
||||
let lastUpdate;
|
||||
if (lastOpen) {
|
||||
lastUpdate = new Date(lastOpen).toISOString();
|
||||
} else {
|
||||
lastUpdate = await getLastUpdate(roomId);
|
||||
}
|
||||
// RC 0.60.0
|
||||
const { result } = await this.sdk.get('chat.syncMessages', { roomId, lastUpdate });
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function loadMissedMessages(args) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const data = await load.call(this, { rid: args.rid, lastOpen: args.lastOpen });
|
||||
|
||||
if (data) {
|
||||
const { updated, deleted } = data;
|
||||
await updateMessages({ rid: args.rid, update: updated, remove: deleted });
|
||||
}
|
||||
resolve();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import { ILastMessage } from '../../definitions';
|
||||
import log from '../../utils/log';
|
||||
import database from '../database';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
import updateMessages from './updateMessages';
|
||||
|
||||
const getLastUpdate = async (rid: string) => {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
const sub = await subsCollection.find(rid);
|
||||
return sub.lastOpen?.toISOString();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
async function load({ rid: roomId, lastOpen }: { rid: string; lastOpen: string }) {
|
||||
let lastUpdate;
|
||||
if (lastOpen) {
|
||||
lastUpdate = new Date(lastOpen).toISOString();
|
||||
} else {
|
||||
lastUpdate = await getLastUpdate(roomId);
|
||||
}
|
||||
// RC 0.60.0
|
||||
// @ts-ignore // this method dont have type
|
||||
const { result } = await sdk.get('chat.syncMessages', { roomId, lastUpdate });
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function loadMissedMessages(args: { rid: string; lastOpen: string }): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const data = await load({ rid: args.rid, lastOpen: args.lastOpen });
|
||||
if (data) {
|
||||
const { updated, deleted }: { updated: ILastMessage[]; deleted: ILastMessage[] } = data;
|
||||
// @ts-ignore // TODO: remove loaderItem obligatoriness
|
||||
await updateMessages({ rid: args.rid, update: updated, remove: deleted });
|
||||
}
|
||||
resolve();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -7,13 +7,22 @@ import { getMessageById } from '../database/services/Message';
|
|||
import { MESSAGE_TYPE_LOAD_NEXT_CHUNK } from '../../constants/messageTypeLoad';
|
||||
import { generateLoadMoreId } from '../utils';
|
||||
import updateMessages from './updateMessages';
|
||||
import { IMessage, TMessageModel } from '../../definitions';
|
||||
import RocketChat from '../rocketchat';
|
||||
|
||||
const COUNT = 50;
|
||||
|
||||
export default function loadNextMessages(args) {
|
||||
interface ILoadNextMessages {
|
||||
rid: string;
|
||||
ts: string;
|
||||
tmid: string;
|
||||
loaderItem: TMessageModel;
|
||||
}
|
||||
|
||||
export default function loadNextMessages(args: ILoadNextMessages): Promise<IMessage | []> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const data = await this.methodCallWrapper('loadNextMessages', args.rid, args.ts, COUNT);
|
||||
const data = await RocketChat.methodCallWrapper('loadNextMessages', args.rid, args.ts, COUNT);
|
||||
let messages = EJSON.fromJSONValue(data?.messages);
|
||||
messages = orderBy(messages, 'ts');
|
||||
if (messages?.length) {
|
||||
|
@ -31,9 +40,8 @@ export default function loadNextMessages(args) {
|
|||
}
|
||||
await updateMessages({ rid: args.rid, update: messages, loaderItem: args.loaderItem });
|
||||
return resolve(messages);
|
||||
} else {
|
||||
return resolve([]);
|
||||
}
|
||||
return resolve([]);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
reject(e);
|
|
@ -1,18 +1,22 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
import { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import FileUpload from '../../utils/fileUpload';
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
import { IUpload, IUser, TUploadModel } from '../../definitions';
|
||||
import { IFileUpload } from '../../utils/fileUpload/interfaces';
|
||||
|
||||
const uploadQueue = {};
|
||||
const uploadQueue: { [index: string]: StatefulPromise<FetchBlobResponse> } = {};
|
||||
|
||||
export function isUploadActive(path) {
|
||||
export function isUploadActive(path: string): boolean {
|
||||
return !!uploadQueue[path];
|
||||
}
|
||||
|
||||
export async function cancelUpload(item) {
|
||||
if (uploadQueue[item.path]) {
|
||||
export async function cancelUpload(item: TUploadModel): Promise<void> {
|
||||
if (!isEmpty(uploadQueue[item.path])) {
|
||||
try {
|
||||
await uploadQueue[item.path].cancel();
|
||||
} catch {
|
||||
|
@ -20,7 +24,7 @@ export async function cancelUpload(item) {
|
|||
}
|
||||
try {
|
||||
const db = database.active;
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await item.destroyPermanently();
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -30,7 +34,13 @@ export async function cancelUpload(item) {
|
|||
}
|
||||
}
|
||||
|
||||
export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
||||
export function sendFileMessage(
|
||||
rid: string,
|
||||
fileInfo: IUpload,
|
||||
tmid: string,
|
||||
server: string,
|
||||
user: IUser
|
||||
): Promise<FetchBlobResponse | void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const { id, token } = user;
|
||||
|
@ -41,16 +51,18 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
|
||||
const db = database.active;
|
||||
const uploadsCollection = db.get('uploads');
|
||||
let uploadRecord;
|
||||
let uploadRecord: TUploadModel;
|
||||
try {
|
||||
uploadRecord = await uploadsCollection.find(fileInfo.path);
|
||||
} catch (error) {
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
uploadRecord = await uploadsCollection.create(u => {
|
||||
u._raw = sanitizedRaw({ id: fileInfo.path }, uploadsCollection.schema);
|
||||
Object.assign(u, fileInfo);
|
||||
u.subscription.id = rid;
|
||||
if (u.subscription) {
|
||||
u.subscription.id = rid;
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -58,7 +70,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
}
|
||||
}
|
||||
|
||||
const formData = [];
|
||||
const formData: IFileUpload[] = [];
|
||||
formData.push({
|
||||
name: 'file',
|
||||
type: fileInfo.type,
|
||||
|
@ -89,9 +101,9 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
|
||||
uploadQueue[fileInfo.path] = FileUpload.fetch('POST', uploadUrl, headers, formData);
|
||||
|
||||
uploadQueue[fileInfo.path].uploadProgress(async (loaded, total) => {
|
||||
uploadQueue[fileInfo.path].uploadProgress(async (loaded: number, total: number) => {
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await uploadRecord.update(u => {
|
||||
u.progress = Math.floor((loaded / total) * 100);
|
||||
});
|
||||
|
@ -105,7 +117,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
if (response.respInfo.status >= 200 && response.respInfo.status < 400) {
|
||||
// If response is all good...
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await uploadRecord.destroyPermanently();
|
||||
});
|
||||
resolve(response);
|
||||
|
@ -114,7 +126,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await uploadRecord.update(u => {
|
||||
u.error = true;
|
||||
});
|
||||
|
@ -132,7 +144,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
|
||||
uploadQueue[fileInfo.path].catch(async error => {
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await uploadRecord.update(u => {
|
||||
u.error = true;
|
||||
});
|
|
@ -1,4 +1,5 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Model } from '@nozbe/watermelondb';
|
||||
|
||||
import messagesStatus from '../../constants/messagesStatus';
|
||||
import database from '../database';
|
||||
|
@ -6,12 +7,14 @@ import log from '../../utils/log';
|
|||
import random from '../../utils/random';
|
||||
import { Encryption } from '../encryption';
|
||||
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../encryption/constants';
|
||||
import { IMessage, IUser, TMessageModel } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
const changeMessageStatus = async (id, tmid, status, message) => {
|
||||
const changeMessageStatus = async (id: string, status: number, tmid?: string, message?: IMessage) => {
|
||||
const db = database.active;
|
||||
const msgCollection = db.get('messages');
|
||||
const threadMessagesCollection = db.get('thread_messages');
|
||||
const successBatch = [];
|
||||
const successBatch: Model[] = [];
|
||||
const messageRecord = await msgCollection.find(id);
|
||||
successBatch.push(
|
||||
messageRecord.prepareUpdate(m => {
|
||||
|
@ -37,7 +40,7 @@ const changeMessageStatus = async (id, tmid, status, message) => {
|
|||
}
|
||||
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await db.batch(...successBatch);
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -45,48 +48,44 @@ const changeMessageStatus = async (id, tmid, status, message) => {
|
|||
}
|
||||
};
|
||||
|
||||
export async function sendMessageCall(message) {
|
||||
export async function sendMessageCall(message: any) {
|
||||
const { _id, tmid } = message;
|
||||
try {
|
||||
const sdk = this.shareSDK || this.sdk;
|
||||
// RC 0.60.0
|
||||
// @ts-ignore
|
||||
const result = await sdk.post('chat.sendMessage', { message });
|
||||
if (result.success) {
|
||||
return changeMessageStatus(_id, tmid, messagesStatus.SENT, result.message);
|
||||
// @ts-ignore
|
||||
return changeMessageStatus(_id, messagesStatus.SENT, tmid, result.message);
|
||||
}
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
return changeMessageStatus(_id, tmid, messagesStatus.ERROR);
|
||||
return changeMessageStatus(_id, messagesStatus.ERROR, tmid);
|
||||
}
|
||||
|
||||
export async function resendMessage(message, tmid) {
|
||||
export async function resendMessage(message: TMessageModel, tmid?: string) {
|
||||
const db = database.active;
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await message.update(m => {
|
||||
m.status = messagesStatus.TEMP;
|
||||
});
|
||||
});
|
||||
let m = {
|
||||
const m = await Encryption.encryptMessage({
|
||||
_id: message.id,
|
||||
rid: message.subscription.id,
|
||||
msg: message.msg
|
||||
};
|
||||
if (tmid) {
|
||||
m = {
|
||||
...m,
|
||||
tmid
|
||||
};
|
||||
}
|
||||
m = await Encryption.encryptMessage(m);
|
||||
await sendMessageCall.call(this, m);
|
||||
rid: message.subscription ? message.subscription.id : '',
|
||||
msg: message.msg,
|
||||
...(tmid && { tmid })
|
||||
} as IMessage);
|
||||
|
||||
await sendMessageCall(m);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
export default async function (rid, msg, tmid, user, tshow) {
|
||||
export default async function (rid: string, msg: string, tmid: string, user: IUser, tshow?: boolean) {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
|
@ -94,19 +93,18 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
const threadCollection = db.get('threads');
|
||||
const threadMessagesCollection = db.get('thread_messages');
|
||||
const messageId = random(17);
|
||||
const batch = [];
|
||||
const batch: Model[] = [];
|
||||
|
||||
let message = {
|
||||
const message = await Encryption.encryptMessage({
|
||||
_id: messageId,
|
||||
rid,
|
||||
msg,
|
||||
tmid,
|
||||
tshow
|
||||
};
|
||||
message = await Encryption.encryptMessage(message);
|
||||
} as IMessage);
|
||||
|
||||
const messageDate = new Date();
|
||||
let tMessageRecord;
|
||||
let tMessageRecord: TMessageModel;
|
||||
|
||||
// If it's replying to a thread
|
||||
if (tmid) {
|
||||
|
@ -116,7 +114,9 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
batch.push(
|
||||
tMessageRecord.prepareUpdate(m => {
|
||||
m.tlm = messageDate;
|
||||
m.tcount += 1;
|
||||
if (m.tcount) {
|
||||
m.tcount += 1;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -128,7 +128,9 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
batch.push(
|
||||
threadCollection.prepareCreate(tm => {
|
||||
tm._raw = sanitizedRaw({ id: tmid }, threadCollection.schema);
|
||||
tm.subscription.id = rid;
|
||||
if (tm.subscription) {
|
||||
tm.subscription.id = rid;
|
||||
}
|
||||
tm.tmid = tmid;
|
||||
tm.msg = tMessageRecord.msg;
|
||||
tm.ts = tMessageRecord.ts;
|
||||
|
@ -147,7 +149,9 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
batch.push(
|
||||
threadMessagesCollection.prepareCreate(tm => {
|
||||
tm._raw = sanitizedRaw({ id: messageId }, threadMessagesCollection.schema);
|
||||
tm.subscription.id = rid;
|
||||
if (tm.subscription) {
|
||||
tm.subscription.id = rid;
|
||||
}
|
||||
tm.rid = tmid;
|
||||
tm.msg = msg;
|
||||
tm.ts = messageDate;
|
||||
|
@ -173,7 +177,9 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
batch.push(
|
||||
msgCollection.prepareCreate(m => {
|
||||
m._raw = sanitizedRaw({ id: messageId }, msgCollection.schema);
|
||||
m.subscription.id = rid;
|
||||
if (m.subscription) {
|
||||
m.subscription.id = rid;
|
||||
}
|
||||
m.msg = msg;
|
||||
m.ts = messageDate;
|
||||
m._updatedAt = messageDate;
|
||||
|
@ -210,7 +216,7 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
}
|
||||
|
||||
try {
|
||||
await db.action(async () => {
|
||||
await db.write(async () => {
|
||||
await db.batch(...batch);
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -218,7 +224,7 @@ export default async function (rid, msg, tmid, user, tshow) {
|
|||
return;
|
||||
}
|
||||
|
||||
await sendMessageCall.call(this, message);
|
||||
await sendMessageCall(message);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
|
@ -127,8 +127,11 @@ const createOrUpdateSubscription = async (subscription, room) => {
|
|||
}
|
||||
}
|
||||
|
||||
let tmp = merge(subscription, room);
|
||||
tmp = await Encryption.decryptSubscription(tmp);
|
||||
let tmp;
|
||||
if (subscription) {
|
||||
tmp = merge(subscription, room);
|
||||
tmp = await Encryption.decryptSubscription(tmp);
|
||||
}
|
||||
let sub;
|
||||
try {
|
||||
sub = await subCollection.find(tmp.rid);
|
||||
|
|
|
@ -13,7 +13,7 @@ import { getSubscriptionByRoomId } from '../database/services/Subscription';
|
|||
interface IUpdateMessages {
|
||||
rid: string;
|
||||
update: IMessage[];
|
||||
remove: IMessage[];
|
||||
remove?: IMessage[];
|
||||
loaderItem?: TMessageModel;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ export default async function updateMessages({
|
|||
threadCollection.prepareCreate(
|
||||
protectedFunction((t: TThreadModel) => {
|
||||
t._raw = sanitizedRaw({ id: thread._id }, threadCollection.schema);
|
||||
t.subscription.id = sub.id;
|
||||
if (t.subscription) t.subscription.id = sub.id;
|
||||
Object.assign(t, thread);
|
||||
})
|
||||
)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
export const getServerTimeSync = async (server: string) => {
|
||||
try {
|
||||
const response = await Promise.race([
|
||||
RNFetchBlob.fetch('GET', `${server}/_timesync`),
|
||||
new Promise<undefined>(res => setTimeout(res, 2000))
|
||||
]);
|
||||
if (response?.data) {
|
||||
return parseInt(response.data);
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
|
@ -34,10 +34,8 @@ export const createChannel = ({
|
|||
return sdk.post(type ? 'groups.create' : 'channels.create', params);
|
||||
};
|
||||
|
||||
export const e2eSetUserPublicAndPrivateKeys = (public_key: string, private_key: string): any =>
|
||||
export const e2eSetUserPublicAndPrivateKeys = (public_key: string, private_key: string) =>
|
||||
// RC 2.2.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post('e2e.setUserPublicAndPrivateKeys', { public_key, private_key });
|
||||
|
||||
export const e2eRequestSubscriptionKeys = (): any =>
|
||||
|
@ -221,12 +219,6 @@ export const teamListRoomsOfUser = ({ teamId, userId }: { teamId: string; userId
|
|||
// @ts-ignore
|
||||
sdk.get('teams.listRoomsOfUser', { teamId, userId });
|
||||
|
||||
export const getTeamInfo = ({ teamId }: { teamId: string }): any =>
|
||||
// RC 3.13.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.get('teams.info', { teamId });
|
||||
|
||||
export const convertChannelToTeam = ({ rid, name, type }: { rid: string; name: string; type: 'c' | 'p' }): any => {
|
||||
const params = {
|
||||
...(type === 'c'
|
||||
|
|
|
@ -18,7 +18,7 @@ const methods = {
|
|||
};
|
||||
|
||||
export const compareServerVersion = (
|
||||
currentServerVersion: string,
|
||||
currentServerVersion: string | null,
|
||||
method: keyof typeof methods,
|
||||
versionToCompare: string
|
||||
): boolean =>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { clearActiveUsers, setActiveUsers } from '../actions/activeUsers';
|
||||
import { UserStatus } from '../definitions/UserStatus';
|
||||
import { IActiveUsers, initialState } from './activeUsers';
|
||||
import { mockedStore } from './mockedStore';
|
||||
|
||||
|
@ -8,7 +9,7 @@ describe('test reducer', () => {
|
|||
expect(state).toEqual(initialState);
|
||||
});
|
||||
it('should return modified store after action', () => {
|
||||
const activeUsers: IActiveUsers = { any: { status: 'online', statusText: 'any' } };
|
||||
const activeUsers: IActiveUsers = { any: { status: UserStatus.ONLINE, statusText: 'any' } };
|
||||
mockedStore.dispatch(setActiveUsers(activeUsers));
|
||||
const state = mockedStore.getState().activeUsers;
|
||||
expect(state).toEqual({ ...activeUsers });
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { TApplicationActions } from '../definitions';
|
||||
import { ACTIVE_USERS } from '../actions/actionsTypes';
|
||||
import { TApplicationActions } from '../definitions';
|
||||
import { UserStatus } from '../definitions/UserStatus';
|
||||
|
||||
type TUserStatus = 'online' | 'offline' | 'away' | 'busy';
|
||||
export interface IActiveUser {
|
||||
status: TUserStatus;
|
||||
status: UserStatus;
|
||||
statusText: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { TActionEnterpriseModules } from '../actions/enterpriseModules';
|
||||
import { ENTERPRISE_MODULES } from '../actions/actionsTypes';
|
||||
|
||||
export type IEnterpriseModules = 'omnichannel-mobile-enterprise' | 'livechat-enterprise';
|
||||
export type IEnterpriseModules = string;
|
||||
|
||||
export const initialState: IEnterpriseModules[] = [];
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
import {
|
||||
loginFailure,
|
||||
loginRequest,
|
||||
loginSuccess,
|
||||
logout,
|
||||
setLocalAuthenticated,
|
||||
setLoginServices,
|
||||
setUser
|
||||
} from '../actions/login';
|
||||
import { UserStatus } from '../definitions/UserStatus';
|
||||
import { initialState } from './login';
|
||||
import { mockedStore } from './mockedStore';
|
||||
|
||||
describe('test selectedUsers reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().login;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return modified store after loginRequest', () => {
|
||||
mockedStore.dispatch(loginRequest({ user: 'carlitos@email.com', password: '123456' }));
|
||||
const state = mockedStore.getState().login;
|
||||
expect(state).toEqual({ ...initialState, isFetching: true, isAuthenticated: false, failure: false, error: {} });
|
||||
});
|
||||
|
||||
it('should return modified store after loginFailure', () => {
|
||||
mockedStore.dispatch(loginFailure({ error: 'error' }));
|
||||
const state = mockedStore.getState().login.error.error;
|
||||
expect(state).toEqual('error');
|
||||
});
|
||||
|
||||
it('should return modified store after loginSuccess', () => {
|
||||
const user = {
|
||||
id: 'ajhsiahsa',
|
||||
token: 'asdasdasdas',
|
||||
username: 'carlitos',
|
||||
name: 'Carlitos',
|
||||
customFields: {
|
||||
phonenumber: ''
|
||||
},
|
||||
emails: [
|
||||
{
|
||||
address: 'carlitos@email.com',
|
||||
verified: true
|
||||
}
|
||||
],
|
||||
roles: ['user'],
|
||||
isFromWebView: false,
|
||||
showMessageInMainThread: false,
|
||||
enableMessageParserEarlyAdoption: false,
|
||||
status: UserStatus.ONLINE,
|
||||
statusText: 'online'
|
||||
};
|
||||
mockedStore.dispatch(loginSuccess(user));
|
||||
const state = mockedStore.getState().login.user;
|
||||
expect(state).toEqual(user);
|
||||
});
|
||||
|
||||
it('should return modified store after setUser', () => {
|
||||
const user = {
|
||||
id: 'ajhsiahsa',
|
||||
token: 'asdasdasdas',
|
||||
username: 'carlito',
|
||||
name: 'Carlitos',
|
||||
customFields: {
|
||||
phonenumber: ''
|
||||
},
|
||||
emails: [
|
||||
{
|
||||
address: 'carlitos@email.com',
|
||||
verified: true
|
||||
}
|
||||
],
|
||||
roles: ['user'],
|
||||
isFromWebView: false,
|
||||
showMessageInMainThread: false,
|
||||
enableMessageParserEarlyAdoption: false
|
||||
};
|
||||
mockedStore.dispatch(setUser(user));
|
||||
const state = mockedStore.getState().login.user.username;
|
||||
expect(state).toEqual(user.username);
|
||||
});
|
||||
|
||||
// TODO PREFERENCE REDUCER WITH EMPTY PREFERENCE - NON USED?
|
||||
// it('should return modified store after setPreference', () => {
|
||||
// mockedStore.dispatch(setPreference({ showAvatar: true }));
|
||||
// const state = mockedStore.getState().login;
|
||||
// console.log(state);
|
||||
// expect(state).toEqual('error');
|
||||
// });
|
||||
|
||||
it('should return modified store after setLocalAuthenticated', () => {
|
||||
mockedStore.dispatch(setLocalAuthenticated(true));
|
||||
const state = mockedStore.getState().login.isLocalAuthenticated;
|
||||
expect(state).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return modified store after setLoginServices', () => {
|
||||
mockedStore.dispatch(setLoginServices({ facebook: { clientId: 'xxx' } }));
|
||||
const state = mockedStore.getState().login.services.facebook.clientId;
|
||||
expect(state).toEqual('xxx');
|
||||
});
|
||||
|
||||
it('should return modified store after logout', () => {
|
||||
mockedStore.dispatch(logout());
|
||||
const state = mockedStore.getState().login;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
});
|
|
@ -1,15 +1,47 @@
|
|||
import { UserStatus } from '../definitions/UserStatus';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { TActionsLogin } from '../actions/login';
|
||||
import { IUser } from '../definitions';
|
||||
|
||||
const initialState = {
|
||||
export interface IUserLogin {
|
||||
id: string;
|
||||
token: string;
|
||||
username: string;
|
||||
name: string;
|
||||
language?: string;
|
||||
status: UserStatus;
|
||||
statusText: string;
|
||||
roles: string[];
|
||||
avatarETag?: string;
|
||||
isFromWebView: boolean;
|
||||
showMessageInMainThread: boolean;
|
||||
enableMessageParserEarlyAdoption: boolean;
|
||||
emails: Record<string, any>[];
|
||||
customFields: Record<string, string>;
|
||||
settings?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface ILogin {
|
||||
user: Partial<IUser>;
|
||||
isLocalAuthenticated: boolean;
|
||||
isAuthenticated: boolean;
|
||||
isFetching: boolean;
|
||||
error: Record<string, any>;
|
||||
services: Record<string, any>;
|
||||
failure: boolean;
|
||||
}
|
||||
|
||||
export const initialState: ILogin = {
|
||||
isLocalAuthenticated: true,
|
||||
isAuthenticated: false,
|
||||
isFetching: false,
|
||||
user: {},
|
||||
error: {},
|
||||
services: {}
|
||||
services: {},
|
||||
failure: false
|
||||
};
|
||||
|
||||
export default function login(state = initialState, action) {
|
||||
export default function login(state = initialState, action: TActionsLogin): ILogin {
|
||||
switch (action.type) {
|
||||
case types.APP.INIT:
|
||||
return initialState;
|
||||
|
@ -60,13 +92,14 @@ export default function login(state = initialState, action) {
|
|||
...state,
|
||||
user: {
|
||||
...state.user,
|
||||
settings: {
|
||||
...state.user.settings,
|
||||
preferences: {
|
||||
...state.user.settings.preferences,
|
||||
...action.preference
|
||||
}
|
||||
}
|
||||
settings: state.user?.settings
|
||||
? {
|
||||
...state.user?.settings,
|
||||
preferences: state.user?.settings?.preferences
|
||||
? { ...state.user.settings.preferences, ...action.preference }
|
||||
: { ...action.preference }
|
||||
}
|
||||
: { profile: {}, preferences: {} }
|
||||
}
|
||||
};
|
||||
case types.LOGIN.SET_LOCAL_AUTHENTICATED:
|
|
@ -0,0 +1,58 @@
|
|||
import { closeRoom, deleteRoom, forwardRoom, leaveRoom, removedRoom, subscribeRoom, unsubscribeRoom } from '../actions/room';
|
||||
import { ERoomType } from '../definitions/ERoomType';
|
||||
import { mockedStore } from './mockedStore';
|
||||
import { initialState } from './room';
|
||||
|
||||
describe('test room reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().room;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return modified store after subscribeRoom', () => {
|
||||
mockedStore.dispatch(subscribeRoom('GENERAL'));
|
||||
const state = mockedStore.getState().room;
|
||||
expect(state.rooms).toEqual(['GENERAL']);
|
||||
});
|
||||
|
||||
it('should return empty store after remove unsubscribeRoom', () => {
|
||||
mockedStore.dispatch(unsubscribeRoom('GENERAL'));
|
||||
const state = mockedStore.getState().room;
|
||||
expect(state.rooms).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return initial state after leaveRoom', () => {
|
||||
mockedStore.dispatch(leaveRoom(ERoomType.c, { rid: ERoomType.c }));
|
||||
const { rid, isDeleting } = mockedStore.getState().room;
|
||||
expect(rid).toEqual(ERoomType.c);
|
||||
expect(isDeleting).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return initial state after deleteRoom', () => {
|
||||
mockedStore.dispatch(deleteRoom(ERoomType.l, { rid: ERoomType.l }));
|
||||
const { rid, isDeleting } = mockedStore.getState().room;
|
||||
expect(rid).toEqual(ERoomType.l);
|
||||
expect(isDeleting).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return initial state after closeRoom', () => {
|
||||
mockedStore.dispatch(closeRoom('CLOSING'));
|
||||
const { rid, isDeleting } = mockedStore.getState().room;
|
||||
expect(rid).toEqual('CLOSING');
|
||||
expect(isDeleting).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return initial state after forwardRoom', () => {
|
||||
const transferData = { roomId: 'FORWARDING' };
|
||||
mockedStore.dispatch(forwardRoom('FORWARDING', transferData));
|
||||
const { rid, isDeleting } = mockedStore.getState().room;
|
||||
expect(rid).toEqual('FORWARDING');
|
||||
expect(isDeleting).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return loading after call removedRoom', () => {
|
||||
mockedStore.dispatch(removedRoom());
|
||||
const { isDeleting } = mockedStore.getState().room;
|
||||
expect(isDeleting).toEqual(false);
|
||||
});
|
||||
});
|
|
@ -1,12 +1,21 @@
|
|||
import { TActionsRoom } from '../actions/room';
|
||||
import { ROOM } from '../actions/actionsTypes';
|
||||
|
||||
const initialState = {
|
||||
rid: null,
|
||||
export type IRoomRecord = string[];
|
||||
|
||||
export interface IRoom {
|
||||
rid: string;
|
||||
isDeleting: boolean;
|
||||
rooms: IRoomRecord;
|
||||
}
|
||||
|
||||
export const initialState: IRoom = {
|
||||
rid: '',
|
||||
isDeleting: false,
|
||||
rooms: []
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
export default function (state = initialState, action: TActionsRoom): IRoom {
|
||||
switch (action.type) {
|
||||
case ROOM.SUBSCRIBE:
|
||||
return {
|
|
@ -57,8 +57,7 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
|
|||
}
|
||||
|
||||
const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt);
|
||||
const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||
|
||||
const subscriptions = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||
const db = database.active;
|
||||
const subCollection = db.get('subscriptions');
|
||||
const messagesCollection = db.get('messages');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createSelector } from 'reselect';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import { IApplicationState } from '../definitions';
|
||||
import { IApplicationState, IUser } from '../definitions';
|
||||
|
||||
interface IServices {
|
||||
facebook: { clientId: string };
|
||||
|
@ -13,7 +13,7 @@ interface IServices {
|
|||
wordpress: { clientId: string; serverURL: string };
|
||||
}
|
||||
|
||||
const getUser = (state: IApplicationState) => {
|
||||
const getUser = (state: IApplicationState): Partial<IUser> => {
|
||||
if (!isEmpty(state.share?.user)) {
|
||||
return state.share.user;
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ const getLoginServices = (state: IApplicationState) => (state.login.services as
|
|||
const getShowFormLoginSetting = (state: IApplicationState) => (state.settings.Accounts_ShowFormLogin as boolean) || false;
|
||||
const getIframeEnabledSetting = (state: IApplicationState) => (state.settings.Accounts_iframe_enabled as boolean) || false;
|
||||
|
||||
export const getUserSelector = createSelector([getUser], user => user);
|
||||
// TODO: we need to change 42 files to fix a correct type, i believe is better to do this later
|
||||
export const getUserSelector = createSelector([getUser], user => user) as any;
|
||||
|
||||
export const getShowLoginButton = createSelector(
|
||||
[getLoginServices, getShowFormLoginSetting, getIframeEnabledSetting],
|
||||
|
|
|
@ -43,6 +43,7 @@ class FileUpload {
|
|||
upload.formData.append(item.name, {
|
||||
// @ts-ignore
|
||||
uri: item.uri,
|
||||
// @ts-ignore
|
||||
type: item.type,
|
||||
name: item.filename
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export interface IFileUpload {
|
||||
name: string;
|
||||
uri?: string;
|
||||
type: string;
|
||||
filename: string;
|
||||
data: any;
|
||||
type?: string;
|
||||
filename?: string;
|
||||
data?: any;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import * as LocalAuthentication from 'expo-local-authentication';
|
||||
import moment from 'moment';
|
||||
import RNBootSplash from 'react-native-bootsplash';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { sha256 } from 'js-sha256';
|
||||
import moment from 'moment';
|
||||
|
||||
import UserPreferences from '../lib/userPreferences';
|
||||
import { store } from '../lib/auxStore';
|
||||
import database from '../lib/database';
|
||||
import { getServerTimeSync } from '../lib/rocketchat/services/getServerTimeSync';
|
||||
import {
|
||||
ATTEMPTS_KEY,
|
||||
BIOMETRY_ENABLED_KEY,
|
||||
|
@ -21,16 +22,25 @@ import { TServerModel } from '../definitions/IServer';
|
|||
import EventEmitter from './events';
|
||||
import { isIOS } from './deviceInfo';
|
||||
|
||||
export const saveLastLocalAuthenticationSession = async (server: string, serverRecord?: TServerModel): Promise<void> => {
|
||||
export const saveLastLocalAuthenticationSession = async (
|
||||
server: string,
|
||||
serverRecord?: TServerModel,
|
||||
timesync?: number | null
|
||||
): Promise<void> => {
|
||||
if (!timesync) {
|
||||
timesync = new Date().getTime();
|
||||
}
|
||||
|
||||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
await serversDB.write(async () => {
|
||||
try {
|
||||
if (!serverRecord) {
|
||||
serverRecord = (await serversCollection.find(server)) as TServerModel;
|
||||
serverRecord = await serversCollection.find(server);
|
||||
}
|
||||
const time = timesync || 0;
|
||||
await serverRecord.update(record => {
|
||||
record.lastLocalAuthenticatedSession = new Date();
|
||||
record.lastLocalAuthenticatedSession = new Date(time);
|
||||
});
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
|
@ -103,6 +113,9 @@ export const localAuthenticate = async (server: string): Promise<void> => {
|
|||
|
||||
// if screen lock is enabled
|
||||
if (serverRecord?.autoLock) {
|
||||
// Get time from server
|
||||
const timesync = await getServerTimeSync(server);
|
||||
|
||||
// Make sure splash screen has been hidden
|
||||
try {
|
||||
await RNBootSplash.hide();
|
||||
|
@ -116,10 +129,10 @@ export const localAuthenticate = async (server: string): Promise<void> => {
|
|||
// `checkHasPasscode` results newPasscode = true if a passcode has been set
|
||||
if (!result?.newPasscode) {
|
||||
// diff to last authenticated session
|
||||
const diffToLastSession = moment().diff(serverRecord?.lastLocalAuthenticatedSession, 'seconds');
|
||||
const diffToLastSession = moment(timesync).diff(serverRecord?.lastLocalAuthenticatedSession, 'seconds');
|
||||
|
||||
// if last authenticated session is older than configured auto lock time, authentication is required
|
||||
if (diffToLastSession >= serverRecord.autoLockTime!) {
|
||||
// if it was not possible to get `timesync` from server or the last authenticated session is older than the configured auto lock time, authentication is required
|
||||
if (!timesync || (serverRecord?.autoLockTime && diffToLastSession >= serverRecord.autoLockTime)) {
|
||||
// set isLocalAuthenticated to false
|
||||
store.dispatch(setLocalAuthenticated(false));
|
||||
|
||||
|
@ -141,7 +154,7 @@ export const localAuthenticate = async (server: string): Promise<void> => {
|
|||
}
|
||||
|
||||
await resetAttempts();
|
||||
await saveLastLocalAuthenticationSession(server, serverRecord);
|
||||
await saveLastLocalAuthenticationSession(server, serverRecord, timesync);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -58,5 +58,33 @@ export const MessageTypeValues = [
|
|||
{
|
||||
value: 'room_unarchived',
|
||||
text: 'Message_HideType_room_unarchived'
|
||||
},
|
||||
{
|
||||
value: 'removed-user-from-team',
|
||||
text: 'Message_HideType_removed_user_from_team'
|
||||
},
|
||||
{
|
||||
value: 'added-user-to-team',
|
||||
text: 'Message_HideType_added_user_to_team'
|
||||
},
|
||||
{
|
||||
value: 'user-added-room-to-team',
|
||||
text: 'Message_HideType_user_added_room_to_team'
|
||||
},
|
||||
{
|
||||
value: 'user-converted-to-channel',
|
||||
text: 'Message_HideType_user_converted_to_channel'
|
||||
},
|
||||
{
|
||||
value: 'user-converted-to-team',
|
||||
text: 'Message_HideType_user_converted_to_team'
|
||||
},
|
||||
{
|
||||
value: 'user-deleted-room-from-team',
|
||||
text: 'Message_HideType_user_deleted_room_from_team'
|
||||
},
|
||||
{
|
||||
value: 'user-removed-room-from-team',
|
||||
text: 'Message_HideType_user_removed_room_from_team'
|
||||
}
|
||||
];
|
||||
|
|
|
@ -22,7 +22,7 @@ export const capitalize = (s: string): string => {
|
|||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
};
|
||||
|
||||
export const formatDate = (date: Date): string =>
|
||||
export const formatDate = (date: string | Date): string =>
|
||||
moment(date).calendar(null, {
|
||||
lastDay: `[${I18n.t('Yesterday')}]`,
|
||||
sameDay: 'LT',
|
||||
|
@ -30,7 +30,7 @@ export const formatDate = (date: Date): string =>
|
|||
sameElse: 'L'
|
||||
});
|
||||
|
||||
export const formatDateThreads = (date: Date): string =>
|
||||
export const formatDateThreads = (date: string | Date): string =>
|
||||
moment(date).calendar(null, {
|
||||
sameDay: 'LT',
|
||||
lastDay: `[${I18n.t('Yesterday')}] LT`,
|
||||
|
|
|
@ -260,7 +260,7 @@ const CannedResponsesListView = ({ navigation, route }: ICannedResponsesListView
|
|||
/>
|
||||
</HeaderButton.Container>
|
||||
),
|
||||
headerTitle: () => <SearchHeader onSearchChangeText={onChangeText} />,
|
||||
headerTitle: () => <SearchHeader onSearchChangeText={onChangeText} testID='team-channels-view-search-header' />,
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import { withTheme } from '../theme';
|
||||
import { forwardRoom, ITransferData } from '../actions/room';
|
||||
import { themes } from '../constants/colors';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import OrSeparator from '../containers/OrSeparator';
|
||||
import Input from '../containers/UIKit/MultiSelect/Input';
|
||||
import { forwardRoom as forwardRoomAction } from '../actions/room';
|
||||
import { IRoom } from '../definitions';
|
||||
import { IBaseScreen, IRoom } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
import { IOptionsField } from './NotificationPreferencesView/options';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -23,33 +20,26 @@ const styles = StyleSheet.create({
|
|||
padding: 16
|
||||
}
|
||||
});
|
||||
|
||||
interface ITransferData {
|
||||
roomId: string;
|
||||
userId?: string;
|
||||
departmentId?: string;
|
||||
}
|
||||
|
||||
interface IUser {
|
||||
username: string;
|
||||
_id: string;
|
||||
}
|
||||
interface IForwardLivechatViewProps {
|
||||
navigation: StackNavigationProp<ChatsStackParamList, 'ForwardLivechatView'>;
|
||||
route: RouteProp<ChatsStackParamList, 'ForwardLivechatView'>;
|
||||
theme: string;
|
||||
forwardRoom: (rid: string, transferData: ITransferData) => void;
|
||||
|
||||
interface IParsedData {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const COUNT_DEPARTMENT = 50;
|
||||
|
||||
const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForwardLivechatViewProps) => {
|
||||
const [departments, setDepartments] = useState<IOptionsField[]>([]);
|
||||
const ForwardLivechatView = ({ navigation, route, theme }: IBaseScreen<ChatsStackParamList, 'ForwardLivechatView'>) => {
|
||||
const [departments, setDepartments] = useState<IParsedData[]>([]);
|
||||
const [departmentId, setDepartment] = useState('');
|
||||
const [departmentTotal, setDepartmentTotal] = useState(0);
|
||||
const [users, setUsers] = useState<IOptionsField[]>([]);
|
||||
const [userId, setUser] = useState();
|
||||
const [room, setRoom] = useState<IRoom>({} as IRoom);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const rid = route.params?.rid;
|
||||
|
||||
|
@ -57,7 +47,7 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward
|
|||
try {
|
||||
const result = await RocketChat.getDepartments({ count: COUNT_DEPARTMENT, text, offset });
|
||||
if (result.success) {
|
||||
const parsedDepartments: IOptionsField[] = result.departments.map(department => ({
|
||||
const parsedDepartments: IParsedData[] = result.departments.map(department => ({
|
||||
label: department.name,
|
||||
value: department._id
|
||||
}));
|
||||
|
@ -116,7 +106,7 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward
|
|||
transferData.departmentId = departmentId;
|
||||
}
|
||||
|
||||
forwardRoom(rid, transferData);
|
||||
dispatch(forwardRoom(rid, transferData));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -171,8 +161,4 @@ const ForwardLivechatView = ({ forwardRoom, navigation, route, theme }: IForward
|
|||
);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
forwardRoom: (rid: string, transferData: ITransferData) => dispatch(forwardRoomAction(rid, transferData))
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps)(withTheme(ForwardLivechatView));
|
||||
export default withTheme(ForwardLivechatView);
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
import { dequal } from 'dequal';
|
||||
import React from 'react';
|
||||
import { Alert, Keyboard, StyleSheet, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/core';
|
||||
|
||||
import Button from '../containers/Button';
|
||||
import I18n from '../i18n';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import { loginRequest } from '../actions/login';
|
||||
import { themes } from '../constants/colors';
|
||||
import { withTheme } from '../theme';
|
||||
import Button from '../containers/Button';
|
||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import LoginServices from '../containers/LoginServices';
|
||||
import sharedStyles from './Styles';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import { OutsideParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
registerDisabled: {
|
||||
|
@ -48,9 +47,7 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
interface ILoginViewProps {
|
||||
navigation: StackNavigationProp<OutsideParamList, 'LoginView'>;
|
||||
route: RouteProp<OutsideParamList, 'LoginView'>;
|
||||
interface ILoginViewProps extends IBaseScreen<OutsideParamList, 'LoginView'> {
|
||||
Site_Name: string;
|
||||
Accounts_RegistrationForm: string;
|
||||
Accounts_RegistrationForm_LinkReplacementText: string;
|
||||
|
@ -63,7 +60,6 @@ interface ILoginViewProps {
|
|||
error: string;
|
||||
};
|
||||
failure: boolean;
|
||||
theme: string;
|
||||
loginRequest: Function;
|
||||
inviteLinkToken: string;
|
||||
}
|
||||
|
@ -132,9 +128,9 @@ class LoginView extends React.Component<ILoginViewProps, any> {
|
|||
}
|
||||
|
||||
const { user, password } = this.state;
|
||||
const { loginRequest } = this.props;
|
||||
const { dispatch } = this.props;
|
||||
Keyboard.dismiss();
|
||||
loginRequest({ user, password });
|
||||
dispatch(loginRequest({ user, password }));
|
||||
};
|
||||
|
||||
renderUserForm = () => {
|
||||
|
@ -243,23 +239,19 @@ class LoginView extends React.Component<ILoginViewProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
server: state.server.server,
|
||||
Site_Name: state.settings.Site_Name,
|
||||
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin,
|
||||
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm,
|
||||
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText,
|
||||
Site_Name: state.settings.Site_Name as string,
|
||||
Accounts_ShowFormLogin: state.settings.Accounts_ShowFormLogin as boolean,
|
||||
Accounts_RegistrationForm: state.settings.Accounts_RegistrationForm as string,
|
||||
Accounts_RegistrationForm_LinkReplacementText: state.settings.Accounts_RegistrationForm_LinkReplacementText as string,
|
||||
isFetching: state.login.isFetching,
|
||||
failure: state.login.failure,
|
||||
error: state.login.error && state.login.error.data,
|
||||
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
||||
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
|
||||
Accounts_PasswordReset: state.settings.Accounts_PasswordReset,
|
||||
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder as string,
|
||||
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder as string,
|
||||
Accounts_PasswordReset: state.settings.Accounts_PasswordReset as boolean,
|
||||
inviteLinkToken: state.inviteLinks.token
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
loginRequest: (params: any) => dispatch(loginRequestAction(params))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(LoginView));
|
||||
export default connect(mapStateToProps)(withTheme(LoginView));
|
||||
|
|
|
@ -71,6 +71,8 @@ interface IMessageItem {
|
|||
msg?: string;
|
||||
starred: boolean;
|
||||
pinned: boolean;
|
||||
type: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface IParams {
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
import React from 'react';
|
||||
import { Keyboard, StyleSheet, Text, View } from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/core';
|
||||
import { connect } from 'react-redux';
|
||||
import RNPickerSelect from 'react-native-picker-select';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { OutsideParamList } from '../stacks/types';
|
||||
import log, { events, logEvent } from '../utils/log';
|
||||
import Button from '../containers/Button';
|
||||
import I18n from '../i18n';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import { loginRequest } from '../actions/login';
|
||||
import { themes } from '../constants/colors';
|
||||
import { withTheme } from '../theme';
|
||||
import Button from '../containers/Button';
|
||||
import FormContainer, { FormContainerInner } from '../containers/FormContainer';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import isValidEmail from '../utils/isValidEmail';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import openLink from '../utils/openLink';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import LoginServices from '../containers/LoginServices';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { getShowLoginButton } from '../selectors/login';
|
||||
import { OutsideParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import isValidEmail from '../utils/isValidEmail';
|
||||
import log, { events, logEvent } from '../utils/log';
|
||||
import openLink from '../utils/openLink';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -51,9 +50,7 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
interface IProps {
|
||||
navigation: StackNavigationProp<OutsideParamList, 'RegisterView'>;
|
||||
route: RouteProp<OutsideParamList, 'RegisterView'>;
|
||||
interface IProps extends IBaseScreen<OutsideParamList, 'RegisterView'> {
|
||||
server: string;
|
||||
Site_Name: string;
|
||||
Gitlab_URL: string;
|
||||
|
@ -63,8 +60,6 @@ interface IProps {
|
|||
Accounts_EmailVerification: boolean;
|
||||
Accounts_ManuallyApproveNewUsers: boolean;
|
||||
showLoginButton: boolean;
|
||||
loginRequest: Function;
|
||||
theme: string;
|
||||
}
|
||||
|
||||
class RegisterView extends React.Component<IProps, any> {
|
||||
|
@ -130,7 +125,7 @@ class RegisterView extends React.Component<IProps, any> {
|
|||
Keyboard.dismiss();
|
||||
|
||||
const { name, email, password, username, customFields } = this.state;
|
||||
const { loginRequest, Accounts_EmailVerification, navigation, Accounts_ManuallyApproveNewUsers } = this.props;
|
||||
const { dispatch, Accounts_EmailVerification, navigation, Accounts_ManuallyApproveNewUsers } = this.props;
|
||||
|
||||
try {
|
||||
await RocketChat.register({
|
||||
|
@ -148,11 +143,11 @@ class RegisterView extends React.Component<IProps, any> {
|
|||
await navigation.goBack();
|
||||
showErrorAlert(I18n.t('Wait_activation_warning'), I18n.t('Registration_Succeeded'));
|
||||
} else {
|
||||
await loginRequest({ user: email, password });
|
||||
dispatch(loginRequest({ user: email, password }));
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e.data?.errorType === 'username-invalid') {
|
||||
return loginRequest({ user: email, password });
|
||||
return dispatch(loginRequest({ user: email, password }));
|
||||
}
|
||||
if (e.data?.error) {
|
||||
logEvent(events.REGISTER_DEFAULT_SIGN_UP_F);
|
||||
|
@ -349,20 +344,16 @@ class RegisterView extends React.Component<IProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
server: state.server.server,
|
||||
Site_Name: state.settings.Site_Name,
|
||||
Gitlab_URL: state.settings.API_Gitlab_URL,
|
||||
CAS_enabled: state.settings.CAS_enabled,
|
||||
CAS_login_url: state.settings.CAS_login_url,
|
||||
Accounts_CustomFields: state.settings.Accounts_CustomFields,
|
||||
Accounts_EmailVerification: state.settings.Accounts_EmailVerification,
|
||||
Accounts_ManuallyApproveNewUsers: state.settings.Accounts_ManuallyApproveNewUsers,
|
||||
Site_Name: state.settings.Site_Name as string,
|
||||
Gitlab_URL: state.settings.API_Gitlab_URL as string,
|
||||
CAS_enabled: state.settings.CAS_enabled as boolean,
|
||||
CAS_login_url: state.settings.CAS_login_url as string,
|
||||
Accounts_CustomFields: state.settings.Accounts_CustomFields as string,
|
||||
Accounts_EmailVerification: state.settings.Accounts_EmailVerification as boolean,
|
||||
Accounts_ManuallyApproveNewUsers: state.settings.Accounts_ManuallyApproveNewUsers as boolean,
|
||||
showLoginButton: getShowLoginButton(state)
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
loginRequest: (params: any) => dispatch(loginRequestAction(params))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RegisterView));
|
||||
export default connect(mapStateToProps)(withTheme(RegisterView));
|
||||
|
|
|
@ -7,8 +7,8 @@ import { Q } from '@nozbe/watermelondb';
|
|||
|
||||
import { compareServerVersion } from '../../lib/utils';
|
||||
import Touch from '../../utils/touch';
|
||||
import { setLoading as setLoadingAction } from '../../actions/selectedUsers';
|
||||
import { closeRoom as closeRoomAction, leaveRoom as leaveRoomAction } from '../../actions/room';
|
||||
import { setLoading } from '../../actions/selectedUsers';
|
||||
import { closeRoom, leaveRoom } from '../../actions/room';
|
||||
import sharedStyles from '../Styles';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import Status from '../../containers/Status';
|
||||
|
@ -334,9 +334,9 @@ class RoomActionsView extends React.Component {
|
|||
const {
|
||||
room: { rid }
|
||||
} = this.state;
|
||||
const { closeRoom } = this.props;
|
||||
const { dispatch } = this.props;
|
||||
|
||||
closeRoom(rid);
|
||||
dispatch(closeRoom(rid));
|
||||
};
|
||||
|
||||
returnLivechat = () => {
|
||||
|
@ -375,16 +375,16 @@ class RoomActionsView extends React.Component {
|
|||
|
||||
addUser = async () => {
|
||||
const { room } = this.state;
|
||||
const { setLoadingInvite, navigation } = this.props;
|
||||
const { dispatch, navigation } = this.props;
|
||||
const { rid } = room;
|
||||
try {
|
||||
setLoadingInvite(true);
|
||||
dispatch(setLoading(true));
|
||||
await RocketChat.addUsersToRoom(rid);
|
||||
navigation.pop();
|
||||
} catch (e) {
|
||||
log(e);
|
||||
} finally {
|
||||
setLoadingInvite(false);
|
||||
dispatch(setLoading(false));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -458,12 +458,12 @@ class RoomActionsView extends React.Component {
|
|||
|
||||
leaveChannel = () => {
|
||||
const { room } = this.state;
|
||||
const { leaveRoom } = this.props;
|
||||
const { dispatch } = this.props;
|
||||
|
||||
showConfirmationAlert({
|
||||
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') }),
|
||||
onPress: () => leaveRoom('channel', room)
|
||||
onPress: () => dispatch(leaveRoom('channel', room))
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -522,7 +522,7 @@ class RoomActionsView extends React.Component {
|
|||
|
||||
leaveTeam = async () => {
|
||||
const { room } = this.state;
|
||||
const { navigation, leaveRoom } = this.props;
|
||||
const { navigation, dispatch } = this.props;
|
||||
|
||||
try {
|
||||
const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id });
|
||||
|
@ -538,21 +538,21 @@ class RoomActionsView extends React.Component {
|
|||
title: 'Leave_Team',
|
||||
data: teamChannels,
|
||||
infoText: 'Select_Team_Channels',
|
||||
nextAction: data => leaveRoom('team', room, data),
|
||||
nextAction: data => dispatch(leaveRoom('team', room, data)),
|
||||
showAlert: () => showErrorAlert(I18n.t('Last_owner_team_room'), I18n.t('Cannot_leave'))
|
||||
});
|
||||
} else {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }),
|
||||
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
|
||||
onPress: () => leaveRoom('team', room)
|
||||
onPress: () => dispatch(leaveRoom('team', room))
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
showConfirmationAlert({
|
||||
message: I18n.t('You_are_leaving_the_team', { team: RocketChat.getRoomTitle(room) }),
|
||||
confirmationText: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
|
||||
onPress: () => leaveRoom('team', room)
|
||||
onPress: () => dispatch(leaveRoom('team', room))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1242,10 +1242,4 @@ const mapStateToProps = state => ({
|
|||
viewCannedResponsesPermission: state.permissions['view-canned-responses']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
leaveRoom: (roomType, room, selected) => dispatch(leaveRoomAction(roomType, room, selected)),
|
||||
closeRoom: rid => dispatch(closeRoomAction(rid)),
|
||||
setLoadingInvite: loading => dispatch(setLoadingAction(loading))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withDimensions(RoomActionsView)));
|
||||
export default connect(mapStateToProps)(withTheme(withDimensions(RoomActionsView)));
|
||||
|
|
|
@ -32,6 +32,7 @@ import { isIOS } from '../../utils/deviceInfo';
|
|||
import { compareServerVersion } from '../../lib/utils';
|
||||
import styles from './styles';
|
||||
import { InsideStackParamList, ChatsStackParamList } from '../../stacks/types';
|
||||
import { IRoom } from '../../definitions';
|
||||
import { IEmoji } from '../../definitions/IEmoji';
|
||||
|
||||
const QUERY_SIZE = 50;
|
||||
|
@ -81,7 +82,7 @@ class SearchMessagesView extends React.Component<ISearchMessagesViewProps, ISear
|
|||
|
||||
private encrypted: boolean | undefined;
|
||||
|
||||
private room: { rid: any; name: any; fname: any; t: any } | null | undefined;
|
||||
private room: Pick<IRoom, 'rid' | 'name' | 'fname' | 't'> | null | undefined;
|
||||
|
||||
static navigationOptions = ({ navigation, route }: INavigationOption) => {
|
||||
const options: StackNavigationOptions = {
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import React from 'react';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { Dispatch } from 'redux';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import React from 'react';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
import { loginRequest as loginRequestAction } from '../actions/login';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { loginRequest } from '../actions/login';
|
||||
import { themes } from '../constants/colors';
|
||||
import Button from '../containers/Button';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { IApplicationState } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { withTheme } from '../theme';
|
||||
import { themes } from '../constants/colors';
|
||||
import { isTablet } from '../utils/deviceInfo';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { withTheme } from '../theme';
|
||||
import { isTablet } from '../utils/deviceInfo';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -39,9 +40,9 @@ interface ISetUsernameViewProps {
|
|||
route: RouteProp<{ SetUsernameView: { title: string } }, 'SetUsernameView'>;
|
||||
server: string;
|
||||
userId: string;
|
||||
loginRequest: ({ resume }: { resume: string }) => void;
|
||||
token: string;
|
||||
theme: string;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
|
||||
class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernameViewState> {
|
||||
|
@ -86,7 +87,7 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
|||
|
||||
submit = async () => {
|
||||
const { username } = this.state;
|
||||
const { loginRequest, token } = this.props;
|
||||
const { dispatch, token } = this.props;
|
||||
|
||||
if (!username.trim()) {
|
||||
return;
|
||||
|
@ -95,7 +96,7 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
|||
this.setState({ saving: true });
|
||||
try {
|
||||
await RocketChat.saveUserProfile({ username });
|
||||
await loginRequest({ resume: token });
|
||||
dispatch(loginRequest({ resume: token }));
|
||||
} catch (e: any) {
|
||||
showErrorAlert(e.message, I18n.t('Oops'));
|
||||
}
|
||||
|
@ -144,13 +145,9 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
server: state.server.server,
|
||||
token: getUserSelector(state).token
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
loginRequest: (params: { resume: string }) => dispatch(loginRequestAction(params))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(SetUsernameView));
|
||||
export default connect(mapStateToProps)(withTheme(SetUsernameView));
|
||||
|
|
|
@ -29,6 +29,7 @@ import Header from './Header';
|
|||
import styles from './styles';
|
||||
import { IAttachment } from './interfaces';
|
||||
import { ISubscription } from '../../definitions/ISubscription';
|
||||
import { IUser } from '../../definitions';
|
||||
|
||||
interface IShareViewState {
|
||||
selected: IAttachment;
|
||||
|
@ -230,6 +231,7 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
},
|
||||
thread?.id,
|
||||
server,
|
||||
// @ts-ignore
|
||||
{ id: user.id, token: user.token }
|
||||
);
|
||||
}
|
||||
|
@ -239,7 +241,7 @@ class ShareView extends Component<IShareViewProps, IShareViewState> {
|
|||
|
||||
// Send text message
|
||||
} else if (text.length) {
|
||||
await RocketChat.sendMessage(room.rid, text, thread?.id, { id: user.id, token: user.token });
|
||||
await RocketChat.sendMessage(room.rid, text, thread?.id, { id: user.id, token: user.token } as IUser);
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import React from 'react';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { FlatList, StyleSheet } from 'react-native';
|
||||
import { Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import I18n from '../i18n';
|
||||
import { UserStatus } from '../definitions/UserStatus';
|
||||
import { setUser } from '../actions/login';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import * as List from '../containers/List';
|
||||
import Loading from '../containers/Loading';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import Status from '../containers/Status/Status';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import { LISTENER } from '../containers/Toast';
|
||||
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { withTheme } from '../theme';
|
||||
import EventEmitter from '../utils/events';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import Loading from '../containers/Loading';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import log, { events, logEvent } from '../utils/log';
|
||||
import { LISTENER } from '../containers/Toast';
|
||||
import { withTheme } from '../theme';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import { setUser as setUserAction } from '../actions/login';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
|
||||
const STATUS = [
|
||||
{
|
||||
|
@ -65,12 +65,9 @@ interface IStatusViewState {
|
|||
loading: boolean;
|
||||
}
|
||||
|
||||
interface IStatusViewProps {
|
||||
navigation: StackNavigationProp<any, 'StatusView'>;
|
||||
interface IStatusViewProps extends IBaseScreen<any, 'StatusView'> {
|
||||
user: IUser;
|
||||
theme: string;
|
||||
isMasterDetail: boolean;
|
||||
setUser: (user: IUser) => void;
|
||||
Accounts_AllowInvisibleStatusOption: boolean;
|
||||
}
|
||||
|
||||
|
@ -111,7 +108,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
|||
};
|
||||
|
||||
setCustomStatus = async (statusText: string) => {
|
||||
const { user, setUser } = this.props;
|
||||
const { user, dispatch } = this.props;
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
|
@ -119,7 +116,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
|||
const result = await RocketChat.setUserStatus(user.status, statusText);
|
||||
if (result.success) {
|
||||
logEvent(events.STATUS_CUSTOM);
|
||||
setUser({ statusText });
|
||||
dispatch(setUser({ statusText }));
|
||||
EventEmitter.emit(LISTENER, { message: I18n.t('Status_saved_successfully') });
|
||||
} else {
|
||||
logEvent(events.STATUS_CUSTOM_F);
|
||||
|
@ -156,7 +153,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
|||
|
||||
renderItem = ({ item }: { item: { id: string; name: string } }) => {
|
||||
const { statusText } = this.state;
|
||||
const { user, setUser } = this.props;
|
||||
const { user, dispatch } = this.props;
|
||||
const { id, name } = item;
|
||||
return (
|
||||
<List.Item
|
||||
|
@ -168,7 +165,7 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
|||
try {
|
||||
const result = await RocketChat.setUserStatus(item.id, statusText);
|
||||
if (result.success) {
|
||||
setUser({ status: item.id });
|
||||
dispatch(setUser({ status: item.id as UserStatus }));
|
||||
}
|
||||
} catch (e: any) {
|
||||
showErrorAlert(I18n.t(e.data.errorType));
|
||||
|
@ -205,14 +202,10 @@ class StatusView extends React.Component<IStatusViewProps, IStatusViewState> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
Accounts_AllowInvisibleStatusOption: state.settings.Accounts_AllowInvisibleStatusOption ?? true
|
||||
Accounts_AllowInvisibleStatusOption: (state.settings.Accounts_AllowInvisibleStatusOption as boolean) ?? true
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
setUser: (user: IUser) => dispatch(setUserAction(user))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(StatusView));
|
||||
export default connect(mapStateToProps)(withTheme(StatusView));
|
||||
|
|
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||
import { Alert, FlatList, Keyboard } from 'react-native';
|
||||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
import { deleteRoom } from '../actions/room';
|
||||
import { themes } from '../constants/colors';
|
||||
|
@ -17,6 +18,7 @@ import SafeAreaView from '../containers/SafeAreaView';
|
|||
import SearchHeader from '../containers/SearchHeader';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { IApplicationState, IBaseScreen } from '../definitions';
|
||||
import { ERoomType } from '../definitions/ERoomType';
|
||||
import { withDimensions } from '../dimensions';
|
||||
import I18n from '../i18n';
|
||||
import database from '../lib/database';
|
||||
|
@ -48,7 +50,7 @@ const keyExtractor = (item: IItem) => item._id;
|
|||
|
||||
// This interface comes from request RocketChat.getTeamListRoom
|
||||
interface IItem {
|
||||
_id: string;
|
||||
_id: ERoomType;
|
||||
fname: string;
|
||||
customFields: object;
|
||||
broadcast: boolean;
|
||||
|
@ -97,6 +99,7 @@ interface ITeamChannelsViewProps extends IProps {
|
|||
showActionSheet: (options: any) => void;
|
||||
showAvatar: boolean;
|
||||
displayMode: string;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChannelsViewState> {
|
||||
private teamId: string;
|
||||
|
@ -438,7 +441,8 @@ class TeamChannelsView extends React.Component<ITeamChannelsViewProps, ITeamChan
|
|||
{
|
||||
text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
|
||||
style: 'destructive',
|
||||
onPress: () => dispatch(deleteRoom(item._id, item.t))
|
||||
// VERIFY ON PR
|
||||
onPress: () => dispatch(deleteRoom(item._id, item))
|
||||
}
|
||||
],
|
||||
{ cancelable: false }
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/node_modules/@types/ejson/index.d.ts b/node_modules/@types/ejson/index.d.ts
|
||||
index 3a35636..278ef98 100755
|
||||
--- a/node_modules/@types/ejson/index.d.ts
|
||||
+++ b/node_modules/@types/ejson/index.d.ts
|
||||
@@ -17,7 +17,7 @@ export function parse(str: string): any;
|
||||
export function stringify(obj: any, options?: StringifyOptions): string;
|
||||
|
||||
export function toJSONValue(obj: any): string;
|
||||
-export function fromJSONValue(obj: string): any;
|
||||
+export function fromJSONValue(obj: Object): any;
|
||||
export function isBinary(value: any): boolean;
|
||||
export function newBinary(len: number): Uint8Array;
|
||||
export function equals(a: any, b: any, options?: CloneOptions): boolean;
|
|
@ -797,6 +797,13 @@ stories.add('System messages', () => (
|
|||
<Message msg='public' type='room_changed_privacy' isInfo />
|
||||
<Message type='room_e2e_disabled' isInfo />
|
||||
<Message type='room_e2e_enabled' isInfo />
|
||||
<Message type='removed-user-from-team' isInfo />
|
||||
<Message type='added-user-to-team' isInfo />
|
||||
<Message type='user-added-room-to-team' isInfo msg='channel-name' />
|
||||
<Message type='user-converted-to-team' isInfo msg='channel-name' />
|
||||
<Message type='user-converted-to-channel' isInfo msg='channel-name' />
|
||||
<Message type='user-deleted-room-from-team' isInfo msg='channel-name' />
|
||||
<Message type='user-removed-room-from-team' isInfo msg='channel-name' />
|
||||
</>
|
||||
));
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue