MM-15218 Open as alert dialog when interactive message is without element (#3088)
* open as alert dialog when interactive message is without element * add missing translations
This commit is contained in:
parent
7410e3c266
commit
ca61faafd5
4 changed files with 132 additions and 10 deletions
|
|
@ -4,6 +4,8 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {submitInteractiveDialog} from 'mattermost-redux/actions/integrations';
|
||||
|
||||
import {showModal} from 'app/actions/navigation';
|
||||
|
||||
import InteractiveDialogController from './interactive_dialog_controller';
|
||||
|
|
@ -11,7 +13,7 @@ import InteractiveDialogController from './interactive_dialog_controller';
|
|||
function mapStateToProps(state) {
|
||||
return {
|
||||
triggerId: state.entities.integrations.dialogTriggerId,
|
||||
dialog: state.entities.integrations.dialog || {},
|
||||
dialogData: state.entities.integrations.dialog || {},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -19,6 +21,7 @@ function mapDispatchToProps(dispatch) {
|
|||
return {
|
||||
actions: bindActionCreators({
|
||||
showModal,
|
||||
submitInteractiveDialog,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,17 @@
|
|||
import {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||
import {Alert} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
export default class InteractiveDialogController extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
showModal: PropTypes.func.isRequired,
|
||||
submitInteractiveDialog: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
triggerId: PropTypes.string,
|
||||
dialog: PropTypes.object,
|
||||
dialogData: PropTypes.object,
|
||||
theme: PropTypes.object,
|
||||
};
|
||||
|
||||
|
|
@ -23,14 +26,18 @@ export default class InteractiveDialogController extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {actions, triggerId} = this.props;
|
||||
const {triggerId} = this.props;
|
||||
if (!triggerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dialogData = this.props.dialog || {};
|
||||
const prevDialogData = prevProps.dialog || {};
|
||||
const dialogData = this.props.dialogData || {};
|
||||
const prevDialogData = prevProps.dialogData || {};
|
||||
if (prevProps.triggerId === triggerId && dialogData.trigger_id === prevDialogData.trigger_id) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -43,9 +50,30 @@ export default class InteractiveDialogController extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
const screen = 'InteractiveDialog';
|
||||
const title = dialogData.dialog.title;
|
||||
const passProps = {};
|
||||
if (dialogData.dialog.elements && dialogData.dialog.elements.length > 0) {
|
||||
this.showInteractiveDialogScreen(dialogData.dialog);
|
||||
} else {
|
||||
this.showAlertDialog(dialogData.dialog, dialogData.url);
|
||||
}
|
||||
}
|
||||
|
||||
showAlertDialog(dialog, url) {
|
||||
const {formatMessage} = this.context.intl;
|
||||
|
||||
Alert.alert(
|
||||
dialog.title,
|
||||
'',
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.alert_dialog.alertCancel', defaultMessage: 'Cancel'}),
|
||||
onPress: () => this.handleCancel(dialog, url),
|
||||
}, {
|
||||
text: dialog.submit_label,
|
||||
onPress: () => this.props.actions.submitInteractiveDialog({...dialog, url}),
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
showInteractiveDialogScreen = (dialog) => {
|
||||
const options = {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
|
|
@ -55,12 +83,18 @@ export default class InteractiveDialogController extends PureComponent {
|
|||
rightButtons: [{
|
||||
id: 'submit-dialog',
|
||||
showAsAction: 'always',
|
||||
text: dialogData.dialog.submit_label,
|
||||
text: dialog.submit_label,
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
actions.showModal(screen, title, passProps, options);
|
||||
this.props.actions.showModal('InteractiveDialog', dialog.title, null, options);
|
||||
}
|
||||
|
||||
handleCancel = (dialog, url) => {
|
||||
if (dialog.notify_on_cancel) {
|
||||
this.props.actions.submitInteractiveDialog({...dialog, url, cancelled: true});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
|
||||
import InteractiveDialogController from './interactive_dialog_controller';
|
||||
|
||||
jest.mock('react-intl');
|
||||
jest.mock('react-native-vector-icons/MaterialIcons', () => ({
|
||||
getImageSource: jest.fn().mockResolvedValue({}),
|
||||
}));
|
||||
|
||||
describe('InteractiveDialogController', () => {
|
||||
test('should open interactive dialog as alert or screen depending on with or without element', () => {
|
||||
let baseProps = getBaseProps('trigger_id_1');
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialogController {...baseProps}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
instance.showAlertDialog = jest.fn();
|
||||
instance.showInteractiveDialogScreen = jest.fn();
|
||||
|
||||
expect(instance.showAlertDialog).toHaveBeenCalledTimes(0);
|
||||
expect(instance.showInteractiveDialogScreen).toHaveBeenCalledTimes(0);
|
||||
|
||||
baseProps = getBaseProps('trigger_id_2');
|
||||
wrapper.setProps({...baseProps});
|
||||
expect(instance.showAlertDialog).toHaveBeenCalledTimes(1);
|
||||
expect(instance.showAlertDialog).toHaveBeenCalledWith(baseProps.dialogData.dialog, baseProps.dialogData.url);
|
||||
expect(instance.showInteractiveDialogScreen).toHaveBeenCalledTimes(0);
|
||||
|
||||
const elements = [{
|
||||
data_source: '',
|
||||
default: '',
|
||||
display_name: 'Number',
|
||||
help_text: '',
|
||||
max_length: 0,
|
||||
min_length: 0,
|
||||
name: 'somenumber',
|
||||
optional: false,
|
||||
options: null,
|
||||
placeholder: '',
|
||||
subtype: 'number',
|
||||
type: 'text',
|
||||
}];
|
||||
|
||||
baseProps = getBaseProps('trigger_id_3', elements);
|
||||
wrapper.setProps({...baseProps});
|
||||
expect(instance.showAlertDialog).toHaveBeenCalledTimes(1);
|
||||
expect(instance.showInteractiveDialogScreen).toHaveBeenCalledTimes(1);
|
||||
expect(instance.showInteractiveDialogScreen).toHaveBeenCalledWith(baseProps.dialogData.dialog);
|
||||
});
|
||||
});
|
||||
|
||||
function getBaseProps(triggerId, elements) {
|
||||
const dialogData = {
|
||||
dialog: {
|
||||
callback_id: 'somecallbackid',
|
||||
elements,
|
||||
icon_url: 'icon_url',
|
||||
notify_on_cancel: true,
|
||||
state: 'somestate',
|
||||
submit_label: 'Submit Test',
|
||||
title: 'Dialog Test',
|
||||
},
|
||||
trigger_id: triggerId,
|
||||
url: 'https://localhost:8065/dialog_submit',
|
||||
};
|
||||
|
||||
return {
|
||||
actions: {
|
||||
showModal: jest.fn(),
|
||||
submitInteractiveDialog: jest.fn(),
|
||||
},
|
||||
triggerId,
|
||||
dialogData,
|
||||
theme: {},
|
||||
};
|
||||
}
|
||||
|
|
@ -137,6 +137,7 @@
|
|||
"mobile.advanced_settings.delete_title": "Delete Documents & Data",
|
||||
"mobile.advanced_settings.timezone": "Timezone",
|
||||
"mobile.advanced_settings.title": "Advanced Settings",
|
||||
"mobile.alert_dialog.alertCancel": "Cancel",
|
||||
"mobile.android.camera_permission_denied_description": "To take photos and videos with your camera, please change your permission settings.",
|
||||
"mobile.android.camera_permission_denied_title": "Camera access is required",
|
||||
"mobile.android.permission_denied_dismiss": "Dismiss",
|
||||
|
|
@ -357,6 +358,8 @@
|
|||
"mobile.post_textbox.empty.title": "Empty Message",
|
||||
"mobile.post_textbox.entire_channel.cancel": "Cancel",
|
||||
"mobile.post_textbox.entire_channel.confirm": "Confirm",
|
||||
"mobile.post_textbox.entire_channel.message": "By using @all or @channel you are about to send notifications to {totalMembers} people. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.entire_channel.message.with_timezones": "By using @all or @channel you are about to send notifications to {totalMembers} people in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.entire_channel.title": "Confirm sending notifications to entire channel",
|
||||
"mobile.post_textbox.uploadFailedDesc": "Some attachments failed to upload to the server. Are you sure you want to post the message?",
|
||||
"mobile.post_textbox.uploadFailedTitle": "Attachment failure",
|
||||
|
|
|
|||
Loading…
Reference in a new issue