From c4e13ff525dabbcaa56f9dac71e6b0caa7ee2d17 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Thu, 22 Jun 2023 15:13:49 +0800 Subject: [PATCH] refactor(console): optimize tenant context and hooks remove the use of useSWR and make the tenant context as the single source of truth for tenant data. also reorg deduplicate hook logics. --- packages/console/src/App.tsx | 10 +- .../console/src/cloud/hooks/use-cloud-swr.ts | 23 ---- .../pages/Main/AutoCreateTenant/index.tsx | 22 ++++ .../console/src/cloud/pages/Main/Redirect.tsx | 30 ++--- .../TenantLandingPageContent/index.tsx | 21 +--- .../console/src/cloud/pages/Main/index.tsx | 93 +++++---------- .../Topbar/TenantSelector/index.module.scss | 6 + .../Topbar/TenantSelector/index.tsx | 53 +++------ .../src/containers/ErrorBoundary/index.tsx | 11 +- .../console/src/contexts/TenantsProvider.tsx | 112 +++++++++++++----- .../src/onboarding/pages/Congrats/index.tsx | 4 +- .../TenantBasicSettings/DeleteCard/index.tsx | 4 +- .../TenantBasicSettings/index.tsx | 36 +----- .../src/components/Button/index.module.scss | 1 + 14 files changed, 196 insertions(+), 230 deletions(-) delete mode 100644 packages/console/src/cloud/hooks/use-cloud-swr.ts create mode 100644 packages/console/src/cloud/pages/Main/AutoCreateTenant/index.tsx diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index b06513988..629fac43c 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -29,7 +29,7 @@ import TenantsProvider, { TenantsContext } from './contexts/TenantsProvider'; void initI18n(); function Content() { - const { tenants, isSettle, currentTenantId } = useContext(TenantsContext); + const { tenants, isInitComplete, currentTenantId } = useContext(TenantsContext); const resources = useMemo( () => @@ -39,7 +39,7 @@ function Content() { // access a URL with Tenant ID, adding the ID from the URL here can possibly remove one // additional redirect. currentTenantId && getManagementApi(currentTenantId).indicator, - ...(tenants ?? []).map(({ id }) => getManagementApi(id).indicator), + ...tenants.map(({ id }) => getManagementApi(id).indicator), isCloud && cloudApi.indicator, meApi.indicator ) @@ -76,7 +76,11 @@ function Content() { - {!isCloud || isSettle ? ( + {/** + * If it's not Cloud (OSS), render the tenant app container directly since only default tenant is available; + * if it's Cloud, render the tenant app container only when init is complete and a tenant ID is available (in a tenant context). + */} + {!isCloud || (isInitComplete && currentTenantId) ? ( diff --git a/packages/console/src/cloud/hooks/use-cloud-swr.ts b/packages/console/src/cloud/hooks/use-cloud-swr.ts deleted file mode 100644 index 456094db0..000000000 --- a/packages/console/src/cloud/hooks/use-cloud-swr.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type router from '@logto/cloud/routes'; -import { type RouterRoutes } from '@withtyped/client'; -import useSWR from 'swr'; - -import { useCloudApi } from './use-cloud-api'; - -type GetRoutes = RouterRoutes['get']; - -const normalizeError = (error: unknown) => { - if (error === undefined || error === null) { - return; - } - - return error instanceof Error ? error : new Error(String(error)); -}; - -export const useCloudSwr = (key: Key) => { - const cloudApi = useCloudApi(); - const response = useSWR(key, async () => cloudApi.get(key)); - - // By default, `useSWR()` uses `any` for the error type which is unexpected under our lint rule set. - return { ...response, error: normalizeError(response.error) }; -}; diff --git a/packages/console/src/cloud/pages/Main/AutoCreateTenant/index.tsx b/packages/console/src/cloud/pages/Main/AutoCreateTenant/index.tsx new file mode 100644 index 000000000..91b4e5b4c --- /dev/null +++ b/packages/console/src/cloud/pages/Main/AutoCreateTenant/index.tsx @@ -0,0 +1,22 @@ +import { useContext, useEffect } from 'react'; + +import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; +import AppLoading from '@/components/AppLoading'; +import { TenantsContext } from '@/contexts/TenantsProvider'; + +export default function AutoCreateTenant() { + const api = useCloudApi(); + const { appendTenant, navigateTenant } = useContext(TenantsContext); + + useEffect(() => { + const createTenant = async () => { + const newTenant = await api.post('/api/tenants', { body: {} }); + appendTenant(newTenant); + navigateTenant(newTenant.id); + }; + + void createTenant(); + }, [api, appendTenant, navigateTenant]); + + return ; +} diff --git a/packages/console/src/cloud/pages/Main/Redirect.tsx b/packages/console/src/cloud/pages/Main/Redirect.tsx index a0152a55f..863f75429 100644 --- a/packages/console/src/cloud/pages/Main/Redirect.tsx +++ b/packages/console/src/cloud/pages/Main/Redirect.tsx @@ -1,5 +1,4 @@ import { useLogto } from '@logto/react'; -import type { TenantInfo } from '@logto/schemas/models'; import { trySafe } from '@silverhand/essentials'; import { useContext, useEffect } from 'react'; import { useHref } from 'react-router-dom'; @@ -7,16 +6,12 @@ import { useHref } from 'react-router-dom'; import AppLoading from '@/components/AppLoading'; import { TenantsContext } from '@/contexts/TenantsProvider'; -type Props = { - tenants: TenantInfo[]; - toTenantId: string; -}; - -function Redirect({ tenants, toTenantId }: Props) { +function Redirect() { const { getAccessToken, signIn } = useLogto(); - const tenant = tenants.find(({ id }) => id === toTenantId); - const { setIsSettle, navigate } = useContext(TenantsContext); - const href = useHref(toTenantId + '/callback'); + const { navigateTenant, tenants, currentTenantId } = useContext(TenantsContext); + + const tenant = tenants.find(({ id }) => id === currentTenantId); + const href = useHref(currentTenantId + '/callback'); useEffect(() => { const validate = async (indicator: string) => { @@ -24,8 +19,7 @@ function Redirect({ tenants, toTenantId }: Props) { // If failed, it means the user finishes the first auth, ands still needs to auth again to // fetch the full-scoped (with all available tenants) token. if (await trySafe(getAccessToken(indicator))) { - setIsSettle(true); - navigate(toTenantId); + navigateTenant(currentTenantId); } else { void signIn(new URL(href, window.location.origin).toString()); } @@ -34,12 +28,14 @@ function Redirect({ tenants, toTenantId }: Props) { if (tenant) { void validate(tenant.indicator); } - }, [getAccessToken, href, navigate, setIsSettle, signIn, tenant, toTenantId]); + }, [currentTenantId, getAccessToken, href, navigateTenant, signIn, tenant]); - if (!tenant) { - /** Fallback to another available tenant instead of showing `Forbidden`. */ - navigate(tenants[0]?.id ?? ''); - } + useEffect(() => { + if (!tenant) { + /** Fallback to another available tenant instead of showing `Forbidden`. */ + navigateTenant(tenants[0]?.id ?? ''); + } + }, [navigateTenant, tenant, tenants]); return ; } diff --git a/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx b/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx index 40eda79ea..86f46587f 100644 --- a/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx +++ b/packages/console/src/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/index.tsx @@ -1,13 +1,11 @@ import { Theme } from '@logto/schemas'; import type { TenantInfo } from '@logto/schemas/models'; import classNames from 'classnames'; -import { useContext, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useContext, useState } from 'react'; import Plus from '@/assets/icons/plus.svg'; import TenantLandingPageImageDark from '@/assets/images/tenant-landing-page-dark.svg'; import TenantLandingPageImage from '@/assets/images/tenant-landing-page.svg'; -import { useCloudSwr } from '@/cloud/hooks/use-cloud-swr'; import { TenantsContext } from '@/contexts/TenantsProvider'; import Button from '@/ds-components/Button'; import DynamicT from '@/ds-components/DynamicT'; @@ -21,21 +19,12 @@ type Props = { }; function TenantLandingPageContent({ className }: Props) { - const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const { tenants, setTenants } = useContext(TenantsContext); - const { data: availableTenants, mutate } = useCloudSwr('/api/tenants'); - - useEffect(() => { - if (availableTenants) { - setTenants(availableTenants); - } - }, [availableTenants, setTenants]); - + const { tenants, appendTenant, navigateTenant } = useContext(TenantsContext); const theme = useTheme(); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); - if (tenants?.length) { + if (tenants.length > 0) { return null; } @@ -66,8 +55,8 @@ function TenantLandingPageContent({ className }: Props) { isOpen={isCreateModalOpen} onClose={async (tenant?: TenantInfo) => { if (tenant) { - void mutate(); - window.location.assign(new URL(`/${tenant.id}`, window.location.origin).toString()); + appendTenant(tenant); + navigateTenant(tenant.id); } setIsCreateModalOpen(false); }} diff --git a/packages/console/src/cloud/pages/Main/index.tsx b/packages/console/src/cloud/pages/Main/index.tsx index 89fd97053..6a82374ef 100644 --- a/packages/console/src/cloud/pages/Main/index.tsx +++ b/packages/console/src/cloud/pages/Main/index.tsx @@ -1,93 +1,56 @@ import { useLogto } from '@logto/react'; import { conditional, yes } from '@silverhand/essentials'; -import { HTTPError } from 'ky'; -import { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect } from 'react'; import { useHref, useSearchParams } from 'react-router-dom'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; -import AppError from '@/components/AppError'; import AppLoading from '@/components/AppLoading'; -import SessionExpired from '@/components/SessionExpired'; import { searchKeys } from '@/consts'; import { TenantsContext } from '@/contexts/TenantsProvider'; import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data'; +import AutoCreateTenant from './AutoCreateTenant'; import Redirect from './Redirect'; import TenantLandingPage from './TenantLandingPage'; -function Protected() { +function Content() { const api = useCloudApi(); - const { tenants, setTenants, currentTenantId, navigate } = useContext(TenantsContext); - const { isOnboarding, isLoaded } = useUserOnboardingData(); - const [error, setError] = useState(); + const { tenants, resetTenants, currentTenantId, isInitComplete } = useContext(TenantsContext); + const { isOnboarding, isLoaded: isOnboardingDataLoaded } = useUserOnboardingData(); + // Load tenants from the cloud API for the first render. useEffect(() => { const loadTenants = async () => { - setError(undefined); - - try { - const data = await api.get('/api/tenants'); - setTenants(data); - } catch (error: unknown) { - setError(error instanceof Error ? error : new Error(String(error))); - } + const data = await api.get('/api/tenants'); + resetTenants(data); }; - if (!tenants) { + if (!isInitComplete) { void loadTenants(); } - }, [api, setTenants, tenants]); + }, [api, resetTenants, tenants, isInitComplete]); - useEffect(() => { - const createFirstTenant = async () => { - setError(undefined); - - try { - const newTenant = await api.post('/api/tenants', { body: {} }); // Use DB default value. - setTenants([newTenant]); - navigate(newTenant.id); - } catch (error: unknown) { - setError(error instanceof Error ? error : new Error(String(error))); - } - }; - - if (isLoaded && isOnboarding && tenants?.length === 0) { - void createFirstTenant(); - } - }, [api, isOnboarding, isLoaded, setTenants, tenants, navigate]); - - if (error) { - if (error instanceof HTTPError && error.response.status === 401) { - return ; - } - - return ; + if (!isInitComplete || !isOnboardingDataLoaded) { + return ; } - if (tenants) { - /** - * Redirect to the first tenant if the current tenant ID is not set or can not be found. - * - * `currentTenantId` can be empty string, so that Boolean is required and `??` is - * not applicable for current case. - */ - - // eslint-disable-next-line no-extra-boolean-cast - const toTenantId = Boolean(currentTenantId) ? currentTenantId : tenants[0]?.id; - if (toTenantId) { - return ; - } - - /** - * Will create a new tenant for new users that need go through onboarding process, - * but create tenant takes time, the screen will have a glance of landing page of empty tenant. - */ - if (isLoaded && !isOnboarding) { - return ; - } + /** + * Trigger a redirect when one of the following conditions is met: + * + * - If a current tenant ID has been set in the URL; or + * - If current tenant ID is not set, but there is at least one tenant available. + */ + if (currentTenantId || tenants[0]) { + return ; } - return ; + // A new user has just signed up and has no tenant, needs to create a new tenant. + if (isOnboarding) { + return ; + } + + // If user has completed onboarding and still has no tenant, redirect to a special landing page. + return ; } function Main() { @@ -110,7 +73,7 @@ function Main() { return ; } - return ; + return ; } export default Main; diff --git a/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.module.scss b/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.module.scss index 3f806ff46..be3b6ee14 100644 --- a/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.module.scss +++ b/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.module.scss @@ -112,6 +112,12 @@ $dropdown-item-height: 40px; } .createTenantButton { + all: unset; + /** + * `inline-size: stretch` is needed since button will have the used value `inline-size: fit-content` by default. + * @see {@link https://html.spec.whatwg.org/multipage/rendering.html#button-layout} + */ + inline-size: stretch; display: flex; align-items: center; padding: _.unit(2.5) _.unit(3) _.unit(2.5) _.unit(4); diff --git a/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.tsx b/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.tsx index a2dc7ac22..cc14843db 100644 --- a/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.tsx +++ b/packages/console/src/containers/AppContent/components/Topbar/TenantSelector/index.tsx @@ -1,16 +1,14 @@ import { adminTenantId } from '@logto/schemas'; import { type TenantInfo } from '@logto/schemas/models'; import classNames from 'classnames'; -import { useContext, useRef, useState, useEffect, useMemo } from 'react'; +import { useContext, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import KeyboardArrowDown from '@/assets/icons/keyboard-arrow-down.svg'; import PlusSign from '@/assets/icons/plus.svg'; import Tick from '@/assets/icons/tick.svg'; -import { useCloudSwr } from '@/cloud/hooks/use-cloud-swr'; import CreateTenantModal from '@/cloud/pages/Main/TenantLandingPage/TenantLandingPageContent/CreateTenantModal'; -import AppError from '@/components/AppError'; -import { maxFreeTenantNumbers } from '@/consts/tenants'; +import { maxFreeTenantNumbers } from '@/consts'; import { TenantsContext } from '@/contexts/TenantsProvider'; import Divider from '@/ds-components/Divider'; import Dropdown, { DropdownItem } from '@/ds-components/Dropdown'; @@ -20,39 +18,26 @@ import { onKeyDownHandler } from '@/utils/a11y'; import TenantEnvTag from './TenantEnvTag'; import * as styles from './index.module.scss'; -function TenantSelector() { +export default function TenantSelector() { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const { tenants, setTenants, currentTenantId } = useContext(TenantsContext); - const { data: availableTenants, mutate, error } = useCloudSwr('/api/tenants'); - - useEffect(() => { - if (availableTenants) { - setTenants(availableTenants); - } - }, [availableTenants, setTenants]); - - const currentTenantInfo = useMemo(() => { - return tenants?.find((tenant) => tenant.id === currentTenantId); - }, [currentTenantId, tenants]); + const { + tenants, + appendTenant, + currentTenant: currentTenantInfo, + currentTenantId, + } = useContext(TenantsContext); const isCreateButtonDisabled = useMemo( () => /** Should not block admin tenant owners from creating more than three tenants */ - tenants && - !tenants.some(({ id }) => id === adminTenantId) && - tenants.length >= maxFreeTenantNumbers, + !tenants.some(({ id }) => id === adminTenantId) && tenants.length >= maxFreeTenantNumbers, [tenants] ); - const anchorRef = useRef(null); const [showDropdown, setShowDropdown] = useState(false); const [showCreateTenantModal, setShowCreateTenantModal] = useState(false); - if (error) { - return ; - } - - if (!tenants?.length || !currentTenantInfo) { + if (tenants.length === 0 || !currentTenantInfo) { return null; } @@ -102,35 +87,29 @@ function TenantSelector() { ))} -
{ - if (isCreateButtonDisabled) { - return; - } setShowCreateTenantModal(true); }} onKeyDown={onKeyDownHandler(() => { - if (isCreateButtonDisabled) { - return; - } setShowCreateTenantModal(true); })} >
{t('cloud.tenant.create_tenant')}
-
+ { if (tenant) { - void mutate(); + appendTenant(tenant); window.location.assign(new URL(`/${tenant.id}`, window.location.origin).toString()); } setShowCreateTenantModal(false); @@ -139,5 +118,3 @@ function TenantSelector() { ); } - -export default TenantSelector; diff --git a/packages/console/src/containers/ErrorBoundary/index.tsx b/packages/console/src/containers/ErrorBoundary/index.tsx index be4845254..a053ddd52 100644 --- a/packages/console/src/containers/ErrorBoundary/index.tsx +++ b/packages/console/src/containers/ErrorBoundary/index.tsx @@ -3,10 +3,9 @@ import { HTTPError } from 'ky'; import type { ReactNode } from 'react'; import { Component } from 'react'; +import AppError from '@/components/AppError'; import SessionExpired from '@/components/SessionExpired'; -import AppError from '../../components/AppError'; - type Props = { children: ReactNode; }; @@ -15,6 +14,14 @@ type State = { error?: Error; }; +/** + * An error boundary that catches errors in its children. + * Note it uses several hooks and contexts: + * + * - Includes `useLogto()` (depending on ``) to provide a "Sign in again" button for session expired errors. + * - Includes `useTranslation()` to provide translations for the error messages. + * - includes `useTheme()` (depending on ``) to provide the local stored theme. + */ class ErrorBoundary extends Component { static getDerivedStateFromError(error: Error): State { return { error }; diff --git a/packages/console/src/contexts/TenantsProvider.tsx b/packages/console/src/contexts/TenantsProvider.tsx index b1b507e02..4838aadae 100644 --- a/packages/console/src/contexts/TenantsProvider.tsx +++ b/packages/console/src/contexts/TenantsProvider.tsx @@ -1,6 +1,6 @@ import { defaultManagementApi } from '@logto/schemas'; import { type TenantInfo, TenantTag } from '@logto/schemas/models'; -import { conditional, noop } from '@silverhand/essentials'; +import { conditionalArray, noop } from '@silverhand/essentials'; import type { ReactNode } from 'react'; import { useCallback, useMemo, createContext, useState } from 'react'; import type { NavigateOptions } from 'react-router-dom'; @@ -12,68 +12,116 @@ type Props = { children: ReactNode; }; +/** @see {@link TenantsProvider} for why `useSWR()` is not applicable for this context. */ type Tenants = { - tenants?: TenantInfo[]; - isSettle: boolean; - setTenants: (tenants: TenantInfo[]) => void; - setIsSettle: (isSettle: boolean) => void; + tenants: readonly TenantInfo[]; + /** Indicates if the tenants data is ready for the first render. */ + isInitComplete: boolean; + /** Reset tenants to the given value. It will overwrite the current tenants data and set `isInitComplete` to `true`. */ + resetTenants: (tenants: TenantInfo[]) => void; + /** Append a new tenant to the current tenants data. */ + appendTenant: (tenant: TenantInfo) => void; + /** Remove a tenant by ID from the current tenants data. */ + removeTenant: (tenantId: string) => void; + /** Update a tenant by ID if it exists in the current tenants data. */ + updateTenant: (tenantId: string, data: Partial) => void; + /** + * The current tenant ID that the URL is pointing to. It is navigated programmatically + * since there's [no easy way](https://stackoverflow.com/questions/34999976/detect-changes-on-the-url) + * to listen to the URL change without polling. + */ currentTenantId: string; + currentTenant?: TenantInfo; setCurrentTenantId: (tenantId: string) => void; - navigate: (tenantId: string, options?: NavigateOptions) => void; + navigateTenant: (tenantId: string, options?: NavigateOptions) => void; }; const { tenantId, indicator } = defaultManagementApi.resource; -const initialTenants = conditional( - !isCloud && [ - { id: tenantId, name: `tenant_${tenantId}`, tag: TenantTag.Development, indicator }, // Make `tag` value to be string type. - ] + +/** + * - For cloud, the initial tenants data is empty, and it will be fetched from the cloud API. + * - OSS has a fixed tenant with ID `default` and no cloud API to dynamically fetch tenants. + */ +const initialTenants = Object.freeze( + conditionalArray( + !isCloud && { id: tenantId, name: `tenant_${tenantId}`, tag: TenantTag.Development, indicator } + ) ); export const TenantsContext = createContext({ tenants: initialTenants, - setTenants: noop, - isSettle: false, - setIsSettle: noop, + isInitComplete: false, + resetTenants: noop, + appendTenant: noop, + removeTenant: noop, + updateTenant: noop, currentTenantId: '', setCurrentTenantId: noop, - navigate: noop, + navigateTenant: noop, }); +/** + * The global tenants context provider for all available tenants of the current users. + * It is used to manage the tenants information, including create, update, and delete; + * also for navigating between tenants. + * + * Note it is not practical to use `useSWR()` for tenants context, since fetching tenants + * requires authentication, and the authentication is managed by the `LogtoProvider` which + * depends and locates inside the `TenantsProvider`. Thus the fetching tenants action should + * be done by a component inside the `LogtoProvider`, which `useSWR()` cannot handle. + */ function TenantsProvider({ children }: Props) { const [tenants, setTenants] = useState(initialTenants); - const [isSettle, setIsSettle] = useState(false); + /** @see {@link initialTenants} */ + const [isInitComplete, setIsInitComplete] = useState(!isCloud); const [currentTenantId, setCurrentTenantId] = useState(getUserTenantId()); - const navigate = useCallback((tenantId: string, options?: NavigateOptions) => { - if (options?.replace) { - window.history.replaceState( - options.state ?? {}, - '', - new URL(`/${tenantId}`, window.location.origin).toString() - ); + const navigateTenant = useCallback((tenantId: string, options?: NavigateOptions) => { + const params = [ + options?.state ?? {}, + '', + new URL(`/${tenantId}`, window.location.origin).toString(), + ] satisfies Parameters; + if (options?.replace) { + window.history.replaceState(...params); return; } - window.history.pushState( - options?.state ?? {}, - '', - new URL(`/${tenantId}`, window.location.origin).toString() - ); + window.history.pushState(...params); setCurrentTenantId(tenantId); }, []); + const currentTenant = useMemo( + () => tenants.find((tenant) => tenant.id === currentTenantId), + [currentTenantId, tenants] + ); + const memorizedContext = useMemo( () => ({ tenants, - setTenants, - isSettle, - setIsSettle, + resetTenants: (tenants: TenantInfo[]) => { + setTenants(tenants); + setIsInitComplete(true); + }, + appendTenant: (tenant: TenantInfo) => { + setTenants((tenants) => [...tenants, tenant]); + }, + removeTenant: (tenantId: string) => { + setTenants((tenants) => tenants.filter((tenant) => tenant.id !== tenantId)); + }, + updateTenant: (tenantId: string, data: Partial) => { + setTenants((tenants) => + tenants.map((tenant) => (tenant.id === tenantId ? { ...tenant, ...data } : tenant)) + ); + }, + isInitComplete, currentTenantId, + currentTenant, setCurrentTenantId, - navigate, + navigateTenant, }), - [currentTenantId, isSettle, navigate, tenants] + [currentTenant, currentTenantId, isInitComplete, navigateTenant, tenants] ); return {children}; diff --git a/packages/console/src/onboarding/pages/Congrats/index.tsx b/packages/console/src/onboarding/pages/Congrats/index.tsx index 33d895820..eb87084e5 100644 --- a/packages/console/src/onboarding/pages/Congrats/index.tsx +++ b/packages/console/src/onboarding/pages/Congrats/index.tsx @@ -21,12 +21,12 @@ import * as styles from './index.module.scss'; function Congrats() { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { update } = useUserOnboardingData(); - const { navigate, currentTenantId } = useContext(TenantsContext); + const { navigateTenant, currentTenantId } = useContext(TenantsContext); const enterAdminConsole = () => { void update({ isOnboardingDone: true }); // Note: navigate to the admin console page directly instead of using the router - navigate(currentTenantId); + navigateTenant(currentTenantId); }; return ( diff --git a/packages/console/src/pages/TenantSettings/TenantBasicSettings/DeleteCard/index.tsx b/packages/console/src/pages/TenantSettings/TenantBasicSettings/DeleteCard/index.tsx index 70132135c..d981e4185 100644 --- a/packages/console/src/pages/TenantSettings/TenantBasicSettings/DeleteCard/index.tsx +++ b/packages/console/src/pages/TenantSettings/TenantBasicSettings/DeleteCard/index.tsx @@ -1,4 +1,4 @@ -import { adminTenantId, defaultTenantId } from '@logto/schemas'; +import { adminTenantId } from '@logto/schemas'; import { useTranslation } from 'react-i18next'; import FormCard from '@/components/FormCard'; @@ -25,7 +25,7 @@ function DeleteCard({ currentTenantId, onClick }: Props) {