mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-23 21:36:37 +00:00
Fix to use the limits file
This commit is contained in:
@@ -34,11 +34,7 @@ import {
|
|||||||
CredenzaTitle
|
CredenzaTitle
|
||||||
} from "@app/components/Credenza";
|
} from "@app/components/Credenza";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import {
|
import { CreditCard, ExternalLink, Check } from "lucide-react";
|
||||||
CreditCard,
|
|
||||||
ExternalLink,
|
|
||||||
Check
|
|
||||||
} from "lucide-react";
|
|
||||||
import {
|
import {
|
||||||
GetOrgSubscriptionResponse,
|
GetOrgSubscriptionResponse,
|
||||||
GetOrgUsageResponse
|
GetOrgUsageResponse
|
||||||
@@ -46,43 +42,45 @@ import {
|
|||||||
import { useTranslations } from "use-intl";
|
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 { tier1LimitSet, tier2LimitSet, tier3LimitSet } from "@server/lib/billing/limitSet";
|
||||||
|
import { FeatureId } from "@server/lib/billing/features";
|
||||||
|
|
||||||
// Plan tier definitions matching the mockup
|
// Plan tier definitions matching the mockup
|
||||||
type PlanId = "free" | "homelab" | "team" | "business" | "enterprise";
|
type PlanId = "starter" | "home" | "team" | "business" | "enterprise";
|
||||||
|
|
||||||
interface PlanOption {
|
type PlanOption = {
|
||||||
id: PlanId;
|
id: PlanId;
|
||||||
name: string;
|
name: string;
|
||||||
price: string;
|
price: string;
|
||||||
priceDetail?: string;
|
priceDetail?: string;
|
||||||
tierType: Tier | null;
|
tierType: Tier | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
const planOptions: PlanOption[] = [
|
const planOptions: PlanOption[] = [
|
||||||
{
|
{
|
||||||
id: "free",
|
id: "starter",
|
||||||
name: "Free",
|
name: "Starter",
|
||||||
price: "Free",
|
price: "Starter",
|
||||||
tierType: null
|
tierType: null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "homelab",
|
id: "home",
|
||||||
name: "Homelab",
|
name: "Home",
|
||||||
price: "$15",
|
price: "$12.50",
|
||||||
priceDetail: "/ month",
|
priceDetail: "/ month",
|
||||||
tierType: "tier1"
|
tierType: "tier1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "team",
|
id: "team",
|
||||||
name: "Team",
|
name: "Team",
|
||||||
price: "$5",
|
price: "$4",
|
||||||
priceDetail: "per user / month",
|
priceDetail: "per user / month",
|
||||||
tierType: "tier2"
|
tierType: "tier2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "business",
|
id: "business",
|
||||||
name: "Business",
|
name: "Business",
|
||||||
price: "$10",
|
price: "$9",
|
||||||
priceDetail: "per user / month",
|
priceDetail: "per user / month",
|
||||||
tierType: "tier3"
|
tierType: "tier3"
|
||||||
},
|
},
|
||||||
@@ -94,6 +92,34 @@ const planOptions: PlanOption[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Tier limits mapping derived from limit sets
|
||||||
|
const tierLimits: Record<Tier, { users: number; sites: number; domains: number; remoteNodes: number }> = {
|
||||||
|
tier1: {
|
||||||
|
users: tier1LimitSet[FeatureId.USERS]?.value ?? 0,
|
||||||
|
sites: tier1LimitSet[FeatureId.SITES]?.value ?? 0,
|
||||||
|
domains: tier1LimitSet[FeatureId.DOMAINS]?.value ?? 0,
|
||||||
|
remoteNodes: tier1LimitSet[FeatureId.REMOTE_EXIT_NODES]?.value ?? 0
|
||||||
|
},
|
||||||
|
tier2: {
|
||||||
|
users: tier2LimitSet[FeatureId.USERS]?.value ?? 0,
|
||||||
|
sites: tier2LimitSet[FeatureId.SITES]?.value ?? 0,
|
||||||
|
domains: tier2LimitSet[FeatureId.DOMAINS]?.value ?? 0,
|
||||||
|
remoteNodes: tier2LimitSet[FeatureId.REMOTE_EXIT_NODES]?.value ?? 0
|
||||||
|
},
|
||||||
|
tier3: {
|
||||||
|
users: tier3LimitSet[FeatureId.USERS]?.value ?? 0,
|
||||||
|
sites: tier3LimitSet[FeatureId.SITES]?.value ?? 0,
|
||||||
|
domains: tier3LimitSet[FeatureId.DOMAINS]?.value ?? 0,
|
||||||
|
remoteNodes: tier3LimitSet[FeatureId.REMOTE_EXIT_NODES]?.value ?? 0
|
||||||
|
},
|
||||||
|
enterprise: {
|
||||||
|
users: 0, // Custom for enterprise
|
||||||
|
sites: 0, // Custom for enterprise
|
||||||
|
domains: 0, // Custom for enterprise
|
||||||
|
remoteNodes: 0 // Custom for enterprise
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default function BillingPage() {
|
export default function BillingPage() {
|
||||||
const { org } = useOrgContext();
|
const { org } = useOrgContext();
|
||||||
const envContext = useEnvContext();
|
const envContext = useEnvContext();
|
||||||
@@ -122,9 +148,7 @@ export default function BillingPage() {
|
|||||||
|
|
||||||
const [hasSubscription, setHasSubscription] = useState(false);
|
const [hasSubscription, setHasSubscription] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [currentTier, setCurrentTier] = useState<
|
const [currentTier, setCurrentTier] = useState<Tier | null>(null);
|
||||||
Tier | null
|
|
||||||
>(null);
|
|
||||||
|
|
||||||
// Usage IDs
|
// Usage IDs
|
||||||
const SITES = "sites";
|
const SITES = "sites";
|
||||||
@@ -135,7 +159,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;
|
||||||
action: "upgrade" | "downgrade";
|
action: "upgrade" | "downgrade";
|
||||||
planName: string;
|
planName: string;
|
||||||
price: string;
|
price: string;
|
||||||
@@ -161,9 +185,7 @@ export default function BillingPage() {
|
|||||||
setTierSubscription(tierSub || null);
|
setTierSubscription(tierSub || null);
|
||||||
|
|
||||||
if (tierSub?.subscription) {
|
if (tierSub?.subscription) {
|
||||||
setCurrentTier(
|
setCurrentTier(tierSub.subscription.type as Tier);
|
||||||
tierSub.subscription.type as Tier
|
|
||||||
);
|
|
||||||
setHasSubscription(
|
setHasSubscription(
|
||||||
tierSub.subscription.status === "active"
|
tierSub.subscription.status === "active"
|
||||||
);
|
);
|
||||||
@@ -207,9 +229,7 @@ export default function BillingPage() {
|
|||||||
fetchUsage();
|
fetchUsage();
|
||||||
}, [org.org.orgId]);
|
}, [org.org.orgId]);
|
||||||
|
|
||||||
const handleStartSubscription = async (
|
const handleStartSubscription = async (tier: Tier) => {
|
||||||
tier: Tier
|
|
||||||
) => {
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await api.post<AxiosResponse<string>>(
|
const response = await api.post<AxiosResponse<string>>(
|
||||||
@@ -323,9 +343,9 @@ export default function BillingPage() {
|
|||||||
|
|
||||||
// Get current plan ID from tier
|
// Get current plan ID from tier
|
||||||
const getCurrentPlanId = (): PlanId => {
|
const getCurrentPlanId = (): PlanId => {
|
||||||
if (!hasSubscription || !currentTier) return "free";
|
if (!hasSubscription || !currentTier) return "starter";
|
||||||
const plan = planOptions.find((p) => p.tierType === currentTier);
|
const plan = planOptions.find((p) => p.tierType === currentTier);
|
||||||
return plan?.id || "free";
|
return plan?.id || "starter";
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentPlanId = getCurrentPlanId();
|
const currentPlanId = getCurrentPlanId();
|
||||||
@@ -342,8 +362,8 @@ export default function BillingPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (plan.id === currentPlanId) {
|
if (plan.id === currentPlanId) {
|
||||||
// If it's the free plan (free with no subscription), show as current but disabled
|
// If it's the starter plan (starter with no subscription), show as current but disabled
|
||||||
if (plan.id === "free" && !hasSubscription) {
|
if (plan.id === "starter" && !hasSubscription) {
|
||||||
return {
|
return {
|
||||||
label: "Current Plan",
|
label: "Current Plan",
|
||||||
action: () => {},
|
action: () => {},
|
||||||
@@ -418,7 +438,10 @@ export default function BillingPage() {
|
|||||||
// Calculate current usage cost for display
|
// Calculate current usage cost for display
|
||||||
const getUserCount = () => getUsageValue(USERS);
|
const getUserCount = () => getUsageValue(USERS);
|
||||||
const getPricePerUser = () => {
|
const getPricePerUser = () => {
|
||||||
console.log("Calculating price per user, tierSubscription:", tierSubscription);
|
console.log(
|
||||||
|
"Calculating price per user, tierSubscription:",
|
||||||
|
tierSubscription
|
||||||
|
);
|
||||||
if (!tierSubscription?.items) return 0;
|
if (!tierSubscription?.items) return 0;
|
||||||
|
|
||||||
// Find the subscription item for USERS feature
|
// Find the subscription item for USERS feature
|
||||||
|
|||||||
Reference in New Issue
Block a user