[IMPROVE] Migrate away from react-native-prompt-android to action sheet (#4300)

* Chore: Migrate away from react-native-prompt-android to action sheet

* fix header provile view with action sheet

* finished change password

* Close livechat and removed closeRoom dispatch

* remove lib react-native-prompt-android

* fix right buttons

* fix profile view in tablets

* fix action and room action for tablets

* remove onSubmitEditing

* fix keyboard for android tablet in landscape

* create base for actionSheet containers

* migrate EnterPasswordSheet to base

* migrate to base component

* fix colors and copy

* remove secure entry

* fix onSubmit

* fix android animation

Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com>
This commit is contained in:
Reinaldo Neto 2022-06-27 16:03:24 -03:00 committed by GitHub
parent 1e9ae6e157
commit 18c44178d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 320 additions and 208 deletions

View File

@ -27,7 +27,6 @@ export const ROOM = createRequestTypes('ROOM', [
'LEAVE',
'DELETE',
'REMOVED',
'CLOSE',
'FORWARD',
'USER_TYPING'
]);

View File

@ -19,7 +19,6 @@ interface IBaseReturn extends Action {
type TSubscribeRoom = IBaseReturn;
type TUnsubscribeRoom = IBaseReturn;
type TCloseRoom = IBaseReturn;
type TRoom = Record<string, any>;
@ -45,7 +44,7 @@ interface IUserTyping extends Action {
status: boolean;
}
export type TActionsRoom = TSubscribeRoom & TUnsubscribeRoom & TCloseRoom & ILeaveRoom & IDeleteRoom & IForwardRoom & IUserTyping;
export type TActionsRoom = TSubscribeRoom & TUnsubscribeRoom & ILeaveRoom & IDeleteRoom & IForwardRoom & IUserTyping;
export function subscribeRoom(rid: string): TSubscribeRoom {
return {
@ -79,13 +78,6 @@ export function deleteRoom(roomType: ERoomType, room: TRoom, selected?: ISelecte
};
}
export function closeRoom(rid: string): TCloseRoom {
return {
type: ROOM.CLOSE,
rid
};
}
export function forwardRoom(rid: string, transferData: ITransferData): IForwardRoom {
return {
type: ROOM.FORWARD,

View File

@ -0,0 +1,137 @@
import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { CustomIcon, TIconsName } from '../../CustomIcon';
import i18n from '../../../i18n';
import { isIOS } from '../../../lib/methods/helpers';
import { useTheme } from '../../../theme';
import sharedStyles from '../../../views/Styles';
import Button from '../../Button';
import { FormTextInput } from '../../TextInput/FormTextInput';
import { useActionSheet } from '../Provider';
const styles = StyleSheet.create({
subtitleText: {
fontSize: 14,
...sharedStyles.textRegular,
marginBottom: 10
},
buttonSeparator: {
marginRight: 8
},
footerButtonsContainer: {
flexDirection: 'row',
paddingTop: 16
},
titleContainerText: {
fontSize: 16,
...sharedStyles.textSemibold
},
titleContainer: {
paddingRight: 80,
marginBottom: 16,
flexDirection: 'row',
alignItems: 'center'
}
});
const FooterButtons = ({
cancelAction = () => {},
confirmAction = () => {},
cancelTitle = '',
confirmTitle = '',
disabled = false,
cancelBackgroundColor = '',
confirmBackgroundColor = ''
}): React.ReactElement => {
const { colors } = useTheme();
return (
<View style={styles.footerButtonsContainer}>
<Button
style={[styles.buttonSeparator, { flex: 1, backgroundColor: cancelBackgroundColor || colors.cancelButton }]}
color={colors.backdropColor}
title={cancelTitle}
onPress={cancelAction}
/>
<Button
style={{ flex: 1, backgroundColor: confirmBackgroundColor || colors.dangerColor }}
title={confirmTitle}
onPress={confirmAction}
disabled={disabled}
/>
</View>
);
};
const ActionSheetContentWithInputAndSubmit = ({
onSubmit = () => {},
onCancel,
title = '',
description = '',
testID = '',
secureTextEntry = true,
placeholder = '',
confirmTitle,
iconName,
iconColor,
customText,
confirmBackgroundColor
}: {
onSubmit: (inputValue: string) => void;
onCancel?: () => void;
title: string;
description: string;
testID: string;
secureTextEntry?: boolean;
placeholder: string;
confirmTitle?: string;
iconName?: TIconsName;
iconColor?: string;
customText?: React.ReactElement;
confirmBackgroundColor?: string;
}): React.ReactElement => {
const { colors } = useTheme();
const [inputValue, setInputValue] = useState('');
const { hideActionSheet } = useActionSheet();
return (
<View style={sharedStyles.containerScrollView}>
<>
<View style={styles.titleContainer}>
{iconName ? <CustomIcon name={iconName} size={32} color={iconColor || colors.dangerColor} /> : null}
<Text style={[styles.titleContainerText, { color: colors.passcodePrimary, paddingLeft: iconName ? 16 : 0 }]}>
{title}
</Text>
</View>
<Text style={[styles.subtitleText, { color: colors.titleText }]}>{description}</Text>
{customText}
</>
<FormTextInput
value={inputValue}
placeholder={placeholder}
onChangeText={value => setInputValue(value)}
onSubmitEditing={() => {
// fix android animation
setTimeout(() => {
hideActionSheet();
}, 100);
if (inputValue) onSubmit(inputValue);
}}
testID={testID}
secureTextEntry={secureTextEntry}
inputStyle={{ borderWidth: 2 }}
bottomSheet={isIOS}
/>
<FooterButtons
confirmBackgroundColor={confirmBackgroundColor || colors.actionTintColor}
cancelAction={onCancel || hideActionSheet}
confirmAction={() => onSubmit(inputValue)}
cancelTitle={i18n.t('Cancel')}
confirmTitle={confirmTitle || i18n.t('Save')}
disabled={!inputValue}
/>
</View>
);
};
export default ActionSheetContentWithInputAndSubmit;

View File

@ -1,36 +0,0 @@
import React from 'react';
import { View } from 'react-native';
import Button from '../Button';
import { useTheme } from '../../theme';
import styles from './styles';
const FooterButtons = ({
cancelAction = () => {},
confirmAction = () => {},
cancelTitle = '',
confirmTitle = '',
disabled = false,
cancelBackgroundColor = '',
confirmBackgroundColor = ''
}): React.ReactElement => {
const { colors } = useTheme();
return (
<View style={styles.footerButtonsContainer}>
<Button
style={[styles.buttonSeparator, { flex: 1, backgroundColor: cancelBackgroundColor || colors.cancelButton }]}
color={colors.backdropColor}
title={cancelTitle}
onPress={cancelAction}
/>
<Button
style={{ flex: 1, backgroundColor: confirmBackgroundColor || colors.dangerColor }}
title={confirmTitle}
onPress={confirmAction}
disabled={disabled}
/>
</View>
);
};
export default FooterButtons;

View File

@ -63,12 +63,5 @@ export default StyleSheet.create({
},
rightContainer: {
paddingLeft: 12
},
footerButtonsContainer: {
flexDirection: 'row',
paddingTop: 16
},
buttonSeparator: {
marginRight: 8
}
});

View File

@ -0,0 +1,24 @@
import React from 'react';
import ActionSheetContentWithInputAndSubmit from '../../../../containers/ActionSheet/ActionSheetContentWithInputAndSubmit';
import I18n from '../../../../i18n';
const CloseLivechatSheet = ({
onSubmit = () => {},
onCancel = () => {}
}: {
onSubmit: (comment: string) => void;
onCancel: () => void;
}) => (
<ActionSheetContentWithInputAndSubmit
title={I18n.t('Closing_chat')}
description={I18n.t('Please_add_a_comment')}
onCancel={onCancel}
onSubmit={onSubmit}
testID='room-actions-view-close-livechat'
placeholder=''
secureTextEntry={false}
/>
);
export default CloseLivechatSheet;

View File

@ -9,6 +9,5 @@ declare module 'react-native-config-reader';
declare module 'react-native-keycommands';
declare module 'react-native-mime-types';
declare module 'react-native-restart';
declare module 'react-native-prompt-android';
declare module 'react-native-jitsi-meet';
declare module 'rn-root-view';

View File

@ -0,0 +1,27 @@
import I18n from '../../../i18n';
import Navigation from '../../navigation/appNavigation';
import { Services } from '../../services';
import { showErrorAlert } from './info';
import log from './log';
export const closeLivechat = async ({
rid,
comment,
isMasterDetail
}: {
rid: string;
isMasterDetail: boolean;
comment?: string;
}) => {
try {
await Services.closeLivechat(rid, comment);
if (isMasterDetail) {
Navigation.navigate('DrawerNavigator');
} else {
Navigation.navigate('RoomsListView');
}
} catch (e: any) {
showErrorAlert(I18n.isTranslated(e.error) ? I18n.t(e.error) : e.reason, I18n.t('Oops'));
log(e);
}
};

View File

@ -347,7 +347,7 @@ export const getTeamListRoom = ({
return sdk.get('teams.listRooms', params);
};
export const closeLivechat = (rid: string, comment: string) =>
export const closeLivechat = (rid: string, comment?: string) =>
// RC 0.29.0
sdk.methodCallWrapper('livechat:closeRoom', rid, comment, { clientAction: true });

View File

@ -1,4 +1,4 @@
import { closeRoom, deleteRoom, forwardRoom, leaveRoom, removedRoom, subscribeRoom, unsubscribeRoom } from '../actions/room';
import { deleteRoom, forwardRoom, leaveRoom, removedRoom, subscribeRoom, unsubscribeRoom } from '../actions/room';
import { ERoomType } from '../definitions/ERoomType';
import { mockedStore } from './mockedStore';
import { initialState } from './room';
@ -35,13 +35,6 @@ describe('test room reducer', () => {
expect(isDeleting).toEqual(true);
});
it('should return initial state after closeRoom', () => {
mockedStore.dispatch(closeRoom('CLOSING'));
const { rid, isDeleting } = mockedStore.getState().room;
expect(rid).toEqual('CLOSING');
expect(isDeleting).toEqual(true);
});
it('should return initial state after forwardRoom', () => {
const transferData = { roomId: 'FORWARDING' };
mockedStore.dispatch(forwardRoom('FORWARDING', transferData));

View File

@ -1,5 +1,4 @@
import { Alert } from 'react-native';
import prompt from 'react-native-prompt-android';
import { delay, put, race, select, take, takeLatest } from 'redux-saga/effects';
import EventEmitter from '../lib/methods/helpers/events';
@ -110,44 +109,6 @@ const handleDeleteRoom = function* handleDeleteRoom({ room, roomType, selected }
}
};
const handleCloseRoom = function* handleCloseRoom({ rid }) {
const isMasterDetail = yield select(state => state.app.isMasterDetail);
const requestComment = yield select(state => state.settings.Livechat_request_comment_when_closing_conversation);
const closeRoom = async (comment = '') => {
try {
await Services.closeLivechat(rid, comment);
if (isMasterDetail) {
Navigation.navigate('DrawerNavigator');
} else {
Navigation.navigate('RoomsListView');
}
} catch {
// do nothing
}
};
if (!requestComment) {
const comment = I18n.t('Chat_closed_by_agent');
return closeRoom(comment);
}
prompt(
I18n.t('Closing_chat'),
I18n.t('Please_add_a_comment'),
[
{ text: I18n.t('Cancel'), onPress: () => {}, style: 'cancel' },
{
text: I18n.t('Submit'),
onPress: comment => closeRoom(comment)
}
],
{
cancelable: true
}
);
};
const handleForwardRoom = function* handleForwardRoom({ transferData }) {
try {
const result = yield Services.forwardLivechat(transferData);
@ -170,7 +131,6 @@ const root = function* root() {
yield takeLatest(types.ROOM.USER_TYPING, watchUserTyping);
yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
yield takeLatest(types.ROOM.DELETE, handleDeleteRoom);
yield takeLatest(types.ROOM.CLOSE, handleCloseRoom);
yield takeLatest(types.ROOM.FORWARD, handleForwardRoom);
};
export default root;

View File

@ -119,11 +119,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
<ModalContainer navigation={navigation} theme={theme}>
<ModalStack.Navigator
screenOptions={{ ...defaultHeader, ...themedHeader(theme), ...StackAnimation } as StackNavigationOptions}>
<ModalStack.Screen
name='RoomActionsView'
component={RoomActionsView}
options={props => RoomActionsView.navigationOptions!({ ...props, isMasterDetail: true })}
/>
<ModalStack.Screen name='RoomActionsView' component={RoomActionsView} />
<ModalStack.Screen name='RoomInfoView' component={RoomInfoView} options={RoomInfoView.navigationOptions} />
<ModalStack.Screen name='SelectListView' component={SelectListView} />
<ModalStack.Screen name='RoomInfoEditView' component={RoomInfoEditView} options={RoomInfoEditView.navigationOptions} />

View File

@ -1,41 +1,27 @@
import { sha256 } from 'js-sha256';
import React, { useState } from 'react';
import { Keyboard, Text, View } from 'react-native';
import React from 'react';
import { Keyboard, Text } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useDispatch } from 'react-redux';
import { deleteAccount } from '../../../../actions/login';
import { useActionSheet } from '../../../../containers/ActionSheet';
import FooterButtons from '../../../../containers/ActionSheet/FooterButtons';
import { CustomIcon } from '../../../../containers/CustomIcon';
import { FormTextInput } from '../../../../containers/TextInput/FormTextInput';
import ActionSheetContentWithInputAndSubmit from '../../../../containers/ActionSheet/ActionSheetContentWithInputAndSubmit';
import i18n from '../../../../i18n';
import { showErrorAlert } from '../../../../lib/methods/helpers';
import { events, logEvent } from '../../../../lib/methods/helpers/log';
import { deleteOwnAccount } from '../../../../lib/services/restApi';
import { useTheme } from '../../../../theme';
import { getTranslations } from './getTranslations';
import styles from './styles';
const AlertHeader = ({ title = '', subTitle = '' }) => {
const { colors } = useTheme();
return (
<>
<View style={styles.titleContainer}>
<CustomIcon name='warning' size={32} color={colors.dangerColor} />
<Text style={[styles.titleContainerText, { color: colors.passcodePrimary }]}>{title}</Text>
</View>
<Text style={[styles.subTitleContainerText, { color: colors.passcodePrimary }]}>{subTitle}</Text>
</>
);
};
import sharedStyles from '../../../Styles';
export function DeleteAccountActionSheetContent(): React.ReactElement {
const [password, setPassword] = useState('');
const { hideActionSheet, showActionSheet } = useActionSheet();
const dispatch = useDispatch();
const insets = useSafeAreaInsets();
const handleDeleteAccount = async () => {
const { colors } = useTheme();
const handleDeleteAccount = async (password: string) => {
Keyboard.dismiss();
try {
await deleteOwnAccount(sha256(password));
@ -71,37 +57,29 @@ export function DeleteAccountActionSheetContent(): React.ReactElement {
};
return (
<View style={styles.container}>
<AlertHeader
<ActionSheetContentWithInputAndSubmit
title={i18n.t('Are_you_sure_you_want_to_delete_your_account')}
subTitle={i18n.t('For_your_security_you_must_enter_your_current_password_to_continue')}
/>
<FormTextInput
value={password}
description={i18n.t('For_your_security_you_must_enter_your_current_password_to_continue')}
onCancel={hideActionSheet}
onSubmit={password => handleDeleteAccount(password)}
placeholder={i18n.t('Password')}
onChangeText={value => setPassword(value)}
onSubmitEditing={handleDeleteAccount}
testID='room-info-edit-view-name'
secureTextEntry
inputStyle={{ borderWidth: 2 }}
bottomSheet
/>
<FooterButtons
cancelTitle={i18n.t('Cancel')}
cancelAction={hideActionSheet}
iconName='warning'
confirmTitle={i18n.t('Delete_Account')}
confirmAction={handleDeleteAccount}
disabled={!password}
confirmBackgroundColor={colors.dangerColor}
/>
</View>
);
}
function ConfirmDeleteAccountActionSheetContent({ changeOwnerRooms = '', removedRooms = '', password = '' }) {
const AlertText = ({ text = '' }) => {
const { colors } = useTheme();
return <Text style={{ fontSize: 14, ...sharedStyles.textRegular, marginBottom: 10, color: colors.dangerColor }}>{text}</Text>;
};
function ConfirmDeleteAccountActionSheetContent({ changeOwnerRooms = '', removedRooms = '', password = '' }) {
const { hideActionSheet } = useActionSheet();
const dispatch = useDispatch();
const { colors } = useTheme();
const handleDeleteAccount = async () => {
hideActionSheet();
await deleteOwnAccount(password, true);
@ -109,18 +87,22 @@ function ConfirmDeleteAccountActionSheetContent({ changeOwnerRooms = '', removed
};
return (
<View style={styles.container}>
<AlertHeader title={i18n.t('Are_you_sure_question_mark')} subTitle={i18n.t('Deleting_a_user_will_delete_all_messages')} />
{!!changeOwnerRooms && (
<Text style={{ ...styles.subTitleContainerText, color: colors.dangerColor }}>{changeOwnerRooms}</Text>
)}
{!!removedRooms && <Text style={{ ...styles.subTitleContainerText, color: colors.dangerColor }}>{removedRooms}</Text>}
<FooterButtons
cancelTitle={i18n.t('Cancel')}
cancelAction={hideActionSheet}
<ActionSheetContentWithInputAndSubmit
title={i18n.t('Are_you_sure_question_mark')}
iconName='warning'
description={i18n.t('Deleting_a_user_will_delete_all_messages')}
onCancel={hideActionSheet}
onSubmit={handleDeleteAccount}
placeholder={i18n.t('Password')}
testID='room-info-edit-view-name'
confirmTitle={i18n.t('Delete_Account_confirm')}
confirmAction={handleDeleteAccount}
confirmBackgroundColor={colors.dangerColor}
customText={
<>
{!!changeOwnerRooms && <AlertText text={changeOwnerRooms} />}
{!!removedRooms && <AlertText text={removedRooms} />}
</>
}
/>
</View>
);
}

View File

@ -1,7 +1,6 @@
import React from 'react';
import { Keyboard, ScrollView, TextInput, View } from 'react-native';
import { connect } from 'react-redux';
import prompt from 'react-native-prompt-android';
import { sha256 } from 'js-sha256';
import ImagePicker, { Image } from 'react-native-image-crop-picker';
import RNPickerSelect from 'react-native-picker-select';
@ -45,6 +44,7 @@ import { twoFactor } from '../../lib/services/twoFactor';
import { TwoFactorMethods } from '../../definitions/ITotp';
import { withActionSheet, IActionSheetProvider } from '../../containers/ActionSheet';
import { DeleteAccountActionSheetContent } from './components/DeleteAccountActionSheetContent';
import ActionSheetContentWithInputAndSubmit from '../../containers/ActionSheet/ActionSheetContentWithInputAndSubmit';
interface IProfileViewProps extends IActionSheetProvider, IBaseScreen<ProfileStackParamList, 'ProfileView'> {
user: IUser;
@ -250,26 +250,25 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}
const requirePassword = !!params.email || newPassword;
if (requirePassword && !params.currentPassword) {
this.setState({ saving: false });
prompt(
I18n.t('Please_enter_your_password'),
I18n.t('For_your_security_you_must_enter_your_current_password_to_continue'),
[
{ text: I18n.t('Cancel'), onPress: () => {}, style: 'cancel' },
{
text: I18n.t('Save'),
onPress: (p: string) => {
this.setState({ currentPassword: p });
this.submit();
}
}
],
{
type: 'secure-text',
cancelable: false
}
);
this.props.showActionSheet({
children: (
<ActionSheetContentWithInputAndSubmit
title={I18n.t('Please_enter_your_password')}
description={I18n.t('For_your_security_you_must_enter_your_current_password_to_continue')}
testID='profile-view-enter-password-sheet'
placeholder={I18n.t('Password')}
onSubmit={(p: string) => {
this.props.hideActionSheet();
this.setState({ currentPassword: p }, () => this.submit());
}}
onCancel={this.props.hideActionSheet}
/>
),
headerHeight: 225
});
return;
}
@ -661,6 +660,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
const mapStateToProps = (state: IApplicationState) => ({
user: getUserSelector(state),
isMasterDetail: state.app.isMasterDetail,
Accounts_AllowEmailChange: state.settings.Accounts_AllowEmailChange as boolean,
Accounts_AllowPasswordChange: state.settings.Accounts_AllowPasswordChange as boolean,
Accounts_AllowRealNameChange: state.settings.Accounts_AllowRealNameChange as boolean,
@ -668,8 +668,7 @@ const mapStateToProps = (state: IApplicationState) => ({
Accounts_AllowUsernameChange: state.settings.Accounts_AllowUsernameChange as boolean,
Accounts_CustomFields: state.settings.Accounts_CustomFields as string,
baseUrl: state.server.server,
Accounts_AllowDeleteOwnAccount: state.settings.Accounts_AllowDeleteOwnAccount as boolean,
isMasterDetail: state.app.isMasterDetail
Accounts_AllowDeleteOwnAccount: state.settings.Accounts_AllowDeleteOwnAccount as boolean
});
export default connect(mapStateToProps)(withTheme(withActionSheet(ProfileView)));

View File

@ -1,13 +1,14 @@
/* eslint-disable complexity */
import { Q } from '@nozbe/watermelondb';
import { StackNavigationOptions } from '@react-navigation/stack';
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
import isEmpty from 'lodash/isEmpty';
import React from 'react';
import { Share, Switch, Text, View } from 'react-native';
import { connect } from 'react-redux';
import { Observable, Subscription } from 'rxjs';
import { CompositeNavigationProp } from '@react-navigation/native';
import { closeRoom, leaveRoom } from '../../actions/room';
import { leaveRoom } from '../../actions/room';
import { setLoading } from '../../actions/selectedUsers';
import Avatar from '../../containers/Avatar';
import * as HeaderButton from '../../containers/HeaderButton';
@ -44,13 +45,17 @@ import {
} from '../../lib/methods/helpers';
import { Services } from '../../lib/services';
import { getSubscriptionByRoomId } from '../../lib/database/services/Subscription';
import { IActionSheetProvider, withActionSheet } from '../../containers/ActionSheet';
import CloseLivechatSheet from '../../ee/omnichannel/containers/CloseLivechatSheet';
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
import { closeLivechat } from '../../lib/methods/helpers/closeLivechat';
import { videoConfStartAndJoin } from '../../lib/methods/videoConf';
interface IOnPressTouch {
<T extends keyof ChatsStackParamList>(item: { route?: T; params?: ChatsStackParamList[T]; event?: Function }): void;
}
interface IRoomActionsViewProps extends IBaseScreen<ChatsStackParamList, 'RoomActionsView'> {
interface IRoomActionsViewProps extends IActionSheetProvider, IBaseScreen<ChatsStackParamList, 'RoomActionsView'> {
userId: string;
jitsiEnabled: boolean;
jitsiEnableTeams: boolean;
@ -69,6 +74,12 @@ interface IRoomActionsViewProps extends IBaseScreen<ChatsStackParamList, 'RoomAc
addTeamChannelPermission?: string[];
convertTeamPermission?: string[];
viewCannedResponsesPermission?: string[];
livechatAllowManualOnHold?: boolean;
livechatRequestComment?: boolean;
navigation: CompositeNavigationProp<
StackNavigationProp<ChatsStackParamList, 'RoomActionsView'>,
StackNavigationProp<MasterDetailInsideStackParamList>
>;
videoConf_Enable_DMs: boolean;
videoConf_Enable_Channels: boolean;
videoConf_Enable_Groups: boolean;
@ -369,9 +380,25 @@ class RoomActionsView extends React.Component<IRoomActionsViewProps, IRoomAction
const {
room: { rid }
} = this.state;
const { dispatch } = this.props;
const { livechatRequestComment, showActionSheet, hideActionSheet, isMasterDetail } = this.props;
dispatch(closeRoom(rid));
if (!livechatRequestComment) {
const comment = I18n.t('Chat_closed_by_agent');
return closeLivechat({ rid, isMasterDetail, comment });
}
showActionSheet({
children: (
<CloseLivechatSheet
onSubmit={(comment: string) => {
hideActionSheet();
closeLivechat({ rid, isMasterDetail, comment });
}}
onCancel={() => hideActionSheet()}
/>
),
headerHeight: 225
});
};
placeOnHoldLivechat = () => {
@ -1363,7 +1390,10 @@ const mapStateToProps = (state: IApplicationState) => ({
viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'],
createTeamPermission: state.permissions['create-team'],
addTeamChannelPermission: state.permissions['add-team-channel'],
convertTeamPermission: state.permissions['convert-team']
convertTeamPermission: state.permissions['convert-team'],
viewCannedResponsesPermission: state.permissions['view-canned-responses'],
livechatAllowManualOnHold: state.settings.Livechat_allow_manual_on_hold as boolean,
livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean
});
export default connect(mapStateToProps)(withTheme(withDimensions(RoomActionsView)));
export default connect(mapStateToProps)(withTheme(withActionSheet(withDimensions(RoomActionsView))));

View File

@ -12,13 +12,14 @@ import { events, logEvent } from '../../lib/methods/helpers/log';
import { isTeamRoom } from '../../lib/methods/helpers/room';
import { IApplicationState, SubscriptionType, TMessageModel, TSubscriptionModel } from '../../definitions';
import { ChatsStackParamList } from '../../stacks/types';
import { TActionSheetOptions, TActionSheetOptionsItem, withActionSheet } from '../../containers/ActionSheet';
import { IActionSheetProvider, TActionSheetOptionsItem, withActionSheet } from '../../containers/ActionSheet';
import i18n from '../../i18n';
import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers';
import { closeRoom } from '../../actions/room';
import { onHoldLivechat, returnLivechat } from '../../lib/services/restApi';
import { closeLivechat as closeLivechatService } from '../../lib/methods/helpers/closeLivechat';
import CloseLivechatSheet from '../../ee/omnichannel/containers/CloseLivechatSheet';
interface IRightButtonsProps {
interface IRightButtonsProps extends IActionSheetProvider {
userId?: string;
threadsEnabled: boolean;
rid: string;
@ -31,7 +32,6 @@ interface IRightButtonsProps {
status?: string;
dispatch: Dispatch;
encrypted?: boolean;
showActionSheet: (item: TActionSheetOptions) => void;
transferLivechatGuestPermission: boolean;
navigation: StackNavigationProp<ChatsStackParamList, 'RoomView'>;
omnichannelPermissions: {
@ -39,6 +39,7 @@ interface IRightButtonsProps {
canReturnQueue: boolean;
canPlaceLivechatOnHold: boolean;
};
livechatRequestComment: boolean;
}
interface IRigthButtonsState {
@ -214,8 +215,29 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
};
closeLivechat = () => {
const { dispatch, rid } = this.props;
dispatch(closeRoom(rid));
const { rid, livechatRequestComment, showActionSheet, hideActionSheet, isMasterDetail } = this.props;
hideActionSheet();
setTimeout(() => {
if (!livechatRequestComment) {
const comment = i18n.t('Chat_closed_by_agent');
return closeLivechatService({ rid, isMasterDetail, comment });
}
showActionSheet({
children: (
<CloseLivechatSheet
onSubmit={(comment: string) => {
hideActionSheet();
closeLivechatService({ rid, isMasterDetail, comment });
}}
onCancel={() => hideActionSheet()}
/>
),
headerHeight: 225
});
}, 300);
};
showMoreActions = () => {
@ -335,7 +357,8 @@ class RightButtonsContainer extends Component<IRightButtonsProps, IRigthButtonsS
const mapStateToProps = (state: IApplicationState) => ({
userId: getUserSelector(state).id,
threadsEnabled: state.settings.Threads_enabled as boolean,
isMasterDetail: state.app.isMasterDetail
isMasterDetail: state.app.isMasterDetail,
livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean
});
export default connect(mapStateToProps)(withActionSheet(RightButtonsContainer));

View File

@ -108,7 +108,6 @@
"react-native-platform-touchable": "1.1.1",
"react-native-popover-view": "4.0.1",
"react-native-progress": "5.0.0",
"react-native-prompt-android": "^1.1.0",
"react-native-reanimated": "2.2.2",
"react-native-restart": "0.0.22",
"react-native-safe-area-context": "3.2.0",

View File

@ -15302,11 +15302,6 @@ react-native-progress@5.0.0:
dependencies:
prop-types "^15.7.2"
react-native-prompt-android@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-native-prompt-android/-/react-native-prompt-android-1.1.0.tgz#3c5168029075cb9f72549fd5f92403372fb234e9"
integrity sha512-4JoyEaT2ZnK9IH+tDFpbTiQBgva8UIFGQf4/Uw/tnEVWBERlVlzcs5B82T9BkeEhEqXhp89JaiSBnLWj30lciw==
react-native-reanimated@2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.2.2.tgz#8bc81c7ee93d599991507bb826050a5eeee1e7f2"