From fb6a65bd462ace1fa26fbfd8692bf33c33c5bedc Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Fri, 10 Mar 2023 09:57:30 +0800 Subject: [PATCH] refactor(console): extract the onboarding app from the admin console (#3340) --- packages/console/src/App.tsx | 6 +- .../cloud/pages/Onboarding/index.module.scss | 6 -- .../src/cloud/pages/Onboarding/index.tsx | 49 ------------ .../src/cloud/scss/cloud-page-size.scss | 1 - packages/console/src/cloud/types.ts | 76 ------------------ packages/console/src/cloud/utils.ts | 4 - .../AppContent/components/Topbar/index.tsx | 15 ++-- .../src/containers/AppContent/index.tsx | 23 +----- .../containers/TenantAppContainer/index.tsx | 30 +++++++ .../console/src/contexts/TenantsProvider.tsx | 12 ++- .../console/src/onboarding/App.module.scss | 6 ++ packages/console/src/onboarding/App.tsx | 70 +++++++++++++++++ .../components/ActionBar/index.module.scss | 0 .../components/ActionBar/index.tsx | 0 .../components/Broadcast/index.module.scss | 0 .../components/Broadcast/index.tsx | 2 +- .../components/CardSelector/CardSelector.tsx | 0 .../MultiCardSelector/index.module.scss | 0 .../CardSelector/MultiCardSelector/index.tsx | 0 .../components/CardSelector/index.tsx | 0 .../components/CardSelector/types.ts | 0 .../EarlyBirdGift/GiftModal/index.module.scss | 0 .../EarlyBirdGift/GiftModal/index.tsx | 0 .../components/EarlyBirdGift/index.tsx | 0 .../components/ProgressBar/index.module.scss | 0 .../components/ProgressBar/index.tsx | 0 .../components/Reservation/index.module.scss | 0 .../components/Reservation/index.tsx | 2 +- .../{cloud => onboarding}/constants/index.ts | 0 .../containers/AppContent/index.module.scss | 13 ++++ .../containers/AppContent/index.tsx | 16 ++++ .../hooks/use-user-onboarding-data.ts | 0 .../pages/About/index.module.scss | 0 .../pages/About/index.tsx | 10 +-- .../pages/About/options.tsx | 2 +- .../pages/Congrats/index.module.scss | 0 .../pages/Congrats/index.tsx | 19 ++--- .../PlatformTabs/PlatformTab.module.scss | 0 .../components/PlatformTabs/PlatformTab.tsx | 0 .../components/PlatformTabs/index.module.scss | 0 .../components/PlatformTabs/index.tsx | 0 .../components/Preview/index.module.scss | 0 .../components/Preview/index.tsx | 0 .../pages/SignInExperience/index.module.scss | 0 .../pages/SignInExperience/index.tsx | 18 ++--- .../pages/SignInExperience/options.tsx | 4 +- .../pages/SignInExperience/utils.ts | 4 +- .../pages/Welcome/index.module.scss | 0 .../pages/Welcome/index.tsx | 12 +-- .../pages/Welcome/options.tsx | 2 +- .../scss/layout.module.scss | 3 +- packages/console/src/onboarding/types.ts | 78 +++++++++++++++++++ packages/console/src/onboarding/utils.ts | 7 ++ packages/console/src/pages/Main/index.tsx | 29 +------ .../src/pages/NotFound/index.module.scss | 5 ++ packages/console/src/pages/NotFound/index.tsx | 10 ++- .../src/tests/ui-cloud/smoke.test.ts | 60 ++++++++++++++ 57 files changed, 359 insertions(+), 235 deletions(-) delete mode 100644 packages/console/src/cloud/pages/Onboarding/index.module.scss delete mode 100644 packages/console/src/cloud/pages/Onboarding/index.tsx delete mode 100644 packages/console/src/cloud/scss/cloud-page-size.scss delete mode 100644 packages/console/src/cloud/utils.ts create mode 100644 packages/console/src/containers/TenantAppContainer/index.tsx create mode 100644 packages/console/src/onboarding/App.module.scss create mode 100644 packages/console/src/onboarding/App.tsx rename packages/console/src/{cloud => onboarding}/components/ActionBar/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/ActionBar/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/Broadcast/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/Broadcast/index.tsx (90%) rename packages/console/src/{cloud => onboarding}/components/CardSelector/CardSelector.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/CardSelector/MultiCardSelector/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/CardSelector/MultiCardSelector/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/CardSelector/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/CardSelector/types.ts (100%) rename packages/console/src/{cloud => onboarding}/components/EarlyBirdGift/GiftModal/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/EarlyBirdGift/GiftModal/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/EarlyBirdGift/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/ProgressBar/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/ProgressBar/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/components/Reservation/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/components/Reservation/index.tsx (96%) rename packages/console/src/{cloud => onboarding}/constants/index.ts (100%) create mode 100644 packages/console/src/onboarding/containers/AppContent/index.module.scss create mode 100644 packages/console/src/onboarding/containers/AppContent/index.tsx rename packages/console/src/{cloud => onboarding}/hooks/use-user-onboarding-data.ts (100%) rename packages/console/src/{cloud => onboarding}/pages/About/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/About/index.tsx (92%) rename packages/console/src/{cloud => onboarding}/pages/About/options.tsx (94%) rename packages/console/src/{cloud => onboarding}/pages/Congrats/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/Congrats/index.tsx (77%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/PlatformTabs/PlatformTab.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/PlatformTabs/PlatformTab.tsx (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/PlatformTabs/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/PlatformTabs/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/Preview/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/components/Preview/index.tsx (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/index.tsx (90%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/options.tsx (88%) rename packages/console/src/{cloud => onboarding}/pages/SignInExperience/utils.ts (94%) rename packages/console/src/{cloud => onboarding}/pages/Welcome/index.module.scss (100%) rename packages/console/src/{cloud => onboarding}/pages/Welcome/index.tsx (89%) rename packages/console/src/{cloud => onboarding}/pages/Welcome/options.tsx (90%) rename packages/console/src/{cloud => onboarding}/scss/layout.module.scss (81%) create mode 100644 packages/console/src/onboarding/types.ts create mode 100644 packages/console/src/onboarding/utils.ts diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index c5c600c34..530f0f00d 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -18,10 +18,10 @@ import initI18n from '@/i18n/init'; import { adminTenantEndpoint } from './consts'; import { isCloud } from './consts/cloud'; import ErrorBoundary from './containers/ErrorBoundary'; +import TenantAppContainer from './containers/TenantAppContainer'; import AppConfirmModalProvider from './contexts/AppConfirmModalProvider'; import AppEndpointsProvider from './contexts/AppEndpointsProvider'; import TenantsProvider, { TenantsContext } from './contexts/TenantsProvider'; -import Main from './pages/Main'; void initI18n(); @@ -39,6 +39,7 @@ const Content = () => { meApi.indicator ) ); + const scopes = [ UserScope.Email, UserScope.Identities, @@ -63,7 +64,7 @@ const Content = () => { {!isCloud || isSettle ? ( -
+ ) : ( @@ -81,4 +82,5 @@ const App = () => { ); }; + export default App; diff --git a/packages/console/src/cloud/pages/Onboarding/index.module.scss b/packages/console/src/cloud/pages/Onboarding/index.module.scss deleted file mode 100644 index f5dea9ff5..000000000 --- a/packages/console/src/cloud/pages/Onboarding/index.module.scss +++ /dev/null @@ -1,6 +0,0 @@ -.onBoarding { - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; -} diff --git a/packages/console/src/cloud/pages/Onboarding/index.tsx b/packages/console/src/cloud/pages/Onboarding/index.tsx deleted file mode 100644 index c30dbbb86..000000000 --- a/packages/console/src/cloud/pages/Onboarding/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Navigate, Route, Routes } from 'react-router-dom'; - -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import { OnboardingPage } from '@/cloud/types'; -import { getOnboardPagePathname } from '@/cloud/utils'; -import NotFound from '@/pages/NotFound'; - -import About from '../About'; -import Congrats from '../Congrats'; -import SignInExperience from '../SignInExperience'; -import Welcome from '../Welcome'; -import * as styles from './index.module.scss'; - -const welcomePathname = getOnboardPagePathname(OnboardingPage.Welcome); - -const Onboarding = () => { - const { - data: { questionnaire }, - isLoaded, - } = useUserOnboardingData(); - - if (!isLoaded) { - return null; - } - - return ( -
- - } /> - } /> - : } - /> - : } - /> - : } - /> - } /> - -
- ); -}; - -export default Onboarding; diff --git a/packages/console/src/cloud/scss/cloud-page-size.scss b/packages/console/src/cloud/scss/cloud-page-size.scss deleted file mode 100644 index e6d4574dc..000000000 --- a/packages/console/src/cloud/scss/cloud-page-size.scss +++ /dev/null @@ -1 +0,0 @@ -$questionnaire-content-width: 858px; diff --git a/packages/console/src/cloud/types.ts b/packages/console/src/cloud/types.ts index 5e68d5607..efcd295da 100644 --- a/packages/console/src/cloud/types.ts +++ b/packages/console/src/cloud/types.ts @@ -1,79 +1,3 @@ -import type { SignInIdentifier } from '@logto/schemas'; -import { z } from 'zod'; - export enum CloudRoute { Callback = 'callback', - Onboarding = 'onboarding', } - -export enum OnboardingPage { - Welcome = 'welcome', - AboutUser = 'about-user', - SignInExperience = 'sign-in-experience', - Congrats = 'congrats', -} - -export enum Project { - Personal = 'personal', - Company = 'company', -} - -export enum DeploymentType { - OpenSource = 'open-source', - Cloud = 'cloud', -} - -export enum Title { - Developer = 'developer', - TeamLead = 'team-lead', - Ceo = 'ceo', - Cto = 'cto', - Product = 'product', - Others = 'others', -} - -export enum CompanySize { - Scale1 = '1', - Scale2 = '1-49', - Scale3 = '50-199', - Scale4 = '200-999', - Scale5 = '1000+', -} - -export enum Reason { - Adoption = 'adoption', - Replacement = 'replacement', - Evaluation = 'evaluation', - Experimentation = 'experimentation', - Aesthetics = 'aesthetics', - Others = 'others', -} - -export const questionnaireGuard = z.object({ - project: z.nativeEnum(Project), - deploymentType: z.nativeEnum(DeploymentType), - titles: z.array(z.nativeEnum(Title)).optional(), - companyName: z.string().optional(), - companySize: z.nativeEnum(CompanySize).optional(), - reasons: z.array(z.nativeEnum(Reason)).optional(), -}); - -export type Questionnaire = z.infer; - -export const userOnboardingDataGuard = z.object({ - questionnaire: questionnaireGuard.optional(), - isOnboardingDone: z.boolean().optional(), -}); - -export type UserOnboardingData = z.infer; - -export enum Authentication { - Password = 'password', - VerificationCode = 'verificationCode', -} - -export type OnboardingSieConfig = { - color: string; - identifier: SignInIdentifier; - authentications: Authentication[]; -}; diff --git a/packages/console/src/cloud/utils.ts b/packages/console/src/cloud/utils.ts deleted file mode 100644 index 76af6f3de..000000000 --- a/packages/console/src/cloud/utils.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { OnboardingPage } from './types'; -import { CloudRoute } from './types'; - -export const getOnboardPagePathname = (page: OnboardingPage) => `/${CloudRoute.Onboarding}/${page}`; diff --git a/packages/console/src/containers/AppContent/components/Topbar/index.tsx b/packages/console/src/containers/AppContent/components/Topbar/index.tsx index bcc4ccd27..b29d2056a 100644 --- a/packages/console/src/containers/AppContent/components/Topbar/index.tsx +++ b/packages/console/src/containers/AppContent/components/Topbar/index.tsx @@ -2,19 +2,20 @@ import classNames from 'classnames'; import { useTranslation } from 'react-i18next'; import Logo from '@/assets/images/logo.svg'; -import EarlyBirdGift from '@/cloud/components/EarlyBirdGift'; import Spacer from '@/components/Spacer'; import { isCloud } from '@/consts/cloud'; +import EarlyBirdGift from '@/onboarding/components/EarlyBirdGift'; import GetStartedProgress from '@/pages/GetStarted/components/GetStartedProgress'; import UserInfo from '../UserInfo'; import * as styles from './index.module.scss'; type Props = { + isLogoOnly?: boolean; className?: string; }; -const Topbar = ({ className }: Props) => { +const Topbar = ({ isLogoOnly = false, className }: Props) => { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); return ( @@ -23,9 +24,13 @@ const Topbar = ({ className }: Props) => {
{t('title')}
- - {isCloud && } - + {!isLogoOnly && ( + <> + + {isCloud && } + + + )}
); }; diff --git a/packages/console/src/containers/AppContent/index.tsx b/packages/console/src/containers/AppContent/index.tsx index b6fe6a2cc..0799a70f8 100644 --- a/packages/console/src/containers/AppContent/index.tsx +++ b/packages/console/src/containers/AppContent/index.tsx @@ -4,10 +4,6 @@ import { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom'; -import Broadcast from '@/cloud/components/Broadcast'; -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import { OnboardingPage } from '@/cloud/types'; -import { getOnboardPagePathname } from '@/cloud/utils'; import AppError from '@/components/AppError'; import AppLoading from '@/components/AppLoading'; import SessionExpired from '@/components/SessionExpired'; @@ -15,6 +11,7 @@ import { isCloud } from '@/consts/cloud'; import useConfigs from '@/hooks/use-configs'; import useScroll from '@/hooks/use-scroll'; import useUserPreferences from '@/hooks/use-user-preferences'; +import Broadcast from '@/onboarding/components/Broadcast'; import { getPath } from '../ConsoleContent/Sidebar'; import { useSidebarMenuItems } from '../ConsoleContent/Sidebar/hook'; @@ -27,16 +24,8 @@ const AppContent = () => { const href = useHref('/callback'); const { isLoading: isPreferencesLoading } = useUserPreferences(); const { isLoading: isConfigsLoading } = useConfigs(); - const { - data: { isOnboardingDone }, - isLoading: isOnboardingDataLoading, - isLoaded: isOnboardingDataLoaded, - } = useUserOnboardingData(); - const isLoading = - isPreferencesLoading || isConfigsLoading || (isCloud && isOnboardingDataLoading); - - const isOnboarding = isCloud && isOnboardingDataLoaded && !isOnboardingDone; + const isLoading = isPreferencesLoading || isConfigsLoading; const location = useLocation(); const navigate = useNavigate(); @@ -54,13 +43,9 @@ const AppContent = () => { useEffect(() => { // Navigate to the first menu item after configs are loaded. if (!isLoading && location.pathname === '/') { - navigate( - isOnboarding - ? getOnboardPagePathname(OnboardingPage.Welcome) - : getPath(firstItem?.title ?? '') - ); + navigate(getPath(firstItem?.title ?? ''), { replace: true }); } - }, [firstItem?.title, isOnboardingDone, isLoading, isOnboarding, location.pathname, navigate]); + }, [firstItem?.title, isLoading, location.pathname, navigate]); if (error) { if (error instanceof LogtoClientError) { diff --git a/packages/console/src/containers/TenantAppContainer/index.tsx b/packages/console/src/containers/TenantAppContainer/index.tsx new file mode 100644 index 000000000..ecc0f9424 --- /dev/null +++ b/packages/console/src/containers/TenantAppContainer/index.tsx @@ -0,0 +1,30 @@ +import { useContext } from 'react'; + +import AppLoading from '@/components/AppLoading'; +import { isCloud } from '@/consts/cloud'; +import { AppEndpointsContext } from '@/contexts/AppEndpointsProvider'; +import OnboardingApp from '@/onboarding/App'; +import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; +import ConsoleApp from '@/pages/Main'; + +const TenantAppContainer = () => { + const { userEndpoint } = useContext(AppEndpointsContext); + const { + data: { isOnboardingDone }, + isLoaded, + } = useUserOnboardingData(); + + if (!userEndpoint || (isCloud && !isLoaded)) { + return ; + } + + const isOnboarding = isCloud && !isOnboardingDone; + + if (isOnboarding) { + return ; + } + + return ; +}; + +export default TenantAppContainer; diff --git a/packages/console/src/contexts/TenantsProvider.tsx b/packages/console/src/contexts/TenantsProvider.tsx index 0a7f005cb..d6ae73064 100644 --- a/packages/console/src/contexts/TenantsProvider.tsx +++ b/packages/console/src/contexts/TenantsProvider.tsx @@ -3,6 +3,7 @@ import { defaultManagementApi } from '@logto/schemas'; import { conditional, noop } from '@silverhand/essentials'; import type { ReactNode } from 'react'; import { useCallback, useMemo, createContext, useState } from 'react'; +import type { NavigateOptions } from 'react-router-dom'; import { isCloud } from '@/consts/cloud'; import { getUserTenantId } from '@/consts/tenants'; @@ -17,7 +18,7 @@ export type Tenants = { setTenants: (tenants: TenantInfo[]) => void; setIsSettle: (isSettle: boolean) => void; currentTenantId: string; - navigate: (tenantId: string) => void; + navigate: (tenantId: string, options?: NavigateOptions) => void; }; const { tenantId, indicator } = defaultManagementApi.resource; @@ -37,8 +38,13 @@ const TenantsProvider = ({ children }: Props) => { const [isSettle, setIsSettle] = useState(false); const [currentTenantId, setCurrentTenantId] = useState(getUserTenantId()); - const navigate = useCallback((tenantId: string) => { - window.history.pushState({}, '', '/' + tenantId); + const navigate = useCallback((tenantId: string, options?: NavigateOptions) => { + if (options?.replace) { + window.history.replaceState(options.state ?? {}, '', '/' + tenantId); + + return; + } + window.history.pushState(options?.state ?? {}, '', '/' + tenantId); setCurrentTenantId(tenantId); }, []); diff --git a/packages/console/src/onboarding/App.module.scss b/packages/console/src/onboarding/App.module.scss new file mode 100644 index 000000000..6c542f6d4 --- /dev/null +++ b/packages/console/src/onboarding/App.module.scss @@ -0,0 +1,6 @@ +@use '@/scss/underscore' as _; + +.app { + position: absolute; + inset: 0; +} diff --git a/packages/console/src/onboarding/App.tsx b/packages/console/src/onboarding/App.tsx new file mode 100644 index 000000000..c17144e42 --- /dev/null +++ b/packages/console/src/onboarding/App.tsx @@ -0,0 +1,70 @@ +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import { SWRConfig } from 'swr'; + +import AppLoading from '@/components/AppLoading'; +import Toast from '@/components/Toast'; +import { getBasename } from '@/consts'; +import AppBoundary from '@/containers/AppBoundary'; +import useSwrOptions from '@/hooks/use-swr-options'; +import NotFound from '@/pages/NotFound'; + +import * as styles from './App.module.scss'; +import AppContent from './containers/AppContent'; +import useUserOnboardingData from './hooks/use-user-onboarding-data'; +import About from './pages/About'; +import Congrats from './pages/Congrats'; +import SignInExperience from './pages/SignInExperience'; +import Welcome from './pages/Welcome'; +import { OnboardingPage, OnboardingRoute } from './types'; +import { getOnboardingPage } from './utils'; + +const welcomePathname = getOnboardingPage(OnboardingPage.Welcome); + +const App = () => { + const swrOptions = useSwrOptions(); + + const { + data: { questionnaire }, + isLoaded, + } = useUserOnboardingData(); + + if (!isLoaded) { + return ; + } + + return ( + +
+ + + + + } /> + }> + } /> + } /> + : } + /> + : + } + /> + : } + /> + + } /> + + + +
+
+ ); +}; + +export default App; diff --git a/packages/console/src/cloud/components/ActionBar/index.module.scss b/packages/console/src/onboarding/components/ActionBar/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/ActionBar/index.module.scss rename to packages/console/src/onboarding/components/ActionBar/index.module.scss diff --git a/packages/console/src/cloud/components/ActionBar/index.tsx b/packages/console/src/onboarding/components/ActionBar/index.tsx similarity index 100% rename from packages/console/src/cloud/components/ActionBar/index.tsx rename to packages/console/src/onboarding/components/ActionBar/index.tsx diff --git a/packages/console/src/cloud/components/Broadcast/index.module.scss b/packages/console/src/onboarding/components/Broadcast/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/Broadcast/index.module.scss rename to packages/console/src/onboarding/components/Broadcast/index.module.scss diff --git a/packages/console/src/cloud/components/Broadcast/index.tsx b/packages/console/src/onboarding/components/Broadcast/index.tsx similarity index 90% rename from packages/console/src/cloud/components/Broadcast/index.tsx rename to packages/console/src/onboarding/components/Broadcast/index.tsx index aad3c2288..38bfda82e 100644 --- a/packages/console/src/cloud/components/Broadcast/index.tsx +++ b/packages/console/src/onboarding/components/Broadcast/index.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; -import { logtoBlogLink } from '@/cloud/constants'; import TextLink from '@/components/TextLink'; +import { logtoBlogLink } from '@/onboarding/constants'; import * as styles from './index.module.scss'; diff --git a/packages/console/src/cloud/components/CardSelector/CardSelector.tsx b/packages/console/src/onboarding/components/CardSelector/CardSelector.tsx similarity index 100% rename from packages/console/src/cloud/components/CardSelector/CardSelector.tsx rename to packages/console/src/onboarding/components/CardSelector/CardSelector.tsx diff --git a/packages/console/src/cloud/components/CardSelector/MultiCardSelector/index.module.scss b/packages/console/src/onboarding/components/CardSelector/MultiCardSelector/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/CardSelector/MultiCardSelector/index.module.scss rename to packages/console/src/onboarding/components/CardSelector/MultiCardSelector/index.module.scss diff --git a/packages/console/src/cloud/components/CardSelector/MultiCardSelector/index.tsx b/packages/console/src/onboarding/components/CardSelector/MultiCardSelector/index.tsx similarity index 100% rename from packages/console/src/cloud/components/CardSelector/MultiCardSelector/index.tsx rename to packages/console/src/onboarding/components/CardSelector/MultiCardSelector/index.tsx diff --git a/packages/console/src/cloud/components/CardSelector/index.tsx b/packages/console/src/onboarding/components/CardSelector/index.tsx similarity index 100% rename from packages/console/src/cloud/components/CardSelector/index.tsx rename to packages/console/src/onboarding/components/CardSelector/index.tsx diff --git a/packages/console/src/cloud/components/CardSelector/types.ts b/packages/console/src/onboarding/components/CardSelector/types.ts similarity index 100% rename from packages/console/src/cloud/components/CardSelector/types.ts rename to packages/console/src/onboarding/components/CardSelector/types.ts diff --git a/packages/console/src/cloud/components/EarlyBirdGift/GiftModal/index.module.scss b/packages/console/src/onboarding/components/EarlyBirdGift/GiftModal/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/EarlyBirdGift/GiftModal/index.module.scss rename to packages/console/src/onboarding/components/EarlyBirdGift/GiftModal/index.module.scss diff --git a/packages/console/src/cloud/components/EarlyBirdGift/GiftModal/index.tsx b/packages/console/src/onboarding/components/EarlyBirdGift/GiftModal/index.tsx similarity index 100% rename from packages/console/src/cloud/components/EarlyBirdGift/GiftModal/index.tsx rename to packages/console/src/onboarding/components/EarlyBirdGift/GiftModal/index.tsx diff --git a/packages/console/src/cloud/components/EarlyBirdGift/index.tsx b/packages/console/src/onboarding/components/EarlyBirdGift/index.tsx similarity index 100% rename from packages/console/src/cloud/components/EarlyBirdGift/index.tsx rename to packages/console/src/onboarding/components/EarlyBirdGift/index.tsx diff --git a/packages/console/src/cloud/components/ProgressBar/index.module.scss b/packages/console/src/onboarding/components/ProgressBar/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/ProgressBar/index.module.scss rename to packages/console/src/onboarding/components/ProgressBar/index.module.scss diff --git a/packages/console/src/cloud/components/ProgressBar/index.tsx b/packages/console/src/onboarding/components/ProgressBar/index.tsx similarity index 100% rename from packages/console/src/cloud/components/ProgressBar/index.tsx rename to packages/console/src/onboarding/components/ProgressBar/index.tsx diff --git a/packages/console/src/cloud/components/Reservation/index.module.scss b/packages/console/src/onboarding/components/Reservation/index.module.scss similarity index 100% rename from packages/console/src/cloud/components/Reservation/index.module.scss rename to packages/console/src/onboarding/components/Reservation/index.module.scss diff --git a/packages/console/src/cloud/components/Reservation/index.tsx b/packages/console/src/onboarding/components/Reservation/index.tsx similarity index 96% rename from packages/console/src/cloud/components/Reservation/index.tsx rename to packages/console/src/onboarding/components/Reservation/index.tsx index 77b8a1181..0bbf2d768 100644 --- a/packages/console/src/cloud/components/Reservation/index.tsx +++ b/packages/console/src/onboarding/components/Reservation/index.tsx @@ -4,8 +4,8 @@ import type { ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import Calendar from '@/assets/images/calendar.svg'; -import { reservationLink } from '@/cloud/constants'; import Button from '@/components/Button'; +import { reservationLink } from '@/onboarding/constants'; import { buildUrl } from '@/utils/url'; import * as styles from './index.module.scss'; diff --git a/packages/console/src/cloud/constants/index.ts b/packages/console/src/onboarding/constants/index.ts similarity index 100% rename from packages/console/src/cloud/constants/index.ts rename to packages/console/src/onboarding/constants/index.ts diff --git a/packages/console/src/onboarding/containers/AppContent/index.module.scss b/packages/console/src/onboarding/containers/AppContent/index.module.scss new file mode 100644 index 000000000..1333ce6b0 --- /dev/null +++ b/packages/console/src/onboarding/containers/AppContent/index.module.scss @@ -0,0 +1,13 @@ +.app { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; +} + +.content { + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; +} diff --git a/packages/console/src/onboarding/containers/AppContent/index.tsx b/packages/console/src/onboarding/containers/AppContent/index.tsx new file mode 100644 index 000000000..a6f357abc --- /dev/null +++ b/packages/console/src/onboarding/containers/AppContent/index.tsx @@ -0,0 +1,16 @@ +import { Outlet } from 'react-router-dom'; + +import Topbar from '@/containers/AppContent/components/Topbar'; + +import * as styles from './index.module.scss'; + +const AppContent = () => ( +
+ +
+ +
+
+); + +export default AppContent; diff --git a/packages/console/src/cloud/hooks/use-user-onboarding-data.ts b/packages/console/src/onboarding/hooks/use-user-onboarding-data.ts similarity index 100% rename from packages/console/src/cloud/hooks/use-user-onboarding-data.ts rename to packages/console/src/onboarding/hooks/use-user-onboarding-data.ts diff --git a/packages/console/src/cloud/pages/About/index.module.scss b/packages/console/src/onboarding/pages/About/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/About/index.module.scss rename to packages/console/src/onboarding/pages/About/index.module.scss diff --git a/packages/console/src/cloud/pages/About/index.tsx b/packages/console/src/onboarding/pages/About/index.tsx similarity index 92% rename from packages/console/src/cloud/pages/About/index.tsx rename to packages/console/src/onboarding/pages/About/index.tsx index 09b61700d..f728c66ae 100644 --- a/packages/console/src/cloud/pages/About/index.tsx +++ b/packages/console/src/onboarding/pages/About/index.tsx @@ -5,18 +5,18 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import Case from '@/assets/images/case.svg'; -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import * as pageLayout from '@/cloud/scss/layout.module.scss'; import Button from '@/components/Button'; import FormField from '@/components/FormField'; import OverlayScrollbar from '@/components/OverlayScrollbar'; import TextInput from '@/components/TextInput'; +import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; +import * as pageLayout from '@/onboarding/scss/layout.module.scss'; import ActionBar from '../../components/ActionBar'; import { CardSelector, MultiCardSelector } from '../../components/CardSelector'; import type { Questionnaire } from '../../types'; import { OnboardingPage } from '../../types'; -import { getOnboardPagePathname } from '../../utils'; +import { getOnboardingPage } from '../../utils'; import * as styles from './index.module.scss'; import { titleOptions, companySizeOptions, reasonOptions } from './options'; @@ -43,11 +43,11 @@ const About = () => { const onNext = async () => { await onSubmit(); - navigate(getOnboardPagePathname(OnboardingPage.SignInExperience)); + navigate(getOnboardingPage(OnboardingPage.SignInExperience), { replace: true }); }; const onBack = async () => { - navigate(getOnboardPagePathname(OnboardingPage.Welcome)); + navigate(getOnboardingPage(OnboardingPage.Welcome), { replace: true }); }; return ( diff --git a/packages/console/src/cloud/pages/About/options.tsx b/packages/console/src/onboarding/pages/About/options.tsx similarity index 94% rename from packages/console/src/cloud/pages/About/options.tsx rename to packages/console/src/onboarding/pages/About/options.tsx index 81942ea43..0f3dcb6ff 100644 --- a/packages/console/src/cloud/pages/About/options.tsx +++ b/packages/console/src/onboarding/pages/About/options.tsx @@ -1,4 +1,4 @@ -import type { Option as SelectorOption } from '@/cloud/components/CardSelector'; +import type { Option as SelectorOption } from '@/onboarding/components/CardSelector'; import { CompanySize, Reason, Title } from '../../types'; diff --git a/packages/console/src/cloud/pages/Congrats/index.module.scss b/packages/console/src/onboarding/pages/Congrats/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/Congrats/index.module.scss rename to packages/console/src/onboarding/pages/Congrats/index.module.scss diff --git a/packages/console/src/cloud/pages/Congrats/index.tsx b/packages/console/src/onboarding/pages/Congrats/index.tsx similarity index 77% rename from packages/console/src/cloud/pages/Congrats/index.tsx rename to packages/console/src/onboarding/pages/Congrats/index.tsx index a90e35ce8..fb1e62156 100644 --- a/packages/console/src/cloud/pages/Congrats/index.tsx +++ b/packages/console/src/onboarding/pages/Congrats/index.tsx @@ -1,18 +1,19 @@ import { AppearanceMode } from '@logto/schemas'; import classNames from 'classnames'; +import { useContext } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { useNavigate } from 'react-router-dom'; import CalendarOutline from '@/assets/images/calendar-outline.svg'; import CongratsImageDark from '@/assets/images/congrats-dark.svg'; import CongratsImageLight from '@/assets/images/congrats.svg'; -import Reservation from '@/cloud/components/Reservation'; -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import * as pageLayout from '@/cloud/scss/layout.module.scss'; import Button from '@/components/Button'; import Divider from '@/components/Divider'; import OverlayScrollbar from '@/components/OverlayScrollbar'; +import { TenantsContext } from '@/contexts/TenantsProvider'; import { useTheme } from '@/hooks/use-theme'; +import Reservation from '@/onboarding/components/Reservation'; +import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; +import * as pageLayout from '@/onboarding/scss/layout.module.scss'; import * as styles from './index.module.scss'; @@ -21,12 +22,12 @@ const Congrats = () => { const theme = useTheme(); const CongratsImage = theme === AppearanceMode.LightMode ? CongratsImageLight : CongratsImageDark; const { update } = useUserOnboardingData(); + const { navigate, currentTenantId } = useContext(TenantsContext); - const navigate = useNavigate(); - - const enterAdminConsole = async () => { - await update({ isOnboardingDone: true }); - navigate('/'); + const enterAdminConsole = () => { + void update({ isOnboardingDone: true }); + // Note: navigate to the admin console page directly instead of using the router + navigate(currentTenantId, { replace: true }); }; return ( diff --git a/packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/PlatformTab.module.scss b/packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/PlatformTab.module.scss similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/PlatformTab.module.scss rename to packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/PlatformTab.module.scss diff --git a/packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/PlatformTab.tsx b/packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/PlatformTab.tsx similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/PlatformTab.tsx rename to packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/PlatformTab.tsx diff --git a/packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/index.module.scss b/packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/index.module.scss rename to packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/index.module.scss diff --git a/packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/index.tsx b/packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/index.tsx similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/PlatformTabs/index.tsx rename to packages/console/src/onboarding/pages/SignInExperience/components/PlatformTabs/index.tsx diff --git a/packages/console/src/cloud/pages/SignInExperience/components/Preview/index.module.scss b/packages/console/src/onboarding/pages/SignInExperience/components/Preview/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/Preview/index.module.scss rename to packages/console/src/onboarding/pages/SignInExperience/components/Preview/index.module.scss diff --git a/packages/console/src/cloud/pages/SignInExperience/components/Preview/index.tsx b/packages/console/src/onboarding/pages/SignInExperience/components/Preview/index.tsx similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/components/Preview/index.tsx rename to packages/console/src/onboarding/pages/SignInExperience/components/Preview/index.tsx diff --git a/packages/console/src/cloud/pages/SignInExperience/index.module.scss b/packages/console/src/onboarding/pages/SignInExperience/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/SignInExperience/index.module.scss rename to packages/console/src/onboarding/pages/SignInExperience/index.module.scss diff --git a/packages/console/src/cloud/pages/SignInExperience/index.tsx b/packages/console/src/onboarding/pages/SignInExperience/index.tsx similarity index 90% rename from packages/console/src/cloud/pages/SignInExperience/index.tsx rename to packages/console/src/onboarding/pages/SignInExperience/index.tsx index 1e96e9b5e..70ab19da0 100644 --- a/packages/console/src/cloud/pages/SignInExperience/index.tsx +++ b/packages/console/src/onboarding/pages/SignInExperience/index.tsx @@ -8,19 +8,19 @@ import useSWR from 'swr'; import Bulb from '@/assets/images/bulb.svg'; import Tools from '@/assets/images/tools.svg'; -import ActionBar from '@/cloud/components/ActionBar'; -import { CardSelector, MultiCardSelector } from '@/cloud/components/CardSelector'; -import { defaultOnboardingSieConfig } from '@/cloud/constants'; -import * as pageLayout from '@/cloud/scss/layout.module.scss'; -import type { OnboardingSieConfig } from '@/cloud/types'; -import { OnboardingPage } from '@/cloud/types'; -import { getOnboardPagePathname } from '@/cloud/utils'; import Button from '@/components/Button'; import ColorPicker from '@/components/ColorPicker'; import FormField from '@/components/FormField'; import OverlayScrollbar from '@/components/OverlayScrollbar'; import type { RequestError } from '@/hooks/use-api'; import useApi from '@/hooks/use-api'; +import ActionBar from '@/onboarding/components/ActionBar'; +import { CardSelector, MultiCardSelector } from '@/onboarding/components/CardSelector'; +import { defaultOnboardingSieConfig } from '@/onboarding/constants'; +import * as pageLayout from '@/onboarding/scss/layout.module.scss'; +import { OnboardingPage } from '@/onboarding/types'; +import type { OnboardingSieConfig } from '@/onboarding/types'; +import { getOnboardingPage } from '@/onboarding/utils'; import Preview from './components/Preview'; import * as styles from './index.module.scss'; @@ -78,7 +78,7 @@ const SignInExperience = () => { }); const handleBack = () => { - navigate(getOnboardPagePathname(OnboardingPage.AboutUser)); + navigate(getOnboardingPage(OnboardingPage.AboutUser), { replace: true }); }; const handleSave = async () => { @@ -88,7 +88,7 @@ const SignInExperience = () => { const handleNext = async () => { await onSubmit(); - navigate(getOnboardPagePathname(OnboardingPage.Congrats)); + navigate(getOnboardingPage(OnboardingPage.Congrats), { replace: true }); }; return ( diff --git a/packages/console/src/cloud/pages/SignInExperience/options.tsx b/packages/console/src/onboarding/pages/SignInExperience/options.tsx similarity index 88% rename from packages/console/src/cloud/pages/SignInExperience/options.tsx rename to packages/console/src/onboarding/pages/SignInExperience/options.tsx index 92004ac23..b1f51573a 100644 --- a/packages/console/src/cloud/pages/SignInExperience/options.tsx +++ b/packages/console/src/onboarding/pages/SignInExperience/options.tsx @@ -5,8 +5,8 @@ import Keyboard from '@/assets/images/keyboard.svg'; import Label from '@/assets/images/label.svg'; import Lock from '@/assets/images/lock.svg'; import Mobile from '@/assets/images/mobile.svg'; -import type { Option as SelectorOption } from '@/cloud/components/CardSelector'; -import { Authentication } from '@/cloud/types'; +import type { Option as SelectorOption } from '@/onboarding/components/CardSelector'; +import { Authentication } from '@/onboarding/types'; export const identifierOptions: SelectorOption[] = [ { diff --git a/packages/console/src/cloud/pages/SignInExperience/utils.ts b/packages/console/src/onboarding/pages/SignInExperience/utils.ts similarity index 94% rename from packages/console/src/cloud/pages/SignInExperience/utils.ts rename to packages/console/src/onboarding/pages/SignInExperience/utils.ts index 1be451d69..a613c3d19 100644 --- a/packages/console/src/cloud/pages/SignInExperience/utils.ts +++ b/packages/console/src/onboarding/pages/SignInExperience/utils.ts @@ -1,8 +1,8 @@ import type { SignInExperience } from '@logto/schemas'; import { SignInIdentifier } from '@logto/schemas'; -import type { OnboardingSieConfig } from '@/cloud/types'; -import { Authentication } from '@/cloud/types'; +import type { OnboardingSieConfig } from '@/onboarding/types'; +import { Authentication } from '@/onboarding/types'; const signInExperienceToOnboardSieConfig = ( signInExperience: SignInExperience diff --git a/packages/console/src/cloud/pages/Welcome/index.module.scss b/packages/console/src/onboarding/pages/Welcome/index.module.scss similarity index 100% rename from packages/console/src/cloud/pages/Welcome/index.module.scss rename to packages/console/src/onboarding/pages/Welcome/index.module.scss diff --git a/packages/console/src/cloud/pages/Welcome/index.tsx b/packages/console/src/onboarding/pages/Welcome/index.tsx similarity index 89% rename from packages/console/src/cloud/pages/Welcome/index.tsx rename to packages/console/src/onboarding/pages/Welcome/index.tsx index b203ec05b..56dd92819 100644 --- a/packages/console/src/cloud/pages/Welcome/index.tsx +++ b/packages/console/src/onboarding/pages/Welcome/index.tsx @@ -5,17 +5,17 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import Congrats from '@/assets/images/congrats.svg'; -import ActionBar from '@/cloud/components/ActionBar'; -import { CardSelector } from '@/cloud/components/CardSelector'; -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import * as pageLayout from '@/cloud/scss/layout.module.scss'; import Button from '@/components/Button'; import FormField from '@/components/FormField'; import OverlayScrollbar from '@/components/OverlayScrollbar'; +import ActionBar from '@/onboarding/components/ActionBar'; +import { CardSelector } from '@/onboarding/components/CardSelector'; +import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; +import * as pageLayout from '@/onboarding/scss/layout.module.scss'; import type { Questionnaire } from '../../types'; import { OnboardingPage } from '../../types'; -import { getOnboardPagePathname } from '../../utils'; +import { getOnboardingPage } from '../../utils'; import * as styles from './index.module.scss'; import { deploymentTypeOptions, projectOptions } from './options'; @@ -45,7 +45,7 @@ const Welcome = () => { const onNext = async () => { await onSubmit(); - navigate(getOnboardPagePathname(OnboardingPage.AboutUser)); + navigate(getOnboardingPage(OnboardingPage.AboutUser), { replace: true }); }; return ( diff --git a/packages/console/src/cloud/pages/Welcome/options.tsx b/packages/console/src/onboarding/pages/Welcome/options.tsx similarity index 90% rename from packages/console/src/cloud/pages/Welcome/options.tsx rename to packages/console/src/onboarding/pages/Welcome/options.tsx index 4dc45b2d0..5f504184e 100644 --- a/packages/console/src/cloud/pages/Welcome/options.tsx +++ b/packages/console/src/onboarding/pages/Welcome/options.tsx @@ -2,7 +2,7 @@ import Building from '@/assets/images/building.svg'; import Cloud from '@/assets/images/cloud.svg'; import Database from '@/assets/images/database.svg'; import Pizza from '@/assets/images/pizza.svg'; -import type { Option as SelectorOption } from '@/cloud/components/CardSelector'; +import type { Option as SelectorOption } from '@/onboarding/components/CardSelector'; import { DeploymentType, Project } from '../../types'; diff --git a/packages/console/src/cloud/scss/layout.module.scss b/packages/console/src/onboarding/scss/layout.module.scss similarity index 81% rename from packages/console/src/cloud/scss/layout.module.scss rename to packages/console/src/onboarding/scss/layout.module.scss index d562f8ff3..4added9a8 100644 --- a/packages/console/src/cloud/scss/layout.module.scss +++ b/packages/console/src/onboarding/scss/layout.module.scss @@ -1,5 +1,4 @@ @use '@/scss/underscore' as _; -@use './cloud-page-size.scss' as size; .page { height: 100%; @@ -16,7 +15,7 @@ .content { margin: 0 auto; - max-width: size.$questionnaire-content-width; + max-width: 858px; border-radius: 16px; padding: _.unit(12); background-color: var(--color-layer-1); diff --git a/packages/console/src/onboarding/types.ts b/packages/console/src/onboarding/types.ts new file mode 100644 index 000000000..a19d515fa --- /dev/null +++ b/packages/console/src/onboarding/types.ts @@ -0,0 +1,78 @@ +import type { SignInIdentifier } from '@logto/schemas'; +import { z } from 'zod'; + +export enum OnboardingRoute { + Onboarding = 'onboarding', +} + +export enum OnboardingPage { + Welcome = 'welcome', + AboutUser = 'about-user', + SignInExperience = 'sign-in-experience', + Congrats = 'congrats', +} + +export enum Project { + Personal = 'personal', + Company = 'company', +} + +export enum DeploymentType { + OpenSource = 'open-source', + Cloud = 'cloud', +} + +export enum Title { + Developer = 'developer', + TeamLead = 'team-lead', + Ceo = 'ceo', + Cto = 'cto', + Product = 'product', + Others = 'others', +} + +export enum CompanySize { + Scale1 = '1', + Scale2 = '1-49', + Scale3 = '50-199', + Scale4 = '200-999', + Scale5 = '1000+', +} + +export enum Reason { + Adoption = 'adoption', + Replacement = 'replacement', + Evaluation = 'evaluation', + Experimentation = 'experimentation', + Aesthetics = 'aesthetics', + Others = 'others', +} + +export const questionnaireGuard = z.object({ + project: z.nativeEnum(Project), + deploymentType: z.nativeEnum(DeploymentType), + titles: z.array(z.nativeEnum(Title)).optional(), + companyName: z.string().optional(), + companySize: z.nativeEnum(CompanySize).optional(), + reasons: z.array(z.nativeEnum(Reason)).optional(), +}); + +export type Questionnaire = z.infer; + +export const userOnboardingDataGuard = z.object({ + questionnaire: questionnaireGuard.optional(), + isOnboardingDone: z.boolean().optional(), +}); + +export type UserOnboardingData = z.infer; + +export enum Authentication { + Password = 'password', + VerificationCode = 'verificationCode', +} + +export type OnboardingSieConfig = { + color: string; + identifier: SignInIdentifier; + authentications: Authentication[]; +}; diff --git a/packages/console/src/onboarding/utils.ts b/packages/console/src/onboarding/utils.ts new file mode 100644 index 000000000..d219a9d4f --- /dev/null +++ b/packages/console/src/onboarding/utils.ts @@ -0,0 +1,7 @@ +import { joinPath } from '@silverhand/essentials'; + +import type { OnboardingPage } from './types'; +import { OnboardingRoute } from './types'; + +export const getOnboardingPage = (page: OnboardingPage) => + joinPath(OnboardingRoute.Onboarding, page); diff --git a/packages/console/src/pages/Main/index.tsx b/packages/console/src/pages/Main/index.tsx index ddb901a6e..33fcc586a 100644 --- a/packages/console/src/pages/Main/index.tsx +++ b/packages/console/src/pages/Main/index.tsx @@ -1,18 +1,11 @@ -import { useContext } from 'react'; -import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; +import { BrowserRouter, Route, Routes } from 'react-router-dom'; import { SWRConfig } from 'swr'; -import useUserOnboardingData from '@/cloud/hooks/use-user-onboarding-data'; -import Onboarding from '@/cloud/pages/Onboarding'; -import { CloudRoute } from '@/cloud/types'; -import AppLoading from '@/components/AppLoading'; import Toast from '@/components/Toast'; import { getBasename } from '@/consts'; -import { isCloud } from '@/consts/cloud'; import AppBoundary from '@/containers/AppBoundary'; import AppContent from '@/containers/AppContent'; import ConsoleContent from '@/containers/ConsoleContent'; -import { AppEndpointsContext } from '@/contexts/AppEndpointsProvider'; import useSwrOptions from '@/hooks/use-swr-options'; import Callback from '@/pages/Callback'; import Welcome from '@/pages/Welcome'; @@ -21,17 +14,6 @@ import HandleSocialCallback from '../Profile/containers/HandleSocialCallback'; const Main = () => { const swrOptions = useSwrOptions(); - const { userEndpoint } = useContext(AppEndpointsContext); - const { - data: { isOnboardingDone }, - isLoaded, - } = useUserOnboardingData(); - - if (!userEndpoint || (isCloud && !isLoaded)) { - return ; - } - - const isOnboarding = isCloud && !isOnboardingDone; return ( @@ -43,14 +25,7 @@ const Main = () => { } /> } /> }> - {isOnboarding ? ( - - } /> - } /> - - ) : ( - } /> - )} + } /> diff --git a/packages/console/src/pages/NotFound/index.module.scss b/packages/console/src/pages/NotFound/index.module.scss index d0f103da7..ca9047a7a 100644 --- a/packages/console/src/pages/NotFound/index.module.scss +++ b/packages/console/src/pages/NotFound/index.module.scss @@ -1,6 +1,11 @@ @use '@/scss/underscore' as _; .container { + height: 100%; + padding: _.unit(6); +} + +.content { height: 100%; color: var(--color-text); text-align: center; diff --git a/packages/console/src/pages/NotFound/index.tsx b/packages/console/src/pages/NotFound/index.tsx index 23680b344..5c1059937 100644 --- a/packages/console/src/pages/NotFound/index.tsx +++ b/packages/console/src/pages/NotFound/index.tsx @@ -13,10 +13,12 @@ const NotFound = () => { const theme = useTheme(); return ( - - {theme === AppearanceMode.LightMode ? : } -
{t('errors.page_not_found')}
-
+
+ + {theme === AppearanceMode.LightMode ? : } +
{t('errors.page_not_found')}
+
+
); }; diff --git a/packages/integration-tests/src/tests/ui-cloud/smoke.test.ts b/packages/integration-tests/src/tests/ui-cloud/smoke.test.ts index 2146be79e..246c61756 100644 --- a/packages/integration-tests/src/tests/ui-cloud/smoke.test.ts +++ b/packages/integration-tests/src/tests/ui-cloud/smoke.test.ts @@ -68,6 +68,66 @@ describe('smoke testing for cloud', () => { expect(page.url()).toBe(new URL(`/${tenantId ?? ''}/onboarding/welcome`, logtoCloudUrl).href); }); + it('can complete the onboarding welcome process and enter the user survey page', async () => { + // Select the project type option + await expect(page).toClick('div[role=radio]:has(input[name=project][value=personal])'); + + // Select the deployment type option + await expect(page).toClick( + 'div[role=radio]:has(input[name=deploymentType][value=open-source])' + ); + + // Click the next button + await expect(page).toClick('div[class$=actions] button:first-child'); + + // Wait for the next page to load + await expect(page).toMatchElement('div[class$=content] div[class$=title]', { + text: 'A little bit about you', + }); + + expect(new URL(page.url()).pathname.endsWith('/onboarding/about-user')).toBeTruthy(); + }); + + it('can complete the onboarding user survey process and enter the sie page', async () => { + // Select the reason option + await expect(page).toClick('div[class$=option]', { text: 'Others' }); + + // Click the next button + await expect(page).toClick('div[class$=actions] button:first-child'); + + // Wait for the next page to load + await expect(page).toMatchElement('div[class$=config] div[class$=title]', { + text: 'Let’s first customize your experience with ease', + }); + + expect(new URL(page.url()).pathname.endsWith('/onboarding/sign-in-experience')).toBeTruthy(); + }); + + it('can complete the sie configuration process and enter the congrats page', async () => { + // Click the finish button + await expect(page).toClick('div[class$=continueActions] button:last-child'); + + // Wait for the next page to load + await expect(page).toMatchElement('div[class$=content] div[class$=title]', { + text: 'Great news! You are qualified to earn Logto Cloud early credit!', + }); + + expect(new URL(page.url()).pathname.endsWith('/onboarding/congrats')).toBeTruthy(); + }); + + it('can complete the onboarding process and enter the admin console', async () => { + // Click the enter ac button + await expect(page).toClick('div[class$=content] >button'); + + // Wait for the admin console to load + const mainContent = await page.waitForSelector('div[class$=main]:has(div[class$=title])'); + await expect(mainContent).toMatchElement('div[class$=title]', { + text: 'How do you want to get started with Logto?', + }); + + expect(new URL(page.url()).pathname.endsWith('/get-started')).toBeTruthy(); + }); + it('can sign out of admin console', async () => { await expect(page).toClick('div[class$=topbar] > div[class$=container]');