MicProtocol / apps /web /src /components /UpgradePrompt.tsx
Benaah's picture
Upload folder using huggingface_hub
fb12607 verified
Raw History Blame Contribute Delete
3.11 kB
"use client";
import React from "react";
import { useRouter } from "next/navigation";
import { Sparkles, X } from "lucide-react";
interface UpgradePromptProps {
/** Which plan the user needs to unlock the feature */
requiredPlan?: "Creator" | "Studio";
/** Short description of the feature the user tried to access */
feature?: string;
/** Optional; if set the prompt shows inline, otherwise it auto-hides after 8 s */
variant?: "banner" | "toast";
/** Called when the user dismisses the prompt */
onDismiss?: () => void;
}
/**
* A small upgrade prompt shown when a user tries to use a feature
* that requires an upgrade.
*/
export default function UpgradePrompt({
requiredPlan = "Creator",
feature = "this feature",
variant = "banner",
onDismiss,
}: UpgradePromptProps) {
const router = useRouter();
const [visible, setVisible] = React.useState(true);
// Auto-dismiss after 8 seconds for the toast variant
React.useEffect(() => {
if (variant !== "toast") return;
const id = setTimeout(() => {
setVisible(false);
onDismiss?.();
}, 8000);
return () => clearTimeout(id);
}, [variant, onDismiss]);
if (!visible) return null;
return (
<div
className="upgrade-prompt"
style={{
display: "flex",
alignItems: "center",
gap: "var(--space-3)",
padding: "var(--space-3) var(--space-4)",
borderRadius: "var(--radius-md)",
background: "linear-gradient(135deg, rgba(108, 92, 231, 0.12), rgba(245, 158, 11, 0.08))",
border: "1px solid rgba(108, 92, 231, 0.2)",
fontSize: "var(--text-sm)",
position: variant === "toast" ? "fixed" : "relative",
bottom: variant === "toast" ? "var(--space-6)" : undefined,
right: variant === "toast" ? "var(--space-6)" : undefined,
zIndex: variant === "toast" ? 1000 : undefined,
maxWidth: variant === "toast" ? 400 : undefined,
boxShadow: variant === "toast" ? "var(--shadow-lg)" : undefined,
}}
role="status"
aria-live="polite"
>
<Sparkles size={18} color="var(--color-primary)" style={{ flexShrink: 0 }} />
<div style={{ flex: 1 }}>
<strong>{feature}</strong> requires the <strong>{requiredPlan}</strong> plan.
{" "}
<button
onClick={() => router.push("/settings/billing")}
className="btn btn-primary"
style={{
fontSize: "var(--text-xs)",
padding: "2px 12px",
height: "auto",
display: "inline-flex",
marginLeft: "var(--space-2)",
}}
>
Upgrade
</button>
</div>
{onDismiss && (
<button
onClick={() => {
setVisible(false);
onDismiss();
}}
style={{
background: "none",
border: "none",
cursor: "pointer",
color: "var(--text-tertiary)",
padding: 2,
}}
aria-label="Dismiss"
>
<X size={14} />
</button>
)}
</div>
);
}