Merge branch 'master' into mark-as-unread

This commit is contained in:
Harrison Healey 2019-10-31 09:15:13 -04:00
commit d59b62daf8
15 changed files with 574 additions and 72 deletions

3
.gitignore vendored
View file

@ -40,6 +40,9 @@ ios/Pods
local.properties
*.iml
android/app/bin
.settings
.project
.classpath
# node.js
#

View file

@ -1,22 +1,37 @@
Please make sure you've read the [pull request](https://developers.mattermost.com/contribute/getting-started/contribution-checklist/) section of our [code contribution guidelines](https://developers.mattermost.com/contribute/getting-started/).
<!-- Thank you for contributing a pull request! Here are a few tips to help you:
When filling in a section please remove the help text and the above text.
1. If this is your first contribution, make sure you've read the Contribution Checklist https://developers.mattermost.com/contribute/getting-started/contribution-checklist/
2. Read our blog post about "Submitting Great PRs" https://developers.mattermost.com/blog/2019-01-24-submitting-great-prs
3. Take a look at other repository specific documentation at https://developers.mattermost.com/contribute
-->
#### Summary
[A brief description of what this pull request does.]
<!--
A brief description of what this pull request does.
-->
#### Ticket Link
[Please link the GitHub issue or Jira ticket this PR addresses.]
<!--
If this pull request addresses a Help Wanted ticket, please link the relevant GitHub issue, e.g.
Fixes https://github.com/mattermost/mattermost-server/issues/XXXXX
Otherwise, link the JIRA ticket.
-->
#### Checklist
[Place an '[x]' (no spaces) in all applicable fields. Please remove unrelated fields.]
<!--
Place an '[x]' (no spaces) in all applicable fields. Please remove unrelated fields.
-->
- [ ] Added or updated unit tests (required for all new features)
- [ ] All new/modified APIs include changes to [mattermost-redux](https://github.com/mattermost/mattermost-redux) (please link)
- [ ] Has UI changes
- [ ] Includes text changes and localization file updates
#### Device Information
This PR was tested on: [Device name(s), OS version(s)]
This PR was tested on: <!-- Device name(s), OS version(s) -->
#### Screenshots
[If the PR includes UI changes, include screenshots (for both iOS and Android if possible).]
<!--
If the PR includes UI changes, include screenshots/GIFs (for both iOS and Android if possible).
-->

View file

@ -84,17 +84,15 @@ export default class SafeAreaIos extends PureComponent {
getSafeAreaInsets = async (dimensions) => {
this.getStatusBarHeight();
const safeAreaInsetsStored = EphemeralStore.safeAreaInsets[PORTRAIT] !== null && EphemeralStore.safeAreaInsets[LANDSCAPE] !== null;
if ((DeviceTypes.IS_IPHONE_WITH_INSETS || mattermostManaged.hasSafeAreaInsets) && !safeAreaInsetsStored) {
if (DeviceTypes.IS_IPHONE_WITH_INSETS || mattermostManaged.hasSafeAreaInsets) {
const window = dimensions?.window || Dimensions.get('window');
const landscape = window.width > window.length;
const orientation = window.width > window.length ? LANDSCAPE : PORTRAIT;
const {safeAreaInsets} = await SafeArea.getSafeAreaInsetsForRootView();
this.setSafeAreaInsets(safeAreaInsets, landscape);
this.setSafeAreaInsets(safeAreaInsets, orientation);
}
}
setSafeAreaInsets = (safeAreaInsets, landscape) => {
const orientation = landscape ? LANDSCAPE : PORTRAIT;
setSafeAreaInsets = (safeAreaInsets, orientation) => {
if (EphemeralStore.safeAreaInsets[orientation] === null) {
EphemeralStore.safeAreaInsets[orientation] = safeAreaInsets;
}
@ -130,8 +128,8 @@ export default class SafeAreaIos extends PureComponent {
this.getStatusBarHeight();
const {width, height} = Dimensions.get('window');
const landscape = width > height;
this.setSafeAreaInsets(safeAreaInsets, landscape);
const orientation = width > height ? LANDSCAPE : PORTRAIT;
this.setSafeAreaInsets(safeAreaInsets, orientation);
}
}

View file

@ -195,9 +195,9 @@ describe('SafeAreaIos', () => {
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
const landscape = false;
const orientation = PORTRAIT;
const instance = wrapper.instance();
instance.setSafeAreaInsets(PORTRAIT_INSETS.safeAreaInsets, landscape);
instance.setSafeAreaInsets(PORTRAIT_INSETS.safeAreaInsets, orientation);
expect(wrapper.state().safeAreaInsets).toEqual(PORTRAIT_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(PORTRAIT_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
@ -211,9 +211,9 @@ describe('SafeAreaIos', () => {
EphemeralStore.safeAreaInsets[PORTRAIT] = PORTRAIT_INSETS.safeAreaInsets;
expect(wrapper.state().safeAreaInsets).not.toEqual(PORTRAIT_INSETS.safeAreaInsets);
const landscape = false;
const orientation = PORTRAIT;
const instance = wrapper.instance();
instance.setSafeAreaInsets(IGNORED_INSETS.safeAreaInsets, landscape);
instance.setSafeAreaInsets(IGNORED_INSETS.safeAreaInsets, orientation);
expect(wrapper.state().safeAreaInsets).toEqual(PORTRAIT_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(PORTRAIT_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
@ -228,9 +228,9 @@ describe('SafeAreaIos', () => {
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
const landscape = true;
const orientation = LANDSCAPE;
const instance = wrapper.instance();
instance.setSafeAreaInsets(LANDSCAPE_INSETS.safeAreaInsets, landscape);
instance.setSafeAreaInsets(LANDSCAPE_INSETS.safeAreaInsets, orientation);
expect(wrapper.state().safeAreaInsets).toEqual(LANDSCAPE_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(LANDSCAPE_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
@ -244,9 +244,9 @@ describe('SafeAreaIos', () => {
EphemeralStore.safeAreaInsets[LANDSCAPE] = LANDSCAPE_INSETS.safeAreaInsets;
expect(wrapper.state().safeAreaInsets).not.toEqual(LANDSCAPE_INSETS.safeAreaInsets);
const landscape = true;
const orientation = LANDSCAPE;
const instance = wrapper.instance();
instance.setSafeAreaInsets(IGNORED_INSETS.safeAreaInsets, landscape);
instance.setSafeAreaInsets(IGNORED_INSETS.safeAreaInsets, orientation);
expect(wrapper.state().safeAreaInsets).toEqual(LANDSCAPE_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(LANDSCAPE_INSETS.safeAreaInsets);
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
@ -302,27 +302,4 @@ describe('SafeAreaIos', () => {
instance.onSafeAreaInsetsForRootViewChange(TEST_INSETS_1);
expect(removeEventListener).toHaveBeenCalledWith('safeAreaInsetsForRootViewDidChange', instance.onSafeAreaInsetsForRootViewChange);
});
test('getSafeAreaInsets should set safe area insets when not already in ephemeral store', async () => {
const wrapper = shallow(
<SafeAreaIos {...baseProps}/>
);
const instance = wrapper.instance();
const setSafeAreaInsets = jest.spyOn(instance, 'setSafeAreaInsets');
expect(EphemeralStore.safeAreaInsets[PORTRAIT]).toEqual(null);
expect(EphemeralStore.safeAreaInsets[LANDSCAPE]).toEqual(null);
await instance.getSafeAreaInsets();
expect(setSafeAreaInsets).toHaveBeenCalled();
setSafeAreaInsets.mockClear();
EphemeralStore.safeAreaInsets[PORTRAIT] = TEST_INSETS_1.safeAreaInsets; /* eslint-disable-line require-atomic-updates */
await instance.getSafeAreaInsets();
expect(setSafeAreaInsets).toHaveBeenCalled();
setSafeAreaInsets.mockClear();
EphemeralStore.safeAreaInsets[LANDSCAPE] = TEST_INSETS_1.safeAreaInsets; /* eslint-disable-line require-atomic-updates */
await instance.getSafeAreaInsets();
expect(setSafeAreaInsets).not.toHaveBeenCalled();
});
});

View file

@ -0,0 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export default {
TERMS_OF_SERVICE: 'https://about.mattermost.com/default-terms/',
PRIVACY_POLICY: 'https://about.mattermost.com/default-privacy-policy/',
};

View file

@ -18,6 +18,7 @@ import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/ut
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
import AppIcon from 'app/components/app_icon';
import Config from 'assets/config';
import AboutLinks from 'app/constants/about_links';
const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn'];
@ -53,11 +54,11 @@ export default class About extends PureComponent {
};
handleTermsOfService = () => {
Linking.openURL(this.props.config.TermsOfServiceLink);
Linking.openURL(AboutLinks.TERMS_OF_SERVICE);
};
handlePrivacyPolicy = () => {
Linking.openURL(this.props.config.PrivacyPolicyLink);
Linking.openURL(AboutLinks.PRIVACY_POLICY);
}
render() {

View file

@ -0,0 +1,397 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NotificationSettings should match snapshot 1`] = `
NotificationSettings {
"context": Object {
"intl": Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": "span",
"timeZone": null,
},
},
"goToNotificationSettingsAutoResponder": [Function],
"goToNotificationSettingsEmail": [Function],
"goToNotificationSettingsMentions": [Function],
"goToNotificationSettingsMobile": [Function],
"handlePress": [Function],
"props": Object {
"actions": Object {
"updateMe": [MockFunction],
},
"componentId": "component-id",
"currentUser": Object {
"id": "current_user_id",
},
"currentUserStatus": "status",
"enableAutoResponder": false,
"intl": Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": "span",
"timeZone": null,
},
"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",
},
"updateMeRequest": Object {},
},
"refs": Object {},
"saveAutoResponder": [Function],
"saveNotificationProps": [Function],
"setState": [Function],
"shouldSaveAutoResponder": [Function],
"state": null,
"updater": Updater {
"_callbacks": Array [],
"_renderer": ReactShallowRenderer {
"_context": Object {
"intl": Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": "span",
"timeZone": null,
},
},
"_didScheduleRenderPhaseUpdate": false,
"_dispatcher": Object {
"readContext": [Function],
"useCallback": [Function],
"useContext": [Function],
"useDebugValue": [Function],
"useEffect": [Function],
"useImperativeHandle": [Function],
"useLayoutEffect": [Function],
"useMemo": [Function],
"useReducer": [Function],
"useRef": [Function],
"useResponder": [Function],
"useState": [Function],
},
"_element": <NotificationSettings
actions={
Object {
"updateMe": [MockFunction],
}
}
componentId="component-id"
currentUser={
Object {
"id": "current_user_id",
}
}
currentUserStatus="status"
enableAutoResponder={false}
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": "span",
"timeZone": null,
}
}
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",
}
}
updateMeRequest={Object {}}
/>,
"_firstWorkInProgressHook": null,
"_forcedUpdate": false,
"_instance": [Circular],
"_isReRender": false,
"_newState": null,
"_numberOfReRenders": 0,
"_renderPhaseUpdates": null,
"_rendered": <View
style={
Object {
"backgroundColor": "#ffffff",
"flex": 1,
}
}
>
<Connect(StatusBar) />
<ScrollViewMock
alwaysBounceVertical={false}
contentContainerStyle={
Object {
"backgroundColor": "rgba(61,60,64,0.06)",
"paddingTop": 35,
}
}
>
<View
style={
Object {
"backgroundColor": "rgba(61,60,64,0.1)",
"height": 1,
"width": "100%",
}
}
/>
<SettingsItem
defaultMessage="Mentions and Replies"
i18nId="mobile.notification_settings.mentions_replies"
iconName="md-at"
iconType="ion"
isDestructor={false}
isLandscape={false}
onPress={[Function]}
separator={true}
showArrow={true}
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",
}
}
/>
<SettingsItem
defaultMessage="Mobile"
i18nId="mobile.notification_settings.mobile"
iconName="md-phone-portrait"
iconType="ion"
isDestructor={false}
isLandscape={false}
onPress={[Function]}
separator={true}
showArrow={true}
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",
}
}
/>
<SettingsItem
defaultMessage="Email"
i18nId="mobile.notification_settings.email"
iconName="ios-mail"
iconType="ion"
isDestructor={false}
isLandscape={false}
onPress={[Function]}
separator={false}
showArrow={true}
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",
}
}
/>
<View
style={
Object {
"backgroundColor": "rgba(61,60,64,0.1)",
"height": 1,
"width": "100%",
}
}
/>
</ScrollViewMock>
</View>,
"_rendering": false,
"_updater": [Circular],
"_workInProgressHook": null,
},
},
}
`;

View file

@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {injectIntl, intlShape} from 'react-intl';
import {intlShape} from 'react-intl';
import {
Alert,
Platform,
@ -23,14 +23,13 @@ import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/ut
import {t} from 'app/utils/i18n';
import {goToScreen} from 'app/actions/navigation';
class NotificationSettings extends PureComponent {
export default class NotificationSettings extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
updateMe: PropTypes.func.isRequired,
}),
componentId: PropTypes.string,
currentUser: PropTypes.object.isRequired,
intl: intlShape.isRequired,
theme: PropTypes.object.isRequired,
updateMeRequest: PropTypes.object.isRequired,
currentUserStatus: PropTypes.string.isRequired,
@ -38,12 +37,17 @@ class NotificationSettings extends PureComponent {
isLandscape: PropTypes.bool.isRequired,
};
static contextTypes = {
intl: intlShape.isRequired,
};
componentWillReceiveProps(nextProps) {
if (this.props.theme !== nextProps.theme) {
setNavigatorStyles(this.props.componentId, nextProps.theme);
}
const {updateMeRequest, intl} = nextProps;
const {updateMeRequest} = nextProps;
const {intl} = this.context;
if (this.props.updateMeRequest !== updateMeRequest && updateMeRequest.status === RequestStatus.FAILURE) {
Alert.alert(
intl.formatMessage({
@ -63,7 +67,8 @@ class NotificationSettings extends PureComponent {
});
goToNotificationSettingsAutoResponder = () => {
const {currentUser, intl} = this.props;
const {currentUser} = this.props;
const {intl} = this.context;
const screen = 'NotificationSettingsAutoResponder';
const title = intl.formatMessage({
id: 'mobile.notification_settings.auto_responder_short',
@ -78,7 +83,7 @@ class NotificationSettings extends PureComponent {
};
goToNotificationSettingsEmail = () => {
const {intl} = this.props;
const {intl} = this.context;
const screen = 'NotificationSettingsEmail';
const title = intl.formatMessage({
id: 'mobile.notification_settings.email_title',
@ -89,7 +94,8 @@ class NotificationSettings extends PureComponent {
};
goToNotificationSettingsMentions = () => {
const {currentUser, intl} = this.props;
const {currentUser} = this.props;
const {intl} = this.context;
const screen = 'NotificationSettingsMentions';
const title = intl.formatMessage({
id: 'mobile.notification_settings.mentions_replies',
@ -104,7 +110,8 @@ class NotificationSettings extends PureComponent {
};
goToNotificationSettingsMobile = () => {
const {currentUser, intl} = this.props;
const {currentUser} = this.props;
const {intl} = this.context;
const screen = 'NotificationSettingsMobile';
const title = intl.formatMessage({
id: 'mobile.notification_settings.mobile_title',
@ -127,14 +134,13 @@ class NotificationSettings extends PureComponent {
saveNotificationProps = (notifyProps) => {
const {currentUser} = this.props;
const {user_id: userId} = notifyProps;
const previousProps = {
const updatedProps = {
...getNotificationProps(currentUser),
user_id: userId,
...notifyProps,
};
if (!deepEqual(previousProps, notifyProps)) {
this.props.actions.updateMe({notify_props: notifyProps});
if (!deepEqual(updatedProps, notifyProps)) {
this.props.actions.updateMe({notify_props: updatedProps});
}
};
@ -158,7 +164,7 @@ class NotificationSettings extends PureComponent {
};
saveAutoResponder = (notifyProps) => {
const {intl} = this.props;
const {intl} = this.context;
if (!notifyProps.auto_responder_message || notifyProps.auto_responder_message === '') {
notifyProps.auto_responder_message = intl.formatMessage({
@ -265,5 +271,3 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
},
};
});
export default injectIntl(NotificationSettings);

View file

@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import Preferences from 'mattermost-redux/constants/preferences';
import {shallowWithIntl} from 'test/intl-test-helper';
import NotificationSettings from './notification_settings.js';
describe('NotificationSettings', () => {
const baseProps = {
actions: {
updateMe: jest.fn(),
},
componentId: 'component-id',
currentUser: {id: 'current_user_id'},
theme: Preferences.THEMES.default,
updateMeRequest: {},
currentUserStatus: 'status',
enableAutoResponder: false,
isLandscape: false,
};
test('should match snapshot', () => {
const wrapper = shallowWithIntl(
<NotificationSettings {...baseProps}/>
);
expect(wrapper.instance()).toMatchSnapshot();
});
test('should include previous notification props when saving new ones', () => {
baseProps.currentUser.notify_props = {previous: 'previous'};
const wrapper = shallowWithIntl(
<NotificationSettings {...baseProps}/>
);
const instance = wrapper.instance();
const newProps = {new: 'new'};
instance.saveNotificationProps(newProps);
expect(baseProps.actions.updateMe).toHaveBeenCalledWith({
notify_props: {
...baseProps.currentUser.notify_props,
...newProps,
},
});
});
});

View file

@ -4,6 +4,7 @@ exports[`thread should match snapshot, has root post 1`] = `
<React.Fragment>
<Connect(SafeAreaIos)
excludeHeader={true}
forceInsets={true}
>
<View
style={
@ -74,6 +75,7 @@ exports[`thread should match snapshot, no root post, loading 1`] = `
<React.Fragment>
<Connect(SafeAreaIos)
excludeHeader={true}
forceInsets={true}
>
<View
style={
@ -143,6 +145,7 @@ exports[`thread should match snapshot, render footer 3`] = `
<React.Fragment>
<Connect(SafeAreaIos)
excludeHeader={true}
forceInsets={true}
>
<View
style={

View file

@ -92,7 +92,10 @@ export default class ThreadIOS extends ThreadBase {
const style = getStyleSheet(theme);
return (
<React.Fragment>
<SafeAreaView excludeHeader={true}>
<SafeAreaView
excludeHeader={true}
forceInsets={true}
>
<View style={style.separator}/>
<StatusBar/>
{content}

View file

@ -99,15 +99,20 @@ export const filterMembersNotInChannel = createSelector(
let profiles;
if (matchTerm) {
profiles = profilesNotInChannel.filter((p) => {
return ((p.id !== currentUserId && p.detele_at === 0) && (
p.username.toLowerCase().includes(matchTerm) || p.email.toLowerCase().includes(matchTerm) ||
p.first_name.toLowerCase().includes(matchTerm) || p.last_name.toLowerCase().includes(matchTerm)));
return (
p.username.toLowerCase().includes(matchTerm) ||
p.email.toLowerCase().includes(matchTerm) ||
p.first_name.toLowerCase().includes(matchTerm) ||
p.last_name.toLowerCase().includes(matchTerm)
) && (p.delete_at === 0 && p.id !== currentUserId);
});
} else {
profiles = profilesNotInChannel.filter((p) => p.delete_at === 0);
}
return profiles.map((p) => p.id);
return profiles.map((p) => {
return p.id;
});
}
);

View file

@ -5,6 +5,7 @@ import assert from 'assert';
import {
getMatchTermForAtMention,
filterMembersNotInChannel,
} from 'app/selectors/autocomplete';
/* eslint-disable max-nested-callbacks */
@ -56,4 +57,42 @@ describe('Selectors.Autocomplete', () => {
});
});
});
it('Should return profiles not in channel', () => {
const state = {
entities: {
channels: {
currentChannelId: 'current-channel-id',
},
users: {
currentUserId: 'current-user-id',
profiles: {
'current-user-id': {id: 'current-user-id', username: 'current', delete_at: 0},
'test-user-id': {id: 'test-user-id', username: 'test', first_name: 'Test', last_name: 'User', email: 'test@example.com', delete_at: 0},
'another-user-id': {id: 'another-user-id', username: 'another', first_name: 'Another', last_name: 'One', email: 'another@example.com', delete_at: 0},
'deleted-user-id': {id: 'deleted-user-id', username: 'deleted', first_name: 'Remvoed', last_name: 'Friend', email: 'deleted@example.com', delete_at: 123},
},
profilesNotInChannel: {
'current-channel-id': new Set(['test-user-id', 'another-user-id', 'deleted-user-id']),
},
},
},
};
let profiles = filterMembersNotInChannel(state, '');
expect(profiles.length).toBe(2);
// filter to get the current user, should return zero results
profiles = filterMembersNotInChannel(state, 'current');
expect(profiles.length).toBe(0);
profiles = filterMembersNotInChannel(state, 'tes');
expect(profiles.length).toBe(1);
profiles = filterMembersNotInChannel(state, 'one');
expect(profiles.length).toBe(1);
profiles = filterMembersNotInChannel(state, 'example');
expect(profiles.length).toBe(2);
});
});

4
package-lock.json generated
View file

@ -7778,8 +7778,8 @@
}
},
"mattermost-redux": {
"version": "github:mattermost/mattermost-redux#ad9a13e34dfbae9981eddda27711c5c14134d009",
"from": "github:mattermost/mattermost-redux#ad9a13e34dfbae9981eddda27711c5c14134d009",
"version": "github:mattermost/mattermost-redux#edaa6ebc4077ec65e51c2864db0abbd04e1d8db9",
"from": "github:mattermost/mattermost-redux#edaa6ebc4077ec65e51c2864db0abbd04e1d8db9",
"requires": {
"gfycat-sdk": "1.4.18",
"isomorphic-fetch": "2.2.1",

View file

@ -23,7 +23,7 @@
"intl": "1.2.5",
"jail-monkey": "2.3.0",
"jsc-android": "241213.1.0",
"mattermost-redux": "github:mattermost/mattermost-redux#ad9a13e34dfbae9981eddda27711c5c14134d009",
"mattermost-redux": "github:mattermost/mattermost-redux#edaa6ebc4077ec65e51c2864db0abbd04e1d8db9",
"mime-db": "1.42.0",
"moment-timezone": "0.5.27",
"prop-types": "15.7.2",