Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(console): avoid getSubscription call before authentication #6426

Merged
merged 1 commit into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions packages/console/src/containers/AppContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,11 @@
const { isLoading: isLoadingPreference } = useUserPreferences();
const { currentTenant } = useContext(TenantsContext);
const isTenantSuspended = isCloud && currentTenant?.isSuspended;
// TODO: @darcyYe remove this

Check warning on line 27 in packages/console/src/containers/AppContent/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/containers/AppContent/index.tsx#L27

[no-warning-comments] Unexpected 'todo' comment: '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<HTMLDivElement>(null);
const { scrollTop } = useScroll(scrollableContent.current);
Expand All @@ -49,12 +44,7 @@
<SubscriptionDataProvider
subscriptionData={{
...subscriptionDta,
logtoSkus,
currentSku,
currentSubscriptionQuota,
currentSubscriptionUsage,
currentSubscriptionScopeResourceUsage,
currentSubscriptionScopeRoleUsage,
...newSubscriptionData,
}}
>
<div className={styles.app}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const SubscriptionDataContext = createContext<FullContext>({
currentSubscriptionUsage: defaultSubscriptionUsage,
currentSubscriptionScopeResourceUsage: {},
currentSubscriptionScopeRoleUsage: {},
mutateSubscriptionQuotaAndUsages: noop,
/* ==== For new pricing model ==== */
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type NewSubscriptionSupplementContext = {
currentSubscriptionUsage: NewSubscriptionUsage;
currentSubscriptionScopeResourceUsage: NewSubscriptionScopeUsage;
currentSubscriptionScopeRoleUsage: NewSubscriptionScopeUsage;
mutateSubscriptionQuotaAndUsages: () => void;
};

export type NewSubscriptionContext = Omit<Context, 'subscriptionPlans' | 'currentPlan'> &
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { cond, condString } from '@silverhand/essentials';
import { useContext, useMemo } from 'react';
import { useCallback, useContext, useMemo } from 'react';

import {
defaultLogtoSku,
defaultTenantResponse,
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';
Expand All @@ -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 {
data: currentSubscriptionQuota,
isLoading: isSubscriptionQuotaLoading,
mutate: mutateSubscriptionQuota,
} = useNewSubscriptionQuota(condString(currentTenant?.id));

const {
scopeResourceUsage: { data: scopeResourceUsage, isLoading: isScopePerResourceUsageLoading },
scopeRoleUsage: { data: scopeRoleUsage, isLoading: isScopePerRoleUsageLoading },
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(
Expand All @@ -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 ?? {},
Expand Down
9 changes: 4 additions & 5 deletions packages/console/src/hooks/use-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@
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,
Expand Down Expand Up @@ -62,7 +61,7 @@

// This is what will happen when the user still has the legacy refresh token without
// organization scope. We should sign them out and redirect to the sign in page.
// TODO: This is a temporary solution to prevent the user from getting stuck in Console,

Check warning on line 64 in packages/console/src/hooks/use-api.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/console/src/hooks/use-api.ts#L64

[no-warning-comments] Unexpected 'todo' comment: 'TODO: This is a temporary solution to...'.
// which can be removed after all legacy refresh tokens are expired, i.e. after Jan 10th,
// 2024.
if (response.status === 403 && data.message === 'Insufficient permissions.') {
Expand Down Expand Up @@ -118,14 +117,14 @@
}: 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;
// Disable toast for specific error codes.
const toastDisabledErrorCodes = Array.isArray(hideErrorToast) ? hideErrorToast : undefined;

const { handleError } = useGlobalRequestErrorHandler(toastDisabledErrorCodes);
const { syncSubscriptionData } = useSubscribe();

const api = useMemo(
() =>
Expand Down Expand Up @@ -162,7 +161,7 @@
response.status >= 200 &&
response.status < 300
) {
syncSubscriptionData();
mutateSubscriptionQuotaAndUsages();
}
},
],
Expand All @@ -179,7 +178,7 @@
getOrganizationToken,
getAccessToken,
i18n.language,
syncSubscriptionData,
mutateSubscriptionQuotaAndUsages,
]
);

Expand Down
41 changes: 9 additions & 32 deletions packages/console/src/hooks/use-subscribe.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
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';

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 = {
Expand All @@ -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,
Expand Down Expand Up @@ -133,7 +109,9 @@ const useSubscribe = () => {
},
});

syncSubscriptionData();
mutateSubscriptionQuotaAndUsages();
onCurrentSubscriptionUpdated();

updateTenant(tenantId, {
planId: rest.planId,
subscription: rest,
Expand Down Expand Up @@ -177,7 +155,6 @@ const useSubscribe = () => {
isSubscribeLoading,
subscribe,
cancelSubscription,
syncSubscriptionData,
visitManagePaymentPage,
};
};
Expand Down
Loading