[MM-13843] Edit channel autocomplete is same as the posting message one (#3038)

* [MM-13843] Edit channle autocomplete is same as the posting message

* [MM-13843] Lint error fixes

* [MM-13843] Address nestedscrollenable warning comment

* [MM-13843] Added test case for edit_channel_info

* [MM-13843] nestedScrollEnabled on at_mention

* [MM-13843] Fix linting issue

* [MM-13843] Fixed test case

* [MM-13843] Address PR comments

* [MM-13843] Made prop not required
This commit is contained in:
Hossein Ahmadian-Yazdi 2019-08-16 00:22:32 -04:00 committed by Miguel Alatzar
parent 4d22a28397
commit ef8813f115
10 changed files with 97 additions and 4 deletions

View file

@ -36,6 +36,7 @@ export default class AtMention extends PureComponent {
theme: PropTypes.object.isRequired,
value: PropTypes.string,
isLandscape: PropTypes.bool.isRequired,
nestedScrollEnabled: PropTypes.bool,
};
static defaultProps = {
@ -207,7 +208,7 @@ export default class AtMention extends PureComponent {
};
render() {
const {maxListHeight, theme} = this.props;
const {maxListHeight, theme, nestedScrollEnabled} = this.props;
const {mentionComplete, sections} = this.state;
if (sections.length === 0 || mentionComplete) {
@ -228,6 +229,7 @@ export default class AtMention extends PureComponent {
renderSectionHeader={this.renderSectionHeader}
ItemSeparatorComponent={AutocompleteDivider}
initialNumToRender={10}
nestedScrollEnabled={nestedScrollEnabled}
/>
);
}

View file

@ -33,12 +33,14 @@ export default class Autocomplete extends PureComponent {
enableDateSuggestion: PropTypes.bool.isRequired,
valueEvent: PropTypes.string,
cursorPositionEvent: PropTypes.string,
nestedScrollEnabled: PropTypes.bool,
};
static defaultProps = {
isSearch: false,
cursorPosition: 0,
enableDateSuggestion: false,
nestedScrollEnabled: false,
};
static getDerivedStateFromProps(props, state) {
@ -191,6 +193,7 @@ export default class Autocomplete extends PureComponent {
onChangeText={this.onChangeText}
onResultCountChange={this.handleAtMentionCountChange}
value={value || ''}
nestedScrollEnabled={this.props.nestedScrollEnabled}
/>
<ChannelMention
{...this.props}
@ -199,6 +202,7 @@ export default class Autocomplete extends PureComponent {
onChangeText={this.onChangeText}
onResultCountChange={this.handleChannelMentionCountChange}
value={value || ''}
nestedScrollEnabled={this.props.nestedScrollEnabled}
/>
<EmojiSuggestion
{...this.props}
@ -207,6 +211,7 @@ export default class Autocomplete extends PureComponent {
onChangeText={this.onChangeText}
onResultCountChange={this.handleEmojiCountChange}
value={value || ''}
nestedScrollEnabled={this.props.nestedScrollEnabled}
/>
<SlashSuggestion
{...this.props}
@ -214,6 +219,7 @@ export default class Autocomplete extends PureComponent {
onChangeText={this.onChangeText}
onResultCountChange={this.handleCommandCountChange}
value={value || ''}
nestedScrollEnabled={this.props.nestedScrollEnabled}
/>
{(this.props.isSearch && this.props.enableDateSuggestion) &&
<DateSuggestion

View file

@ -40,6 +40,7 @@ export default class ChannelMention extends PureComponent {
value: PropTypes.string,
serverVersion: PropTypes.string,
isLandscape: PropTypes.bool.isRequired,
nestedScrollEnabled: PropTypes.bool,
};
static defaultProps = {
@ -211,7 +212,7 @@ export default class ChannelMention extends PureComponent {
};
render() {
const {maxListHeight, theme} = this.props;
const {maxListHeight, theme, nestedScrollEnabled} = this.props;
const {mentionComplete, sections} = this.state;
if (sections.length === 0 || mentionComplete) {
@ -232,6 +233,7 @@ export default class ChannelMention extends PureComponent {
renderSectionHeader={this.renderSectionHeader}
ItemSeparatorComponent={AutocompleteDivider}
initialNumToRender={10}
nestedScrollEnabled={nestedScrollEnabled}
/>
);
}

View file

@ -37,6 +37,7 @@ export default class EmojiSuggestion extends Component {
rootId: PropTypes.string,
value: PropTypes.string,
serverVersion: PropTypes.string,
nestedScrollEnabled: PropTypes.bool,
};
static defaultProps = {
@ -188,7 +189,7 @@ export default class EmojiSuggestion extends Component {
getItemLayout = ({index}) => ({length: 40, offset: 40 * index, index})
render() {
const {maxListHeight, theme} = this.props;
const {maxListHeight, theme, nestedScrollEnabled} = this.props;
if (!this.state.active) {
// If we are not in an active state return null so nothing is rendered
@ -209,6 +210,7 @@ export default class EmojiSuggestion extends Component {
ItemSeparatorComponent={AutocompleteDivider}
pageSize={10}
initialListSize={10}
nestedScrollEnabled={nestedScrollEnabled}
/>
);
}

View file

@ -33,6 +33,7 @@ export default class SlashSuggestion extends Component {
onResultCountChange: PropTypes.func.isRequired,
value: PropTypes.string,
isLandscape: PropTypes.bool.isRequired,
nestedScrollEnabled: PropTypes.bool,
};
static defaultProps = {
@ -151,7 +152,7 @@ export default class SlashSuggestion extends Component {
)
render() {
const {maxListHeight, theme} = this.props;
const {maxListHeight, theme, nestedScrollEnabled} = this.props;
if (!this.state.active) {
// If we are not in an active state return null so nothing is rendered
@ -172,6 +173,7 @@ export default class SlashSuggestion extends Component {
ItemSeparatorComponent={AutocompleteDivider}
pageSize={10}
initialListSize={10}
nestedScrollEnabled={nestedScrollEnabled}
/>
);
}

View file

@ -14,6 +14,7 @@ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import {General} from 'mattermost-redux/constants';
import Autocomplete from 'app/components/autocomplete';
import ErrorText from 'app/components/error_text';
import FormattedText from 'app/components/formatted_text';
import Loading from 'app/components/loading';
@ -220,6 +221,7 @@ export default class EditChannelInfo extends PureComponent {
<KeyboardAwareScrollView
ref={this.scroll}
style={style.container}
keyboardShouldPersistTaps={'always'}
>
{displayError}
<TouchableWithoutFeedback onPress={this.blur}>
@ -330,6 +332,13 @@ export default class EditChannelInfo extends PureComponent {
defaultMessage='(optional)'
/>
</View>
<Autocomplete
cursorPosition={header.length}
maxHeight={200}
onChangeText={this.onHeaderChangeText}
value={header}
nestedScrollEnabled={true}
/>
<View style={[style.inputContainer, padding(isLandscape)]}>
<TextInputWithLocalizedPlaceholder
ref={this.headerInput}

View file

@ -0,0 +1,63 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import Preferences from 'mattermost-redux/constants/preferences';
import Autocomplete from 'app/components/autocomplete';
import EditChannelInfo from './edit_channel_info';
describe('EditChannelInfo', () => {
const baseProps = {
actions: {
dismissModal: jest.fn(),
popTopScreen: jest.fn(),
},
theme: Preferences.THEMES.default,
deviceWidth: 400,
deviceHeight: 600,
channelType: 'O',
enableRightButton: jest.fn(),
saving: false,
editing: true,
error: '',
displayName: 'display_name',
currentTeamUrl: '/team_a',
channelURL: '/team_a/channels/channel_a',
purpose: 'purpose',
header: 'header',
onDisplayNameChange: jest.fn(),
onChannelURLChange: jest.fn(),
onPurposeChange: jest.fn(),
onHeaderChange: jest.fn(),
oldDisplayName: 'old_display_name',
oldChannelURL: '/team_a/channels/channel_old',
oldHeader: 'old_header',
oldPurpose: 'old_purpose',
isLandscape: true,
};
test('should have called onHeaderChangeText on text change from Autocomplete', () => {
const wrapper = shallow(
<EditChannelInfo {...baseProps}/>
);
const instance = wrapper.instance();
instance.enableRightButton = jest.fn();
const autocomplete = wrapper.find(Autocomplete);
expect(autocomplete.exists()).toEqual(true);
expect(autocomplete.props().value).toEqual('header');
expect(autocomplete.props().cursorPosition).toEqual(6);
expect(autocomplete.props().nestedScrollEnabled).toEqual(true);
autocomplete.props().onChangeText('header');
expect(baseProps.onHeaderChange).toHaveBeenCalledTimes(1);
expect(baseProps.onHeaderChange).toHaveBeenCalledWith('header');
expect(instance.enableRightButton).toHaveBeenCalledTimes(1);
expect(instance.enableRightButton).toHaveBeenCalledWith(true);
});
});

View file

@ -493,6 +493,7 @@ export default class ChannelInfo extends PureComponent {
theme,
isBot,
isLandscape,
actions: {popToRoot},
} = this.props;
const style = getStyleSheet(theme);
@ -533,6 +534,7 @@ export default class ChannelInfo extends PureComponent {
isBot={isBot}
hasGuests={currentChannelGuestCount > 0}
isGroupConstrained={currentChannel.group_constrained}
popToRoot={popToRoot}
/>
}
<View style={style.rowsContainer}>

View file

@ -42,6 +42,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
hasGuests: PropTypes.bool.isRequired,
isGroupConstrained: PropTypes.bool,
timeZone: PropTypes.string,
popToRoot: PropTypes.func,
};
static contextTypes = {
@ -137,6 +138,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
isBot,
isGroupConstrained,
timeZone,
popToRoot,
} = this.props;
const style = getStyleSheet(theme);
@ -210,6 +212,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
textStyles={textStyles}
blockStyles={blockStyles}
value={header}
onChannelLinkPress={popToRoot}
/>
</View>
</TouchableHighlight>

View file

@ -35,6 +35,7 @@ import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
import {
popTopScreen,
goToScreen,
popToRoot,
dismissModal,
showModalOverCurrentContext,
} from 'app/actions/navigation';
@ -146,6 +147,7 @@ function mapDispatchToProps(dispatch) {
handleSelectChannel,
popTopScreen,
goToScreen,
popToRoot,
dismissModal,
showModalOverCurrentContext,
}, dispatch),