226 lines
6.9 KiB
TypeScript
226 lines
6.9 KiB
TypeScript
"use client";
|
|
|
|
import { Check, ChevronsUpDown, X } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Collapsible,
|
|
CollapsibleContent,
|
|
CollapsibleTrigger,
|
|
} from "@/components/ui/collapsible";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface Feature {
|
|
name: string;
|
|
values: (boolean | null | string)[];
|
|
}
|
|
|
|
interface FeatureSection {
|
|
category: string;
|
|
features: Feature[];
|
|
}
|
|
|
|
interface Plan {
|
|
name: string;
|
|
ctaText: string;
|
|
ctaHref?: string;
|
|
ctaVariant?: "default" | "outline" | "secondary";
|
|
}
|
|
|
|
interface Pricing42Props {
|
|
plans?: Plan[];
|
|
featureSections?: FeatureSection[];
|
|
className?: string;
|
|
}
|
|
|
|
const CATEGORY_LABELS: Record<string, string> = {
|
|
Usage: "میزان استفاده",
|
|
Features: "امکانات",
|
|
Support: "پشتیبانی",
|
|
};
|
|
|
|
const Pricing42 = ({
|
|
plans = [
|
|
{
|
|
name: "رایگان",
|
|
ctaText: "شروع رایگان",
|
|
ctaHref: "#",
|
|
ctaVariant: "outline",
|
|
},
|
|
{
|
|
name: "استارتاپ",
|
|
ctaText: "شروع رایگان",
|
|
ctaHref: "#",
|
|
ctaVariant: "outline",
|
|
},
|
|
{
|
|
name: "سازمانی",
|
|
ctaText: "درخواست دمو",
|
|
ctaHref: "#",
|
|
ctaVariant: "outline",
|
|
},
|
|
],
|
|
featureSections = [
|
|
{
|
|
category: "Usage",
|
|
features: [
|
|
{
|
|
name: "اعضا",
|
|
values: ["نامحدود", "نامحدود", "نامحدود"],
|
|
},
|
|
{
|
|
name: "تراکنشها",
|
|
values: ["۲۵۰", "نامحدود", "نامحدود"],
|
|
},
|
|
{ name: "تیمها", values: ["۲", "نامحدود", "نامحدود"] },
|
|
],
|
|
},
|
|
{
|
|
category: "Features",
|
|
features: [
|
|
{ name: "گزارشدهی", values: [true, true, true] },
|
|
{ name: "تحلیلها", values: [true, true, true] },
|
|
{ name: "ورود و خروج داده", values: [true, true, true] },
|
|
{ name: "یکپارچهسازیها", values: [true, true, true] },
|
|
{ name: "دستیار هوش مصنوعی", values: [null, true, true] },
|
|
{ name: "نقشهای مدیریتی", values: [null, null, true] },
|
|
{ name: "گزارش ممیزی", values: [null, null, true] },
|
|
],
|
|
},
|
|
{
|
|
category: "Support",
|
|
features: [
|
|
{ name: "پشتیبانی اولویتدار", values: [true, true, true] },
|
|
{ name: "مدیر حساب", values: [null, null, true] },
|
|
{ name: "SLA آپتایم", values: [null, null, true] },
|
|
],
|
|
},
|
|
],
|
|
className,
|
|
}: Pricing42Props) => {
|
|
const [selectedPlan, setSelectedPlan] = useState(1);
|
|
|
|
const renderFeatureValue = (value: boolean | null | string) => {
|
|
if (value === true) {
|
|
return <Check className="size-5" />;
|
|
}
|
|
if (value === false) {
|
|
return <X className="size-5" />;
|
|
}
|
|
if (value === null) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<Check className="size-4 shrink-0" />
|
|
<span className="text-muted-foreground">{value}</span>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<section className={cn("pb-28 lg:py-32", className)}>
|
|
<div className="container">
|
|
{/* Plan Headers */}
|
|
<div>
|
|
{/* Mobile View */}
|
|
<div className="md:hidden">
|
|
<Collapsible className="">
|
|
<>
|
|
<div className="flex items-center justify-between border-b py-4">
|
|
<CollapsibleTrigger className="flex items-center gap-2">
|
|
<h3 className="text-xl font-semibold">
|
|
{plans[selectedPlan].name}
|
|
</h3>
|
|
<ChevronsUpDown
|
|
className={cn("size-5 transition-transform")}
|
|
/>
|
|
</CollapsibleTrigger>
|
|
<Button
|
|
variant={plans[selectedPlan].ctaVariant || "outline"}
|
|
className="w-fit"
|
|
asChild
|
|
>
|
|
<a href={plans[selectedPlan].ctaHref || "#"}>
|
|
{plans[selectedPlan].ctaText}
|
|
</a>
|
|
</Button>
|
|
</div>
|
|
<CollapsibleContent className="flex flex-col space-y-2 p-2">
|
|
{plans.map(
|
|
(plan, index) =>
|
|
index !== selectedPlan && (
|
|
<Button
|
|
size="lg"
|
|
variant="secondary"
|
|
key={index}
|
|
onClick={() => setSelectedPlan(index)}
|
|
>
|
|
{plan.name}
|
|
</Button>
|
|
),
|
|
)}
|
|
</CollapsibleContent>
|
|
</>
|
|
</Collapsible>
|
|
</div>
|
|
|
|
{/* Desktop View */}
|
|
<div className="grid grid-cols-4 gap-4 max-md:hidden">
|
|
<div className="col-span-1 max-md:hidden" />
|
|
{plans.map((plan, index) => (
|
|
<div key={index}>
|
|
<h3 className="mb-3 text-xl font-semibold">{plan.name}</h3>
|
|
<Button variant={plan.ctaVariant || "outline"} asChild>
|
|
<a href={plan.ctaHref || "#"}>{plan.ctaText}</a>
|
|
</Button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Feature Sections */}
|
|
{featureSections.map((section, sectionIndex) => (
|
|
<div key={sectionIndex}>
|
|
<div className="border-b border-primary/40 py-4">
|
|
<h3 className="text-lg font-semibold">
|
|
{CATEGORY_LABELS[section.category] ?? section.category}
|
|
</h3>
|
|
</div>
|
|
{section.features.map((feature, featureIndex) => (
|
|
<div
|
|
key={featureIndex}
|
|
className="grid grid-cols-2 font-medium text-foreground max-md:border-b md:grid-cols-4"
|
|
>
|
|
<span className="inline-flex items-center py-4">
|
|
{feature.name}
|
|
</span>
|
|
{/* Mobile View - Only Selected Plan */}
|
|
<div className="md:hidden">
|
|
<div className="flex items-center gap-1 py-4 md:border-b">
|
|
{renderFeatureValue(feature.values[selectedPlan])}
|
|
</div>
|
|
</div>
|
|
{/* Desktop View - All Plans */}
|
|
<div className="hidden md:col-span-3 md:grid md:grid-cols-3 md:gap-4">
|
|
{feature.values.map((value, i) => (
|
|
<div
|
|
key={i}
|
|
className="flex items-center gap-1 border-b py-4"
|
|
>
|
|
{renderFeatureValue(value)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Pricing42 };
|