MM-15220 Support generic error message in interactive dialog (#3259)
This commit is contained in:
parent
2f65ff853d
commit
be4bddc52a
2 changed files with 80 additions and 12 deletions
|
|
@ -8,6 +8,7 @@ import {Navigation} from 'react-native-navigation';
|
|||
|
||||
import {checkDialogElementForError, checkIfErrorsMatchElements} from 'mattermost-redux/utils/integration_utils';
|
||||
|
||||
import ErrorText from 'app/components/error_text';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
|
||||
|
|
@ -48,10 +49,13 @@ export default class InteractiveDialog extends PureComponent {
|
|||
|
||||
this.state = {
|
||||
values,
|
||||
error: null,
|
||||
errors: {},
|
||||
isLandscape: this.isLandscape(),
|
||||
submitting: false,
|
||||
};
|
||||
|
||||
this.scrollView = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -123,17 +127,29 @@ export default class InteractiveDialog extends PureComponent {
|
|||
|
||||
this.submitted = true;
|
||||
|
||||
if (!data || !data.errors || Object.keys(data.errors).length === 0) {
|
||||
let hasErrors = false;
|
||||
|
||||
if (data) {
|
||||
if (data.errors &&
|
||||
Object.keys(data.errors).length >= 0 &&
|
||||
checkIfErrorsMatchElements(data.errors, elements)
|
||||
) {
|
||||
hasErrors = true;
|
||||
this.setState({errors: data.errors});
|
||||
}
|
||||
|
||||
if (data.error) {
|
||||
hasErrors = true;
|
||||
this.setState({error: data.error});
|
||||
if (this.scrollView?.current) {
|
||||
this.scrollView.current.scrollTo({x: 0, y: 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasErrors) {
|
||||
this.handleHide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkIfErrorsMatchElements(data.errors, elements)) {
|
||||
this.setState({errors: data.errors});
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleHide();
|
||||
}
|
||||
|
||||
notifyOnCancelIfNeeded = () => {
|
||||
|
|
@ -168,13 +184,22 @@ export default class InteractiveDialog extends PureComponent {
|
|||
|
||||
render() {
|
||||
const {introductionText, elements, theme} = this.props;
|
||||
const {errors, isLandscape, values} = this.state;
|
||||
const {error, errors, isLandscape, values} = this.state;
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<ScrollView style={style.scrollView}>
|
||||
<ScrollView
|
||||
ref={this.scrollView}
|
||||
style={style.scrollView}
|
||||
>
|
||||
<StatusBar/>
|
||||
{error && (
|
||||
<ErrorText
|
||||
textStyle={style.errorContainer}
|
||||
error={error}
|
||||
/>
|
||||
)}
|
||||
{Boolean(introductionText) &&
|
||||
<DialogIntroductionText
|
||||
value={introductionText}
|
||||
|
|
@ -216,6 +241,12 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
|||
container: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
},
|
||||
errorContainer: {
|
||||
marginTop: 15,
|
||||
marginLeft: 15,
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
scrollView: {
|
||||
marginBottom: 20,
|
||||
marginTop: 10,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import Preferences from 'mattermost-redux/constants/preferences';
|
|||
|
||||
import InteractiveDialog from './interactive_dialog';
|
||||
|
||||
import ErrorText from 'app/components/error_text';
|
||||
|
||||
describe('InteractiveDialog', () => {
|
||||
const baseProps = {
|
||||
url: 'http://mattermost.com',
|
||||
|
|
@ -18,7 +20,8 @@ describe('InteractiveDialog', () => {
|
|||
state: 'somestate',
|
||||
theme: Preferences.THEMES.default,
|
||||
actions: {
|
||||
submitInteractiveDialog: jest.fn(),
|
||||
submitInteractiveDialog: jest.fn(() => ({})),
|
||||
dismissModal: jest.fn(),
|
||||
},
|
||||
componentId: 'component-id',
|
||||
};
|
||||
|
|
@ -140,4 +143,38 @@ describe('InteractiveDialog', () => {
|
|||
expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledTimes(1);
|
||||
expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledWith(dialog);
|
||||
});
|
||||
|
||||
describe('generic error message', () => {
|
||||
test('should show error when submit returns an error', async () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
actions: {
|
||||
...baseProps.actions,
|
||||
submitInteractiveDialog: async () => ({
|
||||
data: {error: 'This is an error message.'},
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialog {...props}/>
|
||||
);
|
||||
wrapper.instance().scrollView = {current: {scrollTo: jest.fn()}};
|
||||
|
||||
await wrapper.instance().handleSubmit();
|
||||
expect(wrapper.find(ErrorText).find({error: 'This is an error message.'})).toHaveLength(1);
|
||||
expect(wrapper.instance().scrollView.current.scrollTo).toHaveBeenCalledWith({x: 0, y: 0});
|
||||
});
|
||||
|
||||
test('should show no error when submit does not return an error', async () => {
|
||||
const wrapper = shallow(
|
||||
<InteractiveDialog {...baseProps}/>
|
||||
);
|
||||
wrapper.instance().scrollView = {current: {scrollTo: jest.fn()}};
|
||||
|
||||
await wrapper.instance().handleSubmit();
|
||||
expect(wrapper.find(ErrorText)).not.toExist();
|
||||
expect(wrapper.instance().scrollView.current.scrollTo).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue