diff --git a/app/actions/app/global.ts b/app/actions/app/global.ts index d6d8f921b8..8e05287bd3 100644 --- a/app/actions/app/global.ts +++ b/app/actions/app/global.ts @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {logError} from '@app/utils/log'; import {GLOBAL_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; @@ -28,14 +29,15 @@ export const storeMultiServerTutorial = async (prepareRecordsOnly = false) => { } }; -export const storeOnboardingViewedValue = async (prepareRecordsOnly = false) => { +export const storeOnboardingViewedValue = async (value = true) => { try { const {operator} = DatabaseManager.getAppDatabaseAndOperator(); return operator.handleGlobal({ - globals: [{id: GLOBAL_IDENTIFIERS.ONBOARDING, value: 'true'}], - prepareRecordsOnly, + globals: [{id: GLOBAL_IDENTIFIERS.ONBOARDING, value}], + prepareRecordsOnly: false, }); } catch (error) { + logError('storeOnboardingViewedValue', error); return {error}; } }; diff --git a/app/init/launch.ts b/app/init/launch.ts index 6892135fc1..a2df188d4a 100644 --- a/app/init/launch.ts +++ b/app/init/launch.ts @@ -10,7 +10,7 @@ import LocalConfig from '@assets/config.json'; import {Screens, DeepLink, Events, Launch, PushNotification} from '@constants'; import DatabaseManager from '@database/manager'; import {getActiveServerUrl, getServerCredentials, removeServerCredentials} from '@init/credentials'; -import {onboadingViewedValue} from '@queries/app/global'; +import {getOnboardingViewed} from '@queries/app/global'; import {getThemeForCurrentTeam} from '@queries/servers/preference'; import {getCurrentUserId} from '@queries/servers/system'; import {queryMyTeams} from '@queries/servers/team'; @@ -68,7 +68,6 @@ const launchAppFromNotification = async (notification: NotificationWithData) => * @returns a redirection to a screen, either onboarding, add_server, login or home depending on the scenario */ const launchApp = async (props: LaunchProps, resetNavigation = true) => { - const onboardingViewed = LocalConfig.ShowOnboarding ? await onboadingViewedValue() : false; let serverUrl: string | undefined; switch (props?.launchType) { case Launch.DeepLink: @@ -107,10 +106,6 @@ const launchApp = async (props: LaunchProps, resetNavigation = true) => { hasCurrentUser = Boolean(currentUserId); } - if (LocalConfig.ShowOnboarding && !onboardingViewed) { - return resetToOnboarding({...props, goToLoginServerUrl: serverUrl}); - } - let launchType = props.launchType; if (!hasCurrentUser) { // migrating from v1 @@ -140,7 +135,9 @@ const launchApp = async (props: LaunchProps, resetNavigation = true) => { } } - if (!LocalConfig.ShowOnboarding || onboardingViewed) { + const onboardingViewed = LocalConfig.ShowOnboarding ? await getOnboardingViewed() : false; + + if (onboardingViewed) { return launchToServer(props, resetNavigation); } return resetToOnboarding(props); diff --git a/app/managers/session_manager.ts b/app/managers/session_manager.ts index a9779900e1..0715785393 100644 --- a/app/managers/session_manager.ts +++ b/app/managers/session_manager.ts @@ -5,6 +5,7 @@ import CookieManager, {Cookie} from '@react-native-cookies/cookies'; import {AppState, AppStateStatus, DeviceEventEmitter, Platform} from 'react-native'; import FastImage from 'react-native-fast-image'; +import {storeOnboardingViewedValue} from '@actions/app/global'; import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session'; import {Events, Launch} from '@constants'; import DatabaseManager from '@database/manager'; @@ -17,7 +18,7 @@ import NetworkManager from '@managers/network_manager'; import WebsocketManager from '@managers/websocket_manager'; import {queryServerName} from '@queries/app/servers'; import {getCurrentUser} from '@queries/servers/user'; -import {getThemeFromState, resetToOnboarding} from '@screens/navigation'; +import {getThemeFromState} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {deleteFileCache, deleteFileCacheByDir} from '@utils/file'; import {addNewServer} from '@utils/server'; @@ -167,15 +168,19 @@ class SessionManager { if (activeServerUrl === serverUrl) { let displayName = ''; - const launchType: LaunchType = Launch.Normal; + let launchType: LaunchType = Launch.AddServer; if (!Object.keys(DatabaseManager.serverDatabases).length) { EphemeralStore.theme = undefined; + launchType = Launch.Normal; + + // set the onboardingViewed value to false so the launch will show the onboarding screen after all servers were removed + storeOnboardingViewedValue(false); + if (activeServerDisplayName) { displayName = activeServerDisplayName; } } - - resetToOnboarding({launchType, serverUrl, displayName}); + relaunchApp({launchType, serverUrl, displayName}, true); } }; diff --git a/app/queries/app/global.ts b/app/queries/app/global.ts index bc37842faf..94d898479f 100644 --- a/app/queries/app/global.ts +++ b/app/queries/app/global.ts @@ -28,14 +28,11 @@ export const observeMultiServerTutorial = (appDatabase: Database) => { ); }; -export const onboadingViewedValue = async (): Promise => { - const appDatabase = DatabaseManager.appDatabase?.database; - if (!appDatabase) { - return false; - } +export const getOnboardingViewed = async (): Promise => { try { - const onboardingVal = await appDatabase.get(GLOBAL).find(GLOBAL_IDENTIFIERS.ONBOARDING); - return Boolean(onboardingVal?.value) || false; + const {database} = DatabaseManager.getAppDatabaseAndOperator(); + const onboardingVal = await database.get(GLOBAL).find(GLOBAL_IDENTIFIERS.ONBOARDING); + return onboardingVal?.value ?? false; } catch { return false; } diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index 0f5e2a14f0..b985754207 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -281,7 +281,7 @@ export function resetToSelectServer(passProps: LaunchProps) { }); } -export function resetToOnboarding(passProps: LaunchProps & {goToLoginServerUrl?: string}) { +export function resetToOnboarding(passProps: LaunchProps) { const theme = getDefaultThemeByAppearance(); const isDark = tinyColor(theme.sidebarBg).isDark(); StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content'); diff --git a/app/screens/onboarding/illustrations/calls_svg.tsx b/app/screens/onboarding/illustrations/calls.tsx similarity index 99% rename from app/screens/onboarding/illustrations/calls_svg.tsx rename to app/screens/onboarding/illustrations/calls.tsx index fa1a6f6d1f..31813a95e6 100644 --- a/app/screens/onboarding/illustrations/calls_svg.tsx +++ b/app/screens/onboarding/illustrations/calls.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import * as React from 'react'; +import React from 'react'; import {StyleProp, ViewStyle} from 'react-native'; import Svg, {Ellipse, Path, Mask, G} from 'react-native-svg'; diff --git a/app/screens/onboarding/illustrations/chat_svg.tsx b/app/screens/onboarding/illustrations/chat.tsx similarity index 99% rename from app/screens/onboarding/illustrations/chat_svg.tsx rename to app/screens/onboarding/illustrations/chat.tsx index 155174cc17..2295b8981d 100644 --- a/app/screens/onboarding/illustrations/chat_svg.tsx +++ b/app/screens/onboarding/illustrations/chat.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import * as React from 'react'; +import React from 'react'; import {StyleProp, ViewStyle} from 'react-native'; import Svg, { G, diff --git a/app/screens/onboarding/illustrations/integrations_svg.tsx b/app/screens/onboarding/illustrations/integrations.tsx similarity index 99% rename from app/screens/onboarding/illustrations/integrations_svg.tsx rename to app/screens/onboarding/illustrations/integrations.tsx index 118761a02c..641150b532 100644 --- a/app/screens/onboarding/illustrations/integrations_svg.tsx +++ b/app/screens/onboarding/illustrations/integrations.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import * as React from 'react'; +import React from 'react'; import {StyleProp, ViewStyle} from 'react-native'; import Svg, { Rect, diff --git a/app/screens/onboarding/illustrations/team_communication_svg.tsx b/app/screens/onboarding/illustrations/team_communication.tsx similarity index 99% rename from app/screens/onboarding/illustrations/team_communication_svg.tsx rename to app/screens/onboarding/illustrations/team_communication.tsx index d707ccea0f..ffd2545681 100644 --- a/app/screens/onboarding/illustrations/team_communication_svg.tsx +++ b/app/screens/onboarding/illustrations/team_communication.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import * as React from 'react'; +import React from 'react'; import {StyleProp, ViewStyle} from 'react-native'; import Svg, {Ellipse, Path, Mask, G, Defs, ClipPath} from 'react-native-svg'; diff --git a/app/screens/onboarding/index.tsx b/app/screens/onboarding/index.tsx index 89ddf2f349..d89e445349 100644 --- a/app/screens/onboarding/index.tsx +++ b/app/screens/onboarding/index.tsx @@ -6,12 +6,10 @@ import {View, ListRenderItemInfo, useWindowDimensions, SafeAreaView, ScrollView, import Animated, {Easing, useAnimatedRef, useAnimatedScrollHandler, useDerivedValue, useSharedValue} from 'react-native-reanimated'; import {storeOnboardingViewedValue} from '@actions/app/global'; -import {fetchConfigAndLicense} from '@actions/remote/systems'; import {Screens} from '@app/constants'; -import {loginOptions} from '@app/utils/server'; import Background from '@screens/background'; import {goToScreen, loginAnimationOptions} from '@screens/navigation'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {makeStyleSheetFromTheme} from '@utils/theme'; import FooterButtons from './footer_buttons'; import Paginator from './paginator'; @@ -22,14 +20,27 @@ import type {LaunchProps} from '@typings/launch'; interface OnboardingProps extends LaunchProps { theme: Theme; - goToLoginServerUrl: string; } const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView); +const getStyleSheet = makeStyleSheetFromTheme(() => ({ + onBoardingContainer: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + verticalAlign: 'top', + }, + scrollContainer: { + flex: 1, + alignItems: 'center', + height: '100%', + justifyContent: 'center', + }, +})); + const Onboarding = ({ theme, - goToLoginServerUrl, }: OnboardingProps) => { const {width} = useWindowDimensions(); const styles = getStyleSheet(theme); @@ -70,67 +81,12 @@ const Onboarding = ({ } }, [currentIndex.value, slidesRef.current, moveToSlide]); - const initLogin = async () => { - const data = await fetchConfigAndLicense(goToLoginServerUrl, true); - if (data.error) { - return; - } - - displayLogin(data.config!, data.license!); - }; - - const displayLogin = (config: ClientConfig, license: ClientLicense) => { - const {enabledSSOs, hasLoginForm, numberSSOs, ssoOptions} = loginOptions(config, license); - const displayName = 'displayName'; - const passProps = { - config, - hasLoginForm, - license, - serverDisplayName: displayName, - serverUrl: goToLoginServerUrl, - ssoOptions, - theme, - }; - - const redirectSSO = !hasLoginForm && numberSSOs === 1; - const screen = redirectSSO ? Screens.SSO : Screens.LOGIN; - if (redirectSSO) { - // @ts-expect-error ssoType not in definition - passProps.ssoType = enabledSSOs[0]; - } - - goToScreen(screen, '', passProps, loginAnimationOptions()); - }; - const signInHandler = useCallback(() => { - const topBar = { - visible: true, - drawBehind: true, - translucid: true, - noBorder: true, - elevation: 0, - background: { - color: 'transparent', - }, - backButton: { - color: changeOpacity(theme.centerChannelColor, 0.56), - }, - scrollEdgeAppearance: { - active: true, - noBorder: true, - translucid: true, - }, - }; - // mark the onboarding as already viewed storeOnboardingViewedValue(); - if (goToLoginServerUrl) { - initLogin(); - return; - } - goToScreen(Screens.SERVER, '', {theme}, {topBar}); - }, [goToLoginServerUrl]); + goToScreen(Screens.SERVER, '', {theme}, loginAnimationOptions()); + }, []); const renderSlide = useCallback(({item, index}: ListRenderItemInfo) => { return ( @@ -191,19 +147,4 @@ const Onboarding = ({ ); }; -const getStyleSheet = makeStyleSheetFromTheme(() => ({ - onBoardingContainer: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - verticalAlign: 'top', - }, - scrollContainer: { - flex: 1, - alignItems: 'center', - height: '100%', - justifyContent: 'center', - }, -})); - export default Onboarding; diff --git a/app/screens/onboarding/slides_data.tsx b/app/screens/onboarding/slides_data.tsx index a02002dfc9..a0f75c3e18 100644 --- a/app/screens/onboarding/slides_data.tsx +++ b/app/screens/onboarding/slides_data.tsx @@ -5,10 +5,10 @@ import React from 'react'; import {useIntl} from 'react-intl'; import {StyleSheet} from 'react-native'; -import CallsSvg from './illustrations/calls_svg'; -import ChatSvg from './illustrations/chat_svg'; -import IntegrationsSvg from './illustrations/integrations_svg'; -import TeamCommunicationSvg from './illustrations/team_communication_svg'; +import CallsSvg from './illustrations/calls'; +import ChatSvg from './illustrations/chat'; +import IntegrationsSvg from './illustrations/integrations'; +import TeamCommunicationSvg from './illustrations/team_communication'; export type OnboardingItem = { id: string;