diff --git a/packages/console/src/cloud/AppRoutes.tsx b/packages/console/src/cloud/AppRoutes.tsx index ae6d71db3..20127127c 100644 --- a/packages/console/src/cloud/AppRoutes.tsx +++ b/packages/console/src/cloud/AppRoutes.tsx @@ -1,6 +1,7 @@ import { Route, Routes } from 'react-router-dom'; import ProtectedRoutes from '@/containers/ProtectedRoutes'; +import { GlobalAnonymousRoute } from '@/contexts/TenantsProvider'; import Callback from '@/pages/Callback'; import * as styles from './AppRoutes.module.scss'; @@ -12,11 +13,10 @@ function AppRoutes() { return (
- } /> - } /> - } /> + } /> + } /> }> - } /> + } />
diff --git a/packages/console/src/containers/TenantAccess/index.tsx b/packages/console/src/containers/TenantAccess/index.tsx index 460578f61..18045c4fc 100644 --- a/packages/console/src/containers/TenantAccess/index.tsx +++ b/packages/console/src/containers/TenantAccess/index.tsx @@ -59,7 +59,7 @@ export default function TenantAccess() { * We need to exclude the `me` key because it's not tenant-aware. If don't, we * need to manually revalidate the `me` key to make console work again. */ - void mutate((key) => key !== 'me', undefined, false); + void mutate((key) => key !== 'me', undefined, { rollbackOnError: false, throwOnError: false }); }, [mutate, currentTenantId]); useEffect(() => { diff --git a/packages/console/src/contexts/TenantsProvider.tsx b/packages/console/src/contexts/TenantsProvider.tsx index 3c711b17f..122e4bb77 100644 --- a/packages/console/src/contexts/TenantsProvider.tsx +++ b/packages/console/src/contexts/TenantsProvider.tsx @@ -7,6 +7,23 @@ import { useMatch, useNavigate } from 'react-router-dom'; import { isCloud } from '@/consts/env'; +/** + * The routes don't start with a tenant ID. + * + * @remarks + * It's important to keep this single source of truth for all anonymous routes + * because we need to check if the current route is anonymous or not to decide + * if the current tenant ID is available. + * + * This should be more clear once we refactor the file structure and the routes. + */ +export enum GlobalAnonymousRoute { + Callback = '/callback', + SocialDemoCallback = '/social-demo-callback', +} + +const anonymousRoutes: Readonly = Object.freeze(Object.values(GlobalAnonymousRoute)); + /** * The current tenant status of access validation. When it's `validated`, it indicates that a * valid Access Token for the current tenant is available. @@ -83,12 +100,19 @@ function TenantsProvider({ children }: Props) { const [tenants, setTenants] = useState(initialTenants); /** @see {@link initialTenants} */ const [isInitComplete, setIsInitComplete] = useState(!isCloud); - const matched = useMatch('/:tenantId/*'); + const match = useMatch('/:tenantId/*'); const navigate = useNavigate(); - const currentTenantId = useMemo( - () => (isCloud ? matched?.params.tenantId ?? '' : defaultTenantId), - [matched] - ); + const currentTenantId = useMemo(() => { + if (!isCloud) { + return defaultTenantId; + } + + if (!match || anonymousRoutes.includes(match.pathname)) { + return ''; + } + + return match.params.tenantId ?? ''; + }, [match]); const [currentTenantStatus, setCurrentTenantStatus] = useState('pending'); const navigateTenant = useCallback( diff --git a/packages/console/src/onboarding/pages/Congrats/index.tsx b/packages/console/src/onboarding/pages/Congrats/index.tsx index eb87084e5..191c33850 100644 --- a/packages/console/src/onboarding/pages/Congrats/index.tsx +++ b/packages/console/src/onboarding/pages/Congrats/index.tsx @@ -23,9 +23,8 @@ function Congrats() { const { update } = useUserOnboardingData(); const { navigateTenant, currentTenantId } = useContext(TenantsContext); - const enterAdminConsole = () => { - void update({ isOnboardingDone: true }); - // Note: navigate to the admin console page directly instead of using the router + const enterAdminConsole = async () => { + await update({ isOnboardingDone: true }); navigateTenant(currentTenantId); }; diff --git a/packages/console/src/pages/Callback/index.tsx b/packages/console/src/pages/Callback/index.tsx index 20c47154b..b82eb8f5a 100644 --- a/packages/console/src/pages/Callback/index.tsx +++ b/packages/console/src/pages/Callback/index.tsx @@ -19,7 +19,7 @@ function Callback() { return; } - navigate(getTo('/'), { replace: true }); + navigate('/', { replace: true }); }); return ; diff --git a/packages/console/src/pages/ConsoleRoutes/index.tsx b/packages/console/src/pages/ConsoleRoutes/index.tsx index 858220ac3..7eac25248 100644 --- a/packages/console/src/pages/ConsoleRoutes/index.tsx +++ b/packages/console/src/pages/ConsoleRoutes/index.tsx @@ -1,6 +1,7 @@ import { Component, GeneralEvent } from '@logto/app-insights/custom-event'; import { TrackOnce } from '@logto/app-insights/react'; -import { Outlet, Route, Routes } from 'react-router-dom'; +import { ossConsolePath } from '@logto/schemas'; +import { Navigate, Outlet, Route, Routes } from 'react-router-dom'; import { SWRConfig } from 'swr'; import { isCloud, isProduction } from '@/consts/env'; @@ -35,6 +36,12 @@ function Layout() { export function ConsoleRoutes() { return ( + {/** + * OSS doesn't have a tenant concept nor root path handling component, but it may + * navigate to the root path in frontend. In this case, we redirect it to the OSS + * console path to trigger the console routes. + */} + {!isCloud && } />} }> } /> } />