fix(database): fix baseSlug format in products seed to populate product symptoms successfully + format cleanup in ArchivePage

This commit is contained in:
parsa aghaei 2026-07-15 17:46:27 +03:30
parent 6dafe86344
commit 717a61a225
2 changed files with 223 additions and 225 deletions

View File

@ -139,10 +139,6 @@ async function main() {
const cleanIngredients = item.ingredients || '';
const cleanDosage = item.usage_and_dosage || '';
const suitableFor = determineSuitableFor(baseName, cleanDesc);
const baseSlug = slugify(baseName);
const categorySlug = item.category_slug || 'supplements';
const category = await findOrCreateCategory(categorySlug);
// Split baseName into nameFa and nameEn
let baseNameFa = baseName;
let baseNameEn = baseName;
@ -152,6 +148,10 @@ async function main() {
baseNameFa = matchName[2].trim();
}
const baseSlug = slugify(baseNameEn);
const categorySlug = item.category_slug || 'supplements';
const category = await findOrCreateCategory(categorySlug);
for (const variant of item.variants) {
const artNo = variant.art_no;
const barcode = variant.barcode;

View File

@ -6,16 +6,16 @@ import { productService } from "../lib/services/productService";
import { motion, AnimatePresence } from "motion/react";
import { ProductCardSkeleton } from "./Skeleton";
import { toast } from "sonner";
import {
Search,
Filter,
Dog,
Cat,
ShieldCheck,
ChevronLeft,
import {
Search,
Filter,
Dog,
Cat,
ShieldCheck,
ChevronLeft,
ChevronRight,
Activity,
Sparkles,
Activity,
Sparkles,
Stethoscope,
HeartPulse,
Heart,
@ -41,7 +41,7 @@ const CATEGORY_MAP: Record<string, { category?: string; query?: string; symptoms
"immune": { category: "immune" },
"energy": { category: "energy" },
"special-care": { category: "special-care" },
// Persian Fallbacks (for robust matching)
"مفاصل و استخوان": { category: "joints" },
"تقویت سیستم ایمنی و گوارش": { category: "immune" },
@ -52,7 +52,7 @@ const CATEGORY_MAP: Record<string, { category?: string; query?: string; symptoms
"آرتروز سگ‌های پیر": { category: "joints", symptoms: ["درد مفاصل", "سختی در بلند شدن", "لنگیدن"] },
"رشد استخوانی توله‌سگ": { category: "joints", symptoms: ["رشد سریع توله‌سگ"] },
"تقویت رباط و تاندون": { category: "joints", query: "تاندون" },
"پیشگیری از بیماری": { category: "immune", symptoms: ["ضعف بعد از بیماری"] },
"رفع اسهال و یبوست": { category: "immune", symptoms: ["اسهال", "یبوست", "اسهال مزمن"] },
"پروبیوتیک‌ها": { category: "immune", query: "فیبر" },
@ -81,14 +81,14 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
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}` };
if (sameSpecies) return { type: 'neutral', text: `مناسب برای ${activePet.name}` };
return null;
}, [product, activePet]);
@ -105,30 +105,29 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
{product.specialBadge}
</div>
)}
{compatibility && (
<div className={`absolute top-14 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'
}`}>
<div className={`absolute top-14 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>
)}
<div className="aspect-square bg-medical-gray-50 flex items-center justify-center p-8 overflow-hidden relative">
<SafeImage src={product.image} alt={product.name} className="w-full h-full group-hover:scale-110 transition-transform duration-700" imgClassName="object-contain" />
<div className="absolute bottom-4 left-4 flex gap-2">
{(product.suitableFor === "سگ" || product.suitableFor === "هر دو") && (
<div className="w-7 h-7 bg-white rounded-lg flex items-center justify-center text-medical-gray-400 border border-medical-gray-100 shadow-sm">
<Dog className="w-4 h-4" />
</div>
)}
{(product.suitableFor === "گربه" || product.suitableFor === "هر دو") && (
<div className="w-7 h-7 bg-white rounded-lg flex items-center justify-center text-medical-gray-400 border border-medical-gray-100 shadow-sm">
<Cat className="w-4 h-4" />
</div>
)}
{(product.suitableFor === "سگ" || product.suitableFor === "هر دو") && (
<div className="w-7 h-7 bg-white rounded-lg flex items-center justify-center text-medical-gray-400 border border-medical-gray-100 shadow-sm">
<Dog className="w-4 h-4" />
</div>
)}
{(product.suitableFor === "گربه" || product.suitableFor === "هر دو") && (
<div className="w-7 h-7 bg-white rounded-lg flex items-center justify-center text-medical-gray-400 border border-medical-gray-100 shadow-sm">
<Cat className="w-4 h-4" />
</div>
)}
</div>
</div>
@ -144,24 +143,24 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
</span>
)}
</div>
<div className="flex flex-wrap gap-1 mb-6">
{product.symptoms.slice(0, 2).map((s, i) => (
<span key={i} className="text-[9px] font-bold bg-medical-gray-100 text-medical-gray-500 px-2 py-0.5 rounded-md">
{s}
</span>
))}
<div className="flex flex-wrap gap-1">
{product.symptoms.slice(0, 2).map((s, i) => (
<span key={i} className="text-[9px] font-bold bg-medical-gray-100 text-medical-gray-500 px-2 py-0.5 rounded-md">
{s}
</span>
))}
</div>
<div className="mt-auto flex items-center justify-between pt-4 border-t border-medical-gray-50">
<span className="font-black text-medical-gray-900 font-vazir">{product.price}</span>
<button
onClick={handleAddToCart}
disabled={isAdding}
className="w-10 h-10 rounded-xl bg-medical-gray-50 text-canina-blue flex items-center justify-center group-hover:bg-canina-blue group-hover:text-white transition-all disabled:opacity-50"
>
{isAdding ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}
</button>
<span className="font-black text-medical-gray-900 font-vazir">{product.price}</span>
<button
onClick={handleAddToCart}
disabled={isAdding}
className="w-10 h-10 rounded-xl bg-medical-gray-50 text-canina-blue flex items-center justify-center group-hover:bg-canina-blue group-hover:text-white transition-all disabled:opacity-50"
>
{isAdding ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}
</button>
</div>
</div>
</motion.div>
@ -170,12 +169,12 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
import { useRouter } from 'next/navigation';
export default function ArchivePage({
export default function ArchivePage({
initialCategory = "all",
initialSearch = "",
initialPetType = "all",
initialSymptoms = ""
}: {
}: {
initialCategory?: string,
initialSearch?: string,
initialPetType?: string,
@ -228,7 +227,7 @@ export default function ArchivePage({
// Normalize Input (Trim and lowercase)
const normSearch = (initialSearch || "").trim().toLowerCase();
const normCat = initialCategory.trim().toLowerCase();
const mapKey = normSearch || normCat;
const mapping = CATEGORY_MAP[mapKey];
@ -237,7 +236,7 @@ export default function ArchivePage({
}
setIsUpdating(true);
// Reset ALL other filters when a new category/solution is selected from menu
setSelectedPet("all");
setActiveSymptoms([]);
@ -252,7 +251,7 @@ export default function ArchivePage({
} else {
setSelectedCategory(initialCategory);
setSearchQuery(initialSearch);
if (initialSearch && symptoms.includes(initialSearch)) {
setActiveSymptoms([initialSearch]);
}
@ -261,7 +260,7 @@ export default function ArchivePage({
const timer = setTimeout(() => {
window.scrollTo({ top: 0, behavior: "smooth" });
}, 400);
return () => clearTimeout(timer);
}, [initialCategory, initialSearch, symptoms]);
@ -279,34 +278,34 @@ export default function ArchivePage({
}, [selectedCategory, selectedPet, searchQuery, activeSymptoms]);
const fetchProducts = async (resetPage = true) => {
setIsUpdating(true);
try {
const res = await productService.getProducts({
category: selectedCategory,
petType: selectedPet,
query: searchQuery,
// Send the first active symptom to the backend for server-side filtering
symptom: activeSymptoms.length === 1 ? activeSymptoms[0] : undefined,
page: resetPage ? 1 : page,
limit: 20,
});
let result = res.data;
// If multiple symptoms selected, do client-side intersection (rare case)
if (activeSymptoms.length > 1) {
result = result.filter(p => activeSymptoms.every(s => p.symptoms.includes(s)));
}
setFilteredProducts(result);
setMeta(res.meta);
if (resetPage) setPage(1);
} catch (error) {
console.error("Failed to fetch products:", error);
toast.error("خطا در دریافت لیست محصولات از سرور. لطفاً صفحه را رفرش کنید.");
} finally {
setIsUpdating(false);
setIsUpdating(true);
try {
const res = await productService.getProducts({
category: selectedCategory,
petType: selectedPet,
query: searchQuery,
// Send the first active symptom to the backend for server-side filtering
symptom: activeSymptoms.length === 1 ? activeSymptoms[0] : undefined,
page: resetPage ? 1 : page,
limit: 20,
});
let result = res.data;
// If multiple symptoms selected, do client-side intersection (rare case)
if (activeSymptoms.length > 1) {
result = result.filter(p => activeSymptoms.every(s => p.symptoms.includes(s)));
}
};
setFilteredProducts(result);
setMeta(res.meta);
if (resetPage) setPage(1);
} catch (error) {
console.error("Failed to fetch products:", error);
toast.error("خطا در دریافت لیست محصولات از سرور. لطفاً صفحه را رفرش کنید.");
} finally {
setIsUpdating(false);
}
};
useEffect(() => {
fetchProducts(true);
@ -342,17 +341,17 @@ export default function ArchivePage({
return (
<div className="min-h-screen bg-medical-gray-50 pb-20 px-4 pt-10 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto">
{/* Mobile Navigation & Breadcrumbs */}
<div className="lg:hidden mb-10 space-y-4">
<button
<button
onClick={() => router.back()}
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
>
<ChevronRight className="w-5 h-5 font-vazir" />
<span>بازگشت</span>
</button>
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2">
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" />
@ -361,174 +360,173 @@ export default function ArchivePage({
</div>
{/* Desktop Breadcrumbs */}
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="cursor-pointer hover:text-canina-blue" onClick={() => { setSelectedCategory("all"); }}>کاتالوگ</span>
{selectedCategory !== "all" && (
<>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">{CATEGORY_LABELS[selectedCategory] || selectedCategory}</span>
</>
)}
</div>
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="cursor-pointer hover:text-canina-blue" onClick={() => { setSelectedCategory("all"); }}>کاتالوگ</span>
{selectedCategory !== "all" && (
<>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">{CATEGORY_LABELS[selectedCategory] || selectedCategory}</span>
</>
)}
</div>
<div className="flex flex-col lg:flex-row gap-10">
{/* Sidebar Filters */}
<aside className="lg:w-72 flex-shrink-0 space-y-8">
<div className="bg-white rounded-[2rem] p-6 border border-medical-gray-200 shadow-sm">
<div className="flex items-center gap-2 mb-6">
<Filter className="w-5 h-5 text-canina-blue" />
<h3 className="font-black text-medical-gray-900">فیلترهای تخصصی</h3>
<div className="flex items-center gap-2 mb-6">
<Filter className="w-5 h-5 text-canina-blue" />
<h3 className="font-black text-medical-gray-900">فیلترهای تخصصی</h3>
</div>
<div className="space-y-6">
{/* Pet Type */}
<div>
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block mb-3">نوع پت</span>
<div className="grid grid-cols-3 gap-2">
{[
{ id: "all", label: "هر دو", icon: <Activity className="w-3 h-3" /> },
{ id: "سگ", label: "سگ", icon: <Dog className="w-3 h-3" /> },
{ id: "گربه", label: "گربه", icon: <Cat className="w-3 h-3" /> },
].map(pet => (
<button
key={pet.id}
onClick={() => setSelectedPet(pet.id as any)}
className={`py-2 rounded-xl text-[10px] font-black border transition-all flex flex-col items-center gap-1 ${selectedPet === pet.id ? 'bg-canina-blue border-canina-blue text-white shadow-lg shadow-canina-blue/20' : 'bg-white border-medical-gray-200 text-medical-gray-400'}`}
>
{pet.icon}
{pet.label}
</button>
))}
</div>
</div>
<div className="space-y-6">
{/* Pet Type */}
<div>
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block mb-3">نوع پت</span>
<div className="grid grid-cols-3 gap-2">
{[
{ id: "all", label: "هر دو", icon: <Activity className="w-3 h-3" /> },
{ id: "سگ", label: "سگ", icon: <Dog className="w-3 h-3" /> },
{ id: "گربه", label: "گربه", icon: <Cat className="w-3 h-3" /> },
].map(pet => (
<button
key={pet.id}
onClick={() => setSelectedPet(pet.id as any)}
className={`py-2 rounded-xl text-[10px] font-black border transition-all flex flex-col items-center gap-1 ${selectedPet === pet.id ? 'bg-canina-blue border-canina-blue text-white shadow-lg shadow-canina-blue/20' : 'bg-white border-medical-gray-200 text-medical-gray-400'}`}
>
{pet.icon}
{pet.label}
</button>
))}
</div>
</div>
{/* Solutions */}
<div>
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block mb-3">راهکار درمانی</span>
<div className="flex flex-col gap-2">
{categories.map(cat => (
<button
key={cat.id}
onClick={() => setSelectedCategory(cat.id)}
className={`flex items-center gap-3 px-4 py-3 rounded-2xl text-xs font-bold transition-all border ${selectedCategory === cat.id ? 'bg-canina-blue border-canina-blue text-white' : 'bg-white border-medical-gray-100 text-medical-gray-600 hover:border-canina-blue/30'}`}
>
{cat.icon}
{cat.label}
</button>
))}
</div>
</div>
{/* Symptoms Pill Tags */}
<div>
<div className="flex items-center justify-between mb-3">
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">جستجو بر اساس علائم</span>
{activeSymptoms.length > 0 && (
<button
onClick={() => setActiveSymptoms([])}
className="text-[10px] font-bold text-canina-blue hover:underline"
>
پاک کردن
</button>
)}
</div>
<div className="flex flex-wrap gap-1.5 max-h-52 overflow-y-auto scrollbar-thin scrollbar-thumb-medical-gray-200 scrollbar-track-transparent pr-0.5">
{symptoms.length === 0 ? (
<span className="text-[10px] text-medical-gray-400">در حال بارگذاری...</span>
) : symptoms.map(s => (
<button
key={s}
onClick={() => toggleSymptom(s)}
className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${
activeSymptoms.includes(s)
? 'bg-canina-blue border-canina-blue text-white shadow-sm shadow-canina-blue/30'
: 'bg-medical-gray-50 border-medical-gray-200 text-medical-gray-500 hover:border-canina-blue/40 hover:text-canina-blue'
}`}
>
{s}
</button>
))}
</div>
</div>
{/* Solutions */}
<div>
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block mb-3">راهکار درمانی</span>
<div className="flex flex-col gap-2">
{categories.map(cat => (
<button
key={cat.id}
onClick={() => setSelectedCategory(cat.id)}
className={`flex items-center gap-3 px-4 py-3 rounded-2xl text-xs font-bold transition-all border ${selectedCategory === cat.id ? 'bg-canina-blue border-canina-blue text-white' : 'bg-white border-medical-gray-100 text-medical-gray-600 hover:border-canina-blue/30'}`}
>
{cat.icon}
{cat.label}
</button>
))}
</div>
</div>
{/* Symptoms Pill Tags */}
<div>
<div className="flex items-center justify-between mb-3">
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">جستجو بر اساس علائم</span>
{activeSymptoms.length > 0 && (
<button
onClick={() => setActiveSymptoms([])}
className="text-[10px] font-bold text-canina-blue hover:underline"
>
پاک کردن
</button>
)}
</div>
<div className="flex flex-wrap gap-1.5 max-h-52 overflow-y-auto scrollbar-thin scrollbar-thumb-medical-gray-200 scrollbar-track-transparent pr-0.5">
{symptoms.length === 0 ? (
<span className="text-[10px] text-medical-gray-400">در حال بارگذاری...</span>
) : symptoms.map(s => (
<button
key={s}
onClick={() => toggleSymptom(s)}
className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${activeSymptoms.includes(s)
? 'bg-canina-blue border-canina-blue text-white shadow-sm shadow-canina-blue/30'
: 'bg-medical-gray-50 border-medical-gray-200 text-medical-gray-500 hover:border-canina-blue/40 hover:text-canina-blue'
}`}
>
{s}
</button>
))}
</div>
</div>
</div>
</div>
{/* Promo Card */}
<div className="bg-medical-gray-900 rounded-[2rem] p-6 text-white relative overflow-hidden group">
<div className="absolute -top-10 -left-10 w-32 h-32 bg-canina-blue rounded-full blur-3xl opacity-20 group-hover:opacity-40 transition-opacity" />
<h4 className="text-lg font-black italic mb-4 relative z-10 underline decoration-canina-blue underline-offset-8">مشاوره رایگان</h4>
<p className="text-xs text-white/60 leading-relaxed mb-6 relative z-10">اگر نمیدانید کدام ترکیب برای پت شما مناسب است، همین حالا با دامپزشکان ما تماس بگیرید.</p>
<a href="tel:0218888" className="w-full bg-white text-medical-gray-900 py-3 rounded-xl text-xs font-black hover:scale-105 transition-transform relative z-10 flex items-center justify-center">شماره تماس: ۰۲۱-۸۸۸۸</a>
<div className="absolute -top-10 -left-10 w-32 h-32 bg-canina-blue rounded-full blur-3xl opacity-20 group-hover:opacity-40 transition-opacity" />
<h4 className="text-lg font-black italic mb-4 relative z-10 underline decoration-canina-blue underline-offset-8">مشاوره رایگان</h4>
<p className="text-xs text-white/60 leading-relaxed mb-6 relative z-10">اگر نمیدانید کدام ترکیب برای پت شما مناسب است، همین حالا با دامپزشکان ما تماس بگیرید.</p>
<a href="tel:0218888" className="w-full bg-white text-medical-gray-900 py-3 rounded-xl text-xs font-black hover:scale-105 transition-transform relative z-10 flex items-center justify-center">شماره تماس: ۰۲۱-۸۸۸۸</a>
</div>
</aside>
{/* Main Content */}
<main className="flex-1 relative">
<div className="flex flex-col md:flex-row items-center justify-between mb-8 gap-4">
<h2 className="text-3xl font-black text-medical-gray-900">کاتولوگ دارویی <span className="text-canina-blue">Canina</span></h2>
<div className="relative w-full md:w-80">
<Search className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
<input
type="text"
placeholder="جستجوی محصول..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-full py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
/>
</div>
<h2 className="text-3xl font-black text-medical-gray-900">کاتولوگ دارویی <span className="text-canina-blue">Canina</span></h2>
<div className="relative w-full md:w-80">
<Search className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
<input
type="text"
placeholder="جستجوی محصول..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-full py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
/>
</div>
</div>
<AnimatePresence mode="wait">
{isUpdating ? (
{isUpdating ? (
<div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
{Array.from({ length: 8 }).map((_, i) => (
<ProductCardSkeleton key={i} />
))}
{Array.from({ length: 8 }).map((_, i) => (
<ProductCardSkeleton key={i} />
))}
</div>
) : filteredProducts.length > 0 ? (
) : filteredProducts.length > 0 ? (
<>
<div key="grid" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
<div key="grid" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
<AnimatePresence mode="popLayout">
{filteredProducts.map((p: Product) => (
<ArchiveProductCard key={p.id} product={p} onClick={(p) => router.push(`/shop/${p.slug || p.id}`)} />
))}
{filteredProducts.map((p: Product) => (
<ArchiveProductCard key={p.id} product={p} onClick={(p) => router.push(`/shop/${p.slug || p.id}`)} />
))}
</AnimatePresence>
</div>
{page < meta.lastPage && (
<div className="flex justify-center mt-10">
<button
onClick={loadMore}
className="bg-canina-blue text-white px-8 py-3 rounded-xl font-black text-sm hover:scale-105 transition-transform shadow-lg shadow-canina-blue/20"
>
بارگذاری محصولات بیشتر
</button>
</div>
)}
</>
) : (
<div key="empty" className="bg-white rounded-[3rem] p-20 text-center border-2 border-dashed border-medical-gray-200 flex flex-col items-center">
<div className="w-20 h-20 bg-medical-gray-50 rounded-full flex items-center justify-center text-medical-gray-300 mb-6">
<Search className="w-10 h-10" />
</div>
<h3 className="text-2xl font-black text-medical-gray-900 mb-2">محصولی یافت نشد!</h3>
<p className="text-medical-gray-400 max-w-sm mb-8 font-bold">با فیلترهای فعلی محصولی مطابق با نیاز شما پیدا نکردیم. لطفاً فیلترها را گستردهتر کنید یا دکمه ریست را بزنید.</p>
<button
onClick={() => {
router.push('/shop');
setSelectedCategory("all");
setSelectedPet("all");
setActiveSymptoms([]);
setSearchQuery("");
}}
{page < meta.lastPage && (
<div className="flex justify-center mt-10">
<button
onClick={loadMore}
className="bg-canina-blue text-white px-8 py-3 rounded-xl font-black text-sm hover:scale-105 transition-transform shadow-lg shadow-canina-blue/20"
>
پاک کردن همه فیلترها و نمایش همه
</button>
>
بارگذاری محصولات بیشتر
</button>
</div>
)}
</>
) : (
<div key="empty" className="bg-white rounded-[3rem] p-20 text-center border-2 border-dashed border-medical-gray-200 flex flex-col items-center">
<div className="w-20 h-20 bg-medical-gray-50 rounded-full flex items-center justify-center text-medical-gray-300 mb-6">
<Search className="w-10 h-10" />
</div>
<h3 className="text-2xl font-black text-medical-gray-900 mb-2">محصولی یافت نشد!</h3>
<p className="text-medical-gray-400 max-w-sm mb-8 font-bold">با فیلترهای فعلی محصولی مطابق با نیاز شما پیدا نکردیم. لطفاً فیلترها را گستردهتر کنید یا دکمه ریست را بزنید.</p>
<button
onClick={() => {
router.push('/shop');
setSelectedCategory("all");
setSelectedPet("all");
setActiveSymptoms([]);
setSearchQuery("");
}}
className="bg-canina-blue text-white px-8 py-3 rounded-xl font-black text-sm hover:scale-105 transition-transform shadow-lg shadow-canina-blue/20"
>
پاک کردن همه فیلترها و نمایش همه
</button>
</div>
)}
)}
</AnimatePresence>
</main>