Files
43e4aa20-c65e-460c-ad08-288…/src/components/sections/pricing/PricingCardFour.tsx

240 lines
8.3 KiB
TypeScript

"use client";
import { useState } from "react";
import { cls, shouldUseInvertedText } from "@/lib/utils";
import { ArrowRight } from "lucide-react";
import Tag from "@/components/shared/Tag";
import SelectorButton from "@/components/button/SelectorButton";
import AnimationContainer from "@/components/sections/AnimationContainer";
import { useCardAnimation } from "@/components/cardStack/hooks/useCardAnimation";
import { useTheme } from "@/providers/themeProvider/ThemeProvider";
import type { LucideIcon } from "lucide-react";
import type { InvertedBackground } from "@/providers/themeProvider/config/constants";
import type { CardAnimationType } from "@/components/cardStack/types";
interface CtaCard {
title: string;
description: string;
href?: string;
onClick?: () => void;
}
interface PricingPlan {
id: string;
name: string;
price: string;
subtitle: string;
features: string[];
}
interface PricingCardFourProps {
title: string;
tag: string;
tagIcon?: LucideIcon;
ctaCards: [CtaCard, CtaCard];
plans: PricingPlan[];
useInvertedBackground: InvertedBackground;
animationType: CardAnimationType;
featuresElevate Your Brand with Expert Copywriting and Content Enhancement?: string;
ariaLabel?: string;
className?: string;
containerClassName?: string;
leftPanelClassName?: string;
rightPanelClassName?: string;
tagClassName?: string;
titleClassName?: string;
ctaCardClassName?: string;
ctaCardElevate Your Brand with Expert Copywriting and Content EnhancementClassName?: string;
ctaCardDescriptionClassName?: string;
planSelectorClassName?: string;
priceClassName?: string;
subtitleClassName?: string;
featuresElevate Your Brand with Expert Copywriting and Content EnhancementClassName?: string;
featuresGridClassName?: string;
featureItemClassName?: string;
}
const PricingCardFour = ({
title,
tag,
tagIcon: TagIcon,
ctaCards,
plans,
useInvertedBackground,
animationType,
featuresElevate Your Brand with Expert Copywriting and Content Enhancement = "What's included",
ariaLabel = "Pricing section",
className = "",
containerClassName = "",
leftPanelClassName = "",
rightPanelClassName = "",
tagClassName = "",
titleClassName = "",
ctaCardClassName = "",
ctaCardElevate Your Brand with Expert Copywriting and Content EnhancementClassName = "",
ctaCardDescriptionClassName = "",
planSelectorClassName = "",
priceClassName = "",
subtitleClassName = "",
featuresElevate Your Brand with Expert Copywriting and Content EnhancementClassName = "",
featuresGridClassName = "",
featureItemClassName = "",
}: PricingCardFourProps) => {
const [activePlanIndex, setActivePlanIndex] = useState(0);
const activePlan = plans[activePlanIndex];
const theme = useTheme();
const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
const { itemRefs } = useCardAnimation({ animationType, itemCount: 2 });
const handleCtaClick = (ctaCard: CtaCard) => {
if (ctaCard.onClick) {
ctaCard.onClick();
}
if (ctaCard.href) {
window.location.href = ctaCard.href;
}
};
return (
<section
aria-label={ariaLabel}
className={cls(
"relative py-20",
useInvertedBackground === "invertCard"
? "w-content-width-expanded mx-auto rounded-theme-capped bg-foreground"
: "w-full",
useInvertedBackground === "invertDefault" && "bg-foreground",
className
)}
>
<div className={cls("w-content-width mx-auto", containerClassName)}>
<div className="grid grid-cols-1 md:grid-cols-12 gap-6 md:gap-8">
<div
ref={(el) => { itemRefs.current[0] = el; }}
className={cls(
"md:col-span-5 card rounded-theme-capped p-6 md:p-8 flex flex-col gap-4",
leftPanelClassName
)}
>
<Tag
text={tag}
icon={TagIcon}
useInvertedBackground={useInvertedBackground}
className={tagClassName}
/>
<h2 className={cls(
"text-4xl md:text-5xl font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
titleClassName
)}>
{title}
</h2>
<div className="flex flex-col gap-4">
{ctaCards.map((ctaCard, index) => (
<button
key={index}
onClick={() => handleCtaClick(ctaCard)}
className={cls(
"w-full p-4 md:p-5 primary-button rounded-theme text-left flex items-center justify-between gap-4",
ctaCardClassName
)}
>
<div className="flex flex-col gap-0">
<span className={cls("text-base md:text-xl font-medium text-background line-clamp-1", ctaCardElevate Your Brand with Expert Copywriting and Content EnhancementClassName)}>
{ctaCard.title}
</span>
<span className={cls("text-sm text-background/60 line-clamp-1", ctaCardDescriptionClassName)}>
{ctaCard.description}
</span>
</div>
<ArrowRight className="h-[var(--text-base)] w-auto shrink-0 text-background/60" />
</button>
))}
</div>
</div>
<div
ref={(el) => { itemRefs.current[1] = el; }}
className={cls(
"md:col-span-7 card rounded-theme-capped p-6 md:p-8 flex flex-col gap-4",
rightPanelClassName
)}
>
<SelectorButton
options={plans.map((plan) => ({
value: plan.id,
label: plan.name,
}))}
activeValue={activePlan.id}
onValueChange={(value) => {
const index = plans.findIndex((p) => p.id === value);
if (index !== -1) setActivePlanIndex(index);
}}
wrapperClassName={planSelectorClassName}
/>
<AnimationContainer
key={activePlan.id}
className="flex flex-col gap-4"
animationType="fade"
>
<div className="flex flex-col gap-2">
<h3 className={cls(
"text-4xl md:text-5xl font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
priceClassName
)}>
{activePlan.price}
</h3>
<p className={cls(
"text-base",
shouldUseLightText ? "text-background/70" : "text-foreground/70",
subtitleClassName
)}>
{activePlan.subtitle}
</p>
</div>
<div className={cls("w-full h-px", shouldUseLightText ? "bg-background/10" : "bg-foreground/10")} />
<div className="flex flex-col gap-4">
<h4 className={cls(
"text-lg font-medium",
shouldUseLightText ? "text-background" : "text-foreground",
featuresElevate Your Brand with Expert Copywriting and Content EnhancementClassName
)}>
{featuresElevate Your Brand with Expert Copywriting and Content Enhancement}
</h4>
<div className={cls(
"grid grid-cols-1 md:grid-cols-2 gap-3",
featuresGridClassName
)}>
{activePlan.features.map((feature, index) => (
<div
key={index}
className={cls(
"flex items-start gap-2",
featureItemClassName
)}
>
<span className={cls("h-1.5 w-1.5 rounded-full mt-2 shrink-0", shouldUseLightText ? "bg-background" : "bg-foreground")} />
<span className={cls("text-base", shouldUseLightText ? "text-background" : "text-foreground")}>{feature}</span>
</div>
))}
</div>
</div>
</AnimationContainer>
</div>
</div>
</div>
</section>
);
};
PricingCardFour.displayName = "PricingCardFour";
export default PricingCardFour;