mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
fix(console): manual update subscription data when add/delete resources (#6360)
* fix(console): add post response hook to update subscription info for useApi hook * refactor: wrap sync subscription data method
This commit is contained in:
parent
4a324d68c2
commit
6c256f9c73
4 changed files with 55 additions and 22 deletions
|
@ -20,12 +20,13 @@ import { toast } from 'react-hot-toast';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { requestTimeout } from '@/consts';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
|
||||
import { AppDataContext } from '@/contexts/AppDataProvider';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import { useConfirmModal } from '@/hooks/use-confirm-modal';
|
||||
import useRedirectUri from '@/hooks/use-redirect-uri';
|
||||
|
||||
import { useConfirmModal } from './use-confirm-modal';
|
||||
import useRedirectUri from './use-redirect-uri';
|
||||
import useSubscribe from './use-subscribe';
|
||||
|
||||
export class RequestError extends Error {
|
||||
constructor(
|
||||
|
@ -124,6 +125,7 @@ export const useStaticApi = ({
|
|||
const toastDisabledErrorCodes = Array.isArray(hideErrorToast) ? hideErrorToast : undefined;
|
||||
|
||||
const { handleError } = useGlobalRequestErrorHandler(toastDisabledErrorCodes);
|
||||
const { syncSubscriptionData } = useSubscribe();
|
||||
|
||||
const api = useMemo(
|
||||
() =>
|
||||
|
@ -150,10 +152,25 @@ export const useStaticApi = ({
|
|||
}
|
||||
},
|
||||
],
|
||||
afterResponse: [
|
||||
async (request, _options, response) => {
|
||||
if (
|
||||
isCloud &&
|
||||
isDevFeaturesEnabled &&
|
||||
['POST', 'PUT', 'DELETE'].includes(request.method) &&
|
||||
response.status >= 200 &&
|
||||
response.status < 300
|
||||
) {
|
||||
syncSubscriptionData();
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
[
|
||||
prefixUrl,
|
||||
timeout,
|
||||
signal,
|
||||
disableGlobalErrorHandling,
|
||||
handleError,
|
||||
isAuthenticated,
|
||||
|
@ -161,8 +178,7 @@ export const useStaticApi = ({
|
|||
getOrganizationToken,
|
||||
getAccessToken,
|
||||
i18n.language,
|
||||
timeout,
|
||||
signal,
|
||||
syncSubscriptionData,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ReservedPlanId } from '@logto/schemas';
|
||||
import dayjs from 'dayjs';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useContext, useState } from 'react';
|
||||
import { useCallback, useContext, useState } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -13,6 +13,10 @@ 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 = {
|
||||
|
@ -32,10 +36,34 @@ type SubscribeProps = {
|
|||
const useSubscribe = () => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const cloudApi = useCloudApi({ hideErrorToast: true });
|
||||
const { updateTenant } = useContext(TenantsContext);
|
||||
const { updateTenant, currentTenantId } = useContext(TenantsContext);
|
||||
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,
|
||||
|
@ -104,6 +132,8 @@ const useSubscribe = () => {
|
|||
tenantId,
|
||||
},
|
||||
});
|
||||
|
||||
syncSubscriptionData();
|
||||
updateTenant(tenantId, {
|
||||
planId: rest.planId,
|
||||
subscription: rest,
|
||||
|
@ -147,6 +177,7 @@ const useSubscribe = () => {
|
|||
isSubscribeLoading,
|
||||
subscribe,
|
||||
cancelSubscription,
|
||||
syncSubscriptionData,
|
||||
visitManagePaymentPage,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,13 +10,11 @@ import PlanName from '@/components/PlanName';
|
|||
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import Button from '@/ds-components/Button';
|
||||
import FormField from '@/ds-components/FormField';
|
||||
import ModalLayout from '@/ds-components/ModalLayout';
|
||||
import TextInput from '@/ds-components/TextInput';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useNewSubscriptionScopeUsage from '@/hooks/use-new-subscription-scopes-usage';
|
||||
import modalStyles from '@/scss/modal.module.scss';
|
||||
import { trySubmitSafe } from '@/utils/form';
|
||||
import { hasReachedQuotaLimit, hasReachedSubscriptionQuotaLimit } from '@/utils/quota';
|
||||
|
@ -37,10 +35,6 @@ function CreatePermissionModal({ resourceId, totalResourceCount, onClose }: Prop
|
|||
currentSubscriptionQuota,
|
||||
currentSubscriptionScopeResourceUsage,
|
||||
} = useContext(SubscriptionDataContext);
|
||||
const { currentTenantId } = useContext(TenantsContext);
|
||||
const {
|
||||
scopeResourceUsage: { mutate: mutateScopeResourceUsage },
|
||||
} = useNewSubscriptionScopeUsage(currentTenantId);
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
const {
|
||||
|
@ -61,7 +55,6 @@ function CreatePermissionModal({ resourceId, totalResourceCount, onClose }: Prop
|
|||
.post(`api/resources/${resourceId}/scopes`, { json: formData })
|
||||
.json<Scope>();
|
||||
|
||||
void mutateScopeResourceUsage();
|
||||
onClose(createdScope);
|
||||
})
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Resource } from '@logto/schemas';
|
|||
import { isManagementApi, Theme } from '@logto/schemas';
|
||||
import { conditionalArray } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
import { useEffect, useState, useContext } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Outlet, useLocation, useParams } from 'react-router-dom';
|
||||
|
@ -19,13 +19,11 @@ import DetailsPageHeader, { type MenuItem } from '@/components/DetailsPage/Detai
|
|||
import Drawer from '@/components/Drawer';
|
||||
import PageMeta from '@/components/PageMeta';
|
||||
import { ApiResourceDetailsTabs } from '@/consts/page-tabs';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
|
||||
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
||||
import useNewSubscriptionScopeUsage from '@/hooks/use-new-subscription-scopes-usage';
|
||||
import useTenantPathname from '@/hooks/use-tenant-pathname';
|
||||
import useTheme from '@/hooks/use-theme';
|
||||
|
||||
|
@ -43,10 +41,6 @@ const icons = {
|
|||
function ApiResourceDetails() {
|
||||
const { pathname } = useLocation();
|
||||
const { id, guideId } = useParams();
|
||||
const { currentTenantId } = useContext(TenantsContext);
|
||||
const {
|
||||
scopeResourceUsage: { mutate: mutateScopeResourceUsage },
|
||||
} = useNewSubscriptionScopeUsage(currentTenantId);
|
||||
const { navigate, match } = useTenantPathname();
|
||||
const { getDocumentationUrl } = useDocumentationUrl();
|
||||
const isGuideView = !!id && !!guideId && match(`/api-resources/${id}/guide/${guideId}`);
|
||||
|
@ -81,7 +75,6 @@ function ApiResourceDetails() {
|
|||
|
||||
try {
|
||||
await api.delete(`api/resources/${data.id}`);
|
||||
void mutateScopeResourceUsage();
|
||||
toast.success(t('api_resource_details.api_resource_deleted', { name: data.name }));
|
||||
navigate(`/api-resources`);
|
||||
} finally {
|
||||
|
|
Loading…
Reference in a new issue