"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { Check, Loader2, CreditCard, ExternalLink } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent } from "@/components/ui/card"; import { cn, formatPrice } from "@/lib/utils"; import { PLAN_ORDER, PLANS, type PlanKey } from "@/lib/billing/plans"; import type { BillingInterval } from "@/lib/billing/catalog"; import { startStripeCheckoutAction, startPaypalCheckoutAction, openStripePortalAction, cancelSubscriptionAction, } from "@/app/(app)/billing/actions"; interface SubInfo { provider: string; status: string; cancelAtPeriodEnd: boolean | null; periodEnd: string | null; } export function BillingClient({ currentPlan, subscription, stripeConfigured, paypalConfigured, }: { currentPlan: PlanKey; subscription: SubInfo | null; stripeConfigured: boolean; paypalConfigured: boolean; }) { const router = useRouter(); const [interval, setInterval] = useState("month"); const [busy, setBusy] = useState(null); async function go(action: () => Promise<{ ok: boolean; url?: string; error?: string }>, tag: string) { setBusy(tag); const res = await action(); if (res.ok && res.url) { window.location.href = res.url; return; } setBusy(null); if (res.ok) { toast.success("Done"); router.refresh(); } else { toast.error(res.error ?? "Something went wrong"); } } return (
{subscription && currentPlan !== "free" && (
{PLANS[currentPlan].name} plan {subscription.cancelAtPeriodEnd ? "Cancels at period end" : subscription.status} {subscription.provider}
{subscription.periodEnd && (

{subscription.cancelAtPeriodEnd ? "Access until" : "Renews"}{" "} {new Date(subscription.periodEnd).toLocaleDateString()}

)}
{subscription.provider === "stripe" && ( )} {!subscription.cancelAtPeriodEnd && ( )}
)}
{PLAN_ORDER.map((key) => { const plan = PLANS[key]; const isCurrent = key === currentPlan; const price = interval === "year" ? plan.priceYearly : plan.priceMonthly; return ( {plan.highlight && ( Most popular )}

{plan.name}

{plan.tagline}

{formatPrice(price)} /{interval === "year" ? "yr" : "mo"}
{isCurrent ? ( ) : key === "free" ? ( ) : (
{stripeConfigured && ( )} {paypalConfigured && ( )} {!stripeConfigured && !paypalConfigured && (

Billing not configured

)}
)}
    {plan.bullets.slice(0, 5).map((b) => (
  • {b}
  • ))}
); })}
); } function IntervalToggle({ interval, onChange, }: { interval: BillingInterval; onChange: (i: BillingInterval) => void; }) { return (
{(["month", "year"] as const).map((i) => ( ))}
); }