← back to Govarbitrage
src/app/pricing/page.tsx
95 lines
import type { Metadata } from "next";
import { TIERS, TIER_ORDER } from "@/lib/tiers";
import { getCurrentTier } from "@/lib/current-user";
import UpgradeButton from "./UpgradeButton";
export const dynamic = "force-dynamic";
export const metadata: Metadata = {
title: "Pricing",
description:
"Explore GovArbitrage beta access and preview plans. Current listings and full money-math analysis are available on every plan. Checkout uses test or simulated payments.",
alternates: { canonical: "/pricing" },
openGraph: {
title: "Pricing — GovArbitrage",
description:
"Explore GovArbitrage beta access and preview plans. Current listings and full money-math analysis are available on every plan. Checkout uses test or simulated payments.",
url: "/pricing",
type: "website",
},
};
const pricingJsonLd = {
"@context": "https://schema.org",
"@type": "WebPage",
name: "GovArbitrage beta access and preview plans",
description: metadata.description,
};
export default async function PricingPage() {
const current = await getCurrentTier();
return (
<main className="mx-auto max-w-4xl space-y-6 p-5 pt-14 text-foreground">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(pricingJsonLd) }}
/>
<div className="text-center space-y-2">
<h1 className="text-3xl font-semibold tracking-tight">Explore government-surplus deals</h1>
<p className="text-base text-muted-foreground">
Browse current auction listings and full money-math analysis. Paid-plan
features and prices are previews during beta.
</p>
<p className="rounded-lg bg-warning/20 text-foreground text-sm px-4 py-3" data-testid="beta-notice">
Beta access: listing freshness, source access, and money-math analysis are
currently available on every plan. Daily newsletter access depends on
confirmed subscription, not plan. Checkout uses test or simulated payments;
no real charge is made.
</p>
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-3 mt-7">
{TIER_ORDER.map((key) => {
const t = TIERS[key];
const isCurrent = current === key;
return (
<div
key={key}
className="relative rounded-xl border bg-card text-card-foreground p-5"
data-testid={`plan-${key.toLowerCase()}`}
>
<div className="font-bold text-lg">{t.label}</div>
<div className="my-1.5">
<span className="text-4xl font-extrabold">${t.priceUsd}</span>
<span className="text-muted-foreground">{t.priceUsd > 0 ? "/mo" : ""}</span>
</div>
{t.priceUsd > 0 && <div className="text-xs text-muted-foreground">preview price</div>}
<div className="text-muted-foreground text-sm min-h-9">{t.blurb}</div>
<ul className="list-none p-0 my-3.5 space-y-1 text-sm leading-relaxed">
{t.features.map((f) => (
<li key={f}>
<span className="text-positive mr-1.5">✓</span>{f}
</li>
))}
</ul>
{t.priceUsd === 0 ? (
<div className={`py-2.5 font-bold ${isCurrent ? "text-positive" : "text-muted-foreground"}`}>
{isCurrent ? "✓ Your plan" : "Default plan"}
</div>
) : (
<UpgradeButton tier={key as "STANDARD" | "PREMIUM"} label={t.label} current={isCurrent} />
)}
</div>
);
})}
</div>
<p className="text-center text-muted-foreground text-xs leading-relaxed">
Estimates are heuristic and confidence-labeled — always verify comps before bidding.
Paid-plan features and prices are previews and may change before launch.
</p>
</main>
);
}