diff --git a/packages/console/src/components/PlanUsage/PlanUsageCard/index.module.scss b/packages/console/src/components/PlanUsage/PlanUsageCard/index.module.scss index db0b828e8..def6ece6a 100644 --- a/packages/console/src/components/PlanUsage/PlanUsageCard/index.module.scss +++ b/packages/console/src/components/PlanUsage/PlanUsageCard/index.module.scss @@ -24,7 +24,7 @@ color: var(--color-text); &.quotaExceeded { - color: var(--color-danger-default); + color: var(--color-error); } } diff --git a/packages/console/src/components/PlanUsage/PlanUsageCard/index.tsx b/packages/console/src/components/PlanUsage/PlanUsageCard/index.tsx index 7c38fc9ac..6e5c19f23 100644 --- a/packages/console/src/components/PlanUsage/PlanUsageCard/index.tsx +++ b/packages/console/src/components/PlanUsage/PlanUsageCard/index.tsx @@ -159,7 +159,10 @@ function PlanUsageCard({
= 1 && styles.quotaExceeded + typeof usagePercent === 'number' && + usagePercent >= 1 && + !isPaidTenant && + styles.quotaExceeded )} > logtoSkus.find(({ id }) => id === latestProPlanId), [logtoSkus]); + const { tokenLimit } = currentSubscriptionQuota; + + const tokenUsagePercent = useMemo(() => { + // Unlimited + if (tokenLimit === null) { + return 0; + } + + return periodicUsage.tokenLimit / tokenLimit; + }, [periodicUsage.tokenLimit, tokenLimit]); + + if ( + tokenUsagePercent < 0.9 || // Usage is less than 90% + isPaidPlan(planId, isEnterprisePlan) || // Add-on enabled + !proSku // Pro SKU not found + ) { + return null; + } + + const isExceeded = tokenUsagePercent >= 1; + + return ( + { + try { + setIsLoading(true); + await subscribe({ + skuId: proSku.id, + planId: proSku.id, + tenantId: currentTenantId, + callbackPage: subscriptionPage, + }); + setIsLoading(false); + } catch (error: unknown) { + setIsLoading(false); + + const [result, exceededSkuQuotaKeys] = await parseExceededSkuQuotaLimitError(error); + + if (result) { + await show({ + ModalContent: () => ( + + ), + title: 'subscription.not_eligible_modal.upgrade_title', + confirmButtonText: 'general.got_it', + confirmButtonType: 'primary', + isCancelButtonVisible: false, + }); + return; + } + + void toastResponseError(error); + } + }} + > + , + }} + > + {t(`subscription.token_usage_notification.${isExceeded ? 'exceeded' : 'close_to_limit'}`)} + + + ); +} + +export default TokenLimitExceededNotification; diff --git a/packages/console/src/pages/TenantSettings/Subscription/CurrentPlan/index.tsx b/packages/console/src/pages/TenantSettings/Subscription/CurrentPlan/index.tsx index 29066d2f5..f2a01bacf 100644 --- a/packages/console/src/pages/TenantSettings/Subscription/CurrentPlan/index.tsx +++ b/packages/console/src/pages/TenantSettings/Subscription/CurrentPlan/index.tsx @@ -13,6 +13,7 @@ import { isPaidPlan } from '@/utils/subscription'; import AddOnUsageChangesNotification from './AddOnUsageChangesNotification'; import MauLimitExceedNotification from './MauLimitExceededNotification'; import PaymentOverdueNotification from './PaymentOverdueNotification'; +import TokenLimitExceededNotification from './TokenLimitExceededNotification'; import styles from './index.module.scss'; type Props = { @@ -58,6 +59,10 @@ function CurrentPlan({ periodicUsage, usageAddOnSkus }: Props) { {isPaidPlan(planId, isEnterprisePlan) && !isEnterprisePlan && ( )} + diff --git a/packages/phrases/src/locales/en/translation/admin-console/subscription/index.ts b/packages/phrases/src/locales/en/translation/admin-console/subscription/index.ts index 488e033e5..7b0812f8a 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/subscription/index.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/subscription/index.ts @@ -69,6 +69,12 @@ const subscription = { subscription_check_timeout: 'Subscription check timed out. Please refresh later.', no_subscription: 'No subscription', usage, + token_usage_notification: { + exceeded: + 'You have exceeded your token usage limit. Users will not be able to access the Logto service properly. Please upgrade your plan to premium promptly to avoid any inconvenience.', + close_to_limit: + 'You almost reached your token usage limit. Logto will stop granting tokens when the limit is reached. Please upgrade your plan to premium to avoid any inconvenience.', + }, }; export default Object.freeze(subscription);