Files
reui-blocks/blocks/feature281.tsx
T
2026-07-23 06:55:21 +03:30

239 lines
9.9 KiB
TypeScript

"use client";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import {
FaApple,
FaGoogle,
FaLinkedin,
FaMicrosoft,
FaTwitter,
} from "react-icons/fa";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export const Highlight = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<motion.span
className={cn(
"bg-emerald-100 px-1 py-0.5 font-bold text-emerald-700 dark:bg-emerald-700/[0.2] dark:text-emerald-500",
className,
)}
>
{children}
</motion.span>
);
};
const CARDS = [
{
id: 0,
name: "مدیریت فروش",
designation: "سامانه مدیریت ارتباط با مشتری",
userImage: "/block-media/shadcnblocks/block/guri3/avatar1.png",
companyIcon: FaApple,
content: (
<p className="text-pretty">
پیاده‌سازی فوق‌العاده روان بود.{" "}
<Highlight>تمام تعاملات، سرنخ‌ها و قراردادها در یک فضای کاری متمرکز جمع می‌شود. تیم فروش بدون جابجایی بین ابزارها، سریع‌تر پیش‌بینی می‌کند و معاملات بیشتری می‌بندد.</Highlight> از اولین تماس تا تمدید قرارداد، هر مرحله فروش قابل ردیابی است. گزارش‌های لحظه‌ای به مدیران کمک می‌کند گلوگاه‌ها را قبل از از دست دادن درآمد شناسایی کنند.
</p>
),
},
{
id: 1,
name: "ارتباط با مشتری",
designation: "پایپ‌لاین فروش",
userImage: "/block-media/shadcnblocks/block/guri3/avatar2.png",
companyIcon: FaLinkedin,
content: (
<p className="text-pretty">
به‌عنوان مدیر فروش، دید لحظه‌ای پایپ‌لاین برایم تعیین‌کننده است.{" "}
<Highlight>پروفایل یکپارچه مشتری، تاریخچه تماس و وضعیت معامله را همزمان نشان می‌دهد. تیم‌ها با دید مشترک، هماهنگ‌تر پیش می‌روند و نرخ تبدیل بالاتر می‌رود.</Highlight> تمام تعاملات، سرنخ‌ها و قراردادها در یک فضای کاری متمرکز جمع می‌شود. تیم فروش بدون جابجایی بین ابزارها، سریع‌تر پیش‌بینی می‌کند و معاملات بیشتری می‌بندد.
</p>
),
},
{
id: 2,
name: "مدیریت فروش",
designation: "سامانه مدیریت ارتباط با مشتری",
userImage: "/block-media/shadcnblocks/block/guri3/avatar3.png",
companyIcon: FaTwitter,
content: (
<p className="text-pretty">
امکانات دسترس‌پذیری عالی است.{" "}
<Highlight>از اولین تماس تا تمدید قرارداد، هر مرحله فروش قابل ردیابی است. گزارش‌های لحظه‌ای به مدیران کمک می‌کند گلوگاه‌ها را قبل از از دست دادن درآمد شناسایی کنند.</Highlight> پروفایل یکپارچه مشتری، تاریخچه تماس و وضعیت معامله را همزمان نشان می‌دهد. تیم‌ها با دید مشترک، هماهنگ‌تر پیش می‌روند و نرخ تبدیل بالاتر می‌رود.
</p>
),
},
{
id: 3,
name: "هر سرنخ را تا قرارداد دنبال کنید",
designation: "فروش تیم‌تان را یکجا مدیریت کنید",
userImage: "/block-media/shadcnblocks/block/guri3/avatar4.png",
companyIcon: FaGoogle,
content: (
<p className="text-pretty">
عملکرد استثنایی است.{" "}
<Highlight>تمام تعاملات، سرنخ‌ها و قراردادها در یک فضای کاری متمرکز جمع می‌شود. تیم فروش بدون جابجایی بین ابزارها، سریع‌تر پیش‌بینی می‌کند و معاملات بیشتری می‌بندد.</Highlight> از اولین تماس تا تمدید قرارداد، هر مرحله فروش قابل ردیابی است. گزارش‌های لحظه‌ای به مدیران کمک می‌کند گلوگاه‌ها را قبل از از دست دادن درآمد شناسایی کنند.
</p>
),
},
{
id: 4,
name: "روابط مشتری را در یک نگاه ببینید",
designation: "پایپ‌لاین فروش را شفاف کنید",
userImage: "/block-media/shadcnblocks/block/guri3/avatar5.png",
companyIcon: FaMicrosoft,
content: (
<p className="text-pretty">
برای نیازهای سازمانی ما عالی است.{" "}
<Highlight>پروفایل یکپارچه مشتری، تاریخچه تماس و وضعیت معامله را همزمان نشان می‌دهد. تیم‌ها با دید مشترک، هماهنگ‌تر پیش می‌روند و نرخ تبدیل بالاتر می‌رود.</Highlight> تمام تعاملات، سرنخ‌ها و قراردادها در یک فضای کاری متمرکز جمع می‌شود. تیم فروش بدون جابجایی بین ابزارها، سریع‌تر پیش‌بینی می‌کند و معاملات بیشتری می‌بندد.
</p>
),
},
];
type Card = {
id: number;
name: string;
designation: string;
userImage: string;
companyIcon: React.ComponentType<{ className?: string }>;
content: React.ReactNode;
};
interface Feature281Props {
className?: string;
}
const Feature281 = ({ className }: Feature281Props) => {
return (
<section
dir="rtl"
lang="fa"
className={cn(
"relative h-full w-full overflow-hidden py-32",
className,
)}
>
<div className="container flex w-full min-w-0 max-w-6xl flex-col items-center justify-center">
<div className="relative flex h-full min-w-0 flex-col items-center justify-center gap-8 text-center">
<p className="rounded-full bg-muted px-4 py-1 text-xs font-medium">
ارتباط با مشتری
</p>
<h1 className="w-full text-2xll font-semibold tracking-tighter text-balance lg:text-2xll">
پایپ‌لاین فروش
</h1>
</div>
<div className="mt-24 flex w-full min-w-0 items-center justify-center px-2">
<CardStack items={CARDS} />
</div>
<Button variant="ghost" className="group/btn mt-8 w-fit" asChild>
<a href="#">
مدیریت فروش
<ArrowRight className="ms-2 size-4 transition-transform group-hover/btn:translate-x-1 rtl:rotate-180 rtl:group-hover/btn:-translate-x-1" />
</a>
</Button>
</div>
</section>
);
};
export { Feature281 };
// Below is the modified component from Aceternity UI
// Original source: npx shadcn@latest add https://ui.aceternity.com/registry/card-stack.json
// Modified to follow our coding standards and design system
// We respect copyright and attribution to the original creators
const CardStack = ({
items,
offset,
scaleFactor,
}: {
items: Card[];
offset?: number;
scaleFactor?: number;
}) => {
const intervalRef = useRef<NodeJS.Timeout | undefined>(undefined);
const CARD_OFFSET = offset || 10;
const SCALE_FACTOR = scaleFactor || 0.06;
const [cards, setCards] = useState<Card[]>(items);
const startFlipping = useCallback(() => {
intervalRef.current = setInterval(() => {
setCards((prevCards: Card[]) => {
const newArray = [...prevCards];
newArray.unshift(newArray.pop()!);
return newArray;
});
}, 5000);
}, []);
useEffect(() => {
startFlipping();
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [startFlipping]);
return (
<div className="relative h-60 w-full max-w-96 min-w-0">
{cards.map((card, index) => {
const CompanyIcon = card.companyIcon;
return (
<motion.div
key={card.id}
className="absolute inset-x-0 flex h-60 w-full max-w-96 flex-col justify-between overflow-hidden rounded-3xl border border-neutral-200 bg-white p-4 text-start shadow-xl shadow-black/[0.1] dark:border-white/[0.1] dark:bg-black dark:shadow-white/[0.05]"
style={{
transformOrigin: "top center",
}}
animate={{
top: index * -CARD_OFFSET,
scale: 1 - index * SCALE_FACTOR,
zIndex: cards.length - index,
}}
transition={{
duration: 0.5,
type: "spring",
bounce: 0.3,
}}
>
<div className="min-w-0 overflow-hidden font-normal text-neutral-700 dark:text-neutral-200">
{card.content}
</div>
<div className="mt-3 flex min-w-0 items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-2">
<Avatar key={index} className="size-12 shrink-0">
<AvatarImage src={card.userImage} alt={card.name} />
</Avatar>
<div className="min-w-0">
<p className="truncate font-medium">{card.name}</p>
<p className="truncate text-muted-foreground/80">
{card.designation}
</p>
</div>
</div>
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-muted-foreground/15">
<CompanyIcon className="size-5" />
</div>
</div>
</motion.div>
);
})}
</div>
);
};