From eca4501af8c93a9ca737df8419bd94c19a8722ae Mon Sep 17 00:00:00 2001 From: simeng-li Date: Fri, 9 Aug 2024 16:33:19 +0800 Subject: [PATCH] refactor(console): avoid getSubscription call before authentication (#6426) avoid getSubscription call before authentication --- .../src/containers/AppContent/index.tsx | 20 ++------ .../SubscriptionDataProvider/index.tsx | 1 + .../SubscriptionDataProvider/types.ts | 1 + .../use-new-subscription-data.ts | 50 ++++++++++++++++--- packages/console/src/hooks/use-api.ts | 9 ++-- packages/console/src/hooks/use-subscribe.ts | 41 ++++----------- 6 files changed, 62 insertions(+), 60 deletions(-) diff --git a/packages/console/src/containers/AppContent/index.tsx b/packages/console/src/containers/AppContent/index.tsx index a5c741748..d6ece9696 100644 --- a/packages/console/src/containers/AppContent/index.tsx +++ b/packages/console/src/containers/AppContent/index.tsx @@ -24,16 +24,11 @@ export default function AppContent() { const { isLoading: isLoadingPreference } = useUserPreferences(); const { currentTenant } = useContext(TenantsContext); const isTenantSuspended = isCloud && currentTenant?.isSuspended; + // TODO: @darcyYe remove this const { isLoading: isLoadingSubscriptionData, ...subscriptionDta } = useSubscriptionData(); - const { - isLoading: isLoadingNewSubscriptionData, - logtoSkus, - currentSku, - currentSubscriptionQuota, - currentSubscriptionUsage, - currentSubscriptionScopeResourceUsage, - currentSubscriptionScopeRoleUsage, - } = useNewSubscriptionData(); + + const { isLoading: isLoadingNewSubscriptionData, ...newSubscriptionData } = + useNewSubscriptionData(); const scrollableContent = useRef(null); const { scrollTop } = useScroll(scrollableContent.current); @@ -49,12 +44,7 @@ export default function AppContent() {
diff --git a/packages/console/src/contexts/SubscriptionDataProvider/index.tsx b/packages/console/src/contexts/SubscriptionDataProvider/index.tsx index fea1c98e8..f0c83c637 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/index.tsx +++ b/packages/console/src/contexts/SubscriptionDataProvider/index.tsx @@ -32,6 +32,7 @@ export const SubscriptionDataContext = createContext({ currentSubscriptionUsage: defaultSubscriptionUsage, currentSubscriptionScopeResourceUsage: {}, currentSubscriptionScopeRoleUsage: {}, + mutateSubscriptionQuotaAndUsages: noop, /* ==== For new pricing model ==== */ }); diff --git a/packages/console/src/contexts/SubscriptionDataProvider/types.ts b/packages/console/src/contexts/SubscriptionDataProvider/types.ts index 5bbc83528..6cb185880 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/types.ts +++ b/packages/console/src/contexts/SubscriptionDataProvider/types.ts @@ -23,6 +23,7 @@ type NewSubscriptionSupplementContext = { currentSubscriptionUsage: NewSubscriptionUsage; currentSubscriptionScopeResourceUsage: NewSubscriptionScopeUsage; currentSubscriptionScopeRoleUsage: NewSubscriptionScopeUsage; + mutateSubscriptionQuotaAndUsages: () => void; }; export type NewSubscriptionContext = Omit & diff --git a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts index 5e7791007..3c5a023f3 100644 --- a/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts +++ b/packages/console/src/contexts/SubscriptionDataProvider/use-new-subscription-data.ts @@ -1,5 +1,5 @@ import { cond, condString } from '@silverhand/essentials'; -import { useContext, useMemo } from 'react'; +import { useCallback, useContext, useMemo } from 'react'; import { defaultLogtoSku, @@ -7,7 +7,7 @@ import { defaultSubscriptionQuota, defaultSubscriptionUsage, } from '@/consts'; -import { isCloud } from '@/consts/env'; +import { isCloud, isDevFeaturesEnabled } from '@/consts/env'; import { TenantsContext } from '@/contexts/TenantsProvider'; import useLogtoSkus from '@/hooks/use-logto-skus'; import useNewSubscriptionQuota from '@/hooks/use-new-subscription-quota'; @@ -26,15 +26,48 @@ const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolea isLoading: isSubscriptionLoading, mutate: mutateSubscription, } = useSubscription(condString(currentTenant?.id)); - const { data: currentSubscriptionQuota, isLoading: isSubscriptionQuotaLoading } = - useNewSubscriptionQuota(condString(currentTenant?.id)); - const { data: currentSubscriptionUsage, isLoading: isSubscriptionUsageLoading } = - useNewSubscriptionUsage(condString(currentTenant?.id)); + const { - scopeResourceUsage: { data: scopeResourceUsage, isLoading: isScopePerResourceUsageLoading }, - scopeRoleUsage: { data: scopeRoleUsage, isLoading: isScopePerRoleUsageLoading }, + data: currentSubscriptionQuota, + isLoading: isSubscriptionQuotaLoading, + mutate: mutateSubscriptionQuota, + } = useNewSubscriptionQuota(condString(currentTenant?.id)); + + const { + data: currentSubscriptionUsage, + isLoading: isSubscriptionUsageLoading, + mutate: mutateSubscriptionUsage, + } = useNewSubscriptionUsage(condString(currentTenant?.id)); + + const { + scopeResourceUsage: { + data: scopeResourceUsage, + isLoading: isScopePerResourceUsageLoading, + mutate: mutateScopeResourceUsage, + }, + scopeRoleUsage: { + data: scopeRoleUsage, + isLoading: isScopePerRoleUsageLoading, + mutate: mutateScopeRoleUsage, + }, } = useNewSubscriptionScopeUsage(condString(currentTenant?.id)); + const mutateSubscriptionQuotaAndUsages = useCallback(() => { + if (!isDevFeaturesEnabled) { + return; + } + + void mutateSubscriptionQuota(); + void mutateSubscriptionUsage(); + void mutateScopeResourceUsage(); + void mutateScopeRoleUsage(); + }, [ + mutateScopeResourceUsage, + mutateScopeRoleUsage, + mutateSubscriptionQuota, + mutateSubscriptionUsage, + ]); + const logtoSkus = useMemo(() => cond(isCloud && fetchedLogtoSkus) ?? [], [fetchedLogtoSkus]); const currentSku = useMemo( @@ -54,6 +87,7 @@ const useNewSubscriptionData: () => NewSubscriptionContext & { isLoading: boolea currentSku, currentSubscription: currentSubscription ?? defaultTenantResponse.subscription, onCurrentSubscriptionUpdated: mutateSubscription, + mutateSubscriptionQuotaAndUsages, currentSubscriptionQuota: currentSubscriptionQuota ?? defaultSubscriptionQuota, currentSubscriptionUsage: currentSubscriptionUsage ?? defaultSubscriptionUsage, currentSubscriptionScopeResourceUsage: scopeResourceUsage ?? {}, diff --git a/packages/console/src/hooks/use-api.ts b/packages/console/src/hooks/use-api.ts index 9325d43ff..b46df1724 100644 --- a/packages/console/src/hooks/use-api.ts +++ b/packages/console/src/hooks/use-api.ts @@ -22,12 +22,11 @@ import { useTranslation } from 'react-i18next'; import { requestTimeout } from '@/consts'; import { isCloud, isDevFeaturesEnabled } from '@/consts/env'; import { AppDataContext } from '@/contexts/AppDataProvider'; +import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import { TenantsContext } from '@/contexts/TenantsProvider'; import { useConfirmModal } from '@/hooks/use-confirm-modal'; import useRedirectUri from '@/hooks/use-redirect-uri'; -import useSubscribe from './use-subscribe'; - export class RequestError extends Error { constructor( public readonly status: number, @@ -118,6 +117,7 @@ export const useStaticApi = ({ }: StaticApiProps): KyInstance => { const { isAuthenticated, getAccessToken, getOrganizationToken } = useLogto(); const { i18n } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const { mutateSubscriptionQuotaAndUsages } = useContext(SubscriptionDataContext); // Disable global error handling if `hideErrorToast` is true. const disableGlobalErrorHandling = hideErrorToast === true; @@ -125,7 +125,6 @@ export const useStaticApi = ({ const toastDisabledErrorCodes = Array.isArray(hideErrorToast) ? hideErrorToast : undefined; const { handleError } = useGlobalRequestErrorHandler(toastDisabledErrorCodes); - const { syncSubscriptionData } = useSubscribe(); const api = useMemo( () => @@ -162,7 +161,7 @@ export const useStaticApi = ({ response.status >= 200 && response.status < 300 ) { - syncSubscriptionData(); + mutateSubscriptionQuotaAndUsages(); } }, ], @@ -179,7 +178,7 @@ export const useStaticApi = ({ getOrganizationToken, getAccessToken, i18n.language, - syncSubscriptionData, + mutateSubscriptionQuotaAndUsages, ] ); diff --git a/packages/console/src/hooks/use-subscribe.ts b/packages/console/src/hooks/use-subscribe.ts index 501728262..b2d611d69 100644 --- a/packages/console/src/hooks/use-subscribe.ts +++ b/packages/console/src/hooks/use-subscribe.ts @@ -1,7 +1,7 @@ import { ReservedPlanId } from '@logto/schemas'; import dayjs from 'dayjs'; import { nanoid } from 'nanoid'; -import { useCallback, useContext, useState } from 'react'; +import { useContext, useState } from 'react'; import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; @@ -9,14 +9,11 @@ import { toastResponseError, useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { type CreateTenantData } from '@/components/CreateTenantModal/types'; import { isDevFeaturesEnabled } from '@/consts/env'; import { checkoutStateQueryKey } from '@/consts/subscriptions'; +import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider'; import { GlobalRoute, TenantsContext } from '@/contexts/TenantsProvider'; import { createLocalCheckoutSession } from '@/utils/checkout'; import { dropLeadingSlash } from '@/utils/url'; -import useNewSubscriptionQuota from './use-new-subscription-quota'; -import useNewSubscriptionScopeUsage from './use-new-subscription-scopes-usage'; -import useNewSubscriptionUsage from './use-new-subscription-usage'; -import useSubscription from './use-subscription'; import useTenantPathname from './use-tenant-pathname'; type SubscribeProps = { @@ -36,34 +33,13 @@ type SubscribeProps = { const useSubscribe = () => { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const cloudApi = useCloudApi({ hideErrorToast: true }); - const { updateTenant, currentTenantId } = useContext(TenantsContext); + const { updateTenant } = useContext(TenantsContext); + const { mutateSubscriptionQuotaAndUsages, onCurrentSubscriptionUpdated } = + useContext(SubscriptionDataContext); + const { getUrl } = useTenantPathname(); const [isSubscribeLoading, setIsSubscribeLoading] = useState(false); - const { mutate: mutateSubscription } = useSubscription(currentTenantId); - const { mutate: mutateSubscriptionQuota } = useNewSubscriptionQuota(currentTenantId); - const { mutate: mutateSubscriptionUsage } = useNewSubscriptionUsage(currentTenantId); - const { - scopeResourceUsage: { mutate: mutateScopeResourceUsage }, - scopeRoleUsage: { mutate: mutateScopeRoleUsage }, - } = useNewSubscriptionScopeUsage(currentTenantId); - - const syncSubscriptionData = useCallback(() => { - void mutateSubscription(); - if (isDevFeaturesEnabled) { - void mutateSubscriptionQuota(); - void mutateSubscriptionUsage(); - void mutateScopeResourceUsage(); - void mutateScopeRoleUsage(); - } - }, [ - mutateScopeResourceUsage, - mutateScopeRoleUsage, - mutateSubscription, - mutateSubscriptionQuota, - mutateSubscriptionUsage, - ]); - const subscribe = async ({ skuId, planId, @@ -133,7 +109,9 @@ const useSubscribe = () => { }, }); - syncSubscriptionData(); + mutateSubscriptionQuotaAndUsages(); + onCurrentSubscriptionUpdated(); + updateTenant(tenantId, { planId: rest.planId, subscription: rest, @@ -177,7 +155,6 @@ const useSubscribe = () => { isSubscribeLoading, subscribe, cancelSubscription, - syncSubscriptionData, visitManagePaymentPage, }; };