2f3ba14093
Admins can now disable specific AI features per tier from Admin > Tier Limits — new feature_flags table (feature x tier -> enabled, defaulting to true so adding a new gated feature never needs a backfill). Covers recipe variations, drink pairing, and meal pairing to start. When disabled for a user's tier, the button stays visible (with a small lock badge) but opens an upgrade dialog instead of running; the API route rejects the call server-side either way (requireFeatureEnabled, re-reads tier from the DB rather than trusting the session's cache, same rationale as checkAndIncrementTierLimit). The upgrade dialog is informational only — no Stripe checkout exists yet (STRIPE_PLAN.md is still just a plan) — its CTA links to /support prefilled as an upgrade-interest suggestion. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { Sparkles } from "lucide-react";
|
|
import { buttonVariants } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
} from "@/components/ui/dialog";
|
|
|
|
export function UpgradeDialog({
|
|
open,
|
|
onOpenChange,
|
|
featureKey,
|
|
featureLabel,
|
|
}: {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
featureKey: string;
|
|
featureLabel: string;
|
|
}) {
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="max-w-sm">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<Sparkles className="h-5 w-5 text-primary" />
|
|
A Pro feature
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
{featureLabel} is available on the Pro plan (€4.99/mo). Free accounts don't include it.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<DialogFooter className="sm:justify-start">
|
|
<Link
|
|
href={`/support?upgrade=${encodeURIComponent(featureKey)}`}
|
|
className={cn(buttonVariants({ variant: "default" }))}
|
|
>
|
|
I'm interested — let us know
|
|
</Link>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|