"use client" import { dmSans125ClassName } from "@/lib/fonts" import { cn } from "@lib/utils" import { PLAN_DISPLAY_NAMES, useTokenUsage } from "@/hooks/use-token-usage" import { Dialog, DialogContent, DialogTrigger, DialogClose, } from "@ui/components/dialog" import { useCustomer } from "autumn-js/react" import { Check, X, LoaderIcon, Settings } from "lucide-react" import { useState } from "react" import { toast } from "sonner" function SectionTitle({ children }: { children: React.ReactNode }) { return (

{children}

) } function SettingsCard({ children }: { children: React.ReactNode }) { return (
{children}
) } function PlanComparisonCard({ name, price, period, description, credits, features, highlight, }: { name: string price: string period: string description: string credits: string features: string[] highlight: boolean }) { return (

{name}

{highlight && ( RECOMMENDED )}
{price} {period && ( {period} )}

{description}

{credits}

of usage included

) } export default function Billing() { const autumn = useCustomer() const [isUpgrading, setIsUpgrading] = useState(false) const [isCancelling, setIsCancelling] = useState(false) const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false) const { usdIncluded, usdSpent, planUsagePct, currentPlan, hasPaidPlan, isLoading: isCheckingStatus, daysRemaining, } = useTokenUsage(autumn) const formatUsd = (n: number) => n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, }) const planDisplayNames = PLAN_DISPLAY_NAMES const handleUpgrade = async () => { setIsUpgrading(true) try { const result = await autumn.attach({ planId: "api_pro", successUrl: `${window.location.origin}/settings#billing`, }) if (result?.paymentUrl) { window.open(result.paymentUrl, "_self") return } autumn.refetch?.() } catch (error) { console.error(error) toast.error("Failed to start checkout. Please try again.") } finally { setIsUpgrading(false) } } const cancellablePlanId = currentPlan === "pro" || currentPlan === "scale" ? (`api_${currentPlan}` as const) : null const handleCancelSubscription = async () => { if (!cancellablePlanId) return setIsCancelling(true) try { await autumn.updateSubscription({ planId: cancellablePlanId, cancelAction: "cancel_end_of_cycle", }) autumn.refetch?.() setIsCancelDialogOpen(false) toast.success( `Subscription cancelled. ${planDisplayNames[currentPlan]} features remain active until the end of your billing period.`, ) } catch (error) { console.error(error) toast.error("Failed to cancel subscription. Please try again.") } finally { setIsCancelling(false) } } return (
Billing & Subscription
{hasPaidPlan ? ( <>

{planDisplayNames[currentPlan]} plan

ACTIVE

Expanded memory with connections and more

Plan usage

{planUsagePct < 1 && planUsagePct > 0 ? "< 1" : Math.round(planUsagePct)} % used
80 ? "#ef4444" : "linear-gradient(to right, #4BA0FA 80%, #002757 100%)", }} title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} />

{daysRemaining !== null ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` : ""}

{cancellablePlanId && (

Cancel {planDisplayNames[currentPlan]}{" "} subscription?

You'll keep Pro features until the end of your current billing period {daysRemaining !== null ? ` (${daysRemaining} day${daysRemaining !== 1 ? "s" : ""} remaining)` : ""} . After that, your account will switch to the Free plan.

)}
) : ( <>

Free Plan

You are on basic plan

Plan usage

{planUsagePct < 1 && planUsagePct > 0 ? "< 1" : Math.round(planUsagePct)} % used

80 ? "#ef4444" : "#0054AD", }} title={`$${formatUsd(usdSpent)} of $${formatUsd(usdIncluded)} used`} />

{daysRemaining !== null ? `Resets in ${daysRemaining} day${daysRemaining !== 1 ? "s" : ""}` : ""}

)}
) }