mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-28 15:56:39 +00:00
Communication improvements
This commit is contained in:
@@ -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" && (() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user