feat: locked-feature upgrade prompts route to billing + track upgrade interest (v0.81.0)

UpgradeDialog's CTA now sends users to Settings > Billing (with a feature-specific banner) instead of a generic support-ticket prefill, and fires a best-effort tracking beacon recording which feature triggered the click. New feature_upgrade_clicks table + Admin > Insights chart ("Most-requested locked features") gives admins visibility into which locked features actually drive upgrade interest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-24 14:12:12 +02:00
parent 1fe379bcdc
commit ce7741c0b6
14 changed files with 6392 additions and 17 deletions
+20 -9
View File
@@ -1,9 +1,8 @@
"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { Sparkles, Check } from "lucide-react";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
@@ -112,6 +111,21 @@ export function UpgradeDialog({
featureLabel: string;
}) {
const copy = FEATURE_COPY[featureKey];
const router = useRouter();
function handleUpgradeClick() {
// keepalive lets this best-effort beacon survive the navigation that
// follows immediately after — a plain fetch would otherwise risk being
// aborted mid-flight by the router.push below.
fetch("/api/v1/users/me/upgrade-interest", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ featureKey }),
keepalive: true,
}).catch(() => {});
onOpenChange(false);
router.push(`/settings/billing?upgrade=${encodeURIComponent(featureKey)}`);
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
@@ -139,12 +153,9 @@ export function UpgradeDialog({
Included on the Pro plan (4.99/mo).
</p>
<DialogFooter className="sm:justify-start">
<Link
href={`/support?upgrade=${encodeURIComponent(featureKey)}`}
className={cn(buttonVariants({ variant: "default" }))}
>
I&apos;m interested let us know
</Link>
<Button onClick={handleUpgradeClick}>
See Pro plans
</Button>
</DialogFooter>
</DialogContent>
</Dialog>