diff --git a/webapp/channels/src/components/root/index.ts b/webapp/channels/src/components/root/index.ts index 27acf5c303..18cb3cca70 100644 --- a/webapp/channels/src/components/root/index.ts +++ b/webapp/channels/src/components/root/index.ts @@ -45,6 +45,9 @@ function mapStateToProps(state: GlobalState) { telemetryEnabled: config.DiagnosticsEnabled === 'true', noAccounts: config.NoAccounts === 'true', telemetryId: config.DiagnosticId, + iosDownloadLink: config.IosAppDownloadLink, + androidDownloadLink: config.AndroidAppDownloadLink, + appDownloadLink: config.AppDownloadLink, permalinkRedirectTeamName: permalinkRedirectTeam ? permalinkRedirectTeam.name : '', showTermsOfService, plugins, diff --git a/webapp/channels/src/components/root/root.test.tsx b/webapp/channels/src/components/root/root.test.tsx index 594cec6a0e..4d4c5e5b08 100644 --- a/webapp/channels/src/components/root/root.test.tsx +++ b/webapp/channels/src/components/root/root.test.tsx @@ -294,4 +294,44 @@ describe('components/Root', () => { wrapper.unmount(); }); }); + + describe('showLandingPageIfNecessary', () => { + const landingProps = { + ...baseProps, + iosDownloadLink: 'http://iosapp.com', + androidDownloadLink: 'http://androidapp.com', + appDownloadLink: 'http://desktopapp.com', + ...{ + location: { + pathname: '/', + search: '', + }, + } as RouteComponentProps, + history: { + push: jest.fn(), + } as unknown as RouteComponentProps['history'], + }; + + test('should show for normal cases', () => { + const wrapper = shallow(); + (wrapper.instance() as any).onConfigLoaded(); + expect(landingProps.history.push).toHaveBeenCalledWith('/landing#/'); + wrapper.unmount(); + }); + + test('should not show for Desktop App login flow', () => { + const props = { + ...landingProps, + ...{ + location: { + pathname: '/login/desktop', + }, + } as RouteComponentProps, + }; + const wrapper = shallow(); + (wrapper.instance() as any).onConfigLoaded(); + expect(props.history.push).not.toHaveBeenCalled(); + wrapper.unmount(); + }); + }); }); diff --git a/webapp/channels/src/components/root/root.tsx b/webapp/channels/src/components/root/root.tsx index 6221459323..e27f300665 100644 --- a/webapp/channels/src/components/root/root.tsx +++ b/webapp/channels/src/components/root/root.tsx @@ -146,6 +146,9 @@ type Props = { theme: Theme; telemetryEnabled: boolean; telemetryId?: string; + iosDownloadLink?: string; + androidDownloadLink?: string; + appDownloadLink?: string; noAccounts: boolean; showTermsOfService: boolean; permalinkRedirectTeamName: string; @@ -292,30 +295,67 @@ export default class Root extends React.PureComponent { this.props.actions.migrateRecentEmojis(); store.dispatch(loadRecentlyUsedCustomEmojis()); - const iosDownloadLink = getConfig(store.getState()).IosAppDownloadLink; - const androidDownloadLink = getConfig(store.getState()).AndroidAppDownloadLink; - const desktopAppDownloadLink = getConfig(store.getState()).AppDownloadLink; - - const toResetPasswordScreen = this.props.location.pathname === '/reset_password_complete'; - - // redirect to the mobile landing page if the user hasn't seen it before - let landing; - if (UserAgent.isAndroidWeb()) { - landing = androidDownloadLink; - } else if (UserAgent.isIosWeb()) { - landing = iosDownloadLink; - } else { - landing = desktopAppDownloadLink; - } - - if (landing && !this.props.isCloud && !BrowserStore.hasSeenLandingPage() && !toResetPasswordScreen && !this.props.location.pathname.includes('/landing') && !window.location.hostname?.endsWith('.test.mattermost.com') && !UserAgent.isDesktopApp() && !UserAgent.isChromebook()) { - this.props.history.push('/landing#' + this.props.location.pathname + this.props.location.search); - BrowserStore.setLandingPageSeen(true); - } + this.showLandingPageIfNecessary(); Utils.applyTheme(this.props.theme); }; + private showLandingPageIfNecessary = () => { + // We have nothing to redirect to if we're already on Desktop App + // Chromebook has no Desktop App to switch to + if (UserAgent.isDesktopApp() || UserAgent.isChromebook()) { + return; + } + + // Nothing to link to if we've removed the Android App download link + if (UserAgent.isAndroidWeb() && !this.props.androidDownloadLink) { + return; + } + + // Nothing to link to if we've removed the iOS App download link + if (UserAgent.isIosWeb() && !this.props.iosDownloadLink) { + return; + } + + // Nothing to link to if we've removed the Desktop App download link + if (!this.props.appDownloadLink) { + return; + } + + // Only show the landing page once + if (BrowserStore.hasSeenLandingPage()) { + return; + } + + // We don't want to show when resetting the password + if (this.props.location.pathname === '/reset_password_complete') { + return; + } + + // We don't want to show when we're doing Desktop App external login + if (this.props.location.pathname === '/login/desktop') { + return; + } + + // Stop this infinitely redirecting + if (this.props.location.pathname.includes('/landing')) { + return; + } + + // Disabled to avoid breaking the CWS flow + if (this.props.isCloud) { + return; + } + + // Disable for Rainforest tests + if (window.location.hostname?.endsWith('.test.mattermost.com')) { + return; + } + + this.props.history.push('/landing#' + this.props.location.pathname + this.props.location.search); + BrowserStore.setLandingPageSeen(true); + }; + componentDidUpdate(prevProps: Props) { if (!deepEqual(prevProps.theme, this.props.theme)) { Utils.applyTheme(this.props.theme);