Dismiss keyboard on edit post close (#4110)

* Dismiss keyboard on edit post close

* Don't use edit post request

* Focus on error
This commit is contained in:
Miguel Alatzar 2020-04-07 09:50:35 -07:00 committed by GitHub
parent 717350adc6
commit 4e3e557519
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 1989 additions and 1844 deletions

File diff suppressed because it is too large Load diff

View file

@ -392,15 +392,20 @@ export function deletePost(post: ExtendedPost) {
}
export function editPost(post: Post) {
return bindClientFunc({
clientFunc: Client4.patchPost,
onRequest: PostTypes.EDIT_POST_REQUEST,
onSuccess: [PostTypes.RECEIVED_POST, PostTypes.EDIT_POST_SUCCESS],
onFailure: PostTypes.EDIT_POST_FAILURE,
params: [
post,
],
});
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
let data;
try {
data = await Client4.patchPost(post);
} catch (error) {
forceLogoutIfNecessary(error, dispatch, getState);
return {error};
}
dispatch(receivedPost(post));
return {data};
};
}
export function getUnreadPostData(unreadChan: ChannelUnread, state: GlobalState) {

View file

@ -0,0 +1,93 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EditPost should match snapshot 1`] = `
<View
style={
Object {
"flex": 1,
}
}
>
<Connect(StatusBar) />
<View
style={
Object {
"backgroundColor": "rgba(61,60,64,0.03)",
"flex": 1,
}
}
>
<View
style={
Array [
Object {
"backgroundColor": "#ffffff",
"borderBottomColor": "rgba(61,60,64,0.1)",
"borderBottomWidth": 1,
"borderTopColor": "rgba(61,60,64,0.1)",
"borderTopWidth": 1,
"marginTop": 2,
},
null,
Object {
"height": NaN,
},
]
}
>
<TextInputWithLocalizedPlaceholder
blurOnSubmit={false}
disableFullscreenUI={true}
keyboardAppearance="light"
keyboardType="default"
multiline={true}
numberOfLines={10}
onChangeText={[Function]}
onSelectionChange={[Function]}
placeholder={
Object {
"defaultMessage": "Edit the post...",
"id": "edit_post.editPost",
}
}
placeholderTextColor="rgba(61,60,64,0.4)"
style={
Array [
Object {
"color": "#3d3c40",
"fontSize": 14,
"padding": 15,
"textAlignVertical": "top",
},
Object {
"height": NaN,
},
]
}
underlineColorAndroid="transparent"
/>
</View>
</View>
<KeyboardTrackingView
style={
Array [
Object {
"flex": 1,
"justifyContent": "flex-end",
},
Object {
"flex": 0,
},
]
}
>
<Connect(Autocomplete)
cursorPosition={0}
maxHeight={200}
nestedScrollEnabled={true}
onChangeText={[Function]}
onVisible={[Function]}
/>
</KeyboardTrackingView>
</View>
`;

View file

@ -6,6 +6,7 @@ import {intlShape} from 'react-intl';
import {
Platform,
View,
Keyboard,
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {KeyboardTrackingView} from 'react-native-keyboard-tracking-view';
@ -36,7 +37,6 @@ export default class EditPost extends PureComponent {
closeButton: PropTypes.object,
deviceHeight: PropTypes.number,
deviceWidth: PropTypes.number,
editPostRequest: PropTypes.object.isRequired,
post: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
isLandscape: PropTypes.bool.isRequired,
@ -80,28 +80,6 @@ export default class EditPost extends PureComponent {
this.focus();
}
componentWillReceiveProps(nextProps) {
const {editPostRequest} = nextProps;
if (this.props.editPostRequest !== editPostRequest) {
switch (editPostRequest.status) {
case RequestStatus.STARTED:
this.emitEditing(true);
this.setState({error: null, editing: true});
break;
case RequestStatus.SUCCESS:
this.emitEditing(false);
this.setState({error: null, editing: false});
this.close();
break;
case RequestStatus.FAILURE:
this.emitEditing(false);
this.setState({error: editPostRequest.error, editing: false});
break;
}
}
}
navigationButtonPressed({buttonId}) {
switch (buttonId) {
case 'close-edit-post':
@ -114,6 +92,7 @@ export default class EditPost extends PureComponent {
}
close = () => {
Keyboard.dismiss();
dismissModal();
};
@ -134,17 +113,37 @@ export default class EditPost extends PureComponent {
};
focus = () => {
this.messageInput.focus();
if (this.messageInput) {
this.messageInput.focus();
}
};
messageRef = (ref) => {
this.messageInput = ref;
};
onEditPost = () => {
onEditPost = async () => {
const {message} = this.state;
const post = Object.assign({}, this.props.post, {message});
this.props.actions.editPost(post);
const {post, actions} = this.props;
const editedPost = Object.assign({}, post, {message});
this.setState({
editing: true,
error: null,
});
this.emitEditing(true);
const {error} = await actions.editPost(editedPost);
this.emitEditing(false);
if (error) {
this.setState({
editing: false,
error,
}, this.focus);
} else {
this.setState({editing: false}, this.close);
}
};
onPostChangeText = (message) => {
@ -228,7 +227,6 @@ export default class EditPost extends PureComponent {
multiline={true}
numberOfLines={10}
style={[style.input, {height}]}
autoFocus={true}
placeholder={{id: t('edit_post.editPost'), defaultMessage: 'Edit the post...'}}
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)}
underlineColorAndroid='transparent'

View file

@ -0,0 +1,96 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Keyboard} from 'react-native';
import Preferences from '@mm-redux/constants/preferences';
import {shallowWithIntl} from 'test/intl-test-helper';
import EditPost from './edit_post';
describe('EditPost', () => {
const baseProps = {
actions: {
editPost: jest.fn(),
},
post: {},
theme: Preferences.THEMES.default,
isLandscape: false,
};
test('should match snapshot', () => {
const wrapper = shallowWithIntl(
<EditPost {...baseProps}/>,
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should dismiss keyboard on close', () => {
Keyboard.dismiss = jest.fn();
expect(Keyboard.dismiss).not.toHaveBeenCalled();
const wrapper = shallowWithIntl(
<EditPost {...baseProps}/>,
);
wrapper.instance().close();
expect(Keyboard.dismiss).toHaveBeenCalledTimes(1);
});
test('should handle edit post action error', async () => {
const error = 'error';
const props = {
...baseProps,
actions: {
editPost: jest.fn().mockResolvedValueOnce({error}),
},
};
const wrapper = shallowWithIntl(
<EditPost {...props}/>,
);
const instance = wrapper.instance();
instance.emitEditing = jest.fn();
instance.setState = jest.fn();
await instance.onEditPost();
expect(instance.emitEditing.mock.calls).toEqual([
[true],
[false],
]);
expect(instance.setState.mock.calls).toEqual([
[{editing: true, error: null}],
[{editing: false, error}, instance.focus],
]);
});
test('should handle edit post action success', async () => {
const props = {
...baseProps,
actions: {
editPost: jest.fn().mockResolvedValueOnce({}),
},
};
const wrapper = shallowWithIntl(
<EditPost {...props}/>,
);
const instance = wrapper.instance();
instance.emitEditing = jest.fn();
instance.setState = jest.fn();
await instance.onEditPost();
expect(instance.emitEditing.mock.calls).toEqual([
[true],
[false],
]);
expect(instance.setState.mock.calls).toEqual([
[{editing: true, error: null}],
[{editing: false}, instance.close],
]);
});
});

View file

@ -12,11 +12,8 @@ import {getDimensions, isLandscape} from 'app/selectors/device';
import EditPost from './edit_post';
function mapStateToProps(state, ownProps) {
const {editPost: editPostRequest} = state.requests.posts;
return {
...getDimensions(state),
editPostRequest,
post: ownProps.post,
theme: getTheme(state),
isLandscape: isLandscape(state),