From c37d3da7e15b8283ee5f0c0a03751f42f17f3b82 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Tue, 10 Feb 2026 21:33:05 -0800 Subject: [PATCH] show required tier in paid features alert --- messages/en-US.json | 6 +++ src/components/PaidFeaturesAlert.tsx | 59 ++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/messages/en-US.json b/messages/en-US.json index 32f04f0c..685c37cd 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1963,6 +1963,12 @@ "orgAuthNoAccount": "Don't have an account?", "subscriptionRequiredToUse": "A subscription is required to use this feature.", "mustUpgradeToUse": "You must upgrade your subscription to use this feature.", + "subscriptionRequiredTierToUse": "This feature requires {tier} or higher.", + "upgradeToTierToUse": "Upgrade to {tier} or higher to use this feature.", + "subscriptionTierTier1": "Home", + "subscriptionTierTier2": "Team", + "subscriptionTierTier3": "Business", + "subscriptionTierEnterprise": "Enterprise", "idpDisabled": "Identity providers are disabled.", "orgAuthPageDisabled": "Organization auth page is disabled.", "domainRestartedDescription": "Domain verification restarted successfully", diff --git a/src/components/PaidFeaturesAlert.tsx b/src/components/PaidFeaturesAlert.tsx index 437463a7..dfa01fc4 100644 --- a/src/components/PaidFeaturesAlert.tsx +++ b/src/components/PaidFeaturesAlert.tsx @@ -3,18 +3,55 @@ import { Card, CardContent } from "@app/components/ui/card"; import { build } from "@server/build"; import { usePaidStatus } from "@app/hooks/usePaidStatus"; -import { ExternalLink, KeyRound, Sparkles } from "lucide-react"; +import { ExternalLink, KeyRound } from "lucide-react"; import { useTranslations } from "next-intl"; import Link from "next/link"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { Tier } from "@server/types/Tiers"; +const TIER_ORDER: Tier[] = ["tier1", "tier2", "tier3", "enterprise"]; + +const TIER_TRANSLATION_KEYS: Record = { + tier1: "subscriptionTierTier1", + tier2: "subscriptionTierTier2", + tier3: "subscriptionTierTier3", + enterprise: "subscriptionTierEnterprise" +}; + +function getRequiredTier(tiers: Tier[]): Tier | null { + if (tiers.length === 0) return null; + let min: Tier | null = null; + for (const tier of tiers) { + const idx = TIER_ORDER.indexOf(tier); + if (idx === -1) continue; + if (min === null || TIER_ORDER.indexOf(min) > idx) { + min = tier; + } + } + return min; +} + const bannerClassName = "mb-6 border-purple-500/30 bg-linear-to-br from-purple-500/10 via-background to-background overflow-hidden"; const bannerContentClassName = "py-3 px-4"; const bannerRowClassName = "flex items-center gap-2.5 text-sm text-muted-foreground"; const bannerIconClassName = "size-4 shrink-0 text-purple-500"; +const PRICING_URL = "https://pangolin.net/pricing"; + +function tierLinkRenderer(chunks: React.ReactNode) { + return ( + + {chunks} + + + ); +} type Props = { tiers: Tier[]; @@ -22,8 +59,10 @@ type Props = { export function PaidFeaturesAlert({ tiers }: Props) { const t = useTranslations(); - const { hasSaasSubscription, hasEnterpriseLicense, isActive } = usePaidStatus(); + const { hasSaasSubscription, hasEnterpriseLicense, isActive, subscriptionTier } = usePaidStatus(); const { env } = useEnvContext(); + const requiredTier = getRequiredTier(tiers); + const requiredTierName = requiredTier ? t(TIER_TRANSLATION_KEYS[requiredTier]) : null; if (env.flags.disableEnterpriseFeatures) { return null; @@ -36,7 +75,21 @@ export function PaidFeaturesAlert({ tiers }: Props) {
- {isActive ? t("mustUpgradeToUse") : t("subscriptionRequiredToUse")} + + {requiredTierName + ? isActive + ? t.rich("upgradeToTierToUse", { + tier: requiredTierName, + tierLink: tierLinkRenderer + }) + : t.rich("subscriptionRequiredTierToUse", { + tier: requiredTierName, + tierLink: tierLinkRenderer + }) + : isActive + ? t("mustUpgradeToUse") + : t("subscriptionRequiredToUse")} +