canina/frontend/application/components/FeaturedProducts.tsx

177 lines
8.7 KiB
TypeScript

"use client";
import { useState, useEffect, useMemo } from "react";
import { Product } from "../lib/data/products";
import { usePetStore } from "../lib/store/usePetStore";
import { productService } from "../lib/services/productService";
import { motion } from "motion/react";
import { Eye, ShoppingCart, Heart, AlertCircle, Sparkles } from "lucide-react";
import SafeImage from "./SafeImage";
import { ProductCardSkeleton } from "./Skeleton";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useSettingsStore } from "../lib/store/settingsStore";
import { useCartStore } from "../lib/store/cartStore";
import { toast } from "sonner";
function ProductCard({ product }: { product: Product }) {
const router = useRouter();
const getText = useSettingsStore((state) => state.getText);
const { getActivePet } = usePetStore();
const activePet = getActivePet();
const { addItem } = useCartStore();
const nameFa = product.nameFa || product.name;
const nameEn = product.nameEn || "";
const compatibility = useMemo(() => {
if (!activePet) return null;
const sameSpecies = product.suitableFor === activePet.type || product.suitableFor === "هر دو";
const helpsSymptom = (activePet.medicalConditions || []).some((s) => product.symptoms.includes(s));
if (!sameSpecies) return { type: "alert", text: `مخصوص ${product.suitableFor}` };
if (helpsSymptom) return { type: "success", text: `توصیه شده برای ${activePet.name}` };
return { type: "neutral", text: `مناسب برای ${activePet.name}` };
}, [product, activePet]);
return (
<motion.div
initial={{ opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.45 }}
className="group bg-white rounded-3xl border border-medical-gray-200 overflow-hidden hover:shadow-2xl hover:shadow-canina-blue/10 transition-all duration-500 flex flex-col cursor-pointer relative"
>
{/* Category Badge */}
<div className="absolute top-4 right-4 z-30 px-3 py-1 bg-white/95 backdrop-blur-md rounded-full border border-medical-gray-200 text-[10px] font-bold text-medical-gray-600 uppercase tracking-widest shadow-sm">
{product.category}
</div>
{/* Compatibility Tag */}
{compatibility && (
<div className={`absolute top-[3.25rem] right-4 z-10 text-[8px] font-black uppercase tracking-widest px-3 py-1 rounded-full shadow-md flex items-center gap-1 ${
compatibility.type === "alert" ? "bg-amber-100 text-amber-700" :
compatibility.type === "success" ? "bg-green-100 text-green-700" : "bg-medical-gray-100 text-medical-gray-600"
}`}>
{compatibility.type === "alert" ? <AlertCircle className="w-2.5 h-2.5" /> : compatibility.type === "success" ? <Heart className="w-2.5 h-2.5" /> : <Sparkles className="w-2.5 h-2.5" />}
{compatibility.text}
</div>
)}
{/* Image */}
<div className="relative aspect-[4/3] bg-medical-gray-50 flex items-center justify-center overflow-hidden p-5">
<SafeImage
src={product.image}
alt={nameFa}
className="w-full h-full group-hover:scale-105 transition-transform duration-500"
imgClassName="object-contain max-h-[170px] mx-auto"
/>
{/* PDP Link overlay */}
<Link href={`/shop/${product.slug || product.id}`} className="absolute inset-0 z-10" />
{/* Hover Actions */}
<div className="absolute inset-0 bg-canina-blue/60 opacity-0 group-hover:opacity-100 backdrop-blur-sm transition-all duration-300 flex items-center justify-center gap-4 z-20">
<div
onClick={(e) => { e.stopPropagation(); router.push(`/shop/${product.slug || product.id}`); }}
className="w-11 h-11 rounded-full bg-white text-canina-blue flex items-center justify-center hover:scale-110 transition-transform shadow-lg cursor-pointer"
>
<Eye className="w-5 h-5" />
</div>
<div
onClick={(e) => {
e.stopPropagation();
addItem(product, 1);
toast.success(`${nameFa} به سبد خرید اضافه شد.`);
}}
className="w-11 h-11 rounded-full bg-canina-blue text-white flex items-center justify-center hover:scale-110 transition-transform shadow-lg border border-white/20 cursor-pointer"
>
<ShoppingCart className="w-5 h-5" />
</div>
</div>
</div>
{/* Content */}
<Link href={`/shop/${product.slug || product.id}`} className="px-5 py-4 flex flex-col flex-1 gap-3">
{/* Dual-language Name */}
<div className="flex flex-col gap-1">
<h3 dir="rtl" className="text-[14px] font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors leading-snug text-right line-clamp-2 font-vazir">
{nameFa}
</h3>
{nameEn && (
<span dir="ltr" className="text-[11px] font-semibold text-slate-400 font-sans text-left block line-clamp-1">
{nameEn}
</span>
)}
</div>
{/* Short description */}
<p className="text-xs text-medical-gray-500 leading-relaxed line-clamp-2 flex-1">
{product.shortDescription || product.description}
</p>
{/* Footer: Price + CTA */}
<div className="flex items-center justify-between pt-3 border-t border-medical-gray-100">
<div className="text-base font-black text-medical-gray-900 font-vazir whitespace-nowrap">{product.price}</div>
<span className="text-[11px] font-black text-canina-blue uppercase tracking-widest border-b-2 border-canina-blue pb-0.5 hover:text-medical-gray-900 hover:border-medical-gray-900 transition-all whitespace-nowrap">
{getText("product_view_details", "مشاهده جزئیات")}
</span>
</div>
</Link>
</motion.div>
);
}
export default function FeaturedProducts() {
const router = useRouter();
const getText = useSettingsStore((state) => state.getText);
const [products, setProducts] = useState<Product[]>([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
productService.getFeaturedProducts()
.then(setProducts)
.catch(() => toast.error("خطا در دریافت لیست محصولات از سرور."))
.finally(() => setIsLoading(false));
}, []);
return (
<section className="py-16 bg-medical-gray-50">
<div className="max-w-7xl mx-auto px-4">
<div className="flex items-center justify-between w-full mb-12 pb-6 border-b border-medical-gray-200">
<div>
<div className="text-canina-blue text-xs font-bold uppercase tracking-[0.2em] mb-2 font-vazir">
{getText("featured_badge", "بیشترین انتخاب توسط دامپزشکان")}
</div>
<h2 className="text-2xl md:text-3xl lg:text-4xl font-black text-medical-gray-900 font-lalezar tracking-wide">
{getText("featured_title_line1", "محصولات برگزیده و راهکارهای")}{" "}
<span className="text-canina-blue">{getText("featured_title_line2", "درمان تخصصی")}</span>
</h2>
</div>
<button
onClick={() => router.push("/shop")}
className="inline-flex items-center gap-2 text-canina-blue font-black text-sm hover:translate-x-1 transition-all group font-vazir"
>
{getText("featured_view_all", "مشاهده تمامی محصولات")}
<span className="text-lg group-hover:-translate-x-1 transition-transform">←</span>
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{isLoading ? (
Array.from({ length: 4 }).map((_, i) => <ProductCardSkeleton key={i} />)
) : products.length > 0 ? (
products.map((p) => <ProductCard key={p.id} product={p} />)
) : (
<div className="col-span-full py-16 px-8 flex flex-col items-center justify-center text-center bg-white rounded-[2.5rem] border border-medical-gray-200 shadow-xl max-w-lg mx-auto">
<AlertCircle className="w-12 h-12 text-canina-teal mb-4" />
<h3 className="text-xl font-black text-medical-gray-900 mb-2 font-vazir">
{getText("featured_no_products_title", "هیچ محصولی یافت نشد")}
</h3>
<p className="text-sm text-medical-gray-500 font-medium font-vazir leading-relaxed">
{getText("featured_no_products_desc", "در حال حاضر هیچ محصول برجسته‌ای برای نمایش وجود ندارد.")}
</p>
</div>
)}
</div>
</div>
</section>
);
}