diff --git a/apps/web/components/header.tsx b/apps/web/components/header.tsx index bee5d90f..14853f71 100644 --- a/apps/web/components/header.tsx +++ b/apps/web/components/header.tsx @@ -15,7 +15,6 @@ import { LifeBuoy, LayoutGrid, ChevronRight, - Zap, } from "lucide-react" import { Button } from "@ui/components/button" import { cn } from "@lib/utils" @@ -360,7 +359,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) { className="gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium text-white/85 hover:bg-white/[0.06] focus:bg-white/[0.06] focus:text-white cursor-pointer" > - + Upgrade @@ -445,7 +444,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) { )} > - + Upgrade diff --git a/apps/web/components/settings/billing.tsx b/apps/web/components/settings/billing.tsx index 4836ee03..5961b81a 100644 --- a/apps/web/components/settings/billing.tsx +++ b/apps/web/components/settings/billing.tsx @@ -15,6 +15,7 @@ import { useCustomer } from "autumn-js/react" import { Check, Coins, + ArrowRight, ExternalLink, LoaderIcon, Plus, @@ -65,13 +66,17 @@ type AutoTopupsResponse = | { ok: false; reason: string; message?: string } type PlanCardDefinition = { - id: "free" | "pro" + id: "free" | "pro" | "scale" | "enterprise" name: string price: string period: string credits: string + productId: "api_free" | "api_pro" | "api_scale" | "api_enterprise" description: string + includesFrom?: string features: string[] + highlight?: boolean + isContactSales?: boolean } const PLAN_CARDS: PlanCardDefinition[] = [ @@ -81,6 +86,7 @@ const PLAN_CARDS: PlanCardDefinition[] = [ price: "$0", period: "", credits: "$5", + productId: "api_free", description: "Try supermemory with no commitment", features: [ "Pay-as-you-go after $5 runs out", @@ -94,6 +100,7 @@ const PLAN_CARDS: PlanCardDefinition[] = [ price: "$19", period: "/mo", credits: "$20", + productId: "api_pro", description: "For people building with AI memory", features: [ "Auto top-up when balance runs low", @@ -103,6 +110,48 @@ const PLAN_CARDS: PlanCardDefinition[] = [ }, ] +const ADVANCED_PLAN_CARDS: PlanCardDefinition[] = [ + { + id: "scale", + name: "Scale", + price: "$399", + period: "/mo", + credits: "$600", + productId: "api_scale", + description: "For teams and production workloads", + includesFrom: "Pro", + features: [ + "Auto top-up & spend caps", + "Gmail, S3 & Web Crawler connectors", + "Dedicated support", + ], + highlight: true, + }, + { + id: "enterprise", + name: "Enterprise", + price: "Custom", + period: "", + credits: "Unlimited", + productId: "api_enterprise", + description: "Custom deployments with dedicated engineering", + includesFrom: "Scale", + features: [ + "Custom metering & billing", + "Custom integrations & SSO", + "Forward-deployed engineer", + ], + isContactSales: true, + }, +] + +const PLAN_RANK: Record = { + free: 0, + pro: 1, + scale: 2, + enterprise: 3, +} + function SectionTitle({ children, aside, @@ -157,10 +206,24 @@ function PlanCard({ className={cn( "relative flex min-h-[416px] flex-col overflow-hidden rounded-[14px] border p-5", "shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7)]", - "border-white/[0.08] bg-[#14161A]", + plan.highlight + ? "border-[#0B65C9] bg-[#14161A] shadow-[inset_2.42px_2.42px_4.263px_rgba(11,15,21,0.7),0_0_0_1px_rgba(11,101,201,0.72)]" + : "border-white/[0.08] bg-[#14161A]", )} > -

+ {plan.highlight ? ( +

+ + Most popular + +
+ ) : null} +

{plan.name}

@@ -187,25 +250,68 @@ function PlanCard({ {plan.description}

-
- -
-

- {plan.credits} -

-

- of usage included -

+ {plan.isContactSales ? null : ( +
+ +
+

+ {plan.credits} +

+

+ of usage included +

+
-
+ )} -
    + {plan.includesFrom ? ( +
    +
    + + Everything in {plan.includesFrom}, plus + +
    +
    + ) : null} + +
      {plan.features.map((feature) => (
    • - + {feature}
    • ))} @@ -349,6 +455,7 @@ export default function Billing() { const [isCancelling, setIsCancelling] = useState(false) const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false) const [isCreditsDialogOpen, setIsCreditsDialogOpen] = useState(false) + const [showOtherPlans, setShowOtherPlans] = useState(false) const [topUpAmount, setTopUpAmount] = useState(25) const [customTopUpAmount, setCustomTopUpAmount] = useState("") const [topUpPendingAmount, setTopUpPendingAmount] = useState( @@ -446,11 +553,11 @@ export default function Billing() { const planDisplayNames = PLAN_DISPLAY_NAMES - const handleUpgrade = async () => { + const handleUpgrade = async (planId: "api_pro" | "api_scale") => { setIsUpgrading(true) try { const result = await autumn.attach({ - planId: "api_pro", + planId, successUrl: `${window.location.origin}/settings#billing`, }) if ((result as { paymentUrl?: string })?.paymentUrl) { @@ -604,6 +711,10 @@ export default function Billing() { } const getPlanCardAction = (plan: PlanCardDefinition) => { + const disabled = isUpgrading || isCheckingStatus || autumn.isLoading + const isCurrentPlan = plan.id === currentPlan + const isIncludedPlan = PLAN_RANK[currentPlan] > PLAN_RANK[plan.id] + if (plan.id === "free") { return ( ) } @@ -864,6 +994,31 @@ export default function Billing() { /> ))}
    + {showOtherPlans ? ( +
    + {ADVANCED_PLAN_CARDS.map((plan) => ( + + ))} +
    + ) : ( +
    + +
    + )}