MM-31968 Save auto response props on keyboard done (#5273)
This commit is contained in:
parent
5156480220
commit
da8c09ff98
7 changed files with 226 additions and 221 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ NotificationSettings {
|
|||
"updateMeRequest": Object {},
|
||||
},
|
||||
"refs": Object {},
|
||||
"sanitizeNotificationProps": [Function],
|
||||
"saveAutoResponder": [Function],
|
||||
"saveNotificationProps": [Function],
|
||||
"setState": [Function],
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -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);
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue