diff --git a/app/actions/navigation.js b/app/actions/navigation.js
index 94ab126c73..d4cd69ad26 100644
--- a/app/actions/navigation.js
+++ b/app/actions/navigation.js
@@ -360,24 +360,22 @@ export function dismissOverlay(componentId) {
};
}
-export function applyTheme() {
+export function applyTheme(componentId) {
return (dispatch, getState) => {
const theme = getTheme(getState());
- EphemeralStore.getNavigationComponentIds().forEach((componentId) => {
- Navigation.mergeOptions(componentId, {
- topBar: {
- backButton: {
- color: theme.sidebarHeaderTextColor,
- },
- background: {
- color: theme.sidebarHeaderBg,
- },
- title: {
- color: theme.sidebarHeaderTextColor,
- },
+ Navigation.mergeOptions(componentId, {
+ topBar: {
+ backButton: {
+ color: theme.sidebarHeaderTextColor,
},
- });
+ background: {
+ color: theme.sidebarHeaderBg,
+ },
+ title: {
+ color: theme.sidebarHeaderTextColor,
+ },
+ },
});
};
}
diff --git a/app/components/file_attachment_list/file_attachment_document/index.js b/app/components/file_attachment_list/file_attachment_document/index.js
index 753d2d8ff1..31fe7d916f 100644
--- a/app/components/file_attachment_list/file_attachment_document/index.js
+++ b/app/components/file_attachment_list/file_attachment_document/index.js
@@ -16,4 +16,4 @@ function mapDispatchToProps(dispatch) {
};
}
-export default connect(null, mapDispatchToProps)(FileAttachmentDocument);
+export default connect(null, mapDispatchToProps, null, {forwardRef: true})(FileAttachmentDocument);
diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js
index 526bb4a824..b8a7bac8e5 100644
--- a/app/components/markdown/markdown_image/markdown_image.js
+++ b/app/components/markdown/markdown_image/markdown_image.js
@@ -18,6 +18,7 @@ import {
import FormattedText from 'app/components/formatted_text';
import ProgressiveImage from 'app/components/progressive_image';
import CustomPropTypes from 'app/constants/custom_prop_types';
+import {getCurrentServerUrl} from 'app/init/credentials';
import mattermostManaged from 'app/mattermost_managed';
import BottomSheet from 'app/utils/bottom_sheet';
import ImageCacheManager from 'app/utils/image_cache_manager';
@@ -42,7 +43,7 @@ export default class MarkdownImage extends React.Component {
imagesMetadata: PropTypes.object,
linkDestination: PropTypes.string,
isReplyPost: PropTypes.bool,
- serverURL: PropTypes.string.isRequired,
+ serverURL: PropTypes.string,
source: PropTypes.string.isRequired,
errorTextStyle: CustomPropTypes.Style,
};
@@ -95,11 +96,15 @@ export default class MarkdownImage extends React.Component {
this.mounted = false;
}
- getSource = () => {
+ getSource = async () => {
let source = this.props.source;
+ let serverUrl = this.props.serverURL;
+ if (!serverUrl) {
+ serverUrl = await getCurrentServerUrl();
+ }
if (source.startsWith('/')) {
- source = this.props.serverURL + '/' + source;
+ source = serverUrl + source;
}
return source;
diff --git a/app/components/markdown/markdown_link/markdown_link.js b/app/components/markdown/markdown_link/markdown_link.js
index abcdc7b760..3aa9ff3100 100644
--- a/app/components/markdown/markdown_link/markdown_link.js
+++ b/app/components/markdown/markdown_link/markdown_link.js
@@ -9,6 +9,7 @@ import {intlShape} from 'react-intl';
import CustomPropTypes from 'app/constants/custom_prop_types';
import {DeepLinkTypes} from 'app/constants';
+import {getCurrentServerUrl} from 'app/init/credentials';
import mattermostManaged from 'app/mattermost_managed';
import BottomSheet from 'app/utils/bottom_sheet';
import {preventDoubleTap} from 'app/utils/tap';
@@ -24,7 +25,7 @@ export default class MarkdownLink extends PureComponent {
children: CustomPropTypes.Children.isRequired,
href: PropTypes.string.isRequired,
onPermalinkPress: PropTypes.func,
- serverURL: PropTypes.string.isRequired,
+ serverURL: PropTypes.string,
siteURL: PropTypes.string.isRequired,
};
@@ -38,7 +39,7 @@ export default class MarkdownLink extends PureComponent {
intl: intlShape.isRequired,
};
- handlePress = preventDoubleTap(() => {
+ handlePress = preventDoubleTap(async () => {
const {href, onPermalinkPress, serverURL, siteURL} = this.props;
const url = normalizeProtocol(href);
@@ -46,7 +47,12 @@ export default class MarkdownLink extends PureComponent {
return;
}
- const match = matchDeepLink(url, serverURL, siteURL);
+ let serverUrl = serverURL;
+ if (!serverUrl) {
+ serverUrl = await getCurrentServerUrl();
+ }
+
+ const match = matchDeepLink(url, serverUrl, siteURL);
if (match) {
if (match.type === DeepLinkTypes.CHANNEL) {
this.props.actions.handleSelectChannelByName(match.channelName, match.teamName);
diff --git a/app/components/markdown/markdown_table_image/markdown_table_image.js b/app/components/markdown/markdown_table_image/markdown_table_image.js
index b2fdfd5f3e..1a21d0e52a 100644
--- a/app/components/markdown/markdown_table_image/markdown_table_image.js
+++ b/app/components/markdown/markdown_table_image/markdown_table_image.js
@@ -7,6 +7,7 @@ import {intlShape} from 'react-intl';
import {Text} from 'react-native';
import CustomPropTypes from 'app/constants/custom_prop_types';
+import {getCurrentServerUrl} from 'app/init/credentials';
import {preventDoubleTap} from 'app/utils/tap';
export default class MarkdownTableImage extends React.PureComponent {
@@ -17,7 +18,7 @@ export default class MarkdownTableImage extends React.PureComponent {
children: PropTypes.node.isRequired,
source: PropTypes.string.isRequired,
textStyle: CustomPropTypes.Style.isRequired,
- serverURL: PropTypes.string.isRequired,
+ serverURL: PropTypes.string,
theme: PropTypes.object.isRequired,
};
@@ -40,11 +41,16 @@ export default class MarkdownTableImage extends React.PureComponent {
actions.goToScreen(screen, title, passProps);
});
- getImageSource = () => {
+ getImageSource = async () => {
let source = this.props.source;
+ let serverUrl = this.props.serverURL;
+
+ if (!serverUrl) {
+ serverUrl = await getCurrentServerUrl();
+ }
if (source.startsWith('/')) {
- source = `${this.props.serverURL}/${source}`;
+ source = serverUrl + source;
}
return source;
diff --git a/app/components/sidebars/main/teams_list/index.js b/app/components/sidebars/main/teams_list/index.js
index b6c187e213..f72990601e 100644
--- a/app/components/sidebars/main/teams_list/index.js
+++ b/app/components/sidebars/main/teams_list/index.js
@@ -4,14 +4,12 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
-import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
import {getCurrentTeamId, getMySortedTeamIds, getJoinableTeamIds} from 'mattermost-redux/selectors/entities/teams';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {showModal} from 'app/actions/navigation';
import {handleTeamChange} from 'app/actions/views/select_team';
import {getCurrentLocale} from 'app/selectors/i18n';
-import {removeProtocol} from 'app/utils/url';
import TeamsList from './teams_list';
@@ -20,7 +18,6 @@ function mapStateToProps(state) {
return {
currentTeamId: getCurrentTeamId(state),
- currentUrl: removeProtocol(getCurrentUrl(state)),
hasOtherJoinableTeams: getJoinableTeamIds(state).length > 0,
teamIds: getMySortedTeamIds(state, locale),
theme: getTheme(state),
diff --git a/app/components/sidebars/main/teams_list/teams_list.js b/app/components/sidebars/main/teams_list/teams_list.js
index d8f7b28578..afc9272271 100644
--- a/app/components/sidebars/main/teams_list/teams_list.js
+++ b/app/components/sidebars/main/teams_list/teams_list.js
@@ -17,8 +17,10 @@ import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import FormattedText from 'app/components/formatted_text';
import {DeviceTypes, ListTypes, ViewTypes} from 'app/constants';
+import {getCurrentServerUrl} from 'app/init/credentials';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
+import {removeProtocol} from 'app/utils/url';
import tracker from 'app/utils/time_tracker';
import telemetry from 'app/telemetry';
@@ -38,7 +40,6 @@ export default class TeamsList extends PureComponent {
}).isRequired,
closeChannelDrawer: PropTypes.func.isRequired,
currentTeamId: PropTypes.string.isRequired,
- currentUrl: PropTypes.string.isRequired,
hasOtherJoinableTeams: PropTypes.bool,
teamIds: PropTypes.array.isRequired,
theme: PropTypes.object.isRequired,
@@ -51,9 +52,17 @@ export default class TeamsList extends PureComponent {
constructor(props) {
super(props);
+ this.state = {
+ serverUrl: '',
+ };
+
MaterialIcon.getImageSource('close', 20, props.theme.sidebarHeaderTextColor).then((source) => {
this.closeButton = source;
});
+
+ getCurrentServerUrl().then((url) => {
+ this.setState({serverUrl: removeProtocol(url)});
+ });
}
selectTeam = (teamId) => {
@@ -75,13 +84,14 @@ export default class TeamsList extends PureComponent {
});
};
- goToSelectTeam = preventDoubleTap(() => {
+ goToSelectTeam = preventDoubleTap(async () => {
const {intl} = this.context;
- const {currentUrl, theme, actions} = this.props;
+ const {theme, actions} = this.props;
+ const {serverUrl} = this.state;
const screen = 'SelectTeam';
const title = intl.formatMessage({id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'});
const passProps = {
- currentUrl,
+ currentUrl: serverUrl,
theme,
};
const options = {
@@ -117,6 +127,7 @@ export default class TeamsList extends PureComponent {
renderItem = ({item}) => {
return (
@@ -155,6 +166,7 @@ export default class TeamsList extends PureComponent {
{moreAction}
{
Navigation.events().registerComponentDidAppearListener(({componentId}) => {
EphemeralStore.addNavigationComponentId(componentId);
});
+
+ Navigation.events().registerComponentDidDisappearListener(({componentId}) => {
+ EphemeralStore.removeNavigationComponentId(componentId);
+ });
});
diff --git a/app/screens/index.js b/app/screens/index.js
index 3228745d07..a4f5b62a5f 100644
--- a/app/screens/index.js
+++ b/app/screens/index.js
@@ -66,7 +66,7 @@ export function registerScreens(store, Provider) {
Navigation.registerComponent('SelectTeam', () => wrapper(require('app/screens/select_team').default), () => require('app/screens/select_team').default);
Navigation.registerComponent('SelectTimezone', () => wrapper(require('app/screens/settings/timezone/select_timezone').default), () => require('app/screens/settings/timezone/select_timezone').default);
Navigation.registerComponent('Settings', () => wrapper(require('app/screens/settings/general').default), () => require('app/screens/settings/general').default);
- Navigation.registerComponent('SidebarSettings', () => wrapper(require('app/screens//settings/sidebar').default), () => require('app/screens/settings/sidebar').default);
+ Navigation.registerComponent('SidebarSettings', () => wrapper(require('app/screens/settings/sidebar').default), () => require('app/screens/settings/sidebar').default);
Navigation.registerComponent('SSO', () => wrapper(require('app/screens/sso').default), () => require('app/screens/sso').default);
Navigation.registerComponent('Table', () => wrapper(require('app/screens/table').default), () => require('app/screens/table').default);
Navigation.registerComponent('TableImage', () => wrapper(require('app/screens/table_image').default), () => require('app/screens/table_image').default);
diff --git a/app/screens/permalink/permalink.js b/app/screens/permalink/permalink.js
index 3d59012b0b..2f76d25009 100644
--- a/app/screens/permalink/permalink.js
+++ b/app/screens/permalink/permalink.js
@@ -267,41 +267,43 @@ export default class Permalink extends PureComponent {
const {formatMessage} = intl;
let focusChannelId = channelId;
- const post = await actions.getPostThread(focusedPostId, false);
- if (post.error && (!postIds || !postIds.length)) {
- if (this.mounted && isPermalink && post.error.message.toLowerCase() !== 'network request failed') {
- this.setState({
- error: formatMessage({
- id: 'permalink.error.access',
- defaultMessage: 'Permalink belongs to a deleted message or to a channel to which you do not have access.',
- }),
- title: formatMessage({
- id: 'mobile.search.no_results',
- defaultMessage: 'No Results Found',
- }),
- });
- } else if (this.mounted) {
- this.setState({error: post.error.message, retry: true});
+ if (focusedPostId) {
+ const post = await actions.getPostThread(focusedPostId, false);
+ if (post.error && (!postIds || !postIds.length)) {
+ if (this.mounted && isPermalink && post.error.message.toLowerCase() !== 'network request failed') {
+ this.setState({
+ error: formatMessage({
+ id: 'permalink.error.access',
+ defaultMessage: 'Permalink belongs to a deleted message or to a channel to which you do not have access.',
+ }),
+ title: formatMessage({
+ id: 'mobile.search.no_results',
+ defaultMessage: 'No Results Found',
+ }),
+ });
+ } else if (this.mounted) {
+ this.setState({error: post.error.message, retry: true});
+ }
+
+ return;
}
- return;
- }
-
- if (!channelId) {
- const focusedPost = post.data && post.data.posts ? post.data.posts[focusedPostId] : null;
- focusChannelId = focusedPost ? focusedPost.channel_id : '';
- if (focusChannelId) {
- const {data: channel} = await actions.getChannel(focusChannelId);
- if (!this.props.myMembers[focusChannelId] && channel && channel.type === General.OPEN_CHANNEL) {
- await actions.joinChannel(currentUserId, channel.team_id, channel.id);
+ if (!channelId) {
+ const focusedPost = post.data && post.data.posts ? post.data.posts[focusedPostId] : null;
+ focusChannelId = focusedPost ? focusedPost.channel_id : '';
+ if (focusChannelId) {
+ const {data: channel} = await actions.getChannel(focusChannelId);
+ if (!this.props.myMembers[focusChannelId] && channel && channel.type === General.OPEN_CHANNEL) {
+ await actions.joinChannel(currentUserId, channel.team_id, channel.id);
+ }
}
}
- }
- await actions.getPostsAround(focusChannelId, focusedPostId, 10);
+ await actions.getPostsAround(focusChannelId, focusedPostId, 10);
- if (this.mounted) {
- this.setState({loading: false});
+ if (this.mounted) {
+ this.setState({loading: false});
+ }
}
};
diff --git a/app/screens/settings/display_settings/display_settings.js b/app/screens/settings/display_settings/display_settings.js
index 363ecc24f7..c134f79976 100644
--- a/app/screens/settings/display_settings/display_settings.js
+++ b/app/screens/settings/display_settings/display_settings.js
@@ -3,6 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
+import {Navigation} from 'react-native-navigation';
import {intlShape} from 'react-intl';
import {
Platform,
@@ -19,6 +20,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
export default class DisplaySettings extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
+ applyTheme: PropTypes.func.isRequired,
goToScreen: PropTypes.func.isRequired,
}).isRequired,
componentId: PropTypes.string,
@@ -35,6 +37,15 @@ export default class DisplaySettings extends PureComponent {
showClockDisplaySettings: false,
};
+ componentDidMount() {
+ this.navigationEventListener = Navigation.events().bindComponent(this);
+ }
+
+ componentDidAppear() {
+ const {actions, componentId} = this.props;
+ actions.applyTheme(componentId);
+ }
+
closeClockDisplaySettings = () => {
this.setState({showClockDisplaySettings: false});
};
@@ -44,7 +55,7 @@ export default class DisplaySettings extends PureComponent {
const {intl} = this.context;
if (Platform.OS === 'ios') {
- const screen = 'ClockDisplay';
+ const screen = 'ClockDisplaySettings';
const title = intl.formatMessage({id: 'user.settings.display.clockDisplay', defaultMessage: 'Clock Display'});
actions.goToScreen(screen, title);
return;
diff --git a/app/screens/settings/display_settings/display_settings.test.js b/app/screens/settings/display_settings/display_settings.test.js
index 4d91bf1c82..8f485108dc 100644
--- a/app/screens/settings/display_settings/display_settings.test.js
+++ b/app/screens/settings/display_settings/display_settings.test.js
@@ -16,6 +16,7 @@ jest.mock('react-intl');
describe('DisplaySettings', () => {
const baseProps = {
actions: {
+ applyTheme: jest.fn(),
goToScreen: jest.fn(),
},
theme: Preferences.THEMES.default,
diff --git a/app/screens/settings/display_settings/index.js b/app/screens/settings/display_settings/index.js
index 12d4b321fe..ab325072aa 100644
--- a/app/screens/settings/display_settings/index.js
+++ b/app/screens/settings/display_settings/index.js
@@ -7,7 +7,7 @@ import {connect} from 'react-redux';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
-import {goToScreen} from 'app/actions/navigation';
+import {applyTheme, goToScreen} from 'app/actions/navigation';
import {getAllowedThemes} from 'app/selectors/theme';
import {isThemeSwitchingEnabled} from 'app/utils/theme';
@@ -28,6 +28,7 @@ function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
goToScreen,
+ applyTheme,
}, dispatch),
};
}
diff --git a/app/screens/settings/general/index.js b/app/screens/settings/general/index.js
index 09cc293abf..146d2b866c 100644
--- a/app/screens/settings/general/index.js
+++ b/app/screens/settings/general/index.js
@@ -9,7 +9,7 @@ import {getCurrentUrl, getConfig} from 'mattermost-redux/selectors/entities/gene
import {getJoinableTeams} from 'mattermost-redux/selectors/entities/teams';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
-import {goToScreen, dismissModal} from 'app/actions/navigation';
+import {applyTheme, goToScreen, dismissModal} from 'app/actions/navigation';
import {purgeOfflineStore} from 'app/actions/views/root';
import {removeProtocol} from 'app/utils/url';
@@ -32,6 +32,7 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
+ applyTheme,
clearErrors,
purgeOfflineStore,
goToScreen,
diff --git a/app/screens/settings/general/settings.js b/app/screens/settings/general/settings.js
index 94cbdba279..65f18e67b3 100644
--- a/app/screens/settings/general/settings.js
+++ b/app/screens/settings/general/settings.js
@@ -25,6 +25,7 @@ import LocalConfig from 'assets/config';
class Settings extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
+ applyTheme: PropTypes.func.isRequired,
clearErrors: PropTypes.func.isRequired,
purgeOfflineStore: PropTypes.func.isRequired,
goToScreen: PropTypes.func.isRequired,
@@ -50,6 +51,11 @@ class Settings extends PureComponent {
this.navigationEventListener = Navigation.events().bindComponent(this);
}
+ componentDidAppear() {
+ const {actions, componentId} = this.props;
+ actions.applyTheme(componentId);
+ }
+
navigationButtonPressed({buttonId}) {
if (buttonId === 'close-settings') {
this.props.actions.dismissModal();
diff --git a/app/screens/settings/theme/index.js b/app/screens/settings/theme/index.js
index 13b93c3bf2..cb353f8a02 100644
--- a/app/screens/settings/theme/index.js
+++ b/app/screens/settings/theme/index.js
@@ -11,7 +11,6 @@ import {savePreferences} from 'mattermost-redux/actions/preferences';
import {getAllowedThemes, getCustomTheme} from 'app/selectors/theme';
import {isLandscape, isTablet} from 'app/selectors/device';
-import {applyTheme} from 'app/actions/navigation';
import Theme from './theme';
@@ -28,7 +27,6 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators({
savePreferences,
- applyTheme,
}, dispatch),
});
diff --git a/app/screens/settings/theme/theme.js b/app/screens/settings/theme/theme.js
index 364cac0661..1521323458 100644
--- a/app/screens/settings/theme/theme.js
+++ b/app/screens/settings/theme/theme.js
@@ -26,7 +26,6 @@ export default class Theme extends React.PureComponent {
static propTypes = {
actions: PropTypes.shape({
savePreferences: PropTypes.func.isRequired,
- applyTheme: PropTypes.func.isRequired,
}).isRequired,
componentId: PropTypes.string,
allowedThemes: PropTypes.arrayOf(PropTypes.object),
@@ -66,7 +65,7 @@ export default class Theme extends React.PureComponent {
userId,
teamId,
allowedThemes,
- actions: {savePreferences, applyTheme},
+ actions: {savePreferences},
} = this.props;
const {customTheme} = this.state;
const selectedTheme = allowedThemes.concat(customTheme).find((theme) => theme.key === key);
@@ -77,8 +76,7 @@ export default class Theme extends React.PureComponent {
name: teamId,
value: JSON.stringify(selectedTheme),
}]);
- applyTheme();
- }
+ };
renderAllowedThemeTiles = () => {
const {theme, allowedThemes, isLandscape, isTablet} = this.props;
diff --git a/app/screens/settings/theme/theme.test.js b/app/screens/settings/theme/theme.test.js
index 0c33caa99a..38dc10bce5 100644
--- a/app/screens/settings/theme/theme.test.js
+++ b/app/screens/settings/theme/theme.test.js
@@ -3,29 +3,14 @@
import React from 'react';
import {shallow} from 'enzyme';
-import {Navigation} from 'react-native-navigation';
-
-import configureMockStore from 'redux-mock-store';
-import thunk from 'redux-thunk';
import Preferences from 'mattermost-redux/constants/preferences';
-import {applyTheme} from 'app/actions/navigation';
-import EphemeralStore from 'app/store/ephemeral_store';
-
import Theme from './theme';
import ThemeTile from './theme_tile';
jest.mock('react-intl');
-jest.mock('react-native-navigation', () => ({
- Navigation: {
- mergeOptions: jest.fn(),
- },
-}));
-
-const mockStore = configureMockStore([thunk]);
-
const allowedThemes = [
{
type: 'Mattermost',
@@ -141,7 +126,6 @@ describe('Theme', () => {
const baseProps = {
actions: {
savePreferences: jest.fn(),
- applyTheme: jest.fn(),
},
allowedThemes,
isLandscape: false,
@@ -159,57 +143,4 @@ describe('Theme', () => {
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper.find(ThemeTile)).toHaveLength(4);
});
-
- test('should apply new theme to all navigation components that have appeared', () => {
- const componentIds = ['component-1', 'component-2', 'component-3'];
- componentIds.forEach((componentId) => {
- EphemeralStore.addNavigationComponentId(componentId);
- });
-
- const store = mockStore({
- entities: {
- preferences: {
- myPreferences: {
- theme: {},
- },
- },
- teams: {
- currentTeamId: 'current-team-id',
- },
- general: {
- config: {},
- },
- },
- });
- baseProps.actions.applyTheme.mockImplementation(() => {
- store.dispatch(applyTheme());
- });
-
- const wrapper = shallow(
- ,
- );
-
- const theme = allowedThemes[0];
- wrapper.instance().setTheme(theme.key);
- expect(baseProps.actions.applyTheme).toHaveBeenCalledTimes(1);
-
- const options = {
- topBar: {
- backButton: {
- color: theme.sidebarHeaderTextColor,
- },
- background: {
- color: theme.sidebarHeaderBg,
- },
- title: {
- color: theme.sidebarHeaderTextColor,
- },
- },
- };
- expect(Navigation.mergeOptions.mock.calls).toEqual([
- [componentIds[2], options],
- [componentIds[1], options],
- [componentIds[0], options],
- ]);
- });
});
diff --git a/app/store/ephemeral_store.js b/app/store/ephemeral_store.js
index a0df7d125c..997abfbb0f 100644
--- a/app/store/ephemeral_store.js
+++ b/app/store/ephemeral_store.js
@@ -19,6 +19,13 @@ class EphemeralStore {
}
this.navigationComponentIdStack.unshift(componentId);
+ };
+
+ removeNavigationComponentId = (componentId) => {
+ const index = this.navigationComponentIdStack.indexOf(componentId);
+ if (index >= 0) {
+ this.navigationComponentIdStack.splice(index, 1);
+ }
}
}
diff --git a/app/utils/url.js b/app/utils/url.js
index e0feebc8fe..a30fd4d319 100644
--- a/app/utils/url.js
+++ b/app/utils/url.js
@@ -99,7 +99,7 @@ export function getScheme(url) {
}
export function matchDeepLink(url, serverURL, siteURL) {
- if (!url || !serverURL || !siteURL) {
+ if (!url || (!serverURL && !siteURL)) {
return null;
}
diff --git a/test/setup.js b/test/setup.js
index f60c19e476..0ce5659147 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -33,6 +33,11 @@ jest.mock('NativeModules', () => {
END: 'END',
},
},
+ RNKeychainManager: {
+ SECURITY_LEVEL_ANY: 'ANY',
+ SECURITY_LEVEL_SECURE_SOFTWARE: 'SOFTWARE',
+ SECURITY_LEVEL_SECURE_HARDWARE: 'HARDWARE',
+ },
};
});
jest.mock('NativeEventEmitter');