mattermost-mobile/app/screens/edit_channel/edit_channel.js
Miguel Alatzar 2d81b497cf [MM-23520] Port mattermost-redux (#4088)
* Remove mattermost-redux

* Move mm-redux files into app/redux

* Add @redux path to tsconfig.json

* Fix imports

* Install missing dependencies

* Fix tsc errors

* Fix i18n_utils test

* Fix more imports

* Remove redux websocket

* Fix tests

* Rename @redux

* Apply changes from mattermost-redux PR 1103

* Remove mattermost-redux mention in template

* Add missing imports

* Rename app/redux/ to app/mm-redux/

* Remove test file

* Fix fetching Sidebar GM profiles

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2020-04-17 21:12:09 -07:00

344 lines
10 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import {
Keyboard,
InteractionManager,
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import SafeAreaView from 'app/components/safe_area_view';
import {General, RequestStatus} from '@mm-redux/constants';
import EventEmitter from '@mm-redux/utils/event_emitter';
import EditChannelInfo from 'app/components/edit_channel_info';
import {NavigationTypes, ViewTypes} from 'app/constants';
import {cleanUpUrlable} from 'app/utils/url';
import {t} from 'app/utils/i18n';
import {popTopScreen, setButtons} from 'app/actions/navigation';
const messages = {
display_name_required: {
id: t('mobile.rename_channel.display_name_required'),
defaultMessage: 'Channel name is required',
},
display_name_maxLength: {
id: t('mobile.rename_channel.display_name_maxLength'),
defaultMessage: 'Channel name must be less than {maxLength, number} characters',
},
display_name_minLength: {
id: t('mobile.rename_channel.display_name_minLength'),
defaultMessage: 'Channel name must be {minLength, number} or more characters',
},
name_required: {
id: t('mobile.rename_channel.name_required'),
defaultMessage: 'URL is required',
},
name_maxLength: {
id: t('mobile.rename_channel.name_maxLength'),
defaultMessage: 'URL must be less than {maxLength, number} characters',
},
name_minLength: {
id: t('mobile.rename_channel.name_minLength'),
defaultMessage: 'URL must be {minLength, number} or more characters',
},
name_lowercase: {
id: t('mobile.rename_channel.name_lowercase'),
defaultMessage: 'URL be lowercase alphanumeric characters',
},
};
export default class EditChannel extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
patchChannel: PropTypes.func.isRequired,
getChannel: PropTypes.func.isRequired,
setChannelDisplayName: PropTypes.func.isRequired,
}),
componentId: PropTypes.string,
theme: PropTypes.object.isRequired,
deviceWidth: PropTypes.number.isRequired,
deviceHeight: PropTypes.number.isRequired,
channel: PropTypes.object.isRequired,
currentTeamUrl: PropTypes.string.isRequired,
updateChannelRequest: PropTypes.object.isRequired,
};
static contextTypes = {
intl: intlShape,
};
rightButton = {
id: 'edit-channel',
enabled: false,
showAsAction: 'always',
};
constructor(props, context) {
super(props);
const {
channel: {
display_name: displayName,
header,
purpose,
name: channelURL,
},
} = props;
this.state = {
error: null,
updating: false,
updateChannelRequest: props.updateChannelRequest,
displayName,
channelURL,
purpose,
header,
};
this.rightButton.color = props.theme.sidebarHeaderTextColor;
this.rightButton.text = context.intl.formatMessage({id: 'mobile.edit_channel', defaultMessage: 'Save'});
const buttons = {
rightButtons: [this.rightButton],
};
setButtons(props.componentId, buttons);
}
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
this.emitCanUpdateChannel(false);
}
static getDerivedStateFromProps(nextProps, state) {
const {updateChannelRequest} = nextProps;
if (state.updateChannelRequest !== updateChannelRequest) {
const newState = {
error: null,
updating: true,
updateChannelRequest,
};
switch (updateChannelRequest.status) {
case RequestStatus.SUCCESS:
newState.updating = false;
break;
case RequestStatus.FAILURE:
newState.error = updateChannelRequest.error;
newState.updating = false;
break;
}
return newState;
}
return null;
}
componentDidUpdate(prevProps) {
if (prevProps.updateChannelRequest !== this.props.updateChannelRequest) {
switch (this.props.updateChannelRequest.status) {
case RequestStatus.STARTED:
this.emitUpdating(true);
break;
case RequestStatus.SUCCESS:
EventEmitter.emit(NavigationTypes.CLOSE_MAIN_SIDEBAR);
InteractionManager.runAfterInteractions(() => {
this.emitUpdating(false);
this.close();
});
break;
case RequestStatus.FAILURE:
this.emitUpdating(false);
break;
}
}
}
navigationButtonPressed({buttonId}) {
switch (buttonId) {
case 'close-edit-channel':
this.close();
break;
case 'edit-channel':
this.onUpdateChannel();
break;
}
}
close = () => {
const {channel: {type}} = this.props;
const isDirect = type === General.DM_CHANNEL || type === General.GM_CHANNEL;
if (!isDirect) {
this.props.actions.setChannelDisplayName(this.state.displayName);
}
popTopScreen();
};
emitCanUpdateChannel = (enabled) => {
const {componentId} = this.props;
const buttons = {
rightButtons: [{...this.rightButton, enabled}],
};
setButtons(componentId, buttons);
};
emitUpdating = (loading) => {
const {componentId} = this.props;
const buttons = {
rightButtons: [{...this.rightButton, enabled: !loading}],
};
setButtons(componentId, buttons);
};
validateDisplayName = (displayName) => {
const {formatMessage} = this.context.intl;
if (!displayName) {
return {error: formatMessage(messages.display_name_required)};
} else if (displayName.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
return {error: formatMessage(
messages.display_name_maxLength,
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH},
)};
} else if (displayName.length < ViewTypes.MIN_CHANNELNAME_LENGTH) {
return {error: formatMessage(
messages.display_name_minLength,
{minLength: ViewTypes.MIN_CHANNELNAME_LENGTH},
)};
}
return {error: null};
};
validateChannelURL = (channelURL) => {
const {formatMessage} = this.context.intl;
if (!channelURL) {
return {error: formatMessage(messages.name_required)};
} else if (channelURL.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
return {error: formatMessage(
messages.name_maxLength,
{maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH},
)};
}
const cleanedName = cleanUpUrlable(channelURL);
if (cleanedName === channelURL) {
return {error: null};
}
return {error: formatMessage(messages.name_lowercase)};
};
onUpdateChannel = async () => {
Keyboard.dismiss();
const {displayName, channelURL, purpose, header} = this.state;
const {channel: {id, type}} = this.props;
const isDirect = type === General.DM_CHANNEL || type === General.GM_CHANNEL;
const channel = {
display_name: isDirect ? '' : displayName,
name: channelURL,
purpose,
header,
};
if (!isDirect) {
let result = this.validateDisplayName(displayName.trim());
if (result.error) {
this.setState({error: result.error});
return;
}
result = this.validateChannelURL(channelURL.trim());
if (result.error) {
this.setState({error: result.error});
return;
}
}
const data = await this.props.actions.patchChannel(id, channel);
if (data.error && data.error.server_error_id === 'store.sql_channel.update.archived_channel.app_error') {
this.props.actions.getChannel(id);
}
};
onDisplayNameChange = (displayName) => {
this.setState({displayName});
};
onChannelURLChange = (channelURL) => {
this.setState({channelURL});
};
onPurposeChange = (purpose) => {
this.setState({purpose});
};
onHeaderChange = (header) => {
this.setState({header});
};
render() {
const {
channel: {
display_name: oldDisplayName,
name: oldChannelURL,
header: oldHeader,
purpose: oldPurpose,
type,
},
theme,
currentTeamUrl,
deviceWidth,
deviceHeight,
} = this.props;
const {
error,
updating,
displayName,
channelURL,
purpose,
header,
} = this.state;
return (
<SafeAreaView
excludeHeader={true}
excludeFooter={true}
>
<EditChannelInfo
theme={theme}
enableRightButton={this.emitCanUpdateChannel}
error={error}
saving={updating}
channelType={type}
currentTeamUrl={currentTeamUrl}
onDisplayNameChange={this.onDisplayNameChange}
onChannelURLChange={this.onChannelURLChange}
onPurposeChange={this.onPurposeChange}
onHeaderChange={this.onHeaderChange}
displayName={displayName}
channelURL={channelURL}
header={header}
purpose={purpose}
editing={true}
oldDisplayName={oldDisplayName}
oldChannelURL={oldChannelURL}
oldPurpose={oldPurpose}
oldHeader={oldHeader}
deviceWidth={deviceWidth}
deviceHeight={deviceHeight}
/>
</SafeAreaView>
);
}
}