MM-31968 Save auto response props on keyboard done (#5273)

This commit is contained in:
Elias Nahum 2021-04-08 20:30:58 -04:00 committed by GitHub
parent 5156480220
commit da8c09ff98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 226 additions and 221 deletions

View file

@ -5,7 +5,10 @@ import {Team} from './teams';
import {PostType} from './posts';
import {$ID, IDMappedObjects, RelationOneToMany, RelationOneToOne} from './utilities';
export type UserNotifyProps = {
auto_responder_active?: 'true' | 'false';
auto_responder_message?: string;
desktop: 'default' | 'all' | 'mention' | 'none';
desktop_notification_sound?: string;
desktop_sound: 'true' | 'false';
email: 'true' | 'false';
mark_unread: 'all' | 'mention';
@ -15,6 +18,7 @@ export type UserNotifyProps = {
first_name: 'true' | 'false';
channel: 'true' | 'false';
mention_keys: string;
user_id?: string;
};
export type UserProfile = {
id: string;

View file

@ -99,6 +99,7 @@ NotificationSettings {
"updateMeRequest": Object {},
},
"refs": Object {},
"sanitizeNotificationProps": [Function],
"saveAutoResponder": [Function],
"saveNotificationProps": [Function],
"setState": [Function],

View file

@ -127,6 +127,22 @@ export default class NotificationSettings extends PureComponent {
});
};
saveAutoResponder = (notifyProps) => {
const {intl} = this.context;
if (!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)) {
const notify_props = this.sanitizeNotificationProps(notifyProps);
this.props.actions.updateMe({notify_props});
}
};
saveNotificationProps = (notifyProps) => {
const {currentUser} = this.props;
const prevProps = getNotificationProps(currentUser);
@ -136,10 +152,22 @@ export default class NotificationSettings extends PureComponent {
};
if (!deepEqual(prevProps, notifyProps)) {
this.props.actions.updateMe({notify_props: updatedProps});
const notify_props = this.sanitizeNotificationProps(updatedProps);
this.props.actions.updateMe({notify_props});
}
};
sanitizeNotificationProps = (notifyProps) => {
const sanitized = {...notifyProps};
Reflect.deleteProperty(sanitized, 'showKeywordsModal');
Reflect.deleteProperty(sanitized, 'showReplyModal');
Reflect.deleteProperty(sanitized, 'androidKeywords');
Reflect.deleteProperty(sanitized, 'newReplyValue');
Reflect.deleteProperty(sanitized, 'user_id');
return sanitized;
}
/**
* shouldSaveAutoResponder
*
@ -150,28 +178,15 @@ export default class NotificationSettings extends PureComponent {
* for some reason the update does not get received on mobile, it does for web
*/
shouldSaveAutoResponder = (notifyProps) => {
const {currentUserStatus} = this.props;
const {currentUser, currentUserStatus} = this.props;
const {auto_responder_active: autoResponderActive} = notifyProps;
const prevProps = getNotificationProps(currentUser);
const enabling = currentUserStatus !== General.OUT_OF_OFFICE && autoResponderActive === 'true';
const disabling = currentUserStatus === General.OUT_OF_OFFICE && autoResponderActive === 'false';
const updatedMsg = prevProps.auto_responder_message !== notifyProps.auto_responder_message;
return enabling || disabling;
};
saveAutoResponder = (notifyProps) => {
const {intl} = this.context;
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.updateMe({notify_props: notifyProps});
}
return enabling || disabling || updatedMsg;
};
render() {

View file

@ -5,9 +5,10 @@ import {connect} from 'react-redux';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {getCurrentUserId, getStatusForUserId} from '@mm-redux/selectors/entities/users';
import {GlobalState} from '@mm-redux/types/store';
import NotificationSettingsAutoResponder from './notification_settings_auto_responder';
function mapStateToProps(state) {
function mapStateToProps(state: GlobalState) {
const currentUserId = getCurrentUserId(state);
const currentUserStatus = getStatusForUserId(state, currentUserId);

View file

@ -1,200 +0,0 @@
// 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 {
View,
} from 'react-native';
import {intlShape} from 'react-intl';
import {SafeAreaView} from 'react-native-safe-area-context';
import {General} from '@mm-redux/constants';
import FormattedText from 'app/components/formatted_text';
import StatusBar from 'app/components/status_bar';
import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
import {getNotificationProps} from 'app/utils/notify_props';
import {
changeOpacity,
makeStyleSheetFromTheme,
getKeyboardAppearanceFromTheme,
} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
import Section from 'app/screens/settings/section';
import SectionItem from 'app/screens/settings/section_item';
export default class NotificationSettingsAutoResponder extends PureComponent {
static propTypes = {
currentUser: PropTypes.object.isRequired,
onBack: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired,
currentUserStatus: PropTypes.string.isRequired,
};
static contextTypes = {
intl: intlShape,
};
constructor(props, context) {
super(props, context);
const {currentUser} = props;
const {intl} = this.context;
const notifyProps = getNotificationProps(currentUser);
this.autoresponderRef = React.createRef();
const autoResponderDefault = intl.formatMessage({
id: 'mobile.notification_settings.auto_responder.default_message',
defaultMessage: 'Hello, I am out of office and unable to respond to messages.',
});
let autoResponderActive = 'false';
if (props.currentUserStatus === General.OUT_OF_OFFICE && notifyProps.auto_responder_active) {
autoResponderActive = 'true';
}
this.state = {
...notifyProps,
auto_responder_active: autoResponderActive,
auto_responder_message: notifyProps.auto_responder_message || autoResponderDefault,
};
}
componentWillUnmount() {
this.saveUserNotifyProps();
}
componentDidMount() {
setTimeout(() => {
requestAnimationFrame(() => {
if (this.autoresponderRef.current) {
this.autoresponderRef.current.focus();
}
});
}, 500);
}
saveUserNotifyProps = () => {
this.props.onBack({
...this.state,
user_id: this.props.currentUser.id,
});
};
onAutoResponseToggle = (active) => {
if (active) {
this.setState({auto_responder_active: 'true'});
return;
}
this.setState({auto_responder_active: 'false'});
};
onAutoResponseChangeText = (message) => {
this.setState({auto_responder_message: message});
};
render() {
const {theme} = this.props;
const {
auto_responder_active: autoResponderActive,
auto_responder_message: autoResponderMessage,
} = this.state;
const style = getStyleSheet(theme);
const autoResponderActiveLabel = (
<FormattedText
id='mobile.notification_settings.auto_responder.enabled'
defaultMessage='Enabled'
/>
);
return (
<SafeAreaView
edges={['left', 'right']}
style={style.container}
>
<StatusBar/>
<View style={style.wrapper}>
<Section
disableHeader={true}
theme={theme}
>
<SectionItem
label={autoResponderActiveLabel}
action={this.onAutoResponseToggle}
actionType='toggle'
selected={autoResponderActive === 'true'}
theme={theme}
/>
</Section>
{autoResponderActive === 'true' && (
<Section
headerId={t('mobile.notification_settings.auto_responder.message_title')}
headerDefaultMessage='CUSTOM MESSAGE'
theme={theme}
>
<View style={style.inputContainer}>
<TextInputWithLocalizedPlaceholder
ref={this.autoresponderRef}
value={autoResponderMessage}
blurOnSubmit={false}
onChangeText={this.onAutoResponseChangeText}
multiline={true}
style={style.input}
autoCapitalize='none'
autoCorrect={false}
placeholder={{id: t('mobile.notification_settings.auto_responder.message_placeholder'), defaultMessage: 'Message'}}
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)}
textAlignVertical='top'
underlineColorAndroid='transparent'
returnKeyType='done'
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
/>
</View>
</Section>
)}
<FormattedText
id={'mobile.notification_settings.auto_responder.footer_message'}
defaultMessage={'Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.'}
style={style.footer}
/>
</View>
</SafeAreaView>
);
}
}
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
wrapper: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
flex: 1,
paddingTop: 35,
},
inputContainer: {
borderTopWidth: 1,
borderBottomWidth: 1,
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
backgroundColor: theme.centerChannelBg,
},
input: {
color: theme.centerChannelColor,
fontSize: 15,
height: 150,
paddingHorizontal: 15,
paddingVertical: 10,
},
footer: {
marginHorizontal: 15,
fontSize: 12,
color: changeOpacity(theme.centerChannelColor, 0.5),
},
};
});

View file

@ -0,0 +1,186 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {intlShape, injectIntl} from 'react-intl';
import {SafeAreaView} from 'react-native-safe-area-context';
import {popTopScreen} from '@actions/navigation';
import FormattedText from '@components/formatted_text';
import StatusBar from '@components/status_bar';
import TextInputWithLocalizedPlaceholder from '@components/text_input_with_localized_placeholder';
import {General} from '@mm-redux/constants';
import Section from '@screens/settings/section';
import SectionItem from '@screens/settings/section_item';
import {t} from '@utils/i18n';
import {getNotificationProps} from '@utils/notify_props';
import {
changeOpacity,
makeStyleSheetFromTheme,
getKeyboardAppearanceFromTheme,
} from '@utils/theme';
import {UserNotifyProps, UserProfile} from '@mm-redux/types/users';
import {Theme} from '@mm-redux/types/preferences';
interface NotificationSettingsAutoResponderProps {
currentUser: UserProfile;
currentUserStatus: string;
intl: typeof intlShape;
onBack: (notifyProps: UserNotifyProps) => void;
theme: Theme;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
return {
container: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
wrapper: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
flex: 1,
paddingTop: 35,
},
inputContainer: {
borderTopWidth: 1,
borderBottomWidth: 1,
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
backgroundColor: theme.centerChannelBg,
},
input: {
color: theme.centerChannelColor,
fontSize: 15,
height: 150,
paddingHorizontal: 15,
paddingVertical: 10,
},
footer: {
marginHorizontal: 15,
fontSize: 12,
color: changeOpacity(theme.centerChannelColor, 0.5),
},
};
});
const NotificationSettingsAutoResponder = ({currentUser, currentUserStatus, intl, onBack, theme} : NotificationSettingsAutoResponderProps) => {
const autoresponderRef = useRef<TextInputWithLocalizedPlaceholder>(null);
const [notifyProps, setNotifyProps] = useState<UserNotifyProps>(getNotificationProps(currentUser));
const style = getStyleSheet(theme);
const onAutoResponseToggle = (active: boolean) => {
setNotifyProps({
...notifyProps,
auto_responder_active: active ? 'true' : 'false',
});
};
const onAutoResponseChangeText = (message: string) => {
setNotifyProps({
...notifyProps,
auto_responder_message: message,
});
};
const onSubmitEditing = () => {
popTopScreen();
};
useEffect(() => {
const autoResponderDefault = intl.formatMessage({
id: 'mobile.notification_settings.auto_responder.default_message',
defaultMessage: 'Hello, I am out of office and unable to respond to messages.',
});
setNotifyProps({
...notifyProps,
auto_responder_active: (currentUserStatus === General.OUT_OF_OFFICE && notifyProps.auto_responder_active) ? 'true' : 'false',
auto_responder_message: notifyProps.auto_responder_message || autoResponderDefault,
});
}, []);
useEffect(() => {
const autoresponderTimeout = setTimeout(() => {
autoresponderRef.current?.focus();
}, 500);
return () => {
clearTimeout(autoresponderTimeout);
onBack({
...notifyProps,
user_id: currentUser.id,
});
};
}, [notifyProps]);
const autoResponderActiveLabel = (
<FormattedText
id='mobile.notification_settings.auto_responder.enabled'
defaultMessage='Enabled'
/>
);
const {
auto_responder_active: autoResponderActive,
auto_responder_message: autoResponderMessage,
} = notifyProps;
return (
<SafeAreaView
edges={['left', 'right']}
style={style.container}
>
<StatusBar/>
<View style={style.wrapper}>
<Section
disableHeader={true}
theme={theme}
>
<SectionItem
label={autoResponderActiveLabel}
action={onAutoResponseToggle}
actionType='toggle'
selected={autoResponderActive === 'true'}
theme={theme}
/>
</Section>
{autoResponderActive === 'true' && (
<Section
headerId={t('mobile.notification_settings.auto_responder.message_title')}
headerDefaultMessage='CUSTOM MESSAGE'
theme={theme}
>
<View style={style.inputContainer}>
<TextInputWithLocalizedPlaceholder
ref={autoresponderRef}
value={autoResponderMessage}
blurOnSubmit={true}
onChangeText={onAutoResponseChangeText}
onSubmitEditing={onSubmitEditing}
multiline={true}
style={style.input}
autoCapitalize='none'
autoCorrect={false}
placeholder={{id: t('mobile.notification_settings.auto_responder.message_placeholder'), defaultMessage: 'Message'}}
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)}
textAlignVertical='top'
underlineColorAndroid='transparent'
returnKeyType='done'
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
/>
</View>
</Section>
)}
<FormattedText
id={'mobile.notification_settings.auto_responder.footer_message'}
defaultMessage={'Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.'}
style={style.footer}
/>
</View>
</SafeAreaView>
);
};
export default injectIntl(NotificationSettingsAutoResponder);

View file

@ -111,8 +111,6 @@ export default class NotificationSettingsMentionsBase extends PureComponent {
}
mentionKeys = mentionKeys.join(',');
Reflect.deleteProperty(notifyProps, 'showKeywordsModal');
Reflect.deleteProperty(notifyProps, 'showReplyModal');
this.props.onBack({
...notifyProps,