Chore: Migrate ee/omnichannel folder to Typescript (#3749)

* Chore: Migrate ee/omnichannel folder to Typescript

* omnichannelstatus and queue list

* boolean searching and react.ref

* test initi

* test and refactor interfaces

* minor tweak

* minor tweaks
This commit is contained in:
Reinaldo Neto 2022-03-07 18:16:20 -03:00 committed by GitHub
parent 091055a255
commit b7e523a267
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 334 additions and 164 deletions

View File

@ -4,7 +4,7 @@ import { MarkdownAST } from '@rocket.chat/message-parser';
import { IAttachment } from './IAttachment'; import { IAttachment } from './IAttachment';
import { IMessage } from './IMessage'; import { IMessage } from './IMessage';
import { IServedBy } from './IServedBy'; import { IServedBy } from './IServedBy';
import { SubscriptionType } from './ISubscription'; import { IVisitor, SubscriptionType } from './ISubscription';
import { IUser } from './IUser'; import { IUser } from './IUser';
interface IRequestTranscript { interface IRequestTranscript {
@ -28,11 +28,8 @@ export interface IRoom {
broadcast: boolean; broadcast: boolean;
encrypted: boolean; encrypted: boolean;
ro: boolean; ro: boolean;
v?: { v?: IVisitor;
_id?: string; status?: string;
token?: string;
status: 'online' | 'busy' | 'away' | 'offline';
};
servedBy?: IServedBy; servedBy?: IServedBy;
departmentId?: string; departmentId?: string;
livechatData?: any; livechatData?: any;
@ -55,13 +52,11 @@ export enum OmnichannelSourceType {
API = 'api', API = 'api',
OTHER = 'other' // catch-all source type 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; t: SubscriptionType.OMNICHANNEL;
v: { v: IVisitor;
_id?: string;
token?: string;
status: 'online' | 'busy' | 'away' | 'offline';
};
email?: { email?: {
// Data used when the room is created from an email, via email Integration. // Data used when the room is created from an email, via email Integration.
inbox: string; inbox: string;
@ -83,6 +78,8 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
sidebarIcon?: string; sidebarIcon?: string;
// The default sidebar icon // The default sidebar icon
defaultIcon?: string; defaultIcon?: string;
_updatedAt?: Date;
queuedAt?: Date;
}; };
transcriptRequest?: IRequestTranscript; transcriptRequest?: IRequestTranscript;
servedBy?: IServedBy; servedBy?: IServedBy;
@ -91,18 +88,22 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
lastMessage?: IMessage & { token?: string }; lastMessage?: IMessage & { token?: string };
tags: any; tags?: string[];
closedAt: any; closedAt?: Date;
metrics: any; metrics?: any;
waitingResponse: any; waitingResponse?: any;
responseBy: any; responseBy?: any;
priorityId: any; priorityId?: any;
livechatData: any; livechatData?: any;
queuedAt?: Date; queuedAt?: Date;
ts: Date; ts: Date;
label?: string; label?: string;
crmData?: unknown; crmData?: unknown;
message?: string;
queueOrder?: string;
estimatedWaitingTimeQueue?: string;
estimatedServiceTimeAt?: Date;
} }
export type TRoomModel = IRoom & Model; export type TRoomModel = IRoom & Model;

View File

@ -17,11 +17,11 @@ export enum SubscriptionType {
} }
export interface IVisitor { export interface IVisitor {
_id: string; _id?: string;
username: string; token?: string;
token: string; status: 'online' | 'busy' | 'away' | 'offline';
status: string; username?: string;
lastMessageTs: Date; lastMessageTs?: Date;
} }
export enum ERoomTypes { export enum ERoomTypes {

View File

@ -1,4 +1,5 @@
// ACTIONS // ACTIONS
import { TActionInquiry } from '../../ee/omnichannel/actions/inquiry';
import { TActionActiveUsers } from '../../actions/activeUsers'; import { TActionActiveUsers } from '../../actions/activeUsers';
import { TActionApp } from '../../actions/app'; import { TActionApp } from '../../actions/app';
import { TActionCreateChannel } from '../../actions/createChannel'; import { TActionCreateChannel } from '../../actions/createChannel';
@ -30,6 +31,7 @@ import { ISelectedUsers } from '../../reducers/selectedUsers';
import { IServer } from '../../reducers/server'; import { IServer } from '../../reducers/server';
import { TSettingsState } from '../../reducers/settings'; import { TSettingsState } from '../../reducers/settings';
import { IShare } from '../../reducers/share'; import { IShare } from '../../reducers/share';
import { IInquiry } from '../../ee/omnichannel/reducers/inquiry';
import { IPermissionsState } from '../../reducers/permissions'; import { IPermissionsState } from '../../reducers/permissions';
import { IEnterpriseModules } from '../../reducers/enterpriseModules'; import { IEnterpriseModules } from '../../reducers/enterpriseModules';
@ -50,7 +52,7 @@ export interface IApplicationState {
usersTyping: any; usersTyping: any;
inviteLinks: IInviteLinks; inviteLinks: IInviteLinks;
createDiscussion: ICreateDiscussion; createDiscussion: ICreateDiscussion;
inquiry: any; inquiry: IInquiry;
enterpriseModules: IEnterpriseModules; enterpriseModules: IEnterpriseModules;
encryption: IEncryption; encryption: IEncryption;
permissions: IPermissionsState; permissions: IPermissionsState;
@ -71,5 +73,6 @@ export type TApplicationActions = TActionActiveUsers &
TActionsShare & TActionsShare &
TActionServer & TActionServer &
TActionApp & TActionApp &
TActionInquiry &
TActionPermissions & TActionPermissions &
TActionEnterpriseModules; TActionEnterpriseModules;

View File

@ -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
};
}

View File

@ -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
};
}

View File

@ -1,19 +1,28 @@
import React, { memo, useEffect, useState } from 'react'; import React, { memo, useEffect, useState } from 'react';
import { Switch, View } from 'react-native'; import { Switch, View } from 'react-native';
import PropTypes from 'prop-types';
import * as List from '../../../containers/List'; import * as List from '../../../containers/List';
import styles from '../../../views/RoomsListView/styles'; import styles from '../../../views/RoomsListView/styles';
import { SWITCH_TRACK_COLOR, themes } from '../../../constants/colors'; import { SWITCH_TRACK_COLOR, themes } from '../../../constants/colors';
import { withTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import UnreadBadge from '../../../presentation/UnreadBadge'; import UnreadBadge from '../../../presentation/UnreadBadge';
import RocketChat from '../../../lib/rocketchat'; import RocketChat from '../../../lib/rocketchat';
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../lib'; import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../lib';
import { IUser } from '../../../definitions/IUser';
const OmnichannelStatus = memo(({ searching, goQueue, theme, queueSize, inquiryEnabled, user }) => { interface IOmnichannelStatus {
if (searching > 0 || !(RocketChat.isOmnichannelModuleAvailable() && user?.roles?.includes('livechat-agent'))) { 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; return null;
} }
const { theme } = useTheme();
const [status, setStatus] = useState(isOmnichannelStatusAvailable(user)); const [status, setStatus] = useState(isOmnichannelStatusAvailable(user));
useEffect(() => { useEffect(() => {
@ -48,16 +57,4 @@ const OmnichannelStatus = memo(({ searching, goQueue, theme, queueSize, inquiryE
); );
}); });
OmnichannelStatus.propTypes = { export default OmnichannelStatus;
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);

View File

@ -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 EventEmitter from '../../../utils/events';
import subscribeInquiry from './subscriptions/inquiry'; 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 // RC 0.26.0
export const changeLivechatStatus = () => RocketChat.methodCallWrapper('livechat:changeLivechatStatus'); export const changeLivechatStatus = () => sdk.methodCallWrapper('livechat:changeLivechatStatus');
// RC 2.4.0 // 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 // this inquiry is added to the db by the subscriptions stream
// and will be removed by the queue stream // and will be removed by the queue stream
// RC 2.4.0 // 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 { class Omnichannel {
private inquirySub: { stop: () => void } | null;
constructor() { constructor() {
this.inquirySub = null; this.inquirySub = null;
EventEmitter.addEventListener('INQUIRY_SUBSCRIBE', this.subscribeInquiry); 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(); const omnichannel = new Omnichannel();

View File

@ -2,11 +2,28 @@ import log from '../../../../utils/log';
import { store } from '../../../../lib/auxStore'; import { store } from '../../../../lib/auxStore';
import RocketChat from '../../../../lib/rocketchat'; import RocketChat from '../../../../lib/rocketchat';
import { inquiryQueueAdd, inquiryQueueRemove, inquiryQueueUpdate, inquiryRequest } from '../../actions/inquiry'; 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; interface IDdpMessage {
let queueListener; 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'; const streamTopic = 'stream-livechat-inquiry-queue-observer';
@ -15,7 +32,7 @@ export default function subscribeInquiry() {
store.dispatch(inquiryRequest()); store.dispatch(inquiryRequest());
}; };
const handleQueueMessageReceived = ddpMessage => { const handleQueueMessageReceived = (ddpMessage: IDdpMessage) => {
const [{ type, ...sub }] = ddpMessage.fields.args; const [{ type, ...sub }] = ddpMessage.fields.args;
// added can be ignored, since it is handled by 'changed' event // 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 the sub isn't on the queue anymore
if (sub.status !== 'queued') { if (sub.status !== 'queued') {
// remove it from the queue // remove it from the queue
store.dispatch(inquiryQueueRemove(sub._id)); if (sub._id) {
store.dispatch(inquiryQueueRemove(sub._id));
}
return; return;
} }
@ -53,23 +72,28 @@ export default function subscribeInquiry() {
} }
}; };
connectedListener = RocketChat.onStreamData('connected', handleConnection); connectedListener = sdk.onStreamData('connected', handleConnection);
queueListener = RocketChat.onStreamData(streamTopic, handleQueueMessageReceived); queueListener = sdk.onStreamData(streamTopic, handleQueueMessageReceived);
try { try {
const { user } = store.getState().login; 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) { if (result.success) {
const { departments } = result; const { departments } = result;
if (!departments.length || RocketChat.hasRole('livechat-manager')) { 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); const departmentIds = departments.map(({ departmentId }) => departmentId);
departmentIds.forEach(departmentId => { departmentIds.forEach(departmentId => {
// subscribe to all departments of the agent // 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));
}); });
} }
}); });

View File

@ -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 });
});
});

View File

@ -1,12 +1,19 @@
import { IOmnichannelRoom, TApplicationActions } from '../../../definitions';
import { INQUIRY } from '../../../actions/actionsTypes'; import { INQUIRY } from '../../../actions/actionsTypes';
const initialState = { export interface IInquiry {
enabled: boolean;
queued: IOmnichannelRoom[];
error: any;
}
export const initialState: IInquiry = {
enabled: false, enabled: false,
queued: [], queued: [],
error: {} error: {}
}; };
export default function inquiry(state = initialState, action) { export default function inquiry(state = initialState, action: TApplicationActions): IInquiry {
switch (action.type) { switch (action.type) {
case INQUIRY.SUCCESS: case INQUIRY.SUCCESS:
return { return {

View File

@ -1,5 +1,7 @@
import { createSelector } from 'reselect'; 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); export const getInquiryQueueSelector = createSelector([getInquiryQueue], queue => queue);

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import { CompositeNavigationProp } from '@react-navigation/native';
import { FlatList } from 'react-native'; import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
import { FlatList, ListRenderItem } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { dequal } from 'dequal'; import { dequal } from 'dequal';
@ -19,18 +20,50 @@ import * as HeaderButton from '../../../containers/HeaderButton';
import RocketChat from '../../../lib/rocketchat'; import RocketChat from '../../../lib/rocketchat';
import { events, logEvent } from '../../../utils/log'; import { events, logEvent } from '../../../utils/log';
import { getInquiryQueueSelector } from '../selectors/inquiry'; 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 INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12;
const getItemLayout = (data, index) => ({ const getItemLayout = (data: IOmnichannelRoom[] | null | undefined, index: number) => ({
length: ROW_HEIGHT, length: ROW_HEIGHT,
offset: ROW_HEIGHT * index, offset: ROW_HEIGHT * index,
index index
}); });
const keyExtractor = item => item.rid; const keyExtractor = (item: IOmnichannelRoom) => item.rid;
class QueueListView extends React.Component { class QueueListView extends React.Component<IQueueListView, any> {
static navigationOptions = ({ navigation, isMasterDetail }) => { private getScrollRef?: React.Ref<FlatList<IOmnichannelRoom>>;
const options = {
private onEndReached: ((info: { distanceFromEnd: number }) => void) | null | undefined;
static navigationOptions = ({ navigation, isMasterDetail }: INavigationOptions) => {
const options: StackNavigationOptions = {
title: I18n.t('Queued_chats') title: I18n.t('Queued_chats')
}; };
if (isMasterDetail) { if (isMasterDetail) {
@ -39,24 +72,7 @@ class QueueListView extends React.Component {
return options; return options;
}; };
static propTypes = { shouldComponentUpdate(nextProps: IQueueListView) {
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) {
const { queued } = this.props; const { queued } = this.props;
if (!dequal(nextProps.queued, queued)) { if (!dequal(nextProps.queued, queued)) {
return true; return true;
@ -65,7 +81,7 @@ class QueueListView extends React.Component {
return false; return false;
} }
onPressItem = (item = {}) => { onPressItem = (item = {} as IOmnichannelRoom) => {
logEvent(events.QL_GO_ROOM); logEvent(events.QL_GO_ROOM);
const { navigation, isMasterDetail } = this.props; const { navigation, isMasterDetail } = this.props;
if (isMasterDetail) { 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 { const {
user: { id: userId, username, token }, user: { id: userId, username, token },
server, server,
@ -152,7 +168,7 @@ class QueueListView extends React.Component {
} }
} }
const mapStateToProps = state => ({ const mapStateToProps = (state: IApplicationState) => ({
user: getUserSelector(state), user: getUserSelector(state),
isMasterDetail: state.app.isMasterDetail, isMasterDetail: state.app.isMasterDetail,
server: state.server.server, server: state.server.server,

View File

@ -1,7 +1,7 @@
import { ChatsStackParamList } from '../stacks/types'; import { ChatsStackParamList } from '../stacks/types';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import { ISubscription, IVisitor, SubscriptionType, TSubscriptionModel } from '../definitions/ISubscription'; import { IOmnichannelRoom, SubscriptionType, IVisitor, TSubscriptionModel, ISubscription } from '../definitions';
interface IGoRoomItem { interface IGoRoomItem {
search?: boolean; // comes from spotlight search?: boolean; // comes from spotlight
@ -13,7 +13,7 @@ interface IGoRoomItem {
visitor?: IVisitor; visitor?: IVisitor;
} }
export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription; export type TGoRoomItem = IGoRoomItem | TSubscriptionModel | ISubscription | IOmnichannelRoomVisitor;
const navigate = ({ const navigate = ({
item, 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 ({ export const goRoom = async ({
item, item,
isMasterDetail = false, isMasterDetail = false,

View File

@ -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;
}