Compare commits
29 Commits
develop
...
chore.ts-a
Author | SHA1 | Date |
---|---|---|
|
c68b1d56a0 | |
|
0a64d5836e | |
|
35b670647d | |
|
e5a284e9db | |
|
629f17d967 | |
|
b346ab8372 | |
|
2575d1dc9e | |
|
c378686a7a | |
|
416be2b755 | |
|
730162fec9 | |
|
6ed46ae994 | |
|
f40847bc92 | |
|
4148ec554c | |
|
1645bc33b0 | |
|
1778f34198 | |
|
7bbfaa63c8 | |
|
109c525262 | |
|
e49ba5e1c5 | |
|
8a77a5fbcb | |
|
f7e5f2cfa1 | |
|
91ff5ad64d | |
|
4b68cf4522 | |
|
bedc3a7927 | |
|
ff708b1c57 | |
|
2dcadf8633 | |
|
97d4dc9f3b | |
|
a2965a3f93 | |
|
1ec2f4b464 | |
|
8d87401185 |
|
@ -49,11 +49,12 @@ import { sanitizeLikeString } from '../../lib/database/utils';
|
|||
import { CustomIcon } from '../CustomIcon';
|
||||
import { IMessage } from '../../definitions/IMessage';
|
||||
import { forceJpgExtension } from './forceJpgExtension';
|
||||
import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
|
||||
import { IApplicationState, IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions';
|
||||
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
|
||||
import { getPermalinkMessage, hasPermission, search, sendFileMessage } from '../../lib/methods';
|
||||
import { Services } from '../../lib/services';
|
||||
import { TSupportedThemes } from '../../theme';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
|
||||
if (isAndroid) {
|
||||
require('./EmojiKeyboard');
|
||||
|
@ -77,7 +78,7 @@ const videoPickerConfig: Options = {
|
|||
mediaType: 'video'
|
||||
};
|
||||
|
||||
export interface IMessageBoxProps extends IBaseScreen<MasterDetailInsideStackParamList, any> {
|
||||
export interface IMessageBoxProps extends IBaseScreen<ChatsStackParamList & MasterDetailInsideStackParamList, any> {
|
||||
rid: string;
|
||||
baseUrl: string;
|
||||
message: IMessage;
|
||||
|
@ -109,6 +110,9 @@ export interface IMessageBoxProps extends IBaseScreen<MasterDetailInsideStackPar
|
|||
usedCannedResponse: string;
|
||||
uploadFilePermission: string[];
|
||||
serverVersion: string;
|
||||
viewCannedResponsesPermission: boolean;
|
||||
goToCannedResponses: () => void;
|
||||
joined: boolean;
|
||||
}
|
||||
|
||||
interface IMessageBoxState {
|
||||
|
@ -125,6 +129,7 @@ interface IMessageBoxState {
|
|||
tshow: boolean;
|
||||
mentionLoading: boolean;
|
||||
permissionToUpload: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
}
|
||||
|
||||
class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
||||
|
@ -179,7 +184,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
command: {},
|
||||
tshow: false,
|
||||
mentionLoading: false,
|
||||
permissionToUpload: true
|
||||
permissionToUpload: true,
|
||||
canViewCannedResponse: false
|
||||
};
|
||||
this.text = '';
|
||||
this.selection = { start: 0, end: 0 };
|
||||
|
@ -209,7 +215,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
|
||||
async componentDidMount() {
|
||||
const db = database.active;
|
||||
const { rid, tmid, navigation, sharing, usedCannedResponse, isMasterDetail } = this.props;
|
||||
const { rid, tmid, navigation, sharing, usedCannedResponse, isMasterDetail, roomType } = this.props;
|
||||
let msg;
|
||||
try {
|
||||
const threadsCollection = db.get('threads');
|
||||
|
@ -248,6 +254,11 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
this.onChangeText(usedCannedResponse);
|
||||
}
|
||||
|
||||
if (roomType === 'l') {
|
||||
const canViewCannedResponse = await this.canViewCannedResponse();
|
||||
this.setState({ canViewCannedResponse });
|
||||
}
|
||||
|
||||
this.setOptions();
|
||||
|
||||
this.unsubscribeFocus = navigation.addListener('focus', () => {
|
||||
|
@ -307,7 +318,18 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
permissionToUpload
|
||||
} = this.state;
|
||||
|
||||
const { roomType, replying, editing, isFocused, message, theme, usedCannedResponse, uploadFilePermission } = this.props;
|
||||
const {
|
||||
roomType,
|
||||
replying,
|
||||
editing,
|
||||
isFocused,
|
||||
message,
|
||||
theme,
|
||||
usedCannedResponse,
|
||||
uploadFilePermission,
|
||||
viewCannedResponsesPermission,
|
||||
joined
|
||||
} = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
|
@ -317,6 +339,9 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
if (nextProps.roomType !== roomType) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.joined !== joined) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.replying !== replying) {
|
||||
return true;
|
||||
}
|
||||
|
@ -356,6 +381,9 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
if (!dequal(nextProps.uploadFilePermission, uploadFilePermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.viewCannedResponsesPermission, viewCannedResponsesPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.usedCannedResponse !== usedCannedResponse) {
|
||||
return true;
|
||||
}
|
||||
|
@ -363,8 +391,11 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps: IMessageBoxProps) {
|
||||
const { uploadFilePermission } = this.props;
|
||||
if (!dequal(prevProps.uploadFilePermission, uploadFilePermission)) {
|
||||
const { uploadFilePermission, viewCannedResponsesPermission } = this.props;
|
||||
if (
|
||||
!dequal(prevProps.uploadFilePermission, uploadFilePermission) ||
|
||||
prevProps.viewCannedResponsesPermission !== viewCannedResponsesPermission
|
||||
) {
|
||||
this.setOptions();
|
||||
}
|
||||
}
|
||||
|
@ -400,8 +431,17 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
}
|
||||
}
|
||||
|
||||
canViewCannedResponse = async () => {
|
||||
const { viewCannedResponsesPermission, rid } = this.props;
|
||||
const permissions = await hasPermission([viewCannedResponsesPermission], rid);
|
||||
return permissions[0];
|
||||
};
|
||||
|
||||
setOptions = async () => {
|
||||
const { uploadFilePermission, rid } = this.props;
|
||||
const { uploadFilePermission, viewCannedResponsesPermission, rid } = this.props;
|
||||
|
||||
const canViewCannedResponse = await hasPermission([viewCannedResponsesPermission], rid);
|
||||
this.setState({ canViewCannedResponse: canViewCannedResponse[0] });
|
||||
|
||||
// Servers older than 4.2
|
||||
if (!uploadFilePermission) {
|
||||
|
@ -779,10 +819,17 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
|
||||
showMessageBoxActions = () => {
|
||||
logEvent(events.ROOM_SHOW_BOX_ACTIONS);
|
||||
const { permissionToUpload } = this.state;
|
||||
const { showActionSheet } = this.props;
|
||||
const { permissionToUpload, canViewCannedResponse } = this.state;
|
||||
const { showActionSheet, goToCannedResponses } = this.props;
|
||||
|
||||
const options = [];
|
||||
if (canViewCannedResponse) {
|
||||
options.push({
|
||||
title: I18n.t('Canned_Responses'),
|
||||
icon: 'canned-response',
|
||||
onPress: () => goToCannedResponses()
|
||||
});
|
||||
}
|
||||
if (permissionToUpload) {
|
||||
options.push(
|
||||
{
|
||||
|
@ -1167,7 +1214,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
baseUrl: state.server.server,
|
||||
threadsEnabled: state.settings.Threads_enabled,
|
||||
|
@ -1175,7 +1222,8 @@ const mapStateToProps = (state: any) => ({
|
|||
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
|
||||
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize,
|
||||
Message_AudioRecorderEnabled: state.settings.Message_AudioRecorderEnabled,
|
||||
uploadFilePermission: state.permissions['mobile-upload-file']
|
||||
uploadFilePermission: state.permissions['mobile-upload-file'],
|
||||
viewCannedResponsesPermission: state.permissions['view-canned-responses']
|
||||
});
|
||||
|
||||
const dispatchToProps = {
|
||||
|
|
|
@ -184,7 +184,7 @@ export interface IServerRoom extends IRocketChatRecord {
|
|||
unread?: number;
|
||||
alert?: boolean;
|
||||
hideUnreadStatus?: boolean;
|
||||
|
||||
status?: string;
|
||||
sysMes?: string[];
|
||||
muted?: string[];
|
||||
unmuted?: string[];
|
||||
|
|
|
@ -432,6 +432,7 @@
|
|||
"resetting_password": "resetting password",
|
||||
"RESET": "RESET",
|
||||
"Return": "Return",
|
||||
"Return_to_waiting_line": "Return to waiting line",
|
||||
"Review_app_title": "Are you enjoying this app?",
|
||||
"Review_app_desc": "Give us 5 stars on {{store}}",
|
||||
"Review_app_yes": "Sure!",
|
||||
|
|
|
@ -32,6 +32,12 @@ export type ModalStackParamList = {
|
|||
rid: string;
|
||||
t: SubscriptionType;
|
||||
joined: boolean;
|
||||
omnichannelPermissions: {
|
||||
canForwardGuest: boolean;
|
||||
canReturnQueue: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
};
|
||||
};
|
||||
RoomInfoView: {
|
||||
room: ISubscription;
|
||||
|
|
|
@ -32,6 +32,7 @@ export type ChatsStackParamList = {
|
|||
jumpToThreadId?: string;
|
||||
roomUserId?: string | null;
|
||||
usedCannedResponse?: string;
|
||||
status?: string;
|
||||
}
|
||||
| undefined; // Navigates back to RoomView already on stack
|
||||
RoomActionsView: {
|
||||
|
@ -40,6 +41,12 @@ export type ChatsStackParamList = {
|
|||
rid: string;
|
||||
t: SubscriptionType;
|
||||
joined: boolean;
|
||||
omnichannelPermissions: {
|
||||
canForwardGuest: boolean;
|
||||
canReturnQueue: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
};
|
||||
};
|
||||
SelectListView: {
|
||||
data?: TDataSelect[];
|
||||
|
|
|
@ -193,6 +193,7 @@ export default {
|
|||
ROOM_AUDIO_FINISH_F: 'room_audio_finish_f',
|
||||
ROOM_AUDIO_CANCEL: 'room_audio_cancel',
|
||||
ROOM_AUDIO_CANCEL_F: 'room_audio_cancel_f',
|
||||
ROOM_SHOW_MORE_ACTIONS: 'room_show_more_actions',
|
||||
ROOM_SHOW_BOX_ACTIONS: 'room_show_box_actions',
|
||||
ROOM_BOX_ACTION_PHOTO: 'room_box_action_photo',
|
||||
ROOM_BOX_ACTION_PHOTO_F: 'room_box_action_photo_f',
|
||||
|
|
|
@ -21,7 +21,7 @@ import { goRoom } from '../utils/goRoom';
|
|||
import { showErrorAlert } from '../utils/info';
|
||||
import debounce from '../utils/debounce';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import { TSubscriptionModel, SubscriptionType } from '../definitions';
|
||||
import { TSubscriptionModel, SubscriptionType, IApplicationState } from '../definitions';
|
||||
import { getRoomTitle, hasPermission } from '../lib/methods';
|
||||
import { Services } from '../lib/services';
|
||||
|
||||
|
@ -37,7 +37,7 @@ interface IAddExistingChannelViewProps {
|
|||
route: RouteProp<ChatsStackParamList, 'AddExistingChannelView'>;
|
||||
theme: TSupportedThemes;
|
||||
isMasterDetail: boolean;
|
||||
addTeamChannelPermission: string[];
|
||||
addTeamChannelPermission?: string[];
|
||||
}
|
||||
|
||||
const QUERY_SIZE = 50;
|
||||
|
@ -222,7 +222,7 @@ class AddExistingChannelView extends React.Component<IAddExistingChannelViewProp
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
const mapStateToProps = (state: IApplicationState) => ({
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
addTeamChannelPermission: state.permissions['add-team-channel']
|
||||
});
|
||||
|
|
|
@ -65,12 +65,10 @@ interface IRoomActionsViewProps extends IBaseScreen<ChatsStackParamList, 'RoomAc
|
|||
editRoomPermission?: string[];
|
||||
toggleRoomE2EEncryptionPermission?: string[];
|
||||
viewBroadcastMemberListPermission?: string[];
|
||||
transferLivechatGuestPermission?: string[];
|
||||
createTeamPermission?: string[];
|
||||
addTeamChannelPermission?: string[];
|
||||
convertTeamPermission?: string[];
|
||||
viewCannedResponsesPermission?: string[];
|
||||
livechatAllowManualOnHold?: boolean;
|
||||
}
|
||||
|
||||
interface IRoomActionsViewState {
|
||||
|
@ -82,16 +80,11 @@ interface IRoomActionsViewState {
|
|||
canAutoTranslate: boolean;
|
||||
canAddUser: boolean;
|
||||
canInviteUser: boolean;
|
||||
canForwardGuest: boolean;
|
||||
canReturnQueue: boolean;
|
||||
canEdit: boolean;
|
||||
canToggleEncryption: boolean;
|
||||
canCreateTeam: boolean;
|
||||
canAddChannelToTeam: boolean;
|
||||
canConvertTeam: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
isOnHold: boolean;
|
||||
}
|
||||
|
||||
class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomActionsViewState> {
|
||||
|
@ -99,6 +92,12 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
private rid: string;
|
||||
private t: string;
|
||||
private joined: boolean;
|
||||
private omnichannelPermissions: {
|
||||
canForwardGuest: boolean;
|
||||
canReturnQueue: boolean;
|
||||
canViewCannedResponse: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
};
|
||||
private roomObservable?: Observable<TSubscriptionModel>;
|
||||
private subscription?: Subscription;
|
||||
|
||||
|
@ -123,6 +122,7 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
this.rid = props.route.params?.rid;
|
||||
this.t = props.route.params?.t;
|
||||
this.joined = props.route.params?.joined;
|
||||
this.omnichannelPermissions = props.route.params?.omnichannelPermissions;
|
||||
this.state = {
|
||||
room: room || { rid: this.rid, t: this.t },
|
||||
membersCount: 0,
|
||||
|
@ -132,22 +132,17 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
canAutoTranslate: false,
|
||||
canAddUser: false,
|
||||
canInviteUser: false,
|
||||
canForwardGuest: false,
|
||||
canReturnQueue: false,
|
||||
canEdit: false,
|
||||
canToggleEncryption: false,
|
||||
canCreateTeam: false,
|
||||
canAddChannelToTeam: false,
|
||||
canConvertTeam: false,
|
||||
canViewCannedResponse: false,
|
||||
canPlaceLivechatOnHold: false,
|
||||
isOnHold: false
|
||||
canConvertTeam: false
|
||||
};
|
||||
if (room && room.observe && room.rid) {
|
||||
this.roomObservable = room.observe();
|
||||
this.subscription = this.roomObservable.subscribe(changes => {
|
||||
if (this.mounted) {
|
||||
this.setState({ room: changes, isOnHold: !!changes?.onHold });
|
||||
this.setState({ room: changes });
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.state.room = changes;
|
||||
|
@ -215,28 +210,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
canAddChannelToTeam,
|
||||
canConvertTeam
|
||||
});
|
||||
|
||||
// livechat permissions
|
||||
if (room.t === 'l') {
|
||||
const canForwardGuest = await this.canForwardGuest();
|
||||
const canReturnQueue = await this.canReturnQueue();
|
||||
const canViewCannedResponse = await this.canViewCannedResponse();
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
this.setState({ canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: IRoomActionsViewProps, prevState: IRoomActionsViewState) {
|
||||
const { livechatAllowManualOnHold } = this.props;
|
||||
const { room, isOnHold } = this.state;
|
||||
|
||||
if (
|
||||
room.t === 'l' &&
|
||||
(isOnHold !== prevState.isOnHold || prevProps.livechatAllowManualOnHold !== livechatAllowManualOnHold)
|
||||
) {
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
this.setState({ canPlaceLivechatOnHold });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,38 +346,6 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
return result;
|
||||
};
|
||||
|
||||
canForwardGuest = async () => {
|
||||
const { room } = this.state;
|
||||
const { transferLivechatGuestPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await hasPermission([transferLivechatGuestPermission], rid);
|
||||
return permissions[0];
|
||||
};
|
||||
|
||||
canViewCannedResponse = async () => {
|
||||
const { room } = this.state;
|
||||
const { viewCannedResponsesPermission } = this.props;
|
||||
const { rid } = room;
|
||||
const permissions = await hasPermission([viewCannedResponsesPermission], rid);
|
||||
return permissions[0];
|
||||
};
|
||||
|
||||
canPlaceLivechatOnHold = (): boolean => {
|
||||
const { livechatAllowManualOnHold } = this.props;
|
||||
const { room } = this.state;
|
||||
|
||||
return !!(livechatAllowManualOnHold && !room?.lastMessage?.token && room?.lastMessage?.u && !room.onHold);
|
||||
};
|
||||
|
||||
canReturnQueue = async () => {
|
||||
try {
|
||||
const { returnQueue } = await Services.getRoutingConfig();
|
||||
return returnQueue;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
renderEncryptedSwitch = () => {
|
||||
const { room, canToggleEncryption, canEdit } = this.state;
|
||||
const { encrypted } = room;
|
||||
|
@ -1048,20 +989,86 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
);
|
||||
};
|
||||
|
||||
renderOmnichannelSection = () => {
|
||||
const { room } = this.state;
|
||||
const { rid, t } = room;
|
||||
const { theme } = this.props;
|
||||
|
||||
if (t !== 'l' || this.isOmnichannelPreview) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<List.Section>
|
||||
{this.omnichannelPermissions.canForwardGuest ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Forward'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
route: 'ForwardLivechatView',
|
||||
params: { rid }
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='chat-forward' color={themes[theme].titleText} />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{this.omnichannelPermissions.canPlaceLivechatOnHold ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Place_chat_on_hold'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.placeOnHoldLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='pause' color={themes[theme].titleText} />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{this.omnichannelPermissions.canReturnQueue ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Return'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.returnLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='move-to-the-queue' color={themes[theme].titleText} />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<>
|
||||
<List.Item
|
||||
title='Close'
|
||||
color={themes[theme].dangerColor}
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.closeLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='chat-close' color={themes[theme].dangerColor} />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
</List.Section>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
room,
|
||||
membersCount,
|
||||
canViewMembers,
|
||||
canAddUser,
|
||||
canInviteUser,
|
||||
joined,
|
||||
canAutoTranslate,
|
||||
canForwardGuest,
|
||||
canReturnQueue,
|
||||
canViewCannedResponse,
|
||||
canPlaceLivechatOnHold
|
||||
} = this.state;
|
||||
const { room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate } = this.state;
|
||||
const { rid, t, prid } = room;
|
||||
const isGroupChatHandler = isGroupChat(room);
|
||||
|
||||
|
@ -1150,6 +1157,18 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && this.omnichannelPermissions.canViewCannedResponse ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Canned_Responses'
|
||||
onPress={() => this.onPressTouchable({ route: 'CannedResponsesListView', params: { rid } })}
|
||||
left={() => <List.Icon name='canned-response' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['c', 'p', 'd'].includes(t) ? (
|
||||
<>
|
||||
<List.Item
|
||||
|
@ -1277,85 +1296,8 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
|
|||
|
||||
{this.teamChannelActions(t, room)}
|
||||
{this.teamToChannelActions(t, room)}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canViewCannedResponse ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Canned_Responses'
|
||||
onPress={() => this.onPressTouchable({ route: 'CannedResponsesListView', params: { rid } })}
|
||||
left={() => <List.Icon name='canned-response' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Close'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.closeLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='close' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canForwardGuest ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Forward'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
route: 'ForwardLivechatView',
|
||||
params: { rid }
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='user-forward' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canPlaceLivechatOnHold ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Place_chat_on_hold'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.placeOnHoldLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='pause' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{['l'].includes(t) && !this.isOmnichannelPreview && canReturnQueue ? (
|
||||
<>
|
||||
<List.Item
|
||||
title='Return'
|
||||
onPress={() =>
|
||||
this.onPressTouchable({
|
||||
event: this.returnLivechat
|
||||
})
|
||||
}
|
||||
left={() => <List.Icon name='undo' />}
|
||||
showActionIndicator
|
||||
/>
|
||||
<List.Separator />
|
||||
</>
|
||||
) : null}
|
||||
</List.Section>
|
||||
|
||||
{this.renderOmnichannelSection()}
|
||||
{this.renderLastSection()}
|
||||
</List.Container>
|
||||
</SafeAreaView>
|
||||
|
@ -1378,12 +1320,9 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
editRoomPermission: state.permissions['edit-room'],
|
||||
toggleRoomE2EEncryptionPermission: state.permissions['toggle-room-e2e-encryption'],
|
||||
viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'],
|
||||
transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'],
|
||||
createTeamPermission: state.permissions['create-team'],
|
||||
addTeamChannelPermission: state.permissions['add-team-channel'],
|
||||
convertTeamPermission: state.permissions['convert-team'],
|
||||
viewCannedResponsesPermission: state.permissions['view-canned-responses'],
|
||||
livechatAllowManualOnHold: state.settings.Livechat_allow_manual_on_hold as boolean
|
||||
convertTeamPermission: state.permissions['convert-team']
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(withDimensions(RoomActionsView)));
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Dispatch } from 'redux';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
|
@ -11,19 +12,33 @@ import { events, logEvent } from '../../utils/log';
|
|||
import { isTeamRoom } from '../../utils/room';
|
||||
import { IApplicationState, SubscriptionType, TMessageModel, TSubscriptionModel } from '../../definitions';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import { TActionSheetOptions, TActionSheetOptionsItem, withActionSheet } from '../../containers/ActionSheet';
|
||||
import i18n from '../../i18n';
|
||||
import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
|
||||
import { closeRoom } from '../../actions/room';
|
||||
import { onHoldLivechat, returnLivechat } from '../../lib/services/restApi';
|
||||
|
||||
interface IRightButtonsProps {
|
||||
userId?: string;
|
||||
threadsEnabled: boolean;
|
||||
rid?: string;
|
||||
rid: string;
|
||||
t: string;
|
||||
tmid?: string;
|
||||
teamId?: string;
|
||||
isMasterDetail: boolean;
|
||||
toggleFollowThread: Function;
|
||||
joined: boolean;
|
||||
status?: string;
|
||||
dispatch: Dispatch;
|
||||
encrypted?: boolean;
|
||||
showActionSheet: (item: TActionSheetOptions) => void;
|
||||
transferLivechatGuestPermission: boolean;
|
||||
navigation: StackNavigationProp<ChatsStackParamList, 'RoomView'>;
|
||||
omnichannelPermissions: {
|
||||
canForwardGuest: boolean;
|
||||
canReturnQueue: boolean;
|
||||
canPlaceLivechatOnHold: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface IRigthButtonsState {
|
||||
|
@ -71,13 +86,22 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
|
||||
shouldComponentUpdate(nextProps: IRightButtonsProps, nextState: IRigthButtonsState) {
|
||||
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
|
||||
const { teamId } = this.props;
|
||||
const { teamId, status, joined, omnichannelPermissions } = this.props;
|
||||
if (nextProps.teamId !== teamId) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.status !== status) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.joined !== joined) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.isFollowingThread !== isFollowingThread) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.omnichannelPermissions, omnichannelPermissions)) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextState.tunread, tunread)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -157,6 +181,82 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
}
|
||||
};
|
||||
|
||||
returnLivechat = () => {
|
||||
const { rid } = this.props;
|
||||
showConfirmationAlert({
|
||||
message: i18n.t('Would_you_like_to_return_the_inquiry'),
|
||||
confirmationText: i18n.t('Yes'),
|
||||
onPress: async () => {
|
||||
try {
|
||||
await returnLivechat(rid);
|
||||
} catch (e: any) {
|
||||
showErrorAlert(e.reason, i18n.t('Oops'));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
placeOnHoldLivechat = () => {
|
||||
const { navigation, rid } = this.props;
|
||||
showConfirmationAlert({
|
||||
title: i18n.t('Are_you_sure_question_mark'),
|
||||
message: i18n.t('Would_like_to_place_on_hold'),
|
||||
confirmationText: i18n.t('Yes'),
|
||||
onPress: async () => {
|
||||
try {
|
||||
await onHoldLivechat(rid);
|
||||
navigation.navigate('RoomsListView');
|
||||
} catch (e: any) {
|
||||
showErrorAlert(e.data?.error, i18n.t('Oops'));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
closeLivechat = () => {
|
||||
const { dispatch, rid } = this.props;
|
||||
dispatch(closeRoom(rid));
|
||||
};
|
||||
|
||||
showMoreActions = () => {
|
||||
logEvent(events.ROOM_SHOW_MORE_ACTIONS);
|
||||
const { showActionSheet, rid, navigation, omnichannelPermissions } = this.props;
|
||||
|
||||
const options = [] as TActionSheetOptionsItem[];
|
||||
if (omnichannelPermissions.canPlaceLivechatOnHold) {
|
||||
options.push({
|
||||
title: i18n.t('Place_chat_on_hold'),
|
||||
icon: 'pause',
|
||||
onPress: () => this.placeOnHoldLivechat()
|
||||
});
|
||||
}
|
||||
|
||||
if (omnichannelPermissions.canForwardGuest) {
|
||||
options.push({
|
||||
title: i18n.t('Forward_Chat'),
|
||||
icon: 'chat-forward',
|
||||
onPress: () => navigation.navigate('ForwardLivechatView', { rid })
|
||||
});
|
||||
}
|
||||
|
||||
if (omnichannelPermissions.canReturnQueue) {
|
||||
options.push({
|
||||
title: i18n.t('Return_to_waiting_line'),
|
||||
icon: 'move-to-the-queue',
|
||||
onPress: () => this.returnLivechat()
|
||||
});
|
||||
}
|
||||
|
||||
options.push({
|
||||
title: i18n.t('Close'),
|
||||
icon: 'chat-close',
|
||||
onPress: () => this.closeLivechat(),
|
||||
danger: true
|
||||
});
|
||||
|
||||
showActionSheet({ options });
|
||||
};
|
||||
|
||||
goSearchView = () => {
|
||||
logEvent(events.ROOM_GO_SEARCH);
|
||||
const { rid, t, navigation, isMasterDetail, encrypted } = this.props;
|
||||
|
@ -183,10 +283,23 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
|
|||
}
|
||||
};
|
||||
|
||||
isOmnichannelPreview = () => {
|
||||
const { joined, status } = this.props;
|
||||
return !joined && status === 'queued';
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isFollowingThread, tunread, tunreadUser, tunreadGroup } = this.state;
|
||||
const { t, tmid, threadsEnabled, teamId, joined } = this.props;
|
||||
|
||||
if (t === 'l') {
|
||||
if (!this.isOmnichannelPreview()) {
|
||||
return (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='kebab' onPress={this.showMoreActions} testID='room-view-header-omnichannel-kebab' />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (tmid) {
|
||||
|
@ -225,4 +338,4 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
isMasterDetail: state.app.isMasterDetail
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(RightButtonsContainer);
|
||||
export default connect(mapStateToProps)(withActionSheet(RightButtonsContainer));
|
||||
|
|
|
@ -9,6 +9,7 @@ import { dequal } from 'dequal';
|
|||
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { getRoutingConfig } from '../../lib/services/restApi';
|
||||
import { IReduxEmoji } from '../../definitions/IEmoji';
|
||||
import Touch from '../../utils/touch';
|
||||
import { replyBroadcast } from '../../actions/messages';
|
||||
|
@ -67,6 +68,7 @@ import {
|
|||
IApplicationState,
|
||||
IAttachment,
|
||||
IBaseScreen,
|
||||
ILastMessage,
|
||||
ILoggedUser,
|
||||
IMessage,
|
||||
IOmnichannelSource,
|
||||
|
@ -87,6 +89,7 @@ import {
|
|||
canAutoTranslate as canAutoTranslateMethod,
|
||||
getRoomTitle,
|
||||
getUidDirectMessage,
|
||||
hasPermission,
|
||||
isGroupChat,
|
||||
loadSurroundingMessages,
|
||||
loadThreadMessages,
|
||||
|
@ -110,7 +113,10 @@ const stateAttrsUpdate = [
|
|||
'reacting',
|
||||
'readOnly',
|
||||
'member',
|
||||
'showingBlockingLoader'
|
||||
'showingBlockingLoader',
|
||||
'canForwardGuest',
|
||||
'canReturnQueue',
|
||||
'canViewCannedResponses'
|
||||
] as TStateAttrsUpdate[];
|
||||
|
||||
type TRoomUpdate = keyof TSubscriptionModel;
|
||||
|
@ -136,6 +142,8 @@ const roomAttrsUpdate = [
|
|||
'joinCodeRequired',
|
||||
'teamMain',
|
||||
'teamId',
|
||||
'status',
|
||||
'lastMessage',
|
||||
'onHold'
|
||||
] as TRoomUpdate[];
|
||||
|
||||
|
@ -156,6 +164,9 @@ interface IRoomViewProps extends IBaseScreen<ChatsStackParamList, 'RoomView'> {
|
|||
width: number;
|
||||
height: number;
|
||||
insets: EdgeInsets;
|
||||
transferLivechatGuestPermission?: string[]; // TODO: Check if its the correct type
|
||||
viewCannedResponsesPermission?: string[]; // TODO: Check if its the correct type
|
||||
livechatAllowManualOnHold?: boolean;
|
||||
}
|
||||
|
||||
interface IRoomViewState {
|
||||
|
@ -163,7 +174,18 @@ interface IRoomViewState {
|
|||
joined: boolean;
|
||||
room:
|
||||
| TSubscriptionModel
|
||||
| { rid: string; t: string; name?: string; fname?: string; prid?: string; joinCodeRequired?: boolean; sysMes?: boolean };
|
||||
| {
|
||||
rid: string;
|
||||
t: string;
|
||||
name?: string;
|
||||
fname?: string;
|
||||
prid?: string;
|
||||
joinCodeRequired?: boolean;
|
||||
status?: boolean;
|
||||
lastMessage?: ILastMessage;
|
||||
sysMes?: boolean;
|
||||
onHold?: boolean;
|
||||
};
|
||||
roomUpdate: {
|
||||
[K in TRoomUpdate]?: any;
|
||||
};
|
||||
|
@ -195,6 +217,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
private flatList: TListRef;
|
||||
private mounted: boolean;
|
||||
private offset = 0;
|
||||
private subOmnichannel?: Subscription;
|
||||
private subSubscription?: Subscription;
|
||||
private queryUnreads?: Subscription;
|
||||
private retryInit = 0;
|
||||
|
@ -254,7 +277,12 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
reacting: false,
|
||||
readOnly: false,
|
||||
unreadsCount: null,
|
||||
roomUserId
|
||||
roomUserId,
|
||||
canViewCannedResponses: false,
|
||||
canForwardGuest: false,
|
||||
canReturnQueue: false,
|
||||
canPlaceLivechatOnHold: false,
|
||||
isOnHold: false
|
||||
};
|
||||
this.setHeader();
|
||||
|
||||
|
@ -284,6 +312,14 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
this.mounted = true;
|
||||
this.didMountInteraction = InteractionManager.runAfterInteractions(() => {
|
||||
const { isAuthenticated } = this.props;
|
||||
if (this.t === 'l') {
|
||||
this.observeOmnichannel();
|
||||
const canForwardGuest = this.canForwardGuest();
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
const canReturnQueue = this.canReturnQueue();
|
||||
const canViewCannedResponse = this.canViewCannedResponse();
|
||||
this.setState({ canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold });
|
||||
}
|
||||
this.setHeader();
|
||||
if (this.rid) {
|
||||
this.sub?.subscribe?.();
|
||||
|
@ -312,7 +348,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
|
||||
shouldComponentUpdate(nextProps: IRoomViewProps, nextState: IRoomViewState) {
|
||||
const { state } = this;
|
||||
const { roomUpdate, member } = state;
|
||||
const { roomUpdate, member, isOnHold } = state;
|
||||
const { appState, theme, insets, route } = this.props;
|
||||
if (theme !== nextProps.theme) {
|
||||
return true;
|
||||
|
@ -323,7 +359,9 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (member.statusText !== nextState.member.statusText) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isOnHold !== nextState.isOnHold) {
|
||||
return true;
|
||||
}
|
||||
const stateUpdated = stateAttrsUpdate.some(key => nextState[key] !== state[key]);
|
||||
if (stateUpdated) {
|
||||
return true;
|
||||
|
@ -338,7 +376,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps: IRoomViewProps, prevState: IRoomViewState) {
|
||||
const { roomUpdate } = this.state;
|
||||
const { roomUpdate, joined } = this.state;
|
||||
const { appState, insets, route } = this.props;
|
||||
|
||||
if (route?.params?.jumpToMessageId && route?.params?.jumpToMessageId !== prevProps.route?.params?.jumpToMessageId) {
|
||||
|
@ -363,7 +401,14 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
}
|
||||
// If it's a livechat room
|
||||
if (this.t === 'l') {
|
||||
if (!dequal(prevState.roomUpdate.visitor, roomUpdate.visitor)) {
|
||||
if (
|
||||
!dequal(prevState.roomUpdate.lastMessage?.token, roomUpdate.lastMessage?.token) ||
|
||||
!dequal(prevState.roomUpdate.visitor, roomUpdate.visitor) ||
|
||||
!dequal(prevState.roomUpdate.status, roomUpdate.status) ||
|
||||
prevState.joined !== joined
|
||||
) {
|
||||
const canPlaceLivechatOnHold = this.canPlaceLivechatOnHold();
|
||||
this.setState({ canPlaceLivechatOnHold });
|
||||
this.setHeader();
|
||||
}
|
||||
}
|
||||
|
@ -422,6 +467,10 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
if (this.subSubscription && this.subSubscription.unsubscribe) {
|
||||
this.subSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
if (this.subOmnichannel && this.subOmnichannel.unsubscribe) {
|
||||
this.subOmnichannel.unsubscribe();
|
||||
}
|
||||
if (this.queryUnreads && this.queryUnreads.unsubscribe) {
|
||||
this.queryUnreads.unsubscribe();
|
||||
}
|
||||
|
@ -439,13 +488,60 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
console.countReset(`${this.constructor.name}.render calls`);
|
||||
}
|
||||
|
||||
canForwardGuest = async () => {
|
||||
const { transferLivechatGuestPermission } = this.props;
|
||||
const permissions = await hasPermission([transferLivechatGuestPermission], this.rid);
|
||||
return permissions[0] as boolean;
|
||||
};
|
||||
|
||||
canPlaceLivechatOnHold = () => {
|
||||
const { livechatAllowManualOnHold } = this.props;
|
||||
const { room } = this.state;
|
||||
return !!(livechatAllowManualOnHold && !room?.lastMessage?.token && room?.lastMessage?.u && !room.onHold);
|
||||
};
|
||||
|
||||
canViewCannedResponse = async () => {
|
||||
const { viewCannedResponsesPermission } = this.props;
|
||||
const permissions = await hasPermission([viewCannedResponsesPermission], this.rid);
|
||||
return permissions[0] as boolean;
|
||||
};
|
||||
|
||||
canReturnQueue = async () => {
|
||||
try {
|
||||
const { returnQueue } = await getRoutingConfig();
|
||||
return returnQueue;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
observeOmnichannel = () => {
|
||||
try {
|
||||
const db = database.active;
|
||||
const subCollection = db
|
||||
.get('subscriptions')
|
||||
.query(Q.where('rid', this.rid as string))
|
||||
.observe();
|
||||
this.subOmnichannel = subCollection.subscribe(data => {
|
||||
if (data[0]) {
|
||||
if (this.subOmnichannel && this.subOmnichannel.unsubscribe) {
|
||||
this.observeRoom(data[0]);
|
||||
this.subOmnichannel.unsubscribe();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Can't find subscription to observe");
|
||||
}
|
||||
};
|
||||
|
||||
get isOmnichannel() {
|
||||
const { room } = this.state;
|
||||
return room.t === 'l';
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { room, unreadsCount, roomUserId, joined } = this.state;
|
||||
const { room, unreadsCount, roomUserId, joined, canForwardGuest, canReturnQueue, canPlaceLivechatOnHold } = this.state;
|
||||
const { navigation, isMasterDetail, theme, baseUrl, user, insets, route } = this.props;
|
||||
const { rid, tmid } = this;
|
||||
if (!room.rid) {
|
||||
|
@ -472,6 +568,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
let token: string | undefined;
|
||||
let avatar: string | undefined;
|
||||
let visitor: IVisitor | undefined;
|
||||
let status: string | undefined;
|
||||
let sourceType: IOmnichannelSource | undefined;
|
||||
if ('id' in room) {
|
||||
subtitle = room.topic;
|
||||
|
@ -482,6 +579,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
({ id: userId, token } = user);
|
||||
avatar = room.name;
|
||||
visitor = room.visitor;
|
||||
status = room.status;
|
||||
}
|
||||
|
||||
if ('source' in room) {
|
||||
|
@ -491,13 +589,13 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
}
|
||||
|
||||
let numIconsRight = 2;
|
||||
if (tmid) {
|
||||
if (tmid || (status && joined)) {
|
||||
numIconsRight = 1;
|
||||
} else if (teamId && isTeamRoom({ teamId, joined })) {
|
||||
numIconsRight = 3;
|
||||
}
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight });
|
||||
|
||||
const omnichannelPermissions = { canForwardGuest, canReturnQueue, canPlaceLivechatOnHold };
|
||||
navigation.setOptions({
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
|
@ -544,6 +642,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
tmid={tmid}
|
||||
teamId={teamId}
|
||||
joined={joined}
|
||||
status={room.status}
|
||||
omnichannelPermissions={omnichannelPermissions}
|
||||
t={this.t || t}
|
||||
encrypted={encrypted}
|
||||
navigation={navigation}
|
||||
|
@ -555,7 +655,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
|
||||
goRoomActionsView = (screen?: keyof ModalStackParamList) => {
|
||||
logEvent(events.ROOM_GO_RA);
|
||||
const { room, member, joined } = this.state;
|
||||
const { room, member, joined, canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold } = this.state;
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
// @ts-ignore
|
||||
|
@ -567,7 +667,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
room: room as ISubscription,
|
||||
member,
|
||||
showCloseModal: !!screen,
|
||||
joined
|
||||
joined,
|
||||
omnichannelPermissions: { canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold }
|
||||
}
|
||||
});
|
||||
} else if (this.rid && this.t) {
|
||||
|
@ -576,7 +677,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
t: this.t as SubscriptionType,
|
||||
room: room as TSubscriptionModel,
|
||||
member,
|
||||
joined
|
||||
joined,
|
||||
omnichannelPermissions: { canForwardGuest, canReturnQueue, canViewCannedResponse, canPlaceLivechatOnHold }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -692,7 +794,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
return ret;
|
||||
}, {});
|
||||
if (this.mounted) {
|
||||
this.internalSetState({ room: changes, roomUpdate });
|
||||
this.internalSetState({ room: changes, roomUpdate, isOnHold: !!changes?.onHold });
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.state.room = changes;
|
||||
|
@ -1182,6 +1284,11 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
});
|
||||
};
|
||||
|
||||
goToCannedResponses = () => {
|
||||
const { room } = this.state;
|
||||
Navigation.navigate('CannedResponsesListView', { rid: room.rid });
|
||||
};
|
||||
|
||||
renderItem = (item: TAnyMessageModel, previousItem: TAnyMessageModel, highlightedMessage?: string) => {
|
||||
const { room, lastOpen, canAutoTranslate } = this.state;
|
||||
const { user, Message_GroupingPeriod, Message_TimeFormat, useRealName, baseUrl, Message_Read_Receipt_Enabled, theme } =
|
||||
|
@ -1199,7 +1306,6 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
dateSeparator = item.ts;
|
||||
}
|
||||
}
|
||||
|
||||
let content = null;
|
||||
if (item.t && MESSAGE_TYPE_ANY_LOAD.includes(item.t as MessageTypeLoad)) {
|
||||
content = (
|
||||
|
@ -1267,7 +1373,8 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
};
|
||||
|
||||
renderFooter = () => {
|
||||
const { joined, room, selectedMessage, editing, replying, replyWithMention, readOnly, loading } = this.state;
|
||||
const { joined, room, selectedMessage, editing, replying, replyWithMention, readOnly, loading, canViewCannedResponse } =
|
||||
this.state;
|
||||
const { navigation, theme, route } = this.props;
|
||||
|
||||
const usedCannedResponse = route?.params?.usedCannedResponse;
|
||||
|
@ -1334,9 +1441,11 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
|
|||
return (
|
||||
<MessageBox
|
||||
ref={this.messagebox}
|
||||
goToCannedResponses={canViewCannedResponse ? this.goToCannedResponses : null}
|
||||
onSubmit={this.handleSendMessage}
|
||||
rid={this.rid}
|
||||
tmid={this.tmid}
|
||||
joined={joined}
|
||||
roomType={room.t}
|
||||
isFocused={navigation.isFocused}
|
||||
theme={theme}
|
||||
|
@ -1450,7 +1559,10 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
baseUrl: state.server.server,
|
||||
serverVersion: state.server.version,
|
||||
Message_Read_Receipt_Enabled: state.settings.Message_Read_Receipt_Enabled as boolean,
|
||||
Hide_System_Messages: state.settings.Hide_System_Messages as string[]
|
||||
Hide_System_Messages: state.settings.Hide_System_Messages as string[],
|
||||
transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'],
|
||||
viewCannedResponsesPermission: state.permissions['view-canned-responses'],
|
||||
livechatAllowManualOnHold: state.settings.Livechat_allow_manual_on_hold as boolean
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withDimensions(withTheme(withSafeAreaInsets(RoomView))));
|
||||
|
|
Loading…
Reference in New Issue