[GH-15185][MM-5973] Add Channel Settings > Notification Preferences. (#4730)
* Add Channel Settings > Notification Preferences.
Fixes #15185
* Make newly added strings mmjstool compatible.
mmjstool seems to be looking for specific patterns in AST like called with
`formatMessage` and `t()` [1]. Looks like `t()` is just for that purpose.
[1]: a83581379d/mmjstool/src/i18n_extract.js (L97):L100
* Pass only required props to NotificationPreference & ChannelNotificationPreference.
* Fix style issues/nits from code review.
* Use radio button for channel notifications on android, and checkmarks on iOS.
Also changes style according to figma spec.
* Fix missing prop error.
For some reason, `npm run fix` didn't catch this. But `npm run check` did during CircleCI.
* Fix missing i18n strings by passing strings through `t()`.
mmjstool really needs to be smarter to understand these types of cases.
* Address comments from UX code review.
* Remove remnant from merge conflict.
* Fix UI in iOS landscape mode.
* Use SafeArea view for ios landscape view
* Use paddingHorizontal for SafeArea view for iOS landscape mode
This commit is contained in:
parent
93b8680714
commit
b6920770f1
12 changed files with 569 additions and 4 deletions
|
|
@ -268,6 +268,69 @@ exports[`channelInfo should match snapshot 1`] = `
|
|||
}
|
||||
}
|
||||
/>
|
||||
<Connect(NotificationPreference)
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(Pinned)
|
||||
channelId="1234"
|
||||
isLandscape={false}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import StatusBar from '@components/status_bar';
|
|||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import AddMembers from './add_members';
|
||||
import NotificationPreference from './notification_preference';
|
||||
import Archive from './archive';
|
||||
import ChannelInfoHeader from './channel_info_header';
|
||||
import ConvertPrivate from './convert_private';
|
||||
|
|
@ -141,6 +142,11 @@ export default class ChannelInfo extends PureComponent {
|
|||
theme={theme}
|
||||
/>
|
||||
<Separator theme={theme}/>
|
||||
<NotificationPreference
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<Separator theme={theme}/>
|
||||
<Pinned
|
||||
channelId={currentChannel.id}
|
||||
isLandscape={isLandscape}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ function createTouchableComponent(children, action) {
|
|||
}
|
||||
|
||||
function channelInfoRow(props) {
|
||||
const {action, defaultMessage, detail, icon, iconColor, image, imageTintColor, rightArrow, textColor, textId, togglable, theme, shouldRender, isLandscape} = props;
|
||||
const {action, defaultMessage, detail, icon, iconSize, iconColor, image, imageTintColor, rightArrow, textColor, textId, togglable, theme, shouldRender, isLandscape} = props;
|
||||
|
||||
if (!shouldRender) {
|
||||
return null;
|
||||
|
|
@ -34,13 +34,16 @@ function channelInfoRow(props) {
|
|||
const style = getStyleSheet(theme);
|
||||
|
||||
let iconElement = null;
|
||||
let iSize = iconSize;
|
||||
if (!iSize) {
|
||||
iSize = 15;
|
||||
}
|
||||
if (image == null) {
|
||||
iconElement = (
|
||||
<Icon
|
||||
name={icon}
|
||||
size={15}
|
||||
size={iSize}
|
||||
color={iconColor || changeOpacity(theme.centerChannelColor, 0.5)}
|
||||
style={style.leftIcon}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
|
@ -72,7 +75,9 @@ function channelInfoRow(props) {
|
|||
|
||||
const RowComponent = (
|
||||
<View style={[style.container, padding(isLandscape)]}>
|
||||
{iconElement}
|
||||
<View style={style.iconContainer}>
|
||||
{iconElement}
|
||||
</View>
|
||||
<FormattedText
|
||||
style={[style.label, {color: textColor || theme.centerChannelColor}]}
|
||||
id={textId}
|
||||
|
|
@ -100,6 +105,7 @@ channelInfoRow.propTypes = {
|
|||
]),
|
||||
icon: PropTypes.string,
|
||||
iconColor: PropTypes.string,
|
||||
iconSize: PropTypes.number,
|
||||
image: PropTypes.number,
|
||||
imageTintColor: PropTypes.string,
|
||||
isLandscape: PropTypes.bool,
|
||||
|
|
@ -135,6 +141,12 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
fontSize: 15,
|
||||
paddingVertical: 15,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 17,
|
||||
height: 17,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
leftIcon: {
|
||||
width: 17,
|
||||
},
|
||||
|
|
|
|||
19
app/screens/channel_info/notification_preference/index.js
Normal file
19
app/screens/channel_info/notification_preference/index.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {getMyCurrentChannelMembership} from '@mm-redux/selectors/entities/channels';
|
||||
|
||||
import NotificationPreference from './notification_preference';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const channelMember = getMyCurrentChannelMembership(state);
|
||||
|
||||
return {
|
||||
channelId: channelMember?.channel_id,
|
||||
userId: channelMember?.user_id,
|
||||
notifyProps: channelMember?.notify_props,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(NotificationPreference);
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {goToScreen} from '@actions/navigation';
|
||||
import {ViewTypes} from '@constants';
|
||||
import {ChannelNotifyProps} from '@mm-redux/types/channels';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface NotificationPreferenceProps {
|
||||
channelId: string;
|
||||
userId: string;
|
||||
notifyProps: ChannelNotifyProps;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class NotificationPreference extends PureComponent<NotificationPreferenceProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
goToChannelNotificationPreference = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const screen = 'ChannelNotificationPreference';
|
||||
const title = intl.formatMessage({id: 'channel_header.notificationPreference', defaultMessage: 'Mobile Notifications'});
|
||||
|
||||
goToScreen(screen, title, this.props);
|
||||
});
|
||||
|
||||
notificationLevelToText = (notifyLevel: string) => {
|
||||
const {intl} = this.context;
|
||||
|
||||
let textId = '';
|
||||
let defaultMsg = '';
|
||||
switch (notifyLevel) {
|
||||
case ViewTypes.NotificationLevels.DEFAULT: {
|
||||
textId = t('channel_header.notificationPreference.default');
|
||||
defaultMsg = 'Default';
|
||||
break;
|
||||
}
|
||||
case ViewTypes.NotificationLevels.ALL: {
|
||||
textId = t('channel_header.notificationPreference.all');
|
||||
defaultMsg = 'All';
|
||||
break;
|
||||
}
|
||||
case ViewTypes.NotificationLevels.MENTION: {
|
||||
textId = t('channel_header.notificationPreference.mention');
|
||||
defaultMsg = 'Mentions';
|
||||
break;
|
||||
}
|
||||
case ViewTypes.NotificationLevels.NONE: {
|
||||
textId = t('channel_header.notificationPreference.none');
|
||||
defaultMsg = 'Never';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return intl.formatMessage({id: textId, defaultMessage: defaultMsg});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isLandscape, theme, notifyProps, userId, channelId} = this.props;
|
||||
const pushNotifyLevel = notifyProps.push || ViewTypes.NotificationLevels.DEFAULT;
|
||||
|
||||
if (!userId || !channelId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelNotificationPreference}
|
||||
defaultMessage='Mobile Notifications'
|
||||
detail={this.notificationLevelToText(pushNotifyLevel)}
|
||||
icon='mobile'
|
||||
iconSize={20}
|
||||
textId={t('channel_header.notificationPreference')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
ScrollView,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import RadioButtonGroup from 'app/components/radio_button';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import ChannelNotificationPreferenceBase from './channel_notification_preference_base';
|
||||
|
||||
export default class ChannelNotificationPreferenceAndroid extends ChannelNotificationPreferenceBase {
|
||||
getRadioItems = () => {
|
||||
const {intl} = this.context;
|
||||
const items = this.getItems();
|
||||
const radioItems = [];
|
||||
items.forEach((element) => {
|
||||
const e = {
|
||||
label: intl.formatMessage({
|
||||
id: element.id,
|
||||
defaultMessage: element.defaultMessage,
|
||||
}),
|
||||
value: element.value,
|
||||
checked: element.checked,
|
||||
};
|
||||
radioItems.push(e);
|
||||
});
|
||||
return radioItems;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const options = this.getRadioItems();
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<FormattedText
|
||||
id='channel_notifications.preference.header'
|
||||
defaultMessage='Send Notifications'
|
||||
style={style.header}
|
||||
/>
|
||||
<ScrollView
|
||||
contentContainerStyle={style.wrapper}
|
||||
alwaysBounceVertical={false}
|
||||
>
|
||||
<RadioButtonGroup
|
||||
name='pushSettings'
|
||||
onSelect={this.handlePress}
|
||||
options={options}
|
||||
/>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelBg, 0.03),
|
||||
},
|
||||
wrapper: {
|
||||
marginLeft: 16,
|
||||
},
|
||||
header: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.56),
|
||||
fontSize: 13,
|
||||
marginTop: 10,
|
||||
padding: 16,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
ScrollView,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'app/components/safe_area_view';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import SectionItem from 'app/screens/settings/section_item';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
|
||||
import ChannelNotificationPreferenceBase from './channel_notification_preference_base';
|
||||
|
||||
export default class ChannelNotificationPreferenceIos extends ChannelNotificationPreferenceBase {
|
||||
render() {
|
||||
const {theme, isLandscape} = this.props;
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const items = this.getItems();
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
excludeHeader={true}
|
||||
excludeFooter={true}
|
||||
>
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<FormattedText
|
||||
id='channel_notifications.preference.header'
|
||||
defaultMessage='Send Notifications'
|
||||
style={[style.header, padding(isLandscape)]}
|
||||
/>
|
||||
<ScrollView
|
||||
contentContainerStyle={style.scrollView}
|
||||
alwaysBounceVertical={false}
|
||||
>
|
||||
<View style={style.contentContainer}>
|
||||
{items.map((item) => (
|
||||
<View key={item.id}>
|
||||
<View style={style.divider}/>
|
||||
<SectionItem
|
||||
label={(
|
||||
<FormattedText
|
||||
id={item.id}
|
||||
defaultMessage={item.defaultMessage}
|
||||
/>
|
||||
)}
|
||||
action={this.handlePress}
|
||||
actionType='select'
|
||||
actionValue={item.value}
|
||||
selected={item.checked}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</View>),
|
||||
)}
|
||||
<View style={style.divider}/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
},
|
||||
header: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.56),
|
||||
fontSize: 13,
|
||||
textTransform: 'uppercase',
|
||||
marginTop: 10,
|
||||
padding: 16,
|
||||
},
|
||||
divider: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
height: 1,
|
||||
width: '100%',
|
||||
marginLeft: 16,
|
||||
},
|
||||
scrollView: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
},
|
||||
contentContainer: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelBg, 1),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react';
|
||||
|
||||
import {ViewTypes} from '@constants';
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
import SectionItem from '@screens/settings/section_item';
|
||||
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
import ChannelNotificationPreference from './channel_notification_preference';
|
||||
|
||||
function makeProps(pushNotificationLevel) {
|
||||
return {
|
||||
actions: {
|
||||
updateChannelNotifyProps: jest.fn(),
|
||||
},
|
||||
channelId: 'channel_id',
|
||||
userId: 'user_id',
|
||||
notifyProps: {
|
||||
push: pushNotificationLevel,
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
isLandscape: false,
|
||||
};
|
||||
}
|
||||
|
||||
function checkNotificationSelected(pushNotificationLevel, trueIdx) {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelNotificationPreference
|
||||
{...makeProps(pushNotificationLevel)}
|
||||
/>,
|
||||
);
|
||||
|
||||
const sectionItems = wrapper.find(SectionItem);
|
||||
|
||||
expect(sectionItems.exists()).toBe(true);
|
||||
expect(sectionItems.length).toBe(4);
|
||||
|
||||
sectionItems.forEach((sectionItem, idx) => {
|
||||
expect(sectionItem.prop('selected')).toBe(idx === trueIdx);
|
||||
});
|
||||
}
|
||||
|
||||
describe('ChannelNotificationPreference', () => {
|
||||
test('should have correct setting selected', () => {
|
||||
checkNotificationSelected(null, 0);
|
||||
checkNotificationSelected(ViewTypes.NotificationLevels.DEFAULT, 0);
|
||||
checkNotificationSelected(ViewTypes.NotificationLevels.ALL, 1);
|
||||
checkNotificationSelected(ViewTypes.NotificationLevels.MENTION, 2);
|
||||
checkNotificationSelected(ViewTypes.NotificationLevels.NONE, 3);
|
||||
});
|
||||
|
||||
test('should save on click', () => {
|
||||
const props = makeProps('default');
|
||||
const wrapper = shallowWithIntl(
|
||||
<ChannelNotificationPreference {...props}/>,
|
||||
);
|
||||
|
||||
// click on 'Never' -- last item
|
||||
wrapper.find(SectionItem).at(3).dive().simulate('press');
|
||||
|
||||
expect(props.actions.updateChannelNotifyProps).toHaveBeenCalledTimes(1);
|
||||
expect(props.actions.updateChannelNotifyProps).toBeCalledWith(
|
||||
props.userId,
|
||||
props.channelId,
|
||||
{push: ViewTypes.NotificationLevels.NONE},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {ViewTypes} from '@constants';
|
||||
import {alertErrorWithFallback} from 'app/utils/general';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
|
||||
export default class ChannelNotificationPreferenceBase extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
updateChannelNotifyProps: PropTypes.func.isRequired,
|
||||
}),
|
||||
channelId: PropTypes.string.isRequired,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
notifyProps: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
userId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
notificationLevel: props.notifyProps?.push || ViewTypes.NotificationLevels.DEFAULT,
|
||||
};
|
||||
}
|
||||
|
||||
getItems = () => {
|
||||
const {notificationLevel} = this.state;
|
||||
return [{
|
||||
id: t('channel_notifications.preference.global_default'),
|
||||
defaultMessage: 'Global default (Mentions)',
|
||||
value: ViewTypes.NotificationLevels.DEFAULT,
|
||||
checked: notificationLevel === ViewTypes.NotificationLevels.DEFAULT,
|
||||
}, {
|
||||
id: t('channel_notifications.preference.all_activity'),
|
||||
defaultMessage: 'For all activity',
|
||||
value: ViewTypes.NotificationLevels.ALL,
|
||||
checked: notificationLevel === ViewTypes.NotificationLevels.ALL,
|
||||
}, {
|
||||
id: t('channel_notifications.preference.only_mentions'),
|
||||
defaultMessage: 'Only mentions and direct messages',
|
||||
value: ViewTypes.NotificationLevels.MENTION,
|
||||
checked: notificationLevel === ViewTypes.NotificationLevels.MENTION,
|
||||
}, {
|
||||
id: t('channel_notifications.preference.never'),
|
||||
defaultMessage: 'Never',
|
||||
value: ViewTypes.NotificationLevels.NONE,
|
||||
checked: notificationLevel === ViewTypes.NotificationLevels.NONE,
|
||||
}];
|
||||
}
|
||||
|
||||
handlePress = preventDoubleTap(async (newNotificationLevel) => {
|
||||
const {actions, channelId, userId} = this.props;
|
||||
const {notificationLevel} = this.state;
|
||||
|
||||
if (newNotificationLevel === notificationLevel) {
|
||||
// tapped on current selection.
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
notificationLevel: newNotificationLevel,
|
||||
});
|
||||
|
||||
const props = {push: newNotificationLevel};
|
||||
|
||||
const {error} = await actions.updateChannelNotifyProps(userId, channelId, props);
|
||||
if (error) {
|
||||
const {intl} = this.context;
|
||||
alertErrorWithFallback(
|
||||
intl,
|
||||
error,
|
||||
{
|
||||
id: t('channel_notifications.preference.save_error'),
|
||||
defaultMessage: "We couldn't save notification preference. Please check your connection and try again.",
|
||||
},
|
||||
);
|
||||
|
||||
// restore old value.
|
||||
this.setState({
|
||||
notificationLevel,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
26
app/screens/channel_notification_preference/index.js
Normal file
26
app/screens/channel_notification_preference/index.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import {updateChannelNotifyProps} from '@mm-redux/actions/channels';
|
||||
import {getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
|
||||
import ChannelNotificationPreference from './channel_notification_preference';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const theme = getTheme(state);
|
||||
return {
|
||||
theme,
|
||||
isLandscape: isLandscape(state),
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
actions: bindActionCreators({
|
||||
updateChannelNotifyProps,
|
||||
}, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ChannelNotificationPreference);
|
||||
|
|
@ -33,6 +33,7 @@ export function registerScreens(store, Provider) {
|
|||
Navigation.registerComponent('ChannelAddMembers', () => wrapper(require('app/screens/channel_add_members').default), () => require('app/screens/channel_add_members').default);
|
||||
Navigation.registerComponent('ChannelInfo', () => wrapper(require('app/screens/channel_info').default), () => require('app/screens/channel_info').default);
|
||||
Navigation.registerComponent('ChannelMembers', () => wrapper(require('app/screens/channel_members').default), () => require('app/screens/channel_members').default);
|
||||
Navigation.registerComponent('ChannelNotificationPreference', () => wrapper(require('app/screens/channel_notification_preference').default), () => require('app/screens/channel_notification_preference').default);
|
||||
Navigation.registerComponent('ClientUpgrade', () => wrapper(require('app/screens/client_upgrade').default), () => require('app/screens/client_upgrade').default);
|
||||
Navigation.registerComponent('ClockDisplaySettings', () => wrapper(require('app/screens/settings/clock_display').default), () => require('app/screens/settings/clock_display').default);
|
||||
Navigation.registerComponent('Code', () => wrapper(require('app/screens/code').default), () => require('app/screens/code').default);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
"channel_header.addMembers": "Add Members",
|
||||
"channel_header.directchannel.you": "{displayname} (you) ",
|
||||
"channel_header.manageMembers": "Manage Members",
|
||||
"channel_header.notificationPreference": "Mobile Notifications",
|
||||
"channel_header.notificationPreference.all": "All",
|
||||
"channel_header.notificationPreference.default": "Default",
|
||||
"channel_header.notificationPreference.mention": "Mentions",
|
||||
"channel_header.notificationPreference.none": "Never",
|
||||
"channel_header.pinnedPosts": "Pinned Messages",
|
||||
"channel_header.viewMembers": "View Members",
|
||||
"channel_info.header": "Header:",
|
||||
|
|
@ -35,6 +40,12 @@
|
|||
"channel_modal.purposeEx": "E.g.: \"A channel to file bugs and improvements\"",
|
||||
"channel_notifications.ignoreChannelMentions.settings": "Ignore @channel, @here, @all",
|
||||
"channel_notifications.muteChannel.settings": "Mute channel",
|
||||
"channel_notifications.preference.all_activity": "For all activity",
|
||||
"channel_notifications.preference.global_default": "Global default (Mentions)",
|
||||
"channel_notifications.preference.header": "Send Notifications",
|
||||
"channel_notifications.preference.never": "Never",
|
||||
"channel_notifications.preference.only_mentions": "Only mentions and direct messages",
|
||||
"channel_notifications.preference.save_error": "We couldn't save notification preference. Please check your connection and try again.",
|
||||
"channel.channelHasGuests": "This channel has guests",
|
||||
"channel.hasGuests": "This group message has guests",
|
||||
"channel.isGuest": "This person is a guest",
|
||||
|
|
|
|||
Loading…
Reference in a new issue