diff --git a/messages/en-US.json b/messages/en-US.json index 6c76d8a2..f442635e 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1541,6 +1541,10 @@ "billingProcessing": "Processing...", "billingConfirmUpgradeButton": "Confirm Upgrade", "billingConfirmDowngradeButton": "Confirm Downgrade", + "billingLimitViolationWarning": "Usage Exceeds New Plan Limits", + "billingLimitViolationDescription": "Your current usage exceeds the limits of this plan. After downgrading, all actions will be disabled until you reduce usage within the new limits. Please review the features below that are currently over the limits. Limits in violation:", + "billingFeatureLossWarning": "Feature Availability Notice", + "billingFeatureLossDescription": "By downgrading, features not available in the new plan will be automatically disabled. Some settings and configurations may be lost. Please review the pricing matrix to understand which features will no longer be available.", "signUpTerms": { "IAgreeToThe": "I agree to the", "termsOfService": "terms of service", diff --git a/src/app/[orgId]/settings/(private)/billing/page.tsx b/src/app/[orgId]/settings/(private)/billing/page.tsx index 36bd8911..63c65288 100644 --- a/src/app/[orgId]/settings/(private)/billing/page.tsx +++ b/src/app/[orgId]/settings/(private)/billing/page.tsx @@ -34,7 +34,12 @@ import { CredenzaTitle } from "@app/components/Credenza"; import { cn } from "@app/lib/cn"; -import { CreditCard, ExternalLink, Check } from "lucide-react"; +import { CreditCard, ExternalLink, Check, AlertTriangle } from "lucide-react"; +import { + Alert, + AlertTitle, + AlertDescription +} from "@app/components/ui/alert"; import { GetOrgSubscriptionResponse, GetOrgUsageResponse @@ -530,6 +535,63 @@ export default function BillingPage() { return licenseSubscription.items.length; }; + // Check if downgrading to a tier would violate current usage limits + const checkLimitViolations = (targetTier: Tier): Array<{ + feature: string; + currentUsage: number; + newLimit: number; + }> => { + const violations: Array<{ + feature: string; + currentUsage: number; + newLimit: number; + }> = []; + + const limits = tierLimits[targetTier]; + + // Check users + const usersUsage = getUsageValue(USERS); + if (limits.users > 0 && usersUsage > limits.users) { + violations.push({ + feature: "Users", + currentUsage: usersUsage, + newLimit: limits.users + }); + } + + // Check sites + const sitesUsage = getUsageValue(SITES); + if (limits.sites > 0 && sitesUsage > limits.sites) { + violations.push({ + feature: "Sites", + currentUsage: sitesUsage, + newLimit: limits.sites + }); + } + + // Check domains + const domainsUsage = getUsageValue(DOMAINS); + if (limits.domains > 0 && domainsUsage > limits.domains) { + violations.push({ + feature: "Domains", + currentUsage: domainsUsage, + newLimit: limits.domains + }); + } + + // Check remote nodes + const remoteNodesUsage = getUsageValue(REMOTE_EXIT_NODES); + if (limits.remoteNodes > 0 && remoteNodesUsage > limits.remoteNodes) { + violations.push({ + feature: "Remote Exit Nodes", + currentUsage: remoteNodesUsage, + newLimit: limits.remoteNodes + }); + } + + return violations; + }; + if (subscriptionLoading) { return (
@@ -843,6 +905,48 @@ export default function BillingPage() {
+ + {/* Warning for limit violations when downgrading */} + {pendingTier.action === "downgrade" && (() => { + const violations = checkLimitViolations(pendingTier.tier); + if (violations.length > 0) { + return ( + + + + {t("billingLimitViolationWarning") || "Usage Exceeds New Plan Limits"} + + +

+ {t("billingLimitViolationDescription") || "Your current usage exceeds the limits of this plan. The following features will be disabled until you reduce usage:"} +

+
    + {violations.map((violation, index) => ( +
  • + {violation.feature}: + Currently using {violation.currentUsage}, new limit is {violation.newLimit} +
  • + ))} +
+
+
+ ); + } + return null; + })()} + + {/* Warning for feature loss when downgrading */} + {pendingTier.action === "downgrade" && ( + + + + {t("billingFeatureLossWarning") || "Feature Availability Notice"} + + + {t("billingFeatureLossDescription") || "By downgrading, features not available in the new plan will be automatically disabled. Some settings and configurations may be lost. Please review the pricing matrix to understand which features will no longer be available."} + + + )} )}