canina/frontend/application/components/SearchResultsPage.tsx
parsa aghaei 7615aa0e51 fix: resolve seed encoding, search param, and wiki data source issues
- Fix seed-products.ts TS error (implicit any) and BOM handling
- Re-run full seed to restore correct Persian encoding in DB
- Fix productService query→search param mismatch
- Fix IngredientWiki hardcoded port 4000→use settingsStore
- Restore seed-products-data.json from git after accidental corruption
2026-07-11 15:40:49 +03:30

142 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useMemo, useState, useEffect } from "react";
import { Search, ShoppingBag, ChevronLeft, ArrowRight, Activity, Sparkles, HeartPulse, Stethoscope, ShieldCheck, Heart, AlertCircle } from "lucide-react";
import { usePetStore } from "../lib/store/usePetStore";
import { motion } from "motion/react";
import { Product } from "../lib/data/products";
import { productService } from "../lib/services/productService";
import { useRouter } from 'next/navigation';
export default function SearchResultsPage({ query }: { query: string }) {
const router = useRouter();
const { getActivePet } = usePetStore();
const activePet = getActivePet();
const [products, setProducts] = useState<Product[]>([]);
useEffect(() => {
productService.getProducts()
.then(setProducts)
.catch(err => console.error("Error fetching products in SearchResultsPage:", err));
}, []);
const results = products.filter(p =>
p.name.toLowerCase().includes(query.toLowerCase()) ||
p.description.toLowerCase().includes(query.toLowerCase()) ||
p.main_ingredients.some(ing => ing.toLowerCase().includes(query.toLowerCase())) ||
p.symptoms.some(sym => sym.toLowerCase().includes(query.toLowerCase()))
);
const bestSellers = products.slice(0, 3);
return (
<div className="min-h-screen bg-medical-gray-50 py-20 px-6 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto">
<button onClick={() => router.back()} className="flex items-center gap-2 text-medical-gray-400 font-black mb-10 hover:text-canina-blue transition-colors">
<ArrowRight className="w-5 h-5 rotate-180" />
بازگشت
</button>
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
<div>
<h1 className="text-4xl font-black text-medical-gray-900 italic mb-4">
نتایج جستجو برای: <span className="text-canina-blue">"{query}"</span>
</h1>
<p className="text-medical-gray-500 font-medium">
{results.length} محصول با معیارهای شما مطابقت دارد.
</p>
</div>
</div>
{results.length > 0 ? (
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{results.map((product) => {
const compatibility = (() => {
if (!activePet) return null;
const sameSpecies = product.suitableFor === activePet.type || product.suitableFor === "هر دو";
const helpsSymptom = activePet.medicalConditions.some(c => product.symptoms.includes(c));
if (!sameSpecies) return { type: 'alert', text: `مخصوص ${product.suitableFor}` };
if (helpsSymptom) return { type: 'success', text: `توصیه شده برای ${activePet.name}` };
return { type: 'neutral', text: `مناسب برای ${activePet.name}` };
})();
return (
<motion.div
key={product.id}
layoutId={product.id}
onClick={() => router.push(`/shop/${product.slug || product.id}`)}
className="bg-white rounded-[2.5rem] p-8 border border-medical-gray-200 group cursor-pointer hover:shadow-2xl hover:shadow-canina-blue/10 transition-all flex flex-col relative"
>
<div className="relative aspect-square mb-8 bg-medical-gray-50 rounded-[2rem] overflow-hidden p-6 flex items-center justify-center">
<img
src={product.image}
alt={product.name}
className="w-full h-full object-contain group-hover:scale-110 transition-transform duration-500"
referrerPolicy="no-referrer"
/>
{product.specialBadge && (
<div className="absolute top-4 right-4 bg-medical-gray-900 text-white text-[8px] font-black px-3 py-1 rounded-full uppercase tracking-widest">
{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'
}`}>
{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>
<div className="flex-1">
<span className="text-[10px] font-black text-canina-blue uppercase tracking-widest mb-2 block">{product.category}</span>
<h3 className="text-xl font-black text-medical-gray-900 mb-2 leading-tight group-hover:text-canina-blue transition-colors">{product.name}</h3>
<p className="text-xs text-medical-gray-400 line-clamp-2 leading-relaxed mb-6">{product.benefits}</p>
</div>
<div className="flex items-center justify-between pt-6 border-t border-medical-gray-100 italic">
<div>
<span className="text-lg font-black text-medical-gray-900">{product.price}</span>
</div>
<button className="bg-medical-gray-900 text-white w-10 h-10 rounded-xl flex items-center justify-center group-hover:bg-canina-blue transition-colors">
<ChevronLeft className="w-5 h-5" />
</button>
</div>
</motion.div>
)
})}
</div>
) : (
<div className="space-y-16">
<div className="bg-white border border-medical-gray-200 rounded-[3rem] p-12 text-center shadow-sm">
<div className="w-20 h-20 bg-medical-gray-50 rounded-full flex items-center justify-center mx-auto text-medical-gray-300 mb-6">
<Search className="w-10 h-10" />
</div>
<h3 className="text-2xl font-black text-medical-gray-800 mb-4">نتیجهای یافت نشد</h3>
<p className="text-medical-gray-500 font-medium max-w-md mx-auto leading-relaxed">
متاسفیم، هیچ محصولی با عبارت مورد نظر شما مطابقت نداشت. شاید محصولات پرفروش ما برای شما مفید باشند؟
</p>
</div>
<div>
<h3 className="text-2xl font-black text-medical-gray-900 mb-10 italic">محصولات پیشنهادی (پرفروش)</h3>
<div className="grid md:grid-cols-3 gap-8 opacity-60 hover:opacity-100 transition-opacity">
{bestSellers.map(p => (
<div key={p.id} onClick={() => router.push(`/shop/${p.id}`)} className="cursor-pointer group">
<div className="aspect-square bg-white rounded-[2rem] p-6 mb-4 border border-medical-gray-100 flex items-center justify-center">
<img src={p.image} className="w-40 h-40 object-contain group-hover:scale-105 transition-transform" />
</div>
<h4 className="font-black text-medical-gray-900 text-center">{p.name}</h4>
</div>
))}
</div>
</div>
</div>
)}
</div>
</div>
);
}