Communication improvements

This commit is contained in:
Owen
2026-02-10 17:04:22 -08:00
committed by Owen Schwartz
parent 7bfe9d4eef
commit 07d26790b2

View File

@@ -48,6 +48,7 @@ import { useTranslations } from "use-intl";
import Link from "next/link"; import Link from "next/link";
import { Tier } from "@server/types/Tiers"; import { Tier } from "@server/types/Tiers";
import { import {
freeLimitSet,
tier1LimitSet, tier1LimitSet,
tier2LimitSet, tier2LimitSet,
tier3LimitSet tier3LimitSet
@@ -69,7 +70,7 @@ const planOptions: PlanOption[] = [
{ {
id: "starter", id: "starter",
name: "Starter", name: "Starter",
price: "Starter", price: "Free",
tierType: null tierType: null
}, },
{ {
@@ -103,9 +104,15 @@ const planOptions: PlanOption[] = [
// Tier limits mapping derived from limit sets // Tier limits mapping derived from limit sets
const tierLimits: Record< const tierLimits: Record<
Tier, Tier | "starter",
{ users: number; sites: number; domains: number; remoteNodes: number } { 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: { tier1: {
users: tier1LimitSet[FeatureId.USERS]?.value ?? 0, users: tier1LimitSet[FeatureId.USERS]?.value ?? 0,
sites: tier1LimitSet[FeatureId.SITES]?.value ?? 0, sites: tier1LimitSet[FeatureId.SITES]?.value ?? 0,
@@ -171,7 +178,7 @@ export default function BillingPage() {
// Confirmation dialog state // Confirmation dialog state
const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [pendingTier, setPendingTier] = useState<{ const [pendingTier, setPendingTier] = useState<{
tier: Tier; tier: Tier | "starter";
action: "upgrade" | "downgrade"; action: "upgrade" | "downgrade";
planName: string; planName: string;
price: string; price: string;
@@ -390,7 +397,10 @@ export default function BillingPage() {
pendingTier.action === "upgrade" || pendingTier.action === "upgrade" ||
pendingTier.action === "downgrade" 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); handleChangeTier(pendingTier.tier);
} else { } else {
handleStartSubscription(pendingTier.tier); handleStartSubscription(pendingTier.tier);
@@ -402,7 +412,7 @@ export default function BillingPage() {
}; };
const showTierConfirmation = ( const showTierConfirmation = (
tier: Tier, tier: Tier | "starter",
action: "upgrade" | "downgrade", action: "upgrade" | "downgrade",
planName: string, planName: string,
price: string price: string
@@ -469,6 +479,14 @@ export default function BillingPage() {
plan.name, plan.name,
plan.price + (" " + plan.priceDetail || "") 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 { } else {
handleModifySubscription(); handleModifySubscription();
} }
@@ -536,7 +554,7 @@ export default function BillingPage() {
}; };
// Check if downgrading to a tier would violate current usage limits // Check if downgrading to a tier would violate current usage limits
const checkLimitViolations = (targetTier: Tier): Array<{ const checkLimitViolations = (targetTier: Tier | "starter"): Array<{
feature: string; feature: string;
currentUsage: number; currentUsage: number;
newLimit: number; newLimit: number;
@@ -855,56 +873,58 @@ export default function BillingPage() {
</div> </div>
</div> </div>
<div> {tierLimits[pendingTier.tier] && (
<h4 className="font-semibold mb-3"> <div>
{t("billingPlanIncludes") || <h4 className="font-semibold mb-3">
"Plan Includes:"} {t("billingPlanIncludes") ||
</h4> "Plan Includes:"}
<div className="space-y-2"> </h4>
<div className="flex items-center gap-2"> <div className="space-y-2">
<Check className="h-4 w-4 text-green-600" /> <div className="flex items-center gap-2">
<span> <Check className="h-4 w-4 text-green-600" />
{ <span>
tierLimits[pendingTier.tier] {
.users tierLimits[pendingTier.tier]
}{" "} .users
{t("billingUsers") || "Users"} }{" "}
</span> {t("billingUsers") || "Users"}
</div> </span>
<div className="flex items-center gap-2"> </div>
<Check className="h-4 w-4 text-green-600" /> <div className="flex items-center gap-2">
<span> <Check className="h-4 w-4 text-green-600" />
{ <span>
tierLimits[pendingTier.tier] {
.sites tierLimits[pendingTier.tier]
}{" "} .sites
{t("billingSites") || "Sites"} }{" "}
</span> {t("billingSites") || "Sites"}
</div> </span>
<div className="flex items-center gap-2"> </div>
<Check className="h-4 w-4 text-green-600" /> <div className="flex items-center gap-2">
<span> <Check className="h-4 w-4 text-green-600" />
{ <span>
tierLimits[pendingTier.tier] {
.domains tierLimits[pendingTier.tier]
}{" "} .domains
{t("billingDomains") || }{" "}
"Domains"} {t("billingDomains") ||
</span> "Domains"}
</div> </span>
<div className="flex items-center gap-2"> </div>
<Check className="h-4 w-4 text-green-600" /> <div className="flex items-center gap-2">
<span> <Check className="h-4 w-4 text-green-600" />
{ <span>
tierLimits[pendingTier.tier] {
.remoteNodes tierLimits[pendingTier.tier]
}{" "} .remoteNodes
{t("billingRemoteNodes") || }{" "}
"Remote Nodes"} {t("billingRemoteNodes") ||
</span> "Remote Nodes"}
</span>
</div>
</div> </div>
</div> </div>
</div> )}
{/* Warning for limit violations when downgrading */} {/* Warning for limit violations when downgrading */}
{pendingTier.action === "downgrade" && (() => { {pendingTier.action === "downgrade" && (() => {