mattermost-mobile/app/components/sidebars/settings/settings_sidebar.js
Miguel Alatzar 5eee2b7652
[MM-16139] [MM-16140] [MM-16141] Update the remaining screens/components (#2920)
* Update screens

* Update login tests

* Remove done

* Fix failing tests

* Update screens and components

* Check styles fix

* Update tests

* Prevent setState call after component unmounts

* Add empty setButtons func to dummy navigator

* Remove platform check

* Remove Platform import

* Update react-native-navigation version

* Add separate showModalOverCurrentContext function

* check-style fixes

* Remove overriding of AppDelegate's window

* Fix modal over current context animation

* Add showSearchModal navigation action

* Check-style fix

* Address review comments

* Update SettingsSidebar and children

* Update EditProfile screen

* Update SettingsSidebar

* Keep track of latest componentId to appear

* Track componentId in state to use in navigation actions

* Update FlaggedPosts and children

* Update RecentMentions

* Update Settings

* Store componentIds in ephemeral store

* Update AttachmentButton

* Remove unnecessary dismissModal

* Fix typo

* Upate NotificationSettings

* Update NotificationSettingsAutoResponder

* Update NotificationSettingsMentions

* Update NotificationSettingsMobile

* Update CreateChannel and children

* Update MoreChannels

* Update ChannelPeek and children

* Update ChannelNavBar and children

* Update ChannelPostList and children

* Update ChannelInfo and children

* Update ChannelAddMembers

* Update ChannelMembers

* Update EditChannel

* Fix setting of top bar buttons

* Update Channel screen and children

* Update PinnedPosts

* Update LongPost

* Update PostOptions

* Update PostTextboxBase

* Update EditPost

* Check-styles fix

* Update DisplaySettings

* Update Timezone

* Update SelectTimezone

* Update IntlWrapper and Notification

* Update InteractiveDialog and children

* Update ExpandedAnnouncementBanner

* Update ClientUpgradeListener

* Update MoreDirectMessages

* Update SelectorScreen

* Update UserProfile

* Update Thread

* Update About

* Update ImagePreview

* Update TextPreview

* Update AddReaction

* Update ReactionList and children

* Update Code

* Update TermsOfService

* Update Permalink

* Update Permalink

* Update ErrorTeamsList

* Update Search

* Remove navigator prop

* Fix setButtons calls

* Remove navigationComponentId

* Fix test

* Handle in-app notifs in global event handler

* Fix in-app notification handling

* Fix typo

* Fix tests

* Auto dismiss in-app notif after 5 seconds

* Fix typo

* Update overlay dismissal

* Animate in-app notif dismissal and allow gesture dismissal
2019-07-08 10:03:31 -07:00

393 lines
13 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 {
BackHandler,
InteractionManager,
Keyboard,
ScrollView,
View,
} from 'react-native';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import {General} from 'mattermost-redux/constants';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import SafeAreaView from 'app/components/safe_area_view';
import DrawerLayout from 'app/components/sidebars/drawer_layout';
import UserStatus from 'app/components/user_status';
import {DeviceTypes, NavigationTypes} from 'app/constants';
import {confirmOutOfOfficeDisabled} from 'app/utils/status';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
import DrawerItem from './drawer_item';
import UserInfo from './user_info';
import StatusLabel from './status_label';
const DRAWER_INITIAL_OFFSET = 80;
const DRAWER_TABLET_WIDTH = 300;
export default class SettingsDrawer extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
logout: PropTypes.func.isRequired,
setStatus: PropTypes.func.isRequired,
showModal: PropTypes.func.isRequired,
showModalOverCurrentContext: PropTypes.func.isRequired,
dismissModal: PropTypes.func.isRequired,
}).isRequired,
blurPostTextBox: PropTypes.func.isRequired,
children: PropTypes.node,
currentUser: PropTypes.object.isRequired,
deviceWidth: PropTypes.number.isRequired,
isLandscape: PropTypes.bool.isRequired,
status: PropTypes.string,
theme: PropTypes.object.isRequired,
};
static defaultProps = {
currentUser: {},
status: 'offline',
};
static contextTypes = {
intl: intlShape,
};
constructor(props) {
super(props);
MaterialIcon.getImageSource('close', 20, props.theme.sidebarHeaderTextColor).then((source) => {
this.closeButton = source;
});
}
componentDidMount() {
EventEmitter.on('close_settings_sidebar', this.closeSettingsSidebar);
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
}
componentWillUnmount() {
EventEmitter.off('close_settings_sidebar', this.closeSettingsSidebar);
BackHandler.removeEventListener('hardwareBackPress', this.handleAndroidBack);
}
handleAndroidBack = () => {
if (this.refs.drawer && this.drawerOpened) {
this.refs.drawer.closeDrawer();
return true;
}
return false;
};
openSettingsSidebar = () => {
this.props.blurPostTextBox();
if (this.refs.drawer && !this.drawerOpened) {
this.refs.drawer.openDrawer();
}
};
closeSettingsSidebar = () => {
if (this.refs.drawer && this.drawerOpened) {
this.refs.drawer.closeDrawer();
}
};
handleDrawerClose = () => {
this.drawerOpened = false;
Keyboard.dismiss();
};
handleDrawerOpen = () => {
this.drawerOpened = true;
Keyboard.dismiss();
};
handleSetStatus = preventDoubleTap(() => {
const {actions} = this.props;
const items = [{
action: () => this.setStatus(General.ONLINE),
text: {
id: t('mobile.set_status.online'),
defaultMessage: 'Online',
},
}, {
action: () => this.setStatus(General.AWAY),
text: {
id: t('mobile.set_status.away'),
defaultMessage: 'Away',
},
}, {
action: () => this.setStatus(General.DND),
text: {
id: t('mobile.set_status.dnd'),
defaultMessage: 'Do Not Disturb',
},
}, {
action: () => this.setStatus(General.OFFLINE),
text: {
id: t('mobile.set_status.offline'),
defaultMessage: 'Offline',
},
}];
actions.showModalOverCurrentContext('OptionsModal', {items});
});
goToEditProfile = preventDoubleTap(() => {
const {currentUser} = this.props;
const {formatMessage} = this.context.intl;
const commandType = 'ShowModal';
this.openModal(
'EditProfile',
formatMessage({id: 'mobile.routes.edit_profile', defaultMessage: 'Edit Profile'}),
{currentUser, commandType}
);
});
goToFlagged = preventDoubleTap(() => {
const {formatMessage} = this.context.intl;
this.openModal(
'FlaggedPosts',
formatMessage({id: 'search_header.title3', defaultMessage: 'Flagged Posts'}),
);
});
goToMentions = preventDoubleTap(() => {
const {intl} = this.context;
this.openModal(
'RecentMentions',
intl.formatMessage({id: 'search_header.title2', defaultMessage: 'Recent Mentions'}),
);
});
goToUserProfile = preventDoubleTap(() => {
const userId = this.props.currentUser.id;
const {formatMessage} = this.context.intl;
this.openModal(
'UserProfile',
formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'}),
{userId, fromSettings: true}
);
});
goToSettings = preventDoubleTap(() => {
const {intl} = this.context;
this.openModal(
'Settings',
intl.formatMessage({id: 'mobile.routes.settings', defaultMessage: 'Settings'}),
);
});
logout = preventDoubleTap(() => {
const {logout} = this.props.actions;
this.closeSettingsSidebar();
logout();
});
openModal = (screen, title, passProps) => {
this.closeSettingsSidebar();
const {actions} = this.props;
const options = {
topBar: {
leftButtons: [{
id: 'close-settings',
icon: this.closeButton,
}],
},
};
InteractionManager.runAfterInteractions(() => {
actions.showModal(screen, title, passProps, options);
});
};
renderUserStatusIcon = (userId) => {
return (
<UserStatus
size={18}
userId={userId}
/>
);
};
renderUserStatusLabel = (userId) => {
return (
<StatusLabel userId={userId}/>
);
};
renderNavigationView = () => {
const {currentUser, theme} = this.props;
const style = getStyleSheet(theme);
return (
<SafeAreaView
backgroundColor={theme.centerChannelBg}
navBarBackgroundColor={theme.centerChannelBg}
footerColor={theme.centerChannelBg}
footerComponent={<View style={style.container}/>}
headerComponent={<View style={style.container}/>}
theme={theme}
>
<View style={style.container}>
<ScrollView
alwaysBounceVertical={false}
contentContainerStyle={style.wrapper}
>
<UserInfo
onPress={this.goToUserProfile}
user={currentUser}
/>
<View style={style.block}>
<DrawerItem
labelComponent={this.renderUserStatusLabel(currentUser.id)}
leftComponent={this.renderUserStatusIcon(currentUser.id)}
separator={false}
onPress={this.handleSetStatus}
theme={theme}
/>
</View>
<View style={style.separator}/>
<View style={style.block}>
<DrawerItem
defaultMessage='Recent Mentions'
i18nId='search_header.title2'
iconName='ios-at'
iconType='ion'
onPress={this.goToMentions}
separator={true}
theme={theme}
/>
<DrawerItem
defaultMessage='Flagged Posts'
i18nId='search_header.title3'
iconName='ios-flag'
iconType='ion'
onPress={this.goToFlagged}
separator={false}
theme={theme}
/>
</View>
<View style={style.separator}/>
<View style={style.block}>
<DrawerItem
defaultMessage='Edit Profile'
i18nId='mobile.routes.edit_profile'
iconName='ios-person'
iconType='ion'
onPress={this.goToEditProfile}
separator={true}
theme={theme}
/>
<DrawerItem
defaultMessage='Settings'
i18nId='mobile.routes.settings'
iconName='ios-options'
iconType='ion'
onPress={this.goToSettings}
separator={false}
theme={theme}
/>
</View>
<View style={style.separator}/>
<View style={style.block}>
<DrawerItem
centered={true}
defaultMessage='Logout'
i18nId='sidebar_right_menu.logout'
isDestructor={true}
onPress={this.logout}
separator={false}
theme={theme}
/>
</View>
</ScrollView>
</View>
</SafeAreaView>
);
};
confirmReset = (status) => {
const {intl} = this.context;
confirmOutOfOfficeDisabled(intl, status, this.updateStatus);
};
updateStatus = (status) => {
const {currentUser: {id: currentUserId}} = this.props;
this.props.actions.setStatus({
user_id: currentUserId,
status,
});
};
setStatus = (status) => {
const {status: currentUserStatus, actions} = this.props;
if (currentUserStatus === General.OUT_OF_OFFICE) {
actions.dismissModal();
this.closeSettingsSidebar();
this.confirmReset(status);
return;
}
this.updateStatus(status);
EventEmitter.emit(NavigationTypes.NAVIGATION_CLOSE_MODAL);
};
render() {
const {children, deviceWidth} = this.props;
const drawerWidth = DeviceTypes.IS_TABLET ? DRAWER_TABLET_WIDTH : (deviceWidth - DRAWER_INITIAL_OFFSET);
return (
<DrawerLayout
ref='drawer'
renderNavigationView={this.renderNavigationView}
onDrawerClose={this.handleDrawerClose}
onDrawerOpen={this.handleDrawerOpen}
drawerPosition='right'
drawerWidth={drawerWidth}
useNativeAnimations={true}
>
{children}
</DrawerLayout>
);
}
}
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
},
wrapper: {
paddingTop: 0,
},
block: {
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
borderBottomWidth: 1,
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
borderTopWidth: 1,
},
divider: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
height: 1,
},
separator: {
marginTop: 35,
},
};
});