[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:
parent
1e9ae6e157
commit
18c44178d7
|
@ -27,7 +27,6 @@ export const ROOM = createRequestTypes('ROOM', [
|
|||
'LEAVE',
|
||||
'DELETE',
|
||||
'REMOVED',
|
||||
'CLOSE',
|
||||
'FORWARD',
|
||||
'USER_TYPING'
|
||||
]);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -63,12 +63,5 @@ export default StyleSheet.create({
|
|||
},
|
||||
rightContainer: {
|
||||
paddingLeft: 12
|
||||
},
|
||||
footerButtonsContainer: {
|
||||
flexDirection: 'row',
|
||||
paddingTop: 16
|
||||
},
|
||||
buttonSeparator: {
|
||||
marginRight: 8
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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 });
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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
|
||||
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}
|
||||
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}
|
||||
confirmTitle={i18n.t('Delete_Account')}
|
||||
confirmAction={handleDeleteAccount}
|
||||
disabled={!password}
|
||||
/>
|
||||
</View>
|
||||
<ActionSheetContentWithInputAndSubmit
|
||||
title={i18n.t('Are_you_sure_you_want_to_delete_your_account')}
|
||||
description={i18n.t('For_your_security_you_must_enter_your_current_password_to_continue')}
|
||||
onCancel={hideActionSheet}
|
||||
onSubmit={password => handleDeleteAccount(password)}
|
||||
placeholder={i18n.t('Password')}
|
||||
testID='room-info-edit-view-name'
|
||||
iconName='warning'
|
||||
confirmTitle={i18n.t('Delete_Account')}
|
||||
confirmBackgroundColor={colors.dangerColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
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}
|
||||
confirmTitle={i18n.t('Delete_Account_confirm')}
|
||||
confirmAction={handleDeleteAccount}
|
||||
/>
|
||||
</View>
|
||||
<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')}
|
||||
confirmBackgroundColor={colors.dangerColor}
|
||||
customText={
|
||||
<>
|
||||
{!!changeOwnerRooms && <AlertText text={changeOwnerRooms} />}
|
||||
{!!removedRooms && <AlertText text={removedRooms} />}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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))));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue