Files
reui-blocks/blocks/pricing32.tsx
T

267 lines
8.4 KiB
TypeScript

"use client";
import type { LucideIcon } from "lucide-react";
import {
ArrowRight,
Bell,
Book,
Brush,
CalendarCheck2,
CheckSquare,
ClipboardList,
Code,
Database,
FileText,
GitBranch,
GitPullRequest,
LayoutGrid,
LifeBuoy,
MonitorSmartphone,
PhoneCall,
Server,
Settings2,
Slack,
Users,
Zap,
} from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { cn } from "@/lib/utils";
const formatPrice = (value: string | number) =>
`${(typeof value === "string" ? Number(value) : value).toLocaleString("fa-IR")} ریال`;
interface FeatureItem {
icon: LucideIcon;
text: string;
}
interface PricingPlan {
name: string;
priceMonthly: number;
priceYearly: number;
description: string;
bestFor: string;
features?: FeatureItem[];
mostPopular?: boolean;
cta: {
text: string;
href: string;
};
}
const PLANS: PricingPlan[] = [
{
name: "شروع",
priceMonthly: 90000,
priceYearly: 900000,
description: "عالی برای توسعه‌دهندگان مستقل",
bestFor: "فریلنسرهای تازه‌کار",
features: [
{ icon: Code, text: "دسترسی به کامپوننت‌های اصلی" },
{ icon: LayoutGrid, text: "بلاک‌های چیدمان پایه" },
{ icon: MonitorSmartphone, text: "قالب‌های طراحی واکنش‌گرا" },
{ icon: FileText, text: "مستندات مقدماتی" },
{ icon: GitBranch, text: "تاریخچه نسخه‌ها" },
{ icon: LifeBuoy, text: "پشتیبانی انجمن" },
{ icon: Book, text: "راهنمای رابط کاربری به‌صورت پی‌دی‌اف" },
],
cta: {
text: "شروع رایگان",
href: "#",
},
},
{
name: "حرفه‌ای",
mostPopular: true,
priceMonthly: 290000,
priceYearly: 290000,
description: "بهترین گزینه برای تیم‌های در حال رشد",
bestFor: "تیم‌های کوچک توسعه و استارتاپ‌ها",
features: [
{ icon: Code, text: "کتابخانه پیشرفته بلاک رابط کاربری" },
{ icon: Brush, text: "پشتیبانی از تم‌های سفارشی" },
{ icon: Settings2, text: "ابزارهای سیستم طراحی" },
{ icon: CheckSquare, text: "شامل تست کامپوننت‌ها" },
{ icon: Zap, text: "بهبودهای عملکرد" },
{ icon: Server, text: "میزبانی کامپوننت‌های مشترک" },
{ icon: PhoneCall, text: "پشتیبانی ایمیل و چت" },
],
cta: {
text: "شروع رایگان",
href: "#",
},
},
{
name: "تیم",
priceMonthly: 590000,
priceYearly: 590000,
description: "همکاری و رشد سریع",
bestFor: "تیم‌های محصول با چند پروژه",
features: [
{ icon: Users, text: "کنترل دسترسی تیمی" },
{ icon: GitPullRequest, text: "ادغام و بازبینی بلاک‌های رابط کاربری" },
{ icon: CalendarCheck2, text: "نقشه راه اولویت‌دار" },
{ icon: Bell, text: "اعلان به‌روزرسانی‌ها" },
{ icon: Database, text: "تحلیل استفاده از کامپوننت‌ها" },
{ icon: Slack, text: "یکپارچه‌سازی پیام‌رسان تیمی" },
{ icon: ClipboardList, text: "کتابخانه قالب‌های پروژه" },
],
cta: {
text: "شروع رایگان",
href: "#",
},
},
{
name: "تجاری",
priceMonthly: 990000,
priceYearly: 990000,
description: "کنترل و پشتیبانی کامل",
bestFor: "آژانس‌ها و تیم‌های بزرگ",
cta: {
text: "شروع رایگان",
href: "#",
},
},
{
name: "سازمانی",
priceMonthly: 199000,
priceYearly: 1990000,
description: "راهکارهای سفارشی در مقیاس بزرگ",
bestFor: "سازمان‌های بزرگ و پلتفرم‌های SaaS",
cta: {
text: "شروع رایگان",
href: "#",
},
},
];
interface Pricing32Props {
className?: string;
}
const Pricing32 = ({ className }: Pricing32Props) => {
const [checked, setChecked] = useState(true);
return (
<section className={cn("py-32", className)}>
<div className="container">
<div className="flex flex-col items-center justify-center gap-9.5">
<h1 className="text-center font-serif text-2xll leading-none text-foreground md:text-2xll lg:text-2xll">
طرحی برای هر پروژه‌ای که شروع می‌کنید
</h1>
<div className="flex flex-col items-center gap-4">
<div className="flex items-center justify-center gap-4">
<Label
htmlFor="plan-duration"
className={cn(
"text-sm transition-colors",
!checked ? "text-foreground" : "text-muted-foreground",
)}
>
سالانه
</Label>
<span dir="rtl" className="inline-flex shrink-0 items-center">
<Switch
id="plan-duration"
checked={checked}
onCheckedChange={setChecked}
aria-label="تغییر دوره صورتحساب"
/>
</span>
<Label
htmlFor="plan-duration"
className={cn(
"text-sm transition-colors",
checked ? "text-foreground" : "text-muted-foreground",
)}
>
ماهانه
</Label>
</div>
<div className="text-center text-green-600">
تا ۴۰٪ تخفیف با صورتحساب سالانه
</div>
</div>
<div className="mt-3 grid w-full grid-cols-1 gap-5 lg:grid-cols-6">
{PLANS.map((plan, index) => (
<PlanCard
key={index}
plan={plan}
monthly={checked}
className={
index > PLANS.length - 3 ? "lg:col-span-3" : "lg:col-span-2"
}
/>
))}
</div>
</div>
<div className="m-9.5 flex items-center justify-center">
<Button size="lg">مقایسه همه طرح‌ها</Button>
</div>
</div>
</section>
);
};
const PlanCard = ({
plan,
monthly,
className,
}: {
plan: PricingPlan;
monthly: boolean;
className?: string;
}) => {
return (
<div
className={`relative h-full w-full rounded-lg border px-6 py-5 ${className} ${plan?.mostPopular ? "border-primary" : "border-border"} bg-background`}
>
<div className="text-xl">{plan.name}</div>
<div className="h-[2.875rem] overflow-hidden">
<div
className={`text-[2.875rem] leading-none font-semibold transition-transform duration-500 ${monthly ? "translate-y-0" : "translate-y-[-3rem]"}`}
>
<div>{formatPrice(plan.priceMonthly)}</div>
<div>{formatPrice(plan.priceYearly)}</div>
</div>
</div>
<div className="text-xs text-foreground/60">
<div>به ازای هر نفر در {monthly ? "ماه" : "سال"}</div>
<div>{plan.bestFor}</div>
</div>
<div className="mt-4 mb-6 text-lg font-medium text-foreground">
{plan.description}
</div>
<Button
asChild
className="w-full"
variant={plan.mostPopular ? "default" : "outline"}
size="lg"
>
<a href={plan.cta.href}>
{plan.cta.text}
<ArrowRight className="ms-2 size-4 rtl:rotate-180" />
</a>
</Button>
<div className="mt-6 flex flex-col gap-4">
{plan.features?.map((feature, index) => (
<div key={index} className="flex items-center gap-3 text-foreground">
<feature.icon className="size-5 stroke-1" />
{feature.text}
</div>
))}
</div>
{plan.mostPopular && (
<div className="absolute start-1/2 top-0 w-fit -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary px-4 py-1 text-xs font-medium text-primary-foreground">
محبوب‌ترین
</div>
)}
</div>
);
};
export { Pricing32 };