Merge branch 'develop' into chore.dehydrate-login-methods-from-rocketchatjs
This commit is contained in:
commit
0949b1d70e
|
@ -64,5 +64,6 @@ artifacts
|
|||
.vscode/
|
||||
e2e/docker/rc_test_env/docker-compose.yml
|
||||
e2e/docker/data/db
|
||||
e2e/e2e_account.js
|
||||
|
||||
*.p8
|
|
@ -605,7 +605,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
|
||||
getCannedResponses = debounce(async (text?: string) => {
|
||||
const res = await RocketChat.getListCannedResponse({ text });
|
||||
this.setState({ mentions: res?.cannedResponses || [], mentionLoading: false });
|
||||
this.setState({ mentions: res.success ? res.cannedResponses : [], mentionLoading: false });
|
||||
}, 500);
|
||||
|
||||
focus = () => {
|
||||
|
|
|
@ -44,22 +44,22 @@ export type E2EType = 'pending' | 'done';
|
|||
export interface ILastMessage {
|
||||
_id: string;
|
||||
rid: string;
|
||||
tshow: boolean;
|
||||
t: MessageType;
|
||||
tmid: string;
|
||||
msg: string;
|
||||
e2e: E2EType;
|
||||
ts: Date;
|
||||
tshow?: boolean;
|
||||
t?: MessageType;
|
||||
tmid?: string;
|
||||
msg?: string;
|
||||
e2e?: E2EType;
|
||||
ts: string | Date;
|
||||
u: IUserMessage;
|
||||
_updatedAt: Date;
|
||||
urls: string[];
|
||||
mentions: IUserMention[];
|
||||
channels: IUserChannel[];
|
||||
md: MarkdownAST;
|
||||
attachments: IAttachment[];
|
||||
reactions: IReaction[];
|
||||
unread: boolean;
|
||||
status: boolean;
|
||||
_updatedAt: string | Date;
|
||||
urls?: IUrlFromServer[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
md?: MarkdownAST;
|
||||
attachments?: IAttachment[];
|
||||
reactions?: IReaction[];
|
||||
unread?: boolean;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
interface IMessageFile {
|
||||
|
@ -68,38 +68,21 @@ interface IMessageFile {
|
|||
type: string;
|
||||
}
|
||||
|
||||
interface IMessageAttachment {
|
||||
ts: string;
|
||||
title: string;
|
||||
title_link: string;
|
||||
title_link_download: true;
|
||||
image_dimensions: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
image_preview: string;
|
||||
image_url: string;
|
||||
image_type: string;
|
||||
image_size: number;
|
||||
type: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface IMessageFromServer {
|
||||
_id: string;
|
||||
rid: string;
|
||||
msg: string;
|
||||
msg?: string;
|
||||
ts: string | Date; // wm date issue
|
||||
u: IUserMessage;
|
||||
_updatedAt: string | Date;
|
||||
urls: IUrlFromServer[];
|
||||
mentions: IUserMention[];
|
||||
channels: IUserChannel[];
|
||||
md: MarkdownAST;
|
||||
file: IMessageFile;
|
||||
files: IMessageFile[];
|
||||
groupable: false;
|
||||
attachments: IMessageAttachment[];
|
||||
urls?: IUrlFromServer[];
|
||||
mentions?: IUserMention[];
|
||||
channels?: IUserChannel[];
|
||||
md?: MarkdownAST;
|
||||
file?: IMessageFile;
|
||||
files?: IMessageFile[];
|
||||
groupable?: boolean;
|
||||
attachments?: IAttachment[];
|
||||
}
|
||||
|
||||
export interface ILoadMoreMessage {
|
||||
|
@ -135,7 +118,7 @@ export interface IMessage extends IMessageFromServer {
|
|||
translations?: ITranslations[];
|
||||
tmsg?: string;
|
||||
blocks?: any;
|
||||
e2e?: string;
|
||||
e2e?: E2EType;
|
||||
tshow?: boolean;
|
||||
subscription?: { id: string };
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { MarkdownAST } from '@rocket.chat/message-parser';
|
|||
import { IAttachment } from './IAttachment';
|
||||
import { IMessage } from './IMessage';
|
||||
import { IServedBy } from './IServedBy';
|
||||
import { SubscriptionType } from './ISubscription';
|
||||
import { IVisitor, SubscriptionType } from './ISubscription';
|
||||
import { IUser } from './IUser';
|
||||
|
||||
interface IRequestTranscript {
|
||||
|
@ -28,11 +28,8 @@ export interface IRoom {
|
|||
broadcast: boolean;
|
||||
encrypted: boolean;
|
||||
ro: boolean;
|
||||
v?: {
|
||||
_id?: string;
|
||||
token?: string;
|
||||
status: 'online' | 'busy' | 'away' | 'offline';
|
||||
};
|
||||
v?: IVisitor;
|
||||
status?: string;
|
||||
servedBy?: IServedBy;
|
||||
departmentId?: string;
|
||||
livechatData?: any;
|
||||
|
@ -55,13 +52,11 @@ export enum OmnichannelSourceType {
|
|||
API = 'api',
|
||||
OTHER = 'other' // catch-all source type
|
||||
}
|
||||
export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | 'broadcast' | ''> {
|
||||
export interface IOmnichannelRoom extends Partial<Omit<IRoom, 'default' | 'featured' | 'broadcast'>> {
|
||||
_id: string;
|
||||
rid: string;
|
||||
t: SubscriptionType.OMNICHANNEL;
|
||||
v: {
|
||||
_id?: string;
|
||||
token?: string;
|
||||
status: 'online' | 'busy' | 'away' | 'offline';
|
||||
};
|
||||
v: IVisitor;
|
||||
email?: {
|
||||
// Data used when the room is created from an email, via email Integration.
|
||||
inbox: string;
|
||||
|
@ -83,6 +78,8 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
|
|||
sidebarIcon?: string;
|
||||
// The default sidebar icon
|
||||
defaultIcon?: string;
|
||||
_updatedAt?: Date;
|
||||
queuedAt?: Date;
|
||||
};
|
||||
transcriptRequest?: IRequestTranscript;
|
||||
servedBy?: IServedBy;
|
||||
|
@ -91,18 +88,22 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
|
|||
|
||||
lastMessage?: IMessage & { token?: string };
|
||||
|
||||
tags: any;
|
||||
closedAt: any;
|
||||
metrics: any;
|
||||
waitingResponse: any;
|
||||
responseBy: any;
|
||||
priorityId: any;
|
||||
livechatData: any;
|
||||
tags?: string[];
|
||||
closedAt?: Date;
|
||||
metrics?: any;
|
||||
waitingResponse?: any;
|
||||
responseBy?: any;
|
||||
priorityId?: any;
|
||||
livechatData?: any;
|
||||
queuedAt?: Date;
|
||||
|
||||
ts: Date;
|
||||
label?: string;
|
||||
crmData?: unknown;
|
||||
message?: string;
|
||||
queueOrder?: string;
|
||||
estimatedWaitingTimeQueue?: string;
|
||||
estimatedServiceTimeAt?: Date;
|
||||
}
|
||||
|
||||
export type TRoomModel = IRoom & Model;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { ILastMessage } from './IMessage';
|
||||
|
||||
export interface ISearchLocal {
|
||||
avatarETag: string;
|
||||
rid: string;
|
||||
name: string;
|
||||
t: string;
|
||||
fname: string;
|
||||
encrypted: boolean | null;
|
||||
lastMessage?: ILastMessage;
|
||||
}
|
||||
|
||||
export interface ISearch extends ISearchLocal {
|
||||
// return only from api search
|
||||
_id: string;
|
||||
status?: string;
|
||||
username: string;
|
||||
outside?: boolean;
|
||||
search?: boolean;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { IServerRoomItem } from './IRoom';
|
||||
import { IUser } from './IUser';
|
||||
|
||||
export type TSpotlightUser = Pick<IUser, '_id' | 'status' | 'name' | 'username'> & { outside: boolean };
|
||||
|
||||
export type ISpotlightRoom = Pick<IServerRoomItem, '_id' | 'name' | 't'> & Partial<Pick<IServerRoomItem, 'lastMessage'>>;
|
||||
|
||||
export interface ISpotlight {
|
||||
users: TSpotlightUser[];
|
||||
rooms: ISpotlightRoom[];
|
||||
}
|
|
@ -17,11 +17,11 @@ export enum SubscriptionType {
|
|||
}
|
||||
|
||||
export interface IVisitor {
|
||||
_id: string;
|
||||
username: string;
|
||||
token: string;
|
||||
status: string;
|
||||
lastMessageTs: Date;
|
||||
_id?: string;
|
||||
token?: string;
|
||||
status: 'online' | 'busy' | 'away' | 'offline';
|
||||
username?: string;
|
||||
lastMessageTs?: Date;
|
||||
}
|
||||
|
||||
export enum ERoomTypes {
|
||||
|
@ -76,7 +76,7 @@ export interface ISubscription {
|
|||
jitsiTimeout?: number;
|
||||
autoTranslate?: boolean;
|
||||
autoTranslateLanguage?: string;
|
||||
lastMessage?: ILastMessage; // TODO: we need to use IMessage here
|
||||
lastMessage?: ILastMessage | null; // TODO: we need to use IMessage here
|
||||
hideUnreadStatus?: boolean;
|
||||
sysMes?: string[] | boolean;
|
||||
uids?: string[];
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
export interface ITagsOmnichannel {
|
||||
_id: string;
|
||||
name: string;
|
||||
departments: string[];
|
||||
}
|
|
@ -29,7 +29,7 @@ export interface IThreadResult {
|
|||
channels?: IUserChannel[];
|
||||
replies?: string[];
|
||||
tcount?: number;
|
||||
status?: string;
|
||||
status?: number;
|
||||
tlm?: string | Date;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ export interface IUser extends IRocketChatRecord, Omit<ILoggedUser, 'username' |
|
|||
name?: string;
|
||||
services?: IUserServices;
|
||||
emails?: IUserEmail[];
|
||||
status?: UserStatus;
|
||||
status: UserStatus;
|
||||
statusConnection?: string;
|
||||
lastLogin?: Date;
|
||||
avatarOrigin?: string;
|
||||
|
|
|
@ -25,6 +25,7 @@ export * from './IRocketChat';
|
|||
export * from './ICertificate';
|
||||
export * from './IUrl';
|
||||
export * from './ICredentials';
|
||||
export * from './ISearch';
|
||||
|
||||
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
|
||||
navigation: StackNavigationProp<T, S>;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// ACTIONS
|
||||
import { TActionInquiry } from '../../ee/omnichannel/actions/inquiry';
|
||||
import { TActionActiveUsers } from '../../actions/activeUsers';
|
||||
import { TActionApp } from '../../actions/app';
|
||||
import { TActionCreateChannel } from '../../actions/createChannel';
|
||||
|
@ -30,6 +31,7 @@ import { ISelectedUsers } from '../../reducers/selectedUsers';
|
|||
import { IServer } from '../../reducers/server';
|
||||
import { TSettingsState } from '../../reducers/settings';
|
||||
import { IShare } from '../../reducers/share';
|
||||
import { IInquiry } from '../../ee/omnichannel/reducers/inquiry';
|
||||
import { IPermissionsState } from '../../reducers/permissions';
|
||||
import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
||||
|
||||
|
@ -50,7 +52,7 @@ export interface IApplicationState {
|
|||
usersTyping: any;
|
||||
inviteLinks: IInviteLinks;
|
||||
createDiscussion: ICreateDiscussion;
|
||||
inquiry: any;
|
||||
inquiry: IInquiry;
|
||||
enterpriseModules: IEnterpriseModules;
|
||||
encryption: IEncryption;
|
||||
permissions: IPermissionsState;
|
||||
|
@ -71,5 +73,6 @@ export type TApplicationActions = TActionActiveUsers &
|
|||
TActionsShare &
|
||||
TActionServer &
|
||||
TActionApp &
|
||||
TActionInquiry &
|
||||
TActionPermissions &
|
||||
TActionEnterpriseModules;
|
||||
|
|
|
@ -52,4 +52,51 @@ export type ChannelsEndpoints = {
|
|||
'channels.convertToTeam': {
|
||||
POST: (params: { channelId: string; channelName: string }) => { team: ITeam };
|
||||
};
|
||||
'channels.info': {
|
||||
GET: (params: { roomId: string }) => { channel: IServerRoomItem };
|
||||
};
|
||||
'channels.counters': {
|
||||
GET: (params: { roomId: string }) => {
|
||||
joined: boolean;
|
||||
members: number;
|
||||
unreads: number;
|
||||
unreadsFrom: Date;
|
||||
msgs: number;
|
||||
latest: Date;
|
||||
userMentions: number;
|
||||
};
|
||||
};
|
||||
'channels.join': {
|
||||
POST: (params: { roomId: string; joinCode: string | null }) => { channel: IServerRoomItem };
|
||||
};
|
||||
'channels.close': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'channels.kick': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.delete': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'channels.leave': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'channels.addModerator': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.removeModerator': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.addOwner': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.removeOwner': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.addLeader': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'channels.removeLeader': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -11,9 +11,24 @@ export type ChatEndpoints = {
|
|||
'chat.followMessage': {
|
||||
POST: (params: { mid: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.unStarMessage': {
|
||||
POST: (params: { messageId: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.starMessage': {
|
||||
POST: (params: { messageId: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.unfollowMessage': {
|
||||
POST: (params: { mid: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.unPinMessage': {
|
||||
POST: (params: { messageId: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.pinMessage': {
|
||||
POST: (params: { messageId: IMessage['_id'] }) => void;
|
||||
};
|
||||
'chat.reportMessage': {
|
||||
POST: (params: { messageId: IMessage['_id']; description: string }) => void;
|
||||
};
|
||||
'chat.getDiscussions': {
|
||||
GET: (params: { roomId: IRoom['_id']; text?: string; offset: number; count: number }) => {
|
||||
messages: IMessage[];
|
||||
|
@ -39,4 +54,10 @@ export type ChatEndpoints = {
|
|||
message: Pick<IMessage, '_id' | 'rid' | 'u'>;
|
||||
};
|
||||
};
|
||||
'chat.react': {
|
||||
POST: (params: { emoji: string; messageId: string }) => void;
|
||||
};
|
||||
'chat.ignoreUser': {
|
||||
GET: (params: { rid: string; userId: string; ignore: boolean }) => {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -46,4 +46,27 @@ export type GroupsEndpoints = {
|
|||
'groups.convertToTeam': {
|
||||
POST: (params: { roomId: string; roomName: string }) => { team: ITeam };
|
||||
};
|
||||
'groups.counters': {
|
||||
GET: (params: { roomId: string }) => {
|
||||
joined: boolean;
|
||||
members: number;
|
||||
unreads: number;
|
||||
unreadsFrom: Date;
|
||||
msgs: number;
|
||||
latest: Date;
|
||||
userMentions: number;
|
||||
};
|
||||
};
|
||||
'groups.close': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'groups.kick': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'groups.delete': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'groups.leave': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -38,4 +38,16 @@ export type ImEndpoints = {
|
|||
messages: IMessageFromServer[];
|
||||
};
|
||||
};
|
||||
'im.close': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'im.kick': {
|
||||
POST: (params: { roomId: string; userId: string }) => {};
|
||||
};
|
||||
'im.delete': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
'im.leave': {
|
||||
POST: (params: { roomId: string }) => {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ import { UsersEndpoints } from './users';
|
|||
import { TeamsEndpoints } from './teams';
|
||||
import { E2eEndpoints } from './e2e';
|
||||
import { SubscriptionsEndpoints } from './subscriptions';
|
||||
import { VideoConferenceEndpoints } from './videoConference';
|
||||
|
||||
export type Endpoints = ChannelsEndpoints &
|
||||
ChatEndpoints &
|
||||
|
@ -32,4 +33,5 @@ export type Endpoints = ChannelsEndpoints &
|
|||
UsersEndpoints &
|
||||
TeamsEndpoints &
|
||||
E2eEndpoints &
|
||||
SubscriptionsEndpoints;
|
||||
SubscriptionsEndpoints &
|
||||
VideoConferenceEndpoints;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ICannedResponse } from '../../ICannedResponse';
|
||||
import { ILivechatAgent } from '../../ILivechatAgent';
|
||||
import { ILivechatDepartment } from '../../ILivechatDepartment';
|
||||
import { ILivechatDepartmentAgents } from '../../ILivechatDepartmentAgents';
|
||||
|
@ -102,6 +103,8 @@ export type OmnichannelEndpoints = {
|
|||
{
|
||||
_id: string;
|
||||
label: string;
|
||||
visibility?: string;
|
||||
scope?: string;
|
||||
}
|
||||
];
|
||||
}>;
|
||||
|
@ -190,4 +193,10 @@ export type OmnichannelEndpoints = {
|
|||
total: number;
|
||||
};
|
||||
};
|
||||
|
||||
'canned-responses': {
|
||||
GET: (params: PaginatedRequest<{ scope?: string; departmentId?: string; text?: string }>) => PaginatedResult<{
|
||||
cannedResponses: ICannedResponse[];
|
||||
}>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -34,4 +34,7 @@ export type UsersEndpoints = {
|
|||
'users.register': {
|
||||
POST: (params: { name: string; email: string; username: string; pass: string }) => { user: IUserRegistered };
|
||||
};
|
||||
'users.setStatus': {
|
||||
POST: (params: { status: string; message: string }) => {};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export type VideoConferenceEndpoints = {
|
||||
'video-conference/jitsi.update-timeout': {
|
||||
POST: (params: { roomId: string }) => void;
|
||||
};
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
import * as types from '../../../actions/actionsTypes';
|
||||
|
||||
export function inquirySetEnabled(enabled) {
|
||||
return {
|
||||
type: types.INQUIRY.SET_ENABLED,
|
||||
enabled
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryReset() {
|
||||
return {
|
||||
type: types.INQUIRY.RESET
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueAdd(inquiry) {
|
||||
return {
|
||||
type: types.INQUIRY.QUEUE_ADD,
|
||||
inquiry
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueUpdate(inquiry) {
|
||||
return {
|
||||
type: types.INQUIRY.QUEUE_UPDATE,
|
||||
inquiry
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueRemove(inquiryId) {
|
||||
return {
|
||||
type: types.INQUIRY.QUEUE_REMOVE,
|
||||
inquiryId
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryRequest() {
|
||||
return {
|
||||
type: types.INQUIRY.REQUEST
|
||||
};
|
||||
}
|
||||
|
||||
export function inquirySuccess(inquiries) {
|
||||
return {
|
||||
type: types.INQUIRY.SUCCESS,
|
||||
inquiries
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryFailure(error) {
|
||||
return {
|
||||
type: types.INQUIRY.FAILURE,
|
||||
error
|
||||
};
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { IOmnichannelRoom } from '../../../definitions';
|
||||
import { INQUIRY } from '../../../actions/actionsTypes';
|
||||
|
||||
interface IInquirySetEnabled extends Action {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
interface IInquiryQueueAddAndUpdate extends Action {
|
||||
inquiry: IOmnichannelRoom;
|
||||
}
|
||||
|
||||
interface IInquirySuccess extends Action {
|
||||
inquiries: IOmnichannelRoom[];
|
||||
}
|
||||
|
||||
interface IInquiryQueueRemove extends Action {
|
||||
inquiryId: string;
|
||||
}
|
||||
|
||||
interface IInquiryFailure extends Action {
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
export type TActionInquiry = IInquirySetEnabled &
|
||||
IInquiryQueueAddAndUpdate &
|
||||
IInquirySuccess &
|
||||
IInquiryQueueRemove &
|
||||
IInquiryFailure;
|
||||
|
||||
export function inquirySetEnabled(enabled: boolean): IInquirySetEnabled {
|
||||
return {
|
||||
type: INQUIRY.SET_ENABLED,
|
||||
enabled
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryReset(): Action {
|
||||
return {
|
||||
type: INQUIRY.RESET
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueAdd(inquiry: IOmnichannelRoom): IInquiryQueueAddAndUpdate {
|
||||
return {
|
||||
type: INQUIRY.QUEUE_ADD,
|
||||
inquiry
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueUpdate(inquiry: IOmnichannelRoom): IInquiryQueueAddAndUpdate {
|
||||
return {
|
||||
type: INQUIRY.QUEUE_UPDATE,
|
||||
inquiry
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryQueueRemove(inquiryId: string): IInquiryQueueRemove {
|
||||
return {
|
||||
type: INQUIRY.QUEUE_REMOVE,
|
||||
inquiryId
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryRequest(): Action {
|
||||
return {
|
||||
type: INQUIRY.REQUEST
|
||||
};
|
||||
}
|
||||
|
||||
export function inquirySuccess(inquiries: IOmnichannelRoom[]): IInquirySuccess {
|
||||
return {
|
||||
type: INQUIRY.SUCCESS,
|
||||
inquiries
|
||||
};
|
||||
}
|
||||
|
||||
export function inquiryFailure(error: unknown): IInquiryFailure {
|
||||
return {
|
||||
type: INQUIRY.FAILURE,
|
||||
error
|
||||
};
|
||||
}
|
|
@ -1,19 +1,28 @@
|
|||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import * as List from '../../../containers/List';
|
||||
import styles from '../../../views/RoomsListView/styles';
|
||||
import { SWITCH_TRACK_COLOR, themes } from '../../../constants/colors';
|
||||
import { withTheme } from '../../../theme';
|
||||
import { useTheme } from '../../../theme';
|
||||
import UnreadBadge from '../../../presentation/UnreadBadge';
|
||||
import RocketChat from '../../../lib/rocketchat';
|
||||
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../lib';
|
||||
import { IUser } from '../../../definitions/IUser';
|
||||
|
||||
const OmnichannelStatus = memo(({ searching, goQueue, theme, queueSize, inquiryEnabled, user }) => {
|
||||
if (searching > 0 || !(RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) {
|
||||
interface IOmnichannelStatus {
|
||||
searching: boolean;
|
||||
goQueue: () => void;
|
||||
queueSize: number;
|
||||
inquiryEnabled: boolean;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
const OmnichannelStatus = memo(({ searching, goQueue, queueSize, inquiryEnabled, user }: IOmnichannelStatus) => {
|
||||
if (searching || !(RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) {
|
||||
return null;
|
||||
}
|
||||
const { theme } = useTheme();
|
||||
const [status, setStatus] = useState(isOmnichannelStatusAvailable(user));
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -48,16 +57,4 @@ const OmnichannelStatus = memo(({ searching, goQueue, theme, queueSize, inquiryE
|
|||
);
|
||||
});
|
||||
|
||||
OmnichannelStatus.propTypes = {
|
||||
searching: PropTypes.bool,
|
||||
goQueue: PropTypes.func,
|
||||
queueSize: PropTypes.number,
|
||||
inquiryEnabled: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
user: PropTypes.shape({
|
||||
roles: PropTypes.array,
|
||||
statusLivechat: PropTypes.string
|
||||
})
|
||||
};
|
||||
|
||||
export default withTheme(OmnichannelStatus);
|
||||
export default OmnichannelStatus;
|
|
@ -1,21 +1,24 @@
|
|||
import RocketChat from '../../../lib/rocketchat';
|
||||
import sdk from '../../../lib/rocketchat/services/sdk';
|
||||
import { IUser } from '../../../definitions';
|
||||
import EventEmitter from '../../../utils/events';
|
||||
import subscribeInquiry from './subscriptions/inquiry';
|
||||
|
||||
export const isOmnichannelStatusAvailable = user => user?.statusLivechat === 'available';
|
||||
export const isOmnichannelStatusAvailable = (user: IUser): boolean => user?.statusLivechat === 'available';
|
||||
|
||||
// RC 0.26.0
|
||||
export const changeLivechatStatus = () => RocketChat.methodCallWrapper('livechat:changeLivechatStatus');
|
||||
export const changeLivechatStatus = () => sdk.methodCallWrapper('livechat:changeLivechatStatus');
|
||||
|
||||
// RC 2.4.0
|
||||
export const getInquiriesQueued = () => RocketChat.sdk.get('livechat/inquiries.queued');
|
||||
// @ts-ignore
|
||||
export const getInquiriesQueued = () => sdk.get('livechat/inquiries.queued');
|
||||
|
||||
// this inquiry is added to the db by the subscriptions stream
|
||||
// and will be removed by the queue stream
|
||||
// RC 2.4.0
|
||||
export const takeInquiry = inquiryId => RocketChat.methodCallWrapper('livechat:takeInquiry', inquiryId);
|
||||
export const takeInquiry = (inquiryId: string) => sdk.methodCallWrapper('livechat:takeInquiry', inquiryId);
|
||||
|
||||
class Omnichannel {
|
||||
private inquirySub: { stop: () => void } | null;
|
||||
constructor() {
|
||||
this.inquirySub = null;
|
||||
EventEmitter.addEventListener('INQUIRY_SUBSCRIBE', this.subscribeInquiry);
|
||||
|
@ -36,5 +39,5 @@ class Omnichannel {
|
|||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const omnichannel = new Omnichannel();
|
|
@ -2,11 +2,28 @@ import log from '../../../../utils/log';
|
|||
import { store } from '../../../../lib/auxStore';
|
||||
import RocketChat from '../../../../lib/rocketchat';
|
||||
import { inquiryQueueAdd, inquiryQueueRemove, inquiryQueueUpdate, inquiryRequest } from '../../actions/inquiry';
|
||||
import sdk from '../../../../lib/rocketchat/services/sdk';
|
||||
import { ILivechatDepartment } from '../../../../definitions/ILivechatDepartment';
|
||||
import { IOmnichannelRoom } from '../../../../definitions';
|
||||
|
||||
const removeListener = listener => listener.stop();
|
||||
interface IArgsQueueOmnichannel extends IOmnichannelRoom {
|
||||
type: string;
|
||||
}
|
||||
|
||||
let connectedListener;
|
||||
let queueListener;
|
||||
interface IDdpMessage {
|
||||
msg: string;
|
||||
collection: string;
|
||||
id: string;
|
||||
fields: {
|
||||
eventName: string;
|
||||
args: IArgsQueueOmnichannel[];
|
||||
};
|
||||
}
|
||||
|
||||
const removeListener = (listener: any) => listener.stop();
|
||||
|
||||
let connectedListener: any;
|
||||
let queueListener: any;
|
||||
|
||||
const streamTopic = 'stream-livechat-inquiry-queue-observer';
|
||||
|
||||
|
@ -15,7 +32,7 @@ export default function subscribeInquiry() {
|
|||
store.dispatch(inquiryRequest());
|
||||
};
|
||||
|
||||
const handleQueueMessageReceived = ddpMessage => {
|
||||
const handleQueueMessageReceived = (ddpMessage: IDdpMessage) => {
|
||||
const [{ type, ...sub }] = ddpMessage.fields.args;
|
||||
|
||||
// added can be ignored, since it is handled by 'changed' event
|
||||
|
@ -26,7 +43,9 @@ export default function subscribeInquiry() {
|
|||
// if the sub isn't on the queue anymore
|
||||
if (sub.status !== 'queued') {
|
||||
// remove it from the queue
|
||||
if (sub._id) {
|
||||
store.dispatch(inquiryQueueRemove(sub._id));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -53,23 +72,28 @@ export default function subscribeInquiry() {
|
|||
}
|
||||
};
|
||||
|
||||
connectedListener = RocketChat.onStreamData('connected', handleConnection);
|
||||
queueListener = RocketChat.onStreamData(streamTopic, handleQueueMessageReceived);
|
||||
connectedListener = sdk.onStreamData('connected', handleConnection);
|
||||
queueListener = sdk.onStreamData(streamTopic, handleQueueMessageReceived);
|
||||
|
||||
try {
|
||||
const { user } = store.getState().login;
|
||||
RocketChat.getAgentDepartments(user.id).then(result => {
|
||||
|
||||
if (!user.id) {
|
||||
throw new Error('inquiry: @subscribeInquiry user.id not found');
|
||||
}
|
||||
|
||||
RocketChat.getAgentDepartments(user.id).then((result: { success: boolean; departments: ILivechatDepartment[] }) => {
|
||||
if (result.success) {
|
||||
const { departments } = result;
|
||||
|
||||
if (!departments.length || RocketChat.hasRole('livechat-manager')) {
|
||||
RocketChat.subscribe(streamTopic, 'public').catch(e => console.log(e));
|
||||
sdk.subscribe(streamTopic, 'public').catch((e: unknown) => console.log(e));
|
||||
}
|
||||
|
||||
const departmentIds = departments.map(({ departmentId }) => departmentId);
|
||||
departmentIds.forEach(departmentId => {
|
||||
// subscribe to all departments of the agent
|
||||
RocketChat.subscribe(streamTopic, `department/${departmentId}`).catch(e => console.log(e));
|
||||
sdk.subscribe(streamTopic, `department/${departmentId}`).catch((e: unknown) => console.log(e));
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,98 @@
|
|||
import {
|
||||
inquiryFailure,
|
||||
inquiryQueueAdd,
|
||||
inquiryQueueRemove,
|
||||
inquiryQueueUpdate,
|
||||
inquiryReset,
|
||||
inquirySetEnabled,
|
||||
inquirySuccess
|
||||
} from '../actions/inquiry';
|
||||
import { mockedStore } from '../../../reducers/mockedStore';
|
||||
import { initialState } from './inquiry';
|
||||
import { IOmnichannelRoom, OmnichannelSourceType, SubscriptionType } from '../../../definitions';
|
||||
|
||||
describe('test inquiry reduce', () => {
|
||||
const enabledObj = {
|
||||
enabled: true
|
||||
};
|
||||
|
||||
const queued: IOmnichannelRoom = {
|
||||
_id: '_id',
|
||||
rid: 'rid',
|
||||
name: 'Rocket Chat',
|
||||
ts: new Date(),
|
||||
message: 'ola',
|
||||
status: 'queued',
|
||||
v: {
|
||||
_id: 'id-visitor',
|
||||
username: 'guest-24',
|
||||
token: '123456789',
|
||||
status: 'online'
|
||||
},
|
||||
t: SubscriptionType.OMNICHANNEL,
|
||||
queueOrder: '1',
|
||||
estimatedWaitingTimeQueue: '0',
|
||||
estimatedServiceTimeAt: new Date(),
|
||||
source: {
|
||||
type: OmnichannelSourceType.WIDGET,
|
||||
_updatedAt: new Date(),
|
||||
queuedAt: new Date()
|
||||
}
|
||||
};
|
||||
|
||||
const error = 'Error Test';
|
||||
|
||||
it('should return inital state', () => {
|
||||
const state = mockedStore.getState().inquiry;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correct inquiry state after dispatch inquirySetEnabled action', () => {
|
||||
mockedStore.dispatch(inquirySetEnabled(enabledObj.enabled));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual({ ...initialState, ...enabledObj });
|
||||
});
|
||||
|
||||
it('after inquiry state is modified, should return inquiry state as initial state after dispatch inquiryReset action', () => {
|
||||
mockedStore.dispatch(inquiryReset());
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correct inquiry state after dispatch inquiryQueueAdd action', () => {
|
||||
mockedStore.dispatch(inquiryQueueAdd(queued));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual({ ...initialState, queued: [queued] });
|
||||
});
|
||||
|
||||
it('should update correct inquiry state after dispatch inquiryQueueUpdate action', () => {
|
||||
const modifiedQueued: IOmnichannelRoom = { ...queued, message: 'inquiryQueueUpdate' };
|
||||
mockedStore.dispatch(inquiryQueueUpdate(modifiedQueued));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual({ ...initialState, queued: [modifiedQueued] });
|
||||
});
|
||||
|
||||
it('should remove correct from queue in inquiry state after dispatch inquiryQueueRemove action', () => {
|
||||
mockedStore.dispatch(inquiryQueueRemove(queued._id));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correct inquiry state after dispatch inquirySuccess action', () => {
|
||||
mockedStore.dispatch(inquirySuccess([queued]));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual({ ...initialState, queued: [queued] });
|
||||
});
|
||||
|
||||
it('after inquiry state is modified, should return inquiry state as initial state after dispatch inquiryReset action', () => {
|
||||
mockedStore.dispatch(inquiryReset());
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should return correct inquiry state after dispatch inquiryFailure action', () => {
|
||||
mockedStore.dispatch(inquiryFailure(error));
|
||||
const { inquiry } = mockedStore.getState();
|
||||
expect(inquiry).toEqual({ ...initialState, error });
|
||||
});
|
||||
});
|
|
@ -1,12 +1,19 @@
|
|||
import { IOmnichannelRoom, TApplicationActions } from '../../../definitions';
|
||||
import { INQUIRY } from '../../../actions/actionsTypes';
|
||||
|
||||
const initialState = {
|
||||
export interface IInquiry {
|
||||
enabled: boolean;
|
||||
queued: IOmnichannelRoom[];
|
||||
error: any;
|
||||
}
|
||||
|
||||
export const initialState: IInquiry = {
|
||||
enabled: false,
|
||||
queued: [],
|
||||
error: {}
|
||||
};
|
||||
|
||||
export default function inquiry(state = initialState, action) {
|
||||
export default function inquiry(state = initialState, action: TApplicationActions): IInquiry {
|
||||
switch (action.type) {
|
||||
case INQUIRY.SUCCESS:
|
||||
return {
|
|
@ -1,5 +1,7 @@
|
|||
import { createSelector } from 'reselect';
|
||||
|
||||
const getInquiryQueue = state => state.inquiry.queued;
|
||||
import { IApplicationState } from '../../../definitions';
|
||||
|
||||
const getInquiryQueue = (state: IApplicationState) => state.inquiry.queued;
|
||||
|
||||
export const getInquiryQueueSelector = createSelector([getInquiryQueue], queue => queue);
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FlatList } from 'react-native';
|
||||
import { CompositeNavigationProp } from '@react-navigation/native';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { FlatList, ListRenderItem } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
|
||||
|
@ -19,18 +20,50 @@ import * as HeaderButton from '../../../containers/HeaderButton';
|
|||
import RocketChat from '../../../lib/rocketchat';
|
||||
import { events, logEvent } from '../../../utils/log';
|
||||
import { getInquiryQueueSelector } from '../selectors/inquiry';
|
||||
import { IOmnichannelRoom, IApplicationState } from '../../../definitions';
|
||||
import { DisplayMode } from '../../../constants/constantDisplayMode';
|
||||
import { ChatsStackParamList } from '../../../stacks/types';
|
||||
import { MasterDetailInsideStackParamList } from '../../../stacks/MasterDetailStack/types';
|
||||
import { TSettingsValues } from '../../../reducers/settings';
|
||||
|
||||
interface INavigationOptions {
|
||||
isMasterDetail: boolean;
|
||||
navigation: CompositeNavigationProp<
|
||||
StackNavigationProp<ChatsStackParamList, 'QueueListView'>,
|
||||
StackNavigationProp<MasterDetailInsideStackParamList>
|
||||
>;
|
||||
}
|
||||
|
||||
interface IQueueListView extends INavigationOptions {
|
||||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
token: string;
|
||||
};
|
||||
width: number;
|
||||
queued: IOmnichannelRoom[];
|
||||
server: string;
|
||||
useRealName?: TSettingsValues;
|
||||
theme: string;
|
||||
showAvatar: any;
|
||||
displayMode: DisplayMode;
|
||||
}
|
||||
|
||||
const INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12;
|
||||
const getItemLayout = (data, index) => ({
|
||||
const getItemLayout = (data: IOmnichannelRoom[] | null | undefined, index: number) => ({
|
||||
length: ROW_HEIGHT,
|
||||
offset: ROW_HEIGHT * index,
|
||||
index
|
||||
});
|
||||
const keyExtractor = item => item.rid;
|
||||
const keyExtractor = (item: IOmnichannelRoom) => item.rid;
|
||||
|
||||
class QueueListView extends React.Component {
|
||||
static navigationOptions = ({ navigation, isMasterDetail }) => {
|
||||
const options = {
|
||||
class QueueListView extends React.Component<IQueueListView, any> {
|
||||
private getScrollRef?: React.Ref<FlatList<IOmnichannelRoom>>;
|
||||
|
||||
private onEndReached: ((info: { distanceFromEnd: number }) => void) | null | undefined;
|
||||
|
||||
static navigationOptions = ({ navigation, isMasterDetail }: INavigationOptions) => {
|
||||
const options: StackNavigationOptions = {
|
||||
title: I18n.t('Queued_chats')
|
||||
};
|
||||
if (isMasterDetail) {
|
||||
|
@ -39,24 +72,7 @@ class QueueListView extends React.Component {
|
|||
return options;
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
username: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
}),
|
||||
isMasterDetail: PropTypes.bool,
|
||||
width: PropTypes.number,
|
||||
queued: PropTypes.array,
|
||||
server: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
navigation: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
showAvatar: PropTypes.bool,
|
||||
displayMode: PropTypes.string
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: IQueueListView) {
|
||||
const { queued } = this.props;
|
||||
if (!dequal(nextProps.queued, queued)) {
|
||||
return true;
|
||||
|
@ -65,7 +81,7 @@ class QueueListView extends React.Component {
|
|||
return false;
|
||||
}
|
||||
|
||||
onPressItem = (item = {}) => {
|
||||
onPressItem = (item = {} as IOmnichannelRoom) => {
|
||||
logEvent(events.QL_GO_ROOM);
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
|
@ -84,13 +100,13 @@ class QueueListView extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
getRoomTitle = item => RocketChat.getRoomTitle(item);
|
||||
getRoomTitle = (item: IOmnichannelRoom) => RocketChat.getRoomTitle(item);
|
||||
|
||||
getRoomAvatar = item => RocketChat.getRoomAvatar(item);
|
||||
getRoomAvatar = (item: IOmnichannelRoom) => RocketChat.getRoomAvatar(item);
|
||||
|
||||
getUidDirectMessage = room => RocketChat.getUidDirectMessage(room);
|
||||
getUidDirectMessage = (room: IOmnichannelRoom) => RocketChat.getUidDirectMessage(room);
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
renderItem: ListRenderItem<IOmnichannelRoom> = ({ item }) => {
|
||||
const {
|
||||
user: { id: userId, username, token },
|
||||
server,
|
||||
|
@ -152,7 +168,7 @@ class QueueListView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
server: state.server.server,
|
|
@ -4,7 +4,10 @@ import { MESSAGES_TABLE } from '../model/Message';
|
|||
|
||||
const getCollection = (db: TAppDatabase) => db.get(MESSAGES_TABLE);
|
||||
|
||||
export const getMessageById = async (messageId: string) => {
|
||||
export const getMessageById = async (messageId: string | null) => {
|
||||
if (!messageId) {
|
||||
return null;
|
||||
}
|
||||
const db = database.active;
|
||||
const messageCollection = getCollection(db);
|
||||
try {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { ILastMessage, IMessage, IThreadResult } from '../../../definitions';
|
|||
import messagesStatus from '../../../constants/messagesStatus';
|
||||
import normalizeMessage from './normalizeMessage';
|
||||
|
||||
export default (message: Partial<IMessage> | IThreadResult | ILastMessage): IMessage | IThreadResult => {
|
||||
export default (message: Partial<IMessage> | IThreadResult | ILastMessage): IMessage | IThreadResult | null => {
|
||||
message.status = messagesStatus.SENT;
|
||||
return normalizeMessage(message);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import moment from 'moment';
|
||||
|
||||
import parseUrls from './parseUrls';
|
||||
import type { IAttachment, IMessage, IThreadResult } from '../../../definitions';
|
||||
|
||||
function normalizeAttachments(msg) {
|
||||
type TMsg = IMessage & IAttachment;
|
||||
|
||||
function normalizeAttachments(msg: TMsg) {
|
||||
if (typeof msg.attachments !== typeof [] || !msg.attachments || !msg.attachments.length) {
|
||||
msg.attachments = [];
|
||||
}
|
||||
|
@ -11,17 +14,17 @@ function normalizeAttachments(msg) {
|
|||
if (att.ts) {
|
||||
att.ts = moment(att.ts).toDate();
|
||||
}
|
||||
att = normalizeAttachments(att);
|
||||
att = normalizeAttachments(att as TMsg);
|
||||
return att;
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
export default msg => {
|
||||
export default (msg: any): IMessage | IThreadResult | null => {
|
||||
if (!msg) {
|
||||
return null;
|
||||
}
|
||||
msg = normalizeAttachments(msg);
|
||||
msg = normalizeAttachments(msg as TMsg);
|
||||
msg.reactions = msg.reactions || [];
|
||||
msg.unread = msg.unread || false;
|
||||
// TODO: api problems
|
||||
|
@ -30,18 +33,19 @@ export default msg => {
|
|||
// } else {
|
||||
// msg.reactions = Object.keys(msg.reactions).map(key => ({ emoji: key, usernames: msg.reactions[key].usernames.map(username => ({ value: username })) }));
|
||||
// }
|
||||
|
||||
if (!Array.isArray(msg.reactions)) {
|
||||
msg.reactions = Object.keys(msg.reactions).map(key => ({
|
||||
_id: `${msg._id}${key}`,
|
||||
emoji: key,
|
||||
usernames: msg.reactions[key].usernames
|
||||
usernames: msg.reactions ? msg.reactions[key].usernames : []
|
||||
}));
|
||||
}
|
||||
if (msg.translations && Object.keys(msg.translations).length) {
|
||||
msg.translations = Object.keys(msg.translations).map(key => ({
|
||||
_id: `${msg._id}${key}`,
|
||||
language: key,
|
||||
value: msg.translations[key]
|
||||
value: msg.translations ? msg.translations[key] : ''
|
||||
}));
|
||||
msg.autoTranslate = true;
|
||||
}
|
|
@ -7,7 +7,7 @@ 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 { E2EType, IMessage, IUser, TMessageModel } from '../../definitions';
|
||||
import sdk from '../rocketchat/services/sdk';
|
||||
|
||||
const changeMessageStatus = async (id: string, status: number, tmid?: string, message?: IMessage) => {
|
||||
|
@ -145,7 +145,7 @@ export default async function (
|
|||
tm.u = tMessageRecord.u;
|
||||
tm.t = message.t;
|
||||
if (message.t === E2E_MESSAGE_TYPE) {
|
||||
tm.e2e = E2E_STATUS.DONE;
|
||||
tm.e2e = E2E_STATUS.DONE as E2EType;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -170,7 +170,7 @@ export default async function (
|
|||
};
|
||||
tm.t = message.t;
|
||||
if (message.t === E2E_MESSAGE_TYPE) {
|
||||
tm.e2e = E2E_STATUS.DONE;
|
||||
tm.e2e = E2E_STATUS.DONE as E2EType;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -203,7 +203,7 @@ export default async function (
|
|||
}
|
||||
m.t = message.t;
|
||||
if (message.t === E2E_MESSAGE_TYPE) {
|
||||
m.e2e = E2E_STATUS.DONE;
|
||||
m.e2e = E2E_STATUS.DONE as E2EType;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -195,7 +195,10 @@ const createOrUpdateSubscription = async (subscription: ISubscription, room: IRo
|
|||
if (tmp.lastMessage && !rooms.includes(tmp.rid)) {
|
||||
const lastMessage = buildMessage(tmp.lastMessage);
|
||||
const messagesCollection = db.get('messages');
|
||||
const messageRecord = await getMessageById(lastMessage._id);
|
||||
let messageRecord = {} as TMessageModel | null;
|
||||
if (lastMessage) {
|
||||
messageRecord = await getMessageById(lastMessage._id);
|
||||
}
|
||||
|
||||
if (messageRecord) {
|
||||
batch.push(
|
||||
|
@ -206,10 +209,12 @@ const createOrUpdateSubscription = async (subscription: ISubscription, room: IRo
|
|||
} else {
|
||||
batch.push(
|
||||
messagesCollection.prepareCreate(m => {
|
||||
if (lastMessage) {
|
||||
m._raw = sanitizedRaw({ id: lastMessage._id }, messagesCollection.schema);
|
||||
if (m.subscription) {
|
||||
m.subscription.id = lastMessage.rid;
|
||||
}
|
||||
}
|
||||
return Object.assign(m, lastMessage);
|
||||
})
|
||||
);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import { sanitizeLikeString } from '../../database/utils';
|
||||
import database from '../../database/index';
|
||||
import { spotlight } from '../services/restApi';
|
||||
import isGroupChat from './isGroupChat';
|
||||
import { ISearch, ISearchLocal, SubscriptionType } from '../../../definitions';
|
||||
|
||||
let debounce: null | ((reason: string) => void) = null;
|
||||
|
||||
export const localSearch = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<(ISearch | ISearchLocal)[]> => {
|
||||
const searchText = text.trim();
|
||||
const db = database.active;
|
||||
const likeString = sanitizeLikeString(searchText);
|
||||
let subscriptions = await db
|
||||
.get('subscriptions')
|
||||
.query(
|
||||
Q.or(Q.where('name', Q.like(`%${likeString}%`)), Q.where('fname', Q.like(`%${likeString}%`))),
|
||||
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||
)
|
||||
.fetch();
|
||||
|
||||
if (filterUsers && !filterRooms) {
|
||||
subscriptions = subscriptions.filter(item => item.t === 'd' && !isGroupChat(item));
|
||||
} else if (!filterUsers && filterRooms) {
|
||||
subscriptions = subscriptions.filter(item => item.t !== 'd' || isGroupChat(item));
|
||||
}
|
||||
|
||||
const sliceSubscriptions = subscriptions.slice(0, 7);
|
||||
|
||||
const search = sliceSubscriptions.map(sub => ({
|
||||
rid: sub.rid,
|
||||
name: sub.name,
|
||||
fname: sub?.fname || '',
|
||||
avatarETag: sub?.avatarETag || '',
|
||||
t: sub.t,
|
||||
encrypted: sub?.encrypted || null,
|
||||
lastMessage: sub.lastMessage,
|
||||
...(sub.teamId && { teamId: sub.teamId })
|
||||
})) as (ISearch | ISearchLocal)[];
|
||||
|
||||
return search;
|
||||
};
|
||||
|
||||
export const search = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<(ISearch | ISearchLocal)[]> => {
|
||||
const searchText = text.trim();
|
||||
|
||||
if (debounce) {
|
||||
debounce('cancel');
|
||||
}
|
||||
|
||||
const localSearchData = await localSearch({ text, filterUsers, filterRooms });
|
||||
const usernames = localSearchData.map(sub => sub.name);
|
||||
|
||||
const data = localSearchData as (ISearch | ISearchLocal)[];
|
||||
|
||||
try {
|
||||
if (localSearchData.length < 7) {
|
||||
const { users, rooms } = (await Promise.race([
|
||||
spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }),
|
||||
new Promise((resolve, reject) => (debounce = reject))
|
||||
])) as { users: ISearch[]; rooms: ISearch[] };
|
||||
|
||||
if (filterUsers) {
|
||||
users
|
||||
.filter((item1, index) => users.findIndex(item2 => item2._id === item1._id) === index) // Remove duplicated data from response
|
||||
.filter(user => !data.some(sub => user.username === sub.name)) // Make sure to remove users already on local database
|
||||
.forEach(user => {
|
||||
data.push({
|
||||
...user,
|
||||
rid: user.username,
|
||||
name: user.username,
|
||||
t: SubscriptionType.DIRECT,
|
||||
search: true
|
||||
});
|
||||
});
|
||||
}
|
||||
if (filterRooms) {
|
||||
rooms.forEach(room => {
|
||||
// Check if it exists on local database
|
||||
const index = data.findIndex(item => item.rid === room._id);
|
||||
if (index === -1) {
|
||||
data.push({
|
||||
...room,
|
||||
rid: room._id,
|
||||
search: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
debounce = null;
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
return data;
|
||||
}
|
||||
};
|
|
@ -50,6 +50,7 @@ import getRoom from './methods/getRoom';
|
|||
import isGroupChat from './methods/isGroupChat';
|
||||
import roomTypeToApiType from './methods/roomTypeToApiType';
|
||||
import getUserInfo from './services/getUserInfo';
|
||||
import * as search from './methods/search';
|
||||
// Services
|
||||
import sdk from './services/sdk';
|
||||
import toggleFavorite from './services/toggleFavorite';
|
||||
|
@ -85,6 +86,7 @@ const RocketChat = {
|
|||
CURRENT_SERVER,
|
||||
CERTIFICATE_KEY,
|
||||
...restAPis,
|
||||
...search,
|
||||
callJitsi,
|
||||
callJitsiWithoutServer,
|
||||
async subscribeRooms() {
|
||||
|
@ -252,93 +254,6 @@ const RocketChat = {
|
|||
getRooms,
|
||||
readMessages,
|
||||
resendMessage,
|
||||
|
||||
async localSearch({ text, filterUsers = true, filterRooms = true }) {
|
||||
const searchText = text.trim();
|
||||
const db = database.active;
|
||||
const likeString = sanitizeLikeString(searchText);
|
||||
let data = await db
|
||||
.get('subscriptions')
|
||||
.query(
|
||||
Q.or(Q.where('name', Q.like(`%${likeString}%`)), Q.where('fname', Q.like(`%${likeString}%`))),
|
||||
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||
)
|
||||
.fetch();
|
||||
|
||||
if (filterUsers && !filterRooms) {
|
||||
data = data.filter(item => item.t === 'd' && !RocketChat.isGroupChat(item));
|
||||
} else if (!filterUsers && filterRooms) {
|
||||
data = data.filter(item => item.t !== 'd' || RocketChat.isGroupChat(item));
|
||||
}
|
||||
|
||||
data = data.slice(0, 7);
|
||||
|
||||
data = data.map(sub => ({
|
||||
rid: sub.rid,
|
||||
name: sub.name,
|
||||
fname: sub.fname,
|
||||
avatarETag: sub.avatarETag,
|
||||
t: sub.t,
|
||||
encrypted: sub.encrypted,
|
||||
lastMessage: sub.lastMessage,
|
||||
...(sub.teamId && { teamId: sub.teamId })
|
||||
}));
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
async search({ text, filterUsers = true, filterRooms = true }) {
|
||||
const searchText = text.trim();
|
||||
|
||||
if (this.oldPromise) {
|
||||
this.oldPromise('cancel');
|
||||
}
|
||||
|
||||
const data = await this.localSearch({ text, filterUsers, filterRooms });
|
||||
|
||||
const usernames = data.map(sub => sub.name);
|
||||
try {
|
||||
if (data.length < 7) {
|
||||
const { users, rooms } = await Promise.race([
|
||||
RocketChat.spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }),
|
||||
new Promise((resolve, reject) => (this.oldPromise = reject))
|
||||
]);
|
||||
if (filterUsers) {
|
||||
users
|
||||
.filter((item1, index) => users.findIndex(item2 => item2._id === item1._id) === index) // Remove duplicated data from response
|
||||
.filter(user => !data.some(sub => user.username === sub.name)) // Make sure to remove users already on local database
|
||||
.forEach(user => {
|
||||
data.push({
|
||||
...user,
|
||||
rid: user.username,
|
||||
name: user.username,
|
||||
t: 'd',
|
||||
search: true
|
||||
});
|
||||
});
|
||||
}
|
||||
if (filterRooms) {
|
||||
rooms.forEach(room => {
|
||||
// Check if it exists on local database
|
||||
const index = data.findIndex(item => item.rid === room._id);
|
||||
if (index === -1) {
|
||||
data.push({
|
||||
rid: room._id,
|
||||
...room,
|
||||
search: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
delete this.oldPromise;
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
return data;
|
||||
// return [];
|
||||
}
|
||||
},
|
||||
createGroupChat() {
|
||||
const { users } = reduxStore.getState().selectedUsers;
|
||||
const usernames = users.map(u => u.name).join(',');
|
||||
|
|
|
@ -2,6 +2,7 @@ import sdk from './sdk';
|
|||
import { TEAM_TYPE } from '../../../definitions/ITeam';
|
||||
import roomTypeToApiType, { RoomTypes } from '../methods/roomTypeToApiType';
|
||||
import { SubscriptionType, INotificationPreferences } from '../../../definitions';
|
||||
import { ISpotlight } from '../../../definitions/ISpotlight';
|
||||
|
||||
export const createChannel = ({
|
||||
name,
|
||||
|
@ -53,14 +54,12 @@ export const e2eUpdateGroupKey = (uid: string, rid: string, key: string): any =>
|
|||
// RC 0.70.0
|
||||
sdk.post('e2e.updateGroupKey', { uid, rid, key });
|
||||
|
||||
export const e2eRequestRoomKey = (rid: string, e2eKeyId: string) =>
|
||||
export const e2eRequestRoomKey = (rid: string, e2eKeyId: string): Promise<{ message: { msg?: string }; success: boolean }> =>
|
||||
// RC 0.70.0
|
||||
sdk.methodCallWrapper('stream-notify-room-users', `${rid}/e2ekeyRequest`, rid, e2eKeyId);
|
||||
|
||||
export const updateJitsiTimeout = (roomId: string): any =>
|
||||
export const updateJitsiTimeout = (roomId: string) =>
|
||||
// RC 0.74.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post('video-conference/jitsi.update-timeout', { roomId });
|
||||
|
||||
export const register = (credentials: { name: string; email: string; pass: string; username: string }) =>
|
||||
|
@ -74,7 +73,7 @@ export const forgotPassword = (email: string) =>
|
|||
export const sendConfirmationEmail = (email: string): Promise<{ message: string; success: boolean }> =>
|
||||
sdk.methodCallWrapper('sendConfirmationEmail', email);
|
||||
|
||||
export const spotlight = (search: string, usernames: string, type: { users: boolean; rooms: boolean }) =>
|
||||
export const spotlight = (search: string, usernames: string[], type: { users: boolean; rooms: boolean }): Promise<ISpotlight> =>
|
||||
// RC 0.51.0
|
||||
sdk.methodCallWrapper('spotlight', search, usernames, type);
|
||||
|
||||
|
@ -222,14 +221,11 @@ export const convertTeamToChannel = ({ teamId, selected }: { teamId: string; sel
|
|||
return sdk.post('teams.convertToChannel', params);
|
||||
};
|
||||
|
||||
export const joinRoom = (roomId: string, joinCode: string | null, type: 'c' | 'p'): any => {
|
||||
// TODO: join code
|
||||
export const joinRoom = (roomId: string, joinCode: string | null, type: 'c' | 'p') => {
|
||||
// RC 0.48.0
|
||||
if (type === 'p') {
|
||||
return sdk.methodCallWrapper('joinRoom', roomId);
|
||||
return sdk.methodCallWrapper('joinRoom', roomId) as Promise<boolean>;
|
||||
}
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post('channels.join', { roomId, joinCode });
|
||||
};
|
||||
|
||||
|
@ -241,52 +237,38 @@ export const markAsUnread = ({ messageId }: { messageId: string }) =>
|
|||
// RC 0.65.0
|
||||
sdk.post('subscriptions.unread', { firstUnreadMessage: { _id: messageId } });
|
||||
|
||||
export const toggleStarMessage = (messageId: string, starred: boolean): any => {
|
||||
export const toggleStarMessage = (messageId: string, starred: boolean) => {
|
||||
if (starred) {
|
||||
// RC 0.59.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post('chat.unStarMessage', { messageId });
|
||||
}
|
||||
// RC 0.59.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post('chat.starMessage', { messageId });
|
||||
};
|
||||
|
||||
export const togglePinMessage = (messageId: string, pinned: boolean): any => {
|
||||
export const togglePinMessage = (messageId: string, pinned: boolean) => {
|
||||
if (pinned) {
|
||||
// RC 0.59.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post('chat.unPinMessage', { messageId });
|
||||
}
|
||||
// RC 0.59.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post('chat.pinMessage', { messageId });
|
||||
};
|
||||
|
||||
export const reportMessage = (messageId: string): any =>
|
||||
export const reportMessage = (messageId: string) =>
|
||||
// RC 0.64.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post('chat.reportMessage', { messageId, description: 'Message reported by user' });
|
||||
|
||||
export const setUserPreferences = (userId: string, data: Partial<INotificationPreferences>) =>
|
||||
// RC 0.62.0
|
||||
sdk.post('users.setPreferences', { userId, data });
|
||||
|
||||
export const setUserStatus = (status?: string, message?: string): any =>
|
||||
export const setUserStatus = (status: string, message: string) =>
|
||||
// RC 1.2.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post('users.setStatus', { status, message });
|
||||
|
||||
export const setReaction = (emoji: string, messageId: string): any =>
|
||||
export const setReaction = (emoji: string, messageId: string) =>
|
||||
// RC 0.62.2
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post('chat.react', { emoji, messageId });
|
||||
|
||||
export const toggleRead = (read: boolean, roomId: string) => {
|
||||
|
@ -296,20 +278,15 @@ export const toggleRead = (read: boolean, roomId: string) => {
|
|||
return sdk.post('subscriptions.read', { rid: roomId });
|
||||
};
|
||||
|
||||
export const getUserRoles = () =>
|
||||
// RC 0.27.0
|
||||
sdk.methodCallWrapper('getUserRoles');
|
||||
|
||||
export const getRoomCounters = (roomId: string, t: RoomTypes): any =>
|
||||
export const getRoomCounters = (
|
||||
roomId: string,
|
||||
t: SubscriptionType.CHANNEL | SubscriptionType.GROUP | SubscriptionType.OMNICHANNEL
|
||||
) =>
|
||||
// RC 0.65.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.get(`${roomTypeToApiType(t)}.counters`, { roomId });
|
||||
|
||||
export const getChannelInfo = (roomId: string): any =>
|
||||
export const getChannelInfo = (roomId: string) =>
|
||||
// RC 0.48.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.get('channels.info', { roomId });
|
||||
|
||||
export const getUserPreferences = (userId: string): any =>
|
||||
|
@ -367,7 +344,7 @@ export const editLivechat = (userData: any, roomData: any) =>
|
|||
// RC 0.55.0
|
||||
sdk.methodCallWrapper('livechat:saveInfo', userData, roomData);
|
||||
|
||||
export const returnLivechat = (rid: string) =>
|
||||
export const returnLivechat = (rid: string): Promise<boolean> =>
|
||||
// RC 0.72.0
|
||||
sdk.methodCallWrapper('livechat:returnAsInquiry', rid);
|
||||
|
||||
|
@ -408,7 +385,13 @@ export const getRoutingConfig = (): Promise<{
|
|||
// RC 2.0.0
|
||||
sdk.methodCallWrapper('livechat:getRoutingConfig');
|
||||
|
||||
export const getTagsList = () =>
|
||||
export const getTagsList = (): Promise<
|
||||
{
|
||||
_id: string;
|
||||
name: string;
|
||||
departments: string[];
|
||||
}[]
|
||||
> =>
|
||||
// RC 2.0.0
|
||||
sdk.methodCallWrapper('livechat:getTagsList');
|
||||
|
||||
|
@ -422,7 +405,7 @@ export const getCustomFields = () =>
|
|||
// RC 2.2.0
|
||||
sdk.get('livechat/custom-fields');
|
||||
|
||||
export const getListCannedResponse = ({ scope = '', departmentId = '', offset = 0, count = 25, text = '' }): any => {
|
||||
export const getListCannedResponse = ({ scope = '', departmentId = '', offset = 0, count = 25, text = '' }) => {
|
||||
const params = {
|
||||
offset,
|
||||
count,
|
||||
|
@ -432,8 +415,6 @@ export const getListCannedResponse = ({ scope = '', departmentId = '', offset =
|
|||
};
|
||||
|
||||
// RC 3.17.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.get('canned-responses', params);
|
||||
};
|
||||
|
||||
|
@ -446,19 +427,19 @@ export const toggleBlockUser = (rid: string, blocked: string, block: boolean): P
|
|||
return sdk.methodCallWrapper('unblockUser', { rid, blocked });
|
||||
};
|
||||
|
||||
export const leaveRoom = (roomId: string, t: RoomTypes): any =>
|
||||
export const leaveRoom = (roomId: string, t: RoomTypes) =>
|
||||
// RC 0.48.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post(`${roomTypeToApiType(t)}.leave`, { roomId });
|
||||
|
||||
export const deleteRoom = (roomId: string, t: RoomTypes): any =>
|
||||
export const deleteRoom = (roomId: string, t: RoomTypes) =>
|
||||
// RC 0.49.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post(`${roomTypeToApiType(t)}.delete`, { roomId });
|
||||
|
||||
export const toggleMuteUserInRoom = (rid: string, username: string, mute: boolean) => {
|
||||
export const toggleMuteUserInRoom = (
|
||||
rid: string,
|
||||
username: string,
|
||||
mute: boolean
|
||||
): Promise<{ message: { msg: string; result: boolean }; success: boolean }> => {
|
||||
if (mute) {
|
||||
// RC 0.51.0
|
||||
return sdk.methodCallWrapper('muteUserInRoom', { rid, username });
|
||||
|
@ -477,17 +458,14 @@ export const toggleRoomOwner = ({
|
|||
t: SubscriptionType;
|
||||
userId: string;
|
||||
isOwner: boolean;
|
||||
}): any => {
|
||||
}) => {
|
||||
const type = t as SubscriptionType.CHANNEL;
|
||||
if (isOwner) {
|
||||
// RC 0.49.4
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.addOwner`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.addOwner`, { roomId, userId });
|
||||
}
|
||||
// RC 0.49.4
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.removeOwner`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.removeOwner`, { roomId, userId });
|
||||
};
|
||||
|
||||
export const toggleRoomLeader = ({
|
||||
|
@ -500,17 +478,14 @@ export const toggleRoomLeader = ({
|
|||
t: SubscriptionType;
|
||||
userId: string;
|
||||
isLeader: boolean;
|
||||
}): any => {
|
||||
}) => {
|
||||
const type = t as SubscriptionType.CHANNEL;
|
||||
if (isLeader) {
|
||||
// RC 0.58.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.addLeader`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.addLeader`, { roomId, userId });
|
||||
}
|
||||
// RC 0.58.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.removeLeader`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.removeLeader`, { roomId, userId });
|
||||
};
|
||||
|
||||
export const toggleRoomModerator = ({
|
||||
|
@ -523,29 +498,22 @@ export const toggleRoomModerator = ({
|
|||
t: SubscriptionType;
|
||||
userId: string;
|
||||
isModerator: boolean;
|
||||
}): any => {
|
||||
}) => {
|
||||
const type = t as SubscriptionType.CHANNEL;
|
||||
if (isModerator) {
|
||||
// RC 0.49.4
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.addModerator`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.addModerator`, { roomId, userId });
|
||||
}
|
||||
// RC 0.49.4
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
return sdk.post(`${roomTypeToApiType(t)}.removeModerator`, { roomId, userId });
|
||||
return sdk.post(`${roomTypeToApiType(type)}.removeModerator`, { roomId, userId });
|
||||
};
|
||||
|
||||
export const removeUserFromRoom = ({ roomId, t, userId }: { roomId: string; t: SubscriptionType; userId: string }): any =>
|
||||
export const removeUserFromRoom = ({ roomId, t, userId }: { roomId: string; t: RoomTypes; userId: string }) =>
|
||||
// RC 0.48.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post(`${roomTypeToApiType(t)}.kick`, { roomId, userId });
|
||||
|
||||
export const ignoreUser = ({ rid, userId, ignore }: { rid: string; userId: string; ignore: boolean }): any =>
|
||||
export const ignoreUser = ({ rid, userId, ignore }: { rid: string; userId: string; ignore: boolean }) =>
|
||||
// RC 0.64.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.get('chat.ignoreUser', { rid, userId, ignore });
|
||||
|
||||
export const toggleArchiveRoom = (roomId: string, t: SubscriptionType, archive: boolean) => {
|
||||
|
@ -558,10 +526,8 @@ export const toggleArchiveRoom = (roomId: string, t: SubscriptionType, archive:
|
|||
return sdk.post(`${roomTypeToApiType(type)}.unarchive`, { roomId });
|
||||
};
|
||||
|
||||
export const hideRoom = (roomId: string, t: RoomTypes): any =>
|
||||
export const hideRoom = (roomId: string, t: RoomTypes) =>
|
||||
// RC 0.48.0
|
||||
// TODO: missing definitions from server
|
||||
// @ts-ignore
|
||||
sdk.post(`${roomTypeToApiType(t)}.close`, { roomId });
|
||||
|
||||
export const saveRoomSettings = (
|
||||
|
|
|
@ -33,8 +33,7 @@ const Wrapper = ({ accessibilityLabel, theme, children, displayMode, ...props }:
|
|||
styles.centerContainer,
|
||||
{
|
||||
borderColor: themes[theme].separatorColor
|
||||
},
|
||||
displayMode === DisplayMode.Condensed && styles.condensedPaddingVertical
|
||||
}
|
||||
]}>
|
||||
{children}
|
||||
</View>
|
||||
|
|
|
@ -21,9 +21,6 @@ export default StyleSheet.create<any>({
|
|||
containerCondensed: {
|
||||
height: ROW_HEIGHT_CONDENSED
|
||||
},
|
||||
condensedPaddingVertical: {
|
||||
paddingVertical: 20
|
||||
},
|
||||
centerContainer: {
|
||||
flex: 1,
|
||||
paddingVertical: 10,
|
||||
|
@ -33,7 +30,6 @@ export default StyleSheet.create<any>({
|
|||
title: {
|
||||
flex: 1,
|
||||
fontSize: 17,
|
||||
lineHeight: 20,
|
||||
...sharedStyles.textMedium
|
||||
},
|
||||
alert: {
|
||||
|
@ -67,7 +63,6 @@ export default StyleSheet.create<any>({
|
|||
markdownText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
lineHeight: 17,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
avatar: {
|
||||
|
|
|
@ -47,15 +47,6 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
|
|||
}
|
||||
}
|
||||
|
||||
// Force fetch all subscriptions to update columns related to Teams feature
|
||||
// TODO: remove it a couple of releases
|
||||
const teamsMigrationKey = `${server}_TEAMS_MIGRATION`;
|
||||
const teamsMigration = yield UserPreferences.getBoolAsync(teamsMigrationKey);
|
||||
if (!teamsMigration) {
|
||||
roomsUpdatedAt = null;
|
||||
UserPreferences.setBoolAsync(teamsMigrationKey, true);
|
||||
}
|
||||
|
||||
const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt);
|
||||
const subscriptions = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||
const db = database.active;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import Navigation from '../lib/Navigation';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { ISubscription, IVisitor, SubscriptionType, TSubscriptionModel } from '../definitions/ISubscription';
|
||||
import { IOmnichannelRoom, SubscriptionType, IVisitor, TSubscriptionModel, ISubscription } from '../definitions';
|
||||
|
||||
interface IGoRoomItem {
|
||||
search?: boolean; // comes from spotlight
|
||||
|
@ -13,7 +13,7 @@ interface IGoRoomItem {
|
|||
visitor?: IVisitor;
|
||||
}
|
||||
|
||||
export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription;
|
||||
export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription | IOmnichannelRoomVisitor;
|
||||
|
||||
const navigate = ({
|
||||
item,
|
||||
|
@ -42,6 +42,11 @@ const navigate = ({
|
|||
});
|
||||
};
|
||||
|
||||
interface IOmnichannelRoomVisitor extends IOmnichannelRoom {
|
||||
// this visitor came from ee/omnichannel/views/QueueListView
|
||||
visitor: IVisitor;
|
||||
}
|
||||
|
||||
export const goRoom = async ({
|
||||
item,
|
||||
isMasterDetail = false,
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import debounce from '../../utils/debounce';
|
||||
import { avatarURL } from '../../utils/avatar';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import I18n from '../../i18n';
|
||||
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
|
||||
import { themes } from '../../constants/colors';
|
||||
import { TSubscriptionModel } from '../../definitions/ISubscription';
|
||||
import styles from './styles';
|
||||
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
|
||||
import { ISearchLocal } from '../../definitions';
|
||||
import I18n from '../../i18n';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
import { avatarURL } from '../../utils/avatar';
|
||||
import debounce from '../../utils/debounce';
|
||||
import { ICreateDiscussionViewSelectChannel } from './interfaces';
|
||||
import styles from './styles';
|
||||
|
||||
const SelectChannel = ({
|
||||
server,
|
||||
|
@ -21,7 +21,7 @@ const SelectChannel = ({
|
|||
serverVersion,
|
||||
theme
|
||||
}: ICreateDiscussionViewSelectChannel): JSX.Element => {
|
||||
const [channels, setChannels] = useState<TSubscriptionModel[]>([]);
|
||||
const [channels, setChannels] = useState<ISearchLocal[]>([]);
|
||||
|
||||
const getChannels = debounce(async (keyword = '') => {
|
||||
try {
|
||||
|
|
|
@ -20,10 +20,6 @@ const styles = StyleSheet.create({
|
|||
padding: 16
|
||||
}
|
||||
});
|
||||
interface IUser {
|
||||
username: string;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
interface IParsedData {
|
||||
label: string;
|
||||
|
@ -47,7 +43,7 @@ const ForwardLivechatView = ({ navigation, route, theme }: IBaseScreen<ChatsStac
|
|||
try {
|
||||
const result = await RocketChat.getDepartments({ count: COUNT_DEPARTMENT, text, offset });
|
||||
if (result.success) {
|
||||
const parsedDepartments: IParsedData[] = result.departments.map(department => ({
|
||||
const parsedDepartments = result.departments.map(department => ({
|
||||
label: department.name,
|
||||
value: department._id
|
||||
}));
|
||||
|
@ -71,7 +67,7 @@ const ForwardLivechatView = ({ navigation, route, theme }: IBaseScreen<ChatsStac
|
|||
term
|
||||
});
|
||||
if (result.success) {
|
||||
const parsedUsers = result.items.map((user: IUser) => ({ label: user.username, value: user._id }));
|
||||
const parsedUsers = result.items.map(user => ({ label: user.username, value: user._id }));
|
||||
if (!term) {
|
||||
setUsers(parsedUsers);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import Button from '../containers/Button';
|
|||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import { MultiSelect } from '../containers/UIKit/MultiSelect';
|
||||
import { ILivechatVisitor } from '../definitions/ILivechatVisitor';
|
||||
import { ITagsOmnichannel } from '../definitions/ITagsOmnichannel';
|
||||
import { IApplicationState, ISubscription } from '../definitions';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import sharedStyles from './Styles';
|
||||
|
@ -48,12 +47,6 @@ interface ITitle {
|
|||
theme: string;
|
||||
}
|
||||
|
||||
interface IField {
|
||||
_id: string;
|
||||
visibility: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
interface IInputs {
|
||||
livechatData: {
|
||||
[key: string]: any;
|
||||
|
@ -116,17 +109,17 @@ const LivechatEditView = ({
|
|||
const visitor = route.params?.roomUser ?? {};
|
||||
|
||||
const getCustomFields = async () => {
|
||||
const result: any = await RocketChat.getCustomFields();
|
||||
const result = await RocketChat.getCustomFields();
|
||||
if (result.success && result.customFields?.length) {
|
||||
const visitorCustomFields = result.customFields
|
||||
.filter((field: IField) => field.visibility !== 'hidden' && field.scope === 'visitor')
|
||||
.map((field: IField) => ({ [field._id]: (visitor.livechatData && visitor.livechatData[field._id]) || '' }))
|
||||
.reduce((ret: IField, field: IField) => ({ ...field, ...ret }));
|
||||
.filter(field => field.visibility !== 'hidden' && field.scope === 'visitor')
|
||||
.map(field => ({ [field._id]: (visitor.livechatData && visitor.livechatData[field._id]) || '' }))
|
||||
.reduce((ret, field) => ({ ...field, ...ret }), {});
|
||||
|
||||
const livechatCustomFields = result.customFields
|
||||
.filter((field: IField) => field.visibility !== 'hidden' && field.scope === 'room')
|
||||
.map((field: IField) => ({ [field._id]: (livechat.livechatData && livechat.livechatData[field._id]) || '' }))
|
||||
.reduce((ret: IField, field: IField) => ({ ...field, ...ret }));
|
||||
.filter(field => field.visibility !== 'hidden' && field.scope === 'room')
|
||||
.map(field => ({ [field._id]: (livechat.livechatData && livechat.livechatData[field._id]) || '' }))
|
||||
.reduce((ret, field) => ({ ...field, ...ret }), {});
|
||||
|
||||
return setCustomFields({ visitor: visitorCustomFields, livechat: livechatCustomFields });
|
||||
}
|
||||
|
@ -142,7 +135,7 @@ const LivechatEditView = ({
|
|||
}, [availableUserTags]);
|
||||
|
||||
const getTagsList = async (agentDepartments: string[]) => {
|
||||
const tags: ITagsOmnichannel[] = await RocketChat.getTagsList();
|
||||
const tags = await RocketChat.getTagsList();
|
||||
const isAdmin = ['admin', 'livechat-manager'].find(role => user.roles.includes(role));
|
||||
const availableTags = tags
|
||||
.filter(({ departments }) => isAdmin || departments.length === 0 || departments.some(i => agentDepartments.indexOf(i) > -1))
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as List from '../containers/List';
|
|||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import SearchBox from '../containers/SearchBox';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { IApplicationState, IBaseScreen, TSubscriptionModel } from '../definitions';
|
||||
import { IApplicationState, IBaseScreen, ISearch, TSubscriptionModel } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import database from '../lib/database';
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
|
@ -55,18 +55,6 @@ interface IButton {
|
|||
first?: boolean;
|
||||
}
|
||||
|
||||
interface ISearch {
|
||||
_id: string;
|
||||
status: string;
|
||||
username: string;
|
||||
avatarETag: string;
|
||||
outside: boolean;
|
||||
rid: string;
|
||||
name: string;
|
||||
t: string;
|
||||
search: boolean;
|
||||
}
|
||||
|
||||
interface INewMessageViewState {
|
||||
search: (ISearch | TSubscriptionModel)[];
|
||||
chats: TSubscriptionModel[];
|
||||
|
@ -149,7 +137,7 @@ class NewMessageView extends React.Component<INewMessageViewProps, INewMessageVi
|
|||
};
|
||||
|
||||
search = async (text: string) => {
|
||||
const result: ISearch[] | TSubscriptionModel[] = await RocketChat.search({ text, filterRooms: false });
|
||||
const result = (await RocketChat.search({ text, filterRooms: false })) as ISearch[];
|
||||
this.setState({
|
||||
search: result
|
||||
});
|
||||
|
@ -313,7 +301,7 @@ class NewMessageView extends React.Component<INewMessageViewProps, INewMessageVi
|
|||
<FlatList
|
||||
data={search.length > 0 ? search : chats}
|
||||
extraData={this.state}
|
||||
keyExtractor={item => item._id}
|
||||
keyExtractor={item => item._id || item.rid}
|
||||
ListHeaderComponent={this.renderHeader}
|
||||
renderItem={this.renderItem}
|
||||
ItemSeparatorComponent={List.Separator}
|
||||
|
|
|
@ -106,7 +106,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
this.t = props.route.params?.t;
|
||||
this.joined = props.route.params?.joined;
|
||||
this.state = {
|
||||
room: room || ({ rid: this.rid, t: this.t } as any),
|
||||
room: room || { rid: this.rid, t: this.t },
|
||||
membersCount: 0,
|
||||
member: member || {},
|
||||
joined: !!room,
|
||||
|
@ -144,6 +144,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
try {
|
||||
const result = await RocketChat.getChannelInfo(room.rid);
|
||||
if (result.success) {
|
||||
// @ts-ignore
|
||||
this.setState({ room: { ...result.channel, rid: result.channel._id } });
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import { goRoom, TGoRoomItem } from '../../utils/goRoom';
|
|||
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
||||
import log from '../../utils/log';
|
||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
import { RoomTypes } from '../../lib/rocketchat/methods/roomTypeToApiType';
|
||||
import styles from './styles';
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
@ -590,7 +591,8 @@ class RoomMembersView extends React.Component<IRoomMembersViewProps, IRoomMember
|
|||
try {
|
||||
const { room, members, membersFiltered } = this.state;
|
||||
const userId = selectedUser._id;
|
||||
await RocketChat.removeUserFromRoom({ roomId: room.rid, t: room.t, userId });
|
||||
// TODO: interface SubscriptionType on IRoom is wrong
|
||||
await RocketChat.removeUserFromRoom({ roomId: room.rid, t: room.t as RoomTypes, userId });
|
||||
const message = I18n.t('User_has_been_removed_from_s', { s: RocketChat.getRoomTitle(room) });
|
||||
EventEmitter.emit(LISTENER, { message });
|
||||
this.setState({
|
||||
|
|
|
@ -11,7 +11,7 @@ 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 { IApplicationState, IBaseScreen, IUser } from '../definitions';
|
||||
import I18n from '../i18n';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
|
@ -54,19 +54,13 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
interface IUser {
|
||||
id?: string;
|
||||
status?: string;
|
||||
statusText?: string;
|
||||
}
|
||||
|
||||
interface IStatusViewState {
|
||||
statusText: string;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
interface IStatusViewProps extends IBaseScreen<any, 'StatusView'> {
|
||||
user: IUser;
|
||||
user: Pick<IUser, 'id' | 'status' | 'statusText'>;
|
||||
isMasterDetail: boolean;
|
||||
Accounts_AllowInvisibleStatusOption: boolean;
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
export interface ILivechatDepartment {
|
||||
_id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
description: string;
|
||||
showOnRegistration: boolean;
|
||||
showOnOfflineForm: boolean;
|
||||
requestTagBeforeClosingChat: boolean;
|
||||
email: string;
|
||||
chatClosingTags: string[];
|
||||
offlineMessageChannelName: string;
|
||||
numAgents: number;
|
||||
_updatedAt?: Date;
|
||||
businessHourId?: string;
|
||||
}
|
|
@ -28,7 +28,7 @@ Or
|
|||
* If you're running your own Rocket.Chat server, ensure it's started (e.g. `meteor npm start` in the server project directory).
|
||||
* Edit `e2e/data.js`:
|
||||
* Set the `server` to the address of the server under test
|
||||
* Set the `adminUser` and `adminPassword` to an admin user on that environment (or a user with at least `create-user` and `create-c`).
|
||||
* Create a file called `e2e_account.js`, in the same folder as `data.js`. Set the `adminUser` and `adminPassword` to an admin user on that environment (or a user with at least `create-user` and `create-c` permissions). The example of how to create this file is on `e2e/e2e_account.example.js`
|
||||
* Working example configs exist in `./e2e/data/`. Setting `FORCE_DEFAULT_DOCKER_DATA` to `1` in the `runTestsInDocker.sh` script will use the example config automatically
|
||||
|
||||
### 3. Running tests
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
const random = require('./helpers/random');
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
const account = require('./e2e_account');
|
||||
|
||||
const value = random(20);
|
||||
const data = {
|
||||
server: 'https://mobile.rocket.chat',
|
||||
adminUser: 'e2e_admin',
|
||||
adminPassword: 'p7mFh4yLwCRXSnMvG',
|
||||
...account,
|
||||
alternateServer: 'https://stable.rocket.chat',
|
||||
users: {
|
||||
regular: {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// eslint-disable-next-line import/no-unresolved
|
||||
const random = require('./helpers/random');
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
const account = require('./e2e_account');
|
||||
|
||||
const value = random(20);
|
||||
const data = {
|
||||
server: 'https://mobile.rocket.chat',
|
||||
adminUser: 'e2e_admin',
|
||||
adminPassword: 'p7mFh4yLwCRXSnMvG',
|
||||
...account,
|
||||
alternateServer: 'https://stable.rocket.chat',
|
||||
users: {
|
||||
regular: {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
const account = {
|
||||
adminUser: 'Change_here',
|
||||
adminPassword: 'Change_here'
|
||||
};
|
||||
|
||||
module.exports = account;
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue