From e2ac6e6d4d4de66f68ec88b5ba3671bf318a87d0 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 10 Feb 2026 17:04:22 -0800 Subject: [PATCH] Communication improvements --- .../settings/(private)/billing/page.tsx | 128 ++++++++++-------- 1 file changed, 74 insertions(+), 54 deletions(-) diff --git a/src/app/[orgId]/settings/(private)/billing/page.tsx b/src/app/[orgId]/settings/(private)/billing/page.tsx index 63c65288..ad5c3260 100644 --- a/src/app/[orgId]/settings/(private)/billing/page.tsx +++ b/src/app/[orgId]/settings/(private)/billing/page.tsx @@ -48,6 +48,7 @@ import { useTranslations } from "use-intl"; import Link from "next/link"; import { Tier } from "@server/types/Tiers"; import { + freeLimitSet, tier1LimitSet, tier2LimitSet, tier3LimitSet @@ -69,7 +70,7 @@ const planOptions: PlanOption[] = [ { id: "starter", name: "Starter", - price: "Starter", + price: "Free", tierType: null }, { @@ -103,9 +104,15 @@ const planOptions: PlanOption[] = [ // Tier limits mapping derived from limit sets const tierLimits: Record< - Tier, + Tier | "starter", { users: number; sites: number; domains: number; remoteNodes: number } > = { + starter: { + users: freeLimitSet[FeatureId.USERS]?.value ?? 0, + sites: freeLimitSet[FeatureId.SITES]?.value ?? 0, + domains: freeLimitSet[FeatureId.DOMAINS]?.value ?? 0, + remoteNodes: freeLimitSet[FeatureId.REMOTE_EXIT_NODES]?.value ?? 0 + }, tier1: { users: tier1LimitSet[FeatureId.USERS]?.value ?? 0, sites: tier1LimitSet[FeatureId.SITES]?.value ?? 0, @@ -171,7 +178,7 @@ export default function BillingPage() { // Confirmation dialog state const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [pendingTier, setPendingTier] = useState<{ - tier: Tier; + tier: Tier | "starter"; action: "upgrade" | "downgrade"; planName: string; price: string; @@ -390,7 +397,10 @@ export default function BillingPage() { pendingTier.action === "upgrade" || pendingTier.action === "downgrade" ) { - if (hasSubscription) { + // If downgrading to starter (free tier), go to Stripe portal + if (pendingTier.tier === "starter") { + handleModifySubscription(); + } else if (hasSubscription) { handleChangeTier(pendingTier.tier); } else { handleStartSubscription(pendingTier.tier); @@ -402,7 +412,7 @@ export default function BillingPage() { }; const showTierConfirmation = ( - tier: Tier, + tier: Tier | "starter", action: "upgrade" | "downgrade", planName: string, price: string @@ -469,6 +479,14 @@ export default function BillingPage() { plan.name, plan.price + (" " + plan.priceDetail || "") ); + } else if (plan.id === "starter") { + // Show confirmation for downgrading to starter (free tier) + showTierConfirmation( + "starter", + "downgrade", + plan.name, + plan.price + ); } else { handleModifySubscription(); } @@ -536,7 +554,7 @@ export default function BillingPage() { }; // Check if downgrading to a tier would violate current usage limits - const checkLimitViolations = (targetTier: Tier): Array<{ + const checkLimitViolations = (targetTier: Tier | "starter"): Array<{ feature: string; currentUsage: number; newLimit: number; @@ -855,56 +873,58 @@ export default function BillingPage() { -
-

- {t("billingPlanIncludes") || - "Plan Includes:"} -

-
-
- - - { - tierLimits[pendingTier.tier] - .users - }{" "} - {t("billingUsers") || "Users"} - -
-
- - - { - tierLimits[pendingTier.tier] - .sites - }{" "} - {t("billingSites") || "Sites"} - -
-
- - - { - tierLimits[pendingTier.tier] - .domains - }{" "} - {t("billingDomains") || - "Domains"} - -
-
- - - { - tierLimits[pendingTier.tier] - .remoteNodes - }{" "} - {t("billingRemoteNodes") || - "Remote Nodes"} - + {tierLimits[pendingTier.tier] && ( +
+

+ {t("billingPlanIncludes") || + "Plan Includes:"} +

+
+
+ + + { + tierLimits[pendingTier.tier] + .users + }{" "} + {t("billingUsers") || "Users"} + +
+
+ + + { + tierLimits[pendingTier.tier] + .sites + }{" "} + {t("billingSites") || "Sites"} + +
+
+ + + { + tierLimits[pendingTier.tier] + .domains + }{" "} + {t("billingDomains") || + "Domains"} + +
+
+ + + { + tierLimits[pendingTier.tier] + .remoteNodes + }{" "} + {t("billingRemoteNodes") || + "Remote Nodes"} + +
-
+ )} {/* Warning for limit violations when downgrading */} {pendingTier.action === "downgrade" && (() => {