mattermost-mobile/app/screens/settings/notification_settings/notification_settings.js
Chris Duarte 1a3558bc5e Auto responder feature (#1500)
* Add Auto Responder support

Add Auto Responder message support for <Post/>

Add Out Of Office support

Add Confirmation dialog for Out Of Office status reset

Fixing styling issues

Ensure AutoResponder is enabled in settings with ooo status

Save AutoResponder according to Out Of Office status

Fix copy for AutoResponder hint

Fix eslint errors

* Add constants from Redux

* Small refactor

* Add name consistency with the feature "auto responder"

* Add minimum server version of 4.9 for AutoResponder support

* Add ViewTypes.PROFILE_PICTURE_SIZE in post_profile_picture

* Add ExperimentalEnableAutomaticReplies flag

* Update copy and auto responder styles

* Remove unwanted imports

* AutoResponder feauture in 4.9

* Add AutoResponder Thread support

* Fix OOF copy from review

* Change copy for Auto Responder

* Address feedback

* Fix license headers

* Status name translated in Alert

* Add umbrella icon for AutoResponder

* Fix minor issues with rebase

* Fix License headers
2018-06-22 13:09:37 -04:00

543 lines
21 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 {injectIntl, intlShape} from 'react-intl';
import {
Alert,
Modal,
Platform,
ScrollView,
TouchableOpacity,
View,
} from 'react-native';
import deepEqual from 'deep-equal';
import {General, Preferences, RequestStatus} from 'mattermost-redux/constants';
import {getPreferencesByCategory} from 'mattermost-redux/utils/preference_utils';
import FormattedText from 'app/components/formatted_text';
import RadioButtonGroup from 'app/components/radio_button';
import StatusBar from 'app/components/status_bar';
import NotificationPreferences from 'app/notification_preferences';
import SettingsItem from 'app/screens/settings/settings_item';
import {getNotificationProps} from 'app/utils/notify_props';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme';
class NotificationSettings extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
handleUpdateUserNotifyProps: PropTypes.func.isRequired,
}),
config: PropTypes.object.isRequired,
currentUser: PropTypes.object.isRequired,
intl: intlShape.isRequired,
myPreferences: PropTypes.object.isRequired,
navigator: PropTypes.object,
theme: PropTypes.object.isRequired,
updateMeRequest: PropTypes.object.isRequired,
currentUserStatus: PropTypes.string.isRequired,
enableAutoResponder: PropTypes.bool.isRequired,
};
state = {
showEmailNotificationsModal: false,
};
componentWillReceiveProps(nextProps) {
if (this.props.theme !== nextProps.theme) {
setNavigatorStyles(this.props.navigator, nextProps.theme);
}
const {updateMeRequest, intl} = nextProps;
if (this.props.updateMeRequest !== updateMeRequest && updateMeRequest.status === RequestStatus.FAILURE) {
Alert.alert(
intl.formatMessage({
id: 'mobile.notification_settings.save_failed_title',
defaultMessage: 'Connection issue',
}),
intl.formatMessage({
id: 'mobile.notification_settings.save_failed_description',
defaultMessage: 'The notification settings failed to save due to a connection issue, please try again.',
})
);
}
}
handlePress = preventDoubleTap((action) => {
action();
});
goToNotificationSettingsAutoResponder = () => {
const {currentUser, intl, navigator, theme} = this.props;
navigator.push({
backButtonTitle: '',
screen: 'NotificationSettingsAutoResponder',
title: intl.formatMessage({
id: 'mobile.notification_settings.auto_responder_short',
defaultMessage: 'Automatic Replies',
}),
animated: true,
navigatorStyle: {
navBarTextColor: theme.sidebarHeaderTextColor,
navBarBackgroundColor: theme.sidebarHeaderBg,
navBarButtonColor: theme.sidebarHeaderTextColor,
screenBackgroundColor: theme.centerChannelBg,
},
passProps: {
currentUser,
onBack: this.saveAutoResponder,
},
});
};
goToNotificationSettingsEmail = () => {
if (Platform.OS === 'ios') {
const {currentUser, intl, navigator, theme} = this.props;
navigator.push({
backButtonTitle: '',
screen: 'NotificationSettingsEmail',
title: intl.formatMessage({
id: 'mobile.notification_settings.email_title',
defaultMessage: 'Email Notifications',
}),
animated: true,
navigatorStyle: {
navBarTextColor: theme.sidebarHeaderTextColor,
navBarBackgroundColor: theme.sidebarHeaderBg,
navBarButtonColor: theme.sidebarHeaderTextColor,
screenBackgroundColor: theme.centerChannelBg,
},
passProps: {
currentUser,
onBack: this.saveNotificationProps,
},
});
} else {
this.setState({showEmailNotificationsModal: true});
}
};
goToNotificationSettingsMentions = () => {
const {currentUser, intl, navigator, theme} = this.props;
navigator.push({
backButtonTitle: '',
screen: 'NotificationSettingsMentions',
title: intl.formatMessage({id: 'mobile.notification_settings.mentions_replies', defaultMessage: 'Mentions and Replies'}),
animated: true,
navigatorStyle: {
navBarTextColor: theme.sidebarHeaderTextColor,
navBarBackgroundColor: theme.sidebarHeaderBg,
navBarButtonColor: theme.sidebarHeaderTextColor,
screenBackgroundColor: theme.centerChannelBg,
},
passProps: {
currentUser,
onBack: this.saveNotificationProps,
},
});
};
goToNotificationSettingsMobile = () => {
const {currentUser, intl, navigator, theme} = this.props;
NotificationPreferences.getPreferences().then((notificationPreferences) => {
requestAnimationFrame(() => {
navigator.push({
backButtonTitle: '',
screen: 'NotificationSettingsMobile',
title: intl.formatMessage({id: 'mobile.notification_settings.mobile_title', defaultMessage: 'Mobile Notifications'}),
animated: true,
navigatorStyle: {
navBarTextColor: theme.sidebarHeaderTextColor,
navBarBackgroundColor: theme.sidebarHeaderBg,
navBarButtonColor: theme.sidebarHeaderTextColor,
screenBackgroundColor: theme.centerChannelBg,
},
passProps: {
currentUser,
onBack: this.saveNotificationProps,
notificationPreferences,
},
});
});
}).catch((e) => {
Alert.alert('There was a problem getting the device preferences', e.message);
});
};
setEmailNotifications = (emailSetting) => {
this.setState({emailSetting});
};
saveEmailNotifications = () => {
const {config, currentUser} = this.props;
const {emailSetting} = this.state;
this.setState({showEmailNotificationsModal: false});
if (emailSetting) {
let email = emailSetting;
let interval;
const emailBatchingEnabled = config.EnableEmailBatching === 'true';
if (emailBatchingEnabled && emailSetting !== 'false') {
interval = emailSetting;
email = 'true';
}
this.saveNotificationProps({
...getNotificationProps(currentUser),
email,
interval,
});
}
};
saveNotificationProps = (notifyProps) => {
const {currentUser} = this.props;
const {user_id: userId} = notifyProps;
const previousProps = {
...getNotificationProps(currentUser),
user_id: userId,
};
if (notifyProps.interval) {
previousProps.interval = notifyProps.interval;
}
if (!deepEqual(previousProps, notifyProps)) {
this.props.actions.handleUpdateUserNotifyProps(notifyProps);
}
};
/**
* shouldSaveAutoResponder
*
* Necessary in order to properly update the notifyProps when
* enabling/disabling the Auto Responder.
*
* Reason being, on mobile when the AutoResponder is disabled on the server
* for some reason the update does not get received on mobile, it does for web
*/
shouldSaveAutoResponder = (notifyProps) => {
const {currentUserStatus} = this.props;
const {auto_responder_active: autoResponderActive} = notifyProps;
const enabling = currentUserStatus !== General.OUT_OF_OFFICE && autoResponderActive === 'true';
const disabling = currentUserStatus === General.OUT_OF_OFFICE && autoResponderActive === 'false';
return enabling || disabling;
};
saveAutoResponder = (notifyProps) => {
const {intl} = this.props;
if (!notifyProps.auto_responder_message || notifyProps.auto_responder_message === '') {
notifyProps.auto_responder_message = intl.formatMessage({
id: 'mobile.notification_settings.auto_responder.default_message',
defaultMessage: 'Hello, I am out of office and unable to respond to messages.',
});
}
if (this.shouldSaveAutoResponder(notifyProps)) {
this.props.actions.handleUpdateUserNotifyProps(notifyProps);
}
};
renderEmailNotificationSettings = (style) => {
if (Platform.OS === 'ios') {
return null;
}
const {config, currentUser, intl, myPreferences} = this.props;
const notifyProps = getNotificationProps(currentUser);
const sendEmailNotifications = config.SendEmailNotifications === 'true';
const emailBatchingEnabled = sendEmailNotifications && config.EnableEmailBatching === 'true';
const never = notifyProps.email === 'false';
let sendImmediatley = notifyProps.email === 'true';
let sendImmediatleyValue = 'true';
let fifteenMinutes;
let hourly;
let interval;
if (emailBatchingEnabled) {
const emailPreferences = getPreferencesByCategory(myPreferences, Preferences.CATEGORY_NOTIFICATIONS);
if (emailPreferences.size) {
interval = emailPreferences.get(Preferences.EMAIL_INTERVAL).value;
}
}
if (emailBatchingEnabled && notifyProps.email !== 'false') {
sendImmediatley = interval === Preferences.INTERVAL_IMMEDIATE.toString();
fifteenMinutes = interval === Preferences.INTERVAL_FIFTEEN_MINUTES.toString();
hourly = interval === Preferences.INTERVAL_HOUR.toString();
sendImmediatleyValue = Preferences.INTERVAL_IMMEDIATE.toString();
}
let helpText;
if (sendEmailNotifications) {
helpText = (
<FormattedText
id='user.settings.notifications.emailInfo'
defaultMessage='Email notifications are sent for mentions and direct messages when you are offline or away from {siteName} for more than 5 minutes.'
values={{siteName: config.SiteName}}
style={style.modalHelpText}
/>
);
}
const emailOptions = [{
label: intl.formatMessage({
id: 'user.settings.notifications.email.immediately',
defaultMessage: 'Immediately',
}),
value: sendImmediatleyValue,
checked: sendImmediatley,
}];
if (emailBatchingEnabled) {
emailOptions.push({
label: intl.formatMessage({
id: 'user.settings.notifications.email.everyXMinutes',
defaultMessage: 'Every {count, plural, one {minute} other {{count, number} minutes}}',
}, {count: Preferences.INTERVAL_FIFTEEN_MINUTES / 60}),
value: Preferences.INTERVAL_FIFTEEN_MINUTES.toString(),
checked: fifteenMinutes,
}, {
label: intl.formatMessage({
id: 'user.settings.notifications.email.everyHour',
defaultMessage: 'Every hour',
}),
value: Preferences.INTERVAL_HOUR.toString(),
checked: hourly,
});
}
emailOptions.push({
label: intl.formatMessage({
id: 'user.settings.notifications.email.never',
defaultMessage: 'Never',
}),
value: 'false',
checked: never,
});
return (
<Modal
animationType='slide'
transparent={true}
visible={this.state.showEmailNotificationsModal}
onRequestClose={() => this.setState({showEmailNotificationsModal: false})}
>
<View style={style.modalOverlay}>
<View style={style.modal}>
<View style={style.modalBody}>
<View style={style.modalTitleContainer}>
<FormattedText
id='user.settings.notifications.email.send'
defaultMessage='Send email notifications'
style={style.modalTitle}
/>
</View>
{!sendEmailNotifications &&
<FormattedText
id='user.settings.general.emailHelp2'
defaultMessage='Email has been disabled by your System Administrator. No notification emails will be sent until it is enabled.'
style={style.modalOptionDisabled}
/>
}
{sendEmailNotifications &&
<RadioButtonGroup
name='emailSettings'
onSelect={this.setEmailNotifications}
options={emailOptions}
/>
}
{helpText}
</View>
<View style={style.modalFooter}>
<View style={style.divider}/>
<View style={style.modalFooterContainer}>
<TouchableOpacity
style={style.modalFooterOptionContainer}
onPress={this.saveEmailNotifications}
>
<FormattedText
id='mobile.notification_settings.modal_cancel'
defaultMessage='CANCEL'
style={style.modalFooterOption}
/>
</TouchableOpacity>
{sendEmailNotifications &&
<View>
<View style={{marginRight: 10}}/>
<TouchableOpacity
style={style.modalFooterOptionContainer}
onPress={this.saveEmailNotifications}
>
<FormattedText
id='mobile.notification_settings.modal_save'
defaultMessage='SAVE'
style={style.modalFooterOption}
/>
</TouchableOpacity>
</View>
}
</View>
</View>
</View>
</View>
</Modal>
);
};
render() {
const {theme, enableAutoResponder} = this.props;
const style = getStyleSheet(theme);
const showArrow = Platform.OS === 'ios';
const showEmailSeparator = enableAutoResponder;
let autoResponder;
if (enableAutoResponder) {
autoResponder = (
<SettingsItem
defaultMessage='Automatic Direct Message Replies'
i18nId='mobile.notification_settings.ooo_auto_responder'
iconName='beach-access'
iconType='material'
onPress={() => this.handlePress(this.goToNotificationSettingsAutoResponder)}
separator={false}
showArrow={showArrow}
theme={theme}
/>
);
}
return (
<View style={style.container}>
<StatusBar/>
<ScrollView
contentContainerStyle={style.wrapper}
alwaysBounceVertical={false}
>
<View style={style.divider}/>
<SettingsItem
defaultMessage='Mentions and Replies'
i18nId='mobile.notification_settings.mentions_replies'
iconName='md-at'
iconType='ion'
onPress={() => this.handlePress(this.goToNotificationSettingsMentions)}
separator={true}
showArrow={showArrow}
theme={theme}
/>
<SettingsItem
defaultMessage='Mobile'
i18nId='mobile.notification_settings.mobile'
iconName='md-phone-portrait'
iconType='ion'
onPress={() => this.handlePress(this.goToNotificationSettingsMobile)}
separator={true}
showArrow={showArrow}
theme={theme}
/>
<SettingsItem
defaultMessage='Email'
i18nId='mobile.notification_settings.email'
iconName='ios-mail'
iconType='ion'
onPress={() => this.handlePress(this.goToNotificationSettingsEmail)}
separator={showEmailSeparator}
showArrow={showArrow}
theme={theme}
/>
{autoResponder}
<View style={style.divider}/>
</ScrollView>
{this.renderEmailNotificationSettings(style)}
</View>
);
}
}
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
wrapper: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
...Platform.select({
ios: {
paddingTop: 35,
},
}),
},
divider: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
height: 1,
width: '100%',
},
modalOverlay: {
backgroundColor: changeOpacity('#000000', 0.6),
alignItems: 'center',
flex: 1,
},
modal: {
backgroundColor: theme.centerChannelBg,
borderRadius: 4,
marginTop: 20,
width: '95%',
},
modalBody: {
paddingHorizontal: 24,
},
modalTitleContainer: {
marginBottom: 30,
marginTop: 20,
},
modalTitle: {
color: theme.centerChannelColor,
fontSize: 19,
},
modalOptionDisabled: {
color: changeOpacity(theme.centerChannelColor, 0.5),
fontSize: 17,
},
modalHelpText: {
color: changeOpacity(theme.centerChannelColor, 0.5),
fontSize: 13,
marginTop: 20,
},
modalFooter: {
alignItems: 'flex-end',
height: 58,
marginTop: 40,
width: '100%',
},
modalFooterContainer: {
alignItems: 'center',
flex: 1,
flexDirection: 'row',
paddingRight: 24,
},
modalFooterOptionContainer: {
alignItems: 'center',
height: 40,
justifyContent: 'center',
paddingHorizontal: 10,
paddingVertical: 5,
},
modalFooterOption: {
color: theme.linkColor,
fontSize: 14,
},
};
});
export default injectIntl(NotificationSettings);