generated from fahricansecer/boilerplate-fe
Some checks failed
UI Deploy (Next-Auth Support) 🎨 / build-and-deploy (push) Has been cancelled
252 lines
8.9 KiB
TypeScript
252 lines
8.9 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { motion } from "framer-motion";
|
||
import {
|
||
Check,
|
||
X,
|
||
Zap,
|
||
Crown,
|
||
Rocket,
|
||
Sparkles,
|
||
ArrowRight,
|
||
} from "lucide-react";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const plans = [
|
||
{
|
||
id: "free",
|
||
name: "Free",
|
||
icon: Sparkles,
|
||
monthlyPrice: 0,
|
||
yearlyPrice: 0,
|
||
credits: 3,
|
||
description: "AI video üretimini keşfet",
|
||
color: "emerald",
|
||
gradient: "from-emerald-500/15 to-emerald-600/5",
|
||
borderActive: "border-emerald-500/30",
|
||
buttonClass: "btn-ghost",
|
||
buttonLabel: "Mevcut Plan",
|
||
features: [
|
||
{ label: "3 kredi / ay", included: true },
|
||
{ label: "720p video kalitesi", included: true },
|
||
{ label: "Max 30 saniye", included: true },
|
||
{ label: "5 proje limiti", included: true },
|
||
{ label: "Temel şablonlar", included: true },
|
||
{ label: "Öncelikli kuyruk", included: false },
|
||
{ label: "Marka kaldırma", included: false },
|
||
{ label: "API erişimi", included: false },
|
||
],
|
||
},
|
||
{
|
||
id: "pro",
|
||
name: "Pro",
|
||
icon: Zap,
|
||
monthlyPrice: 19,
|
||
yearlyPrice: 190,
|
||
credits: 50,
|
||
description: "İçerik üreticileri için güçlü araçlar",
|
||
color: "violet",
|
||
gradient: "from-violet-500/20 to-violet-600/8",
|
||
borderActive: "border-violet-500/40",
|
||
buttonClass: "btn-primary",
|
||
buttonLabel: "Pro'ya Yükselt",
|
||
recommended: true,
|
||
features: [
|
||
{ label: "50 kredi / ay", included: true },
|
||
{ label: "1080p video kalitesi", included: true },
|
||
{ label: "Max 120 saniye", included: true },
|
||
{ label: "50 proje limiti", included: true },
|
||
{ label: "Tüm şablonlar", included: true },
|
||
{ label: "Öncelikli kuyruk", included: true },
|
||
{ label: "Marka kaldırma", included: true },
|
||
{ label: "API erişimi", included: false },
|
||
],
|
||
},
|
||
{
|
||
id: "business",
|
||
name: "Business",
|
||
icon: Crown,
|
||
monthlyPrice: 49,
|
||
yearlyPrice: 490,
|
||
credits: -1,
|
||
description: "Ajanslar ve profesyonel ekipler",
|
||
color: "cyan",
|
||
gradient: "from-cyan-500/15 to-cyan-600/5",
|
||
borderActive: "border-cyan-500/30",
|
||
buttonClass: "btn-primary",
|
||
buttonLabel: "Business'a Yükselt",
|
||
features: [
|
||
{ label: "Sınırsız kredi", included: true },
|
||
{ label: "1080p video kalitesi", included: true },
|
||
{ label: "Max 180 saniye", included: true },
|
||
{ label: "Sınırsız proje", included: true },
|
||
{ label: "Tüm şablonlar + Özel", included: true },
|
||
{ label: "Öncelikli kuyruk", included: true },
|
||
{ label: "Marka kaldırma", included: true },
|
||
{ label: "API erişimi", included: true },
|
||
],
|
||
},
|
||
];
|
||
|
||
const fadeUp = {
|
||
hidden: { opacity: 0, y: 20 },
|
||
show: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] as const } },
|
||
};
|
||
|
||
export default function PricingPage() {
|
||
const [isYearly, setIsYearly] = useState(false);
|
||
|
||
return (
|
||
<div className="max-w-5xl mx-auto space-y-10 py-4">
|
||
{/* ── Başlık ── */}
|
||
<motion.div
|
||
variants={fadeUp}
|
||
initial="hidden"
|
||
animate="show"
|
||
className="text-center space-y-3"
|
||
>
|
||
<h1 className="font-[family-name:var(--font-display)] text-3xl md:text-4xl font-bold tracking-tight">
|
||
Planını Seç, Üretmeye Başla
|
||
</h1>
|
||
<p className="text-[var(--color-text-muted)] text-sm md:text-base max-w-md mx-auto">
|
||
Her plan ücretsiz deneme ile başlar. İstediğin zaman yükselt veya iptal et.
|
||
</p>
|
||
|
||
{/* Aylık / Yıllık Toggle */}
|
||
<div className="flex items-center justify-center gap-3 pt-2">
|
||
<span className={cn("text-sm", !isYearly ? "text-[var(--color-text-primary)]" : "text-[var(--color-text-muted)]")}>
|
||
Aylık
|
||
</span>
|
||
<button
|
||
onClick={() => setIsYearly(!isYearly)}
|
||
className={cn(
|
||
"relative w-14 h-7 rounded-full transition-colors",
|
||
isYearly ? "bg-violet-500" : "bg-[var(--color-bg-elevated)]"
|
||
)}
|
||
>
|
||
<motion.div
|
||
className="absolute top-0.5 w-6 h-6 rounded-full bg-white shadow-md"
|
||
animate={{ left: isYearly ? "calc(100% - 1.625rem)" : "0.125rem" }}
|
||
transition={{ type: "spring", stiffness: 500, damping: 30 }}
|
||
/>
|
||
</button>
|
||
<span className={cn("text-sm", isYearly ? "text-[var(--color-text-primary)]" : "text-[var(--color-text-muted)]")}>
|
||
Yıllık
|
||
</span>
|
||
{isYearly && (
|
||
<motion.span
|
||
initial={{ opacity: 0, scale: 0.8 }}
|
||
animate={{ opacity: 1, scale: 1 }}
|
||
className="badge badge-emerald text-[10px]"
|
||
>
|
||
%17 tasarruf
|
||
</motion.span>
|
||
)}
|
||
</div>
|
||
</motion.div>
|
||
|
||
{/* ── Plan Kartları ── */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-5">
|
||
{plans.map((plan, i) => {
|
||
const Icon = plan.icon;
|
||
const price = isYearly ? plan.yearlyPrice : plan.monthlyPrice;
|
||
const period = isYearly ? "/yıl" : "/ay";
|
||
|
||
return (
|
||
<motion.div
|
||
key={plan.id}
|
||
initial={{ opacity: 0, y: 24 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: i * 0.1, duration: 0.6, ease: [0.16, 1, 0.3, 1] }}
|
||
className={cn(
|
||
"relative card-surface p-6 flex flex-col bg-gradient-to-br",
|
||
plan.gradient,
|
||
plan.recommended && "glow-violet md:-translate-y-2"
|
||
)}
|
||
>
|
||
{plan.recommended && (
|
||
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
||
<span className="badge bg-violet-500 text-white text-[10px] px-3 py-1 shadow-lg shadow-violet-500/30">
|
||
⚡ Önerilen
|
||
</span>
|
||
</div>
|
||
)}
|
||
|
||
{/* Header */}
|
||
<div className="flex items-center gap-3 mb-4">
|
||
<div className={cn(
|
||
"w-10 h-10 rounded-xl flex items-center justify-center",
|
||
plan.color === "violet" && "bg-violet-500/15 text-violet-400",
|
||
plan.color === "emerald" && "bg-emerald-500/15 text-emerald-400",
|
||
plan.color === "cyan" && "bg-cyan-500/15 text-cyan-400"
|
||
)}>
|
||
<Icon size={20} />
|
||
</div>
|
||
<div>
|
||
<h3 className="font-[family-name:var(--font-display)] text-lg font-bold">{plan.name}</h3>
|
||
<p className="text-[11px] text-[var(--color-text-muted)]">{plan.description}</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Fiyat */}
|
||
<div className="mb-5">
|
||
<div className="flex items-baseline gap-1">
|
||
<span className="font-[family-name:var(--font-display)] text-4xl font-bold">
|
||
${price}
|
||
</span>
|
||
{price > 0 && (
|
||
<span className="text-sm text-[var(--color-text-muted)]">{period}</span>
|
||
)}
|
||
</div>
|
||
<p className="text-xs text-[var(--color-text-ghost)] mt-1">
|
||
{plan.credits === -1 ? "Sınırsız video üretimi" : `${plan.credits} kredi dahil`}
|
||
</p>
|
||
</div>
|
||
|
||
{/* Features */}
|
||
<ul className="space-y-2.5 flex-1 mb-6">
|
||
{plan.features.map((feat) => (
|
||
<li key={feat.label} className="flex items-center gap-2.5 text-sm">
|
||
{feat.included ? (
|
||
<Check size={14} className="text-emerald-400 shrink-0" />
|
||
) : (
|
||
<X size={14} className="text-[var(--color-text-ghost)] shrink-0" />
|
||
)}
|
||
<span className={cn(
|
||
feat.included ? "text-[var(--color-text-secondary)]" : "text-[var(--color-text-ghost)]"
|
||
)}>
|
||
{feat.label}
|
||
</span>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
|
||
{/* CTA */}
|
||
<button className={cn("w-full py-3 rounded-xl font-semibold text-sm flex items-center justify-center gap-2", plan.buttonClass)}>
|
||
{plan.buttonLabel}
|
||
{price > 0 && <ArrowRight size={14} />}
|
||
</button>
|
||
</motion.div>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* ── Trust ── */}
|
||
<motion.div
|
||
variants={fadeUp}
|
||
initial="hidden"
|
||
animate="show"
|
||
className="text-center space-y-2 pt-4"
|
||
>
|
||
<p className="text-xs text-[var(--color-text-ghost)]">
|
||
🔒 Güvenli ödeme • İstediğin zaman iptal • 7 gün para iade garantisi
|
||
</p>
|
||
<p className="text-[10px] text-[var(--color-text-ghost)]">
|
||
Stripe ile güvenli ödeme altyapısı
|
||
</p>
|
||
</motion.div>
|
||
</div>
|
||
);
|
||
}
|