301 lines
18 KiB
TypeScript
301 lines
18 KiB
TypeScript
"use client";
|
||
import { useState, useEffect } from "react";
|
||
import { Product, IngredientInfo } from "../lib/data/products";
|
||
import { motion } from "motion/react";
|
||
import { FlaskConical, CheckCircle2, ChevronRight, ChevronLeft, Beaker, Search } from "lucide-react";
|
||
import { productService } from "../lib/services/productService";
|
||
|
||
import Link from "next/link";
|
||
import Image from "next/image";
|
||
import { useRouter, useSearchParams } from 'next/navigation';
|
||
|
||
import api from "../lib/services/api";
|
||
import { Ingredient } from "../lib/types";
|
||
|
||
export default function IngredientWiki() {
|
||
const router = useRouter();
|
||
const searchParams = useSearchParams();
|
||
const termParam = searchParams.get('term');
|
||
const [ingredientsWiki, setIngredientsWiki] = useState<IngredientInfo[]>([]);
|
||
const [products, setProducts] = useState<Product[]>([]);
|
||
const [searchQuery, setSearchQuery] = useState("");
|
||
|
||
useEffect(() => {
|
||
productService.getProducts({ limit: 999 }).then(res => setProducts(res.data));
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
api.get('/ingredients')
|
||
.then(res => {
|
||
const rawList = Array.isArray(res.data) ? res.data : (res.data?.data || []);
|
||
const apiList: IngredientInfo[] = rawList.map((item: Ingredient) => ({
|
||
id: item.slug || item.id,
|
||
name: item.nameFa ? (item.scientificName ? `${item.nameFa} (${item.scientificName})` : item.nameFa) : (item.nameEn || item.slug),
|
||
description: item.description || '',
|
||
benefits: Array.isArray(item.benefits) ? item.benefits : []
|
||
}));
|
||
setIngredientsWiki(apiList);
|
||
})
|
||
.catch((err) => {
|
||
console.error('[IngredientWiki] Failed to fetch ingredients from API:', err);
|
||
setIngredientsWiki([]);
|
||
});
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (termParam && ingredientsWiki.length > 0) {
|
||
const el = document.getElementById(`wiki-${termParam}`);
|
||
if (el) {
|
||
setTimeout(() => {
|
||
const yOffset = -120;
|
||
const y = el.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
||
window.scrollTo({ top: y, behavior: 'smooth' });
|
||
}, 200);
|
||
}
|
||
}
|
||
}, [termParam, ingredientsWiki]);
|
||
|
||
return (
|
||
<div className="bg-white py-12 px-4 overflow-hidden font-vazir" dir="rtl">
|
||
<div className="max-w-7xl mx-auto">
|
||
|
||
{/* Standard Breadcrumb Navigation & Integrated Back Button */}
|
||
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60 font-vazir" dir="rtl">
|
||
<div className="flex items-center gap-2 text-xs font-bold text-medical-gray-400 whitespace-nowrap">
|
||
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => router.push('/')}>خانه</span>
|
||
<ChevronLeft className="w-3 h-3 text-medical-gray-300" />
|
||
<span className="text-canina-blue font-black">دانشنامه مواد نایاب و ارگانیک</span>
|
||
</div>
|
||
|
||
<button
|
||
onClick={() => router.push('/')}
|
||
className="px-3.5 py-1.5 bg-white border border-medical-gray-200 rounded-lg text-medical-gray-600 shadow-xs flex items-center gap-1.5 font-bold text-xs hover:border-canina-blue hover:text-canina-blue transition-all whitespace-nowrap"
|
||
>
|
||
<ChevronRight className="w-3.5 h-3.5" />
|
||
<span>بازگشت</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div className="flex flex-col items-center text-center mb-20">
|
||
<div className="inline-flex items-center gap-2 px-4 py-2 bg-canina-blue/5 border border-canina-blue/10 rounded-full text-canina-blue text-xs font-black uppercase tracking-widest mb-6">
|
||
<FlaskConical className="w-4 h-4" />
|
||
علم در خدمت کیفیت
|
||
</div>
|
||
<h2 className="text-4xl lg:text-6xl font-black text-medical-gray-900 leading-tight md:max-w-4xl">
|
||
دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کنینا
|
||
</h2>
|
||
<p className="mt-6 text-lg text-medical-gray-500 max-w-2xl leading-relaxed">
|
||
ما از مواد اولیهای استفاده میکنیم که در سطح دارویی فرآوری شدهاند. در اینجا با قدرت بیولوژیک این ترکیبات آشنا شوید.
|
||
</p>
|
||
<div className="relative w-full max-w-md mt-8">
|
||
<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-medical-gray-50 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>
|
||
|
||
{/* Sugar-Free & Gluten-Free Medical Standards Banner */}
|
||
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||
<div className="px-4 py-2 bg-emerald-50 border border-emerald-200 text-emerald-800 rounded-2xl text-xs font-black flex items-center gap-1.5 shadow-xs">
|
||
<CheckCircle2 className="w-4 h-4 text-emerald-600" />
|
||
<span>۱۰۰٪ فاقد قند افزوده (Sugar-Free)</span>
|
||
</div>
|
||
<div className="px-4 py-2 bg-blue-50 border border-blue-200 text-blue-800 rounded-2xl text-xs font-black flex items-center gap-1.5 shadow-xs">
|
||
<CheckCircle2 className="w-4 h-4 text-blue-600" />
|
||
<span>مناسب رژیمهای حساس و فاقد گلوتن</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{(() => {
|
||
const filtered = ingredientsWiki.filter(ing => {
|
||
if (!searchQuery.trim()) return true;
|
||
const q = searchQuery.trim().toLowerCase();
|
||
return ing.name.toLowerCase().includes(q) || ing.description.toLowerCase().includes(q);
|
||
});
|
||
if (filtered.length === 0) {
|
||
return (
|
||
<div className="text-center py-20">
|
||
<Search className="w-12 h-12 text-medical-gray-300 mx-auto mb-4" />
|
||
<h3 className="text-xl font-black text-medical-gray-900 mb-2">مادهای یافت نشد</h3>
|
||
<p className="text-medical-gray-400 font-bold">با عبارت جستجو شده ماده مؤثرهای مطابقت ندارد.</p>
|
||
</div>
|
||
);
|
||
}
|
||
return (
|
||
<div className="space-y-32">
|
||
{filtered.map((ing, idx) => {
|
||
const hasIngredient = products.filter(p => {
|
||
const ingNameClean = ing.name.split('(')[0].trim().toLowerCase();
|
||
const ingIdClean = ing.id.replace(/-/g, ' ').toLowerCase();
|
||
|
||
return p.main_ingredients?.some(mi => {
|
||
const miClean = mi.toLowerCase();
|
||
return miClean.includes(ingNameClean) ||
|
||
ingNameClean.includes(miClean) ||
|
||
miClean.includes(ingIdClean) ||
|
||
(ing.id === 'green-mussel' && (miClean.includes('صدف') || miClean.includes('mussel'))) ||
|
||
(ing.id === 'collagen' && miClean.includes('کلاژن')) ||
|
||
(ing.id === 'silver' && (miClean.includes('نقره') || miClean.includes('silver'))) ||
|
||
(ing.id === 'peat-extract' && (miClean.includes('پیت') || miClean.includes('moor') || miClean.includes('عصاره'))) ||
|
||
(ing.id === 'colostrum' && (miClean.includes('آغوز') || miClean.includes('colostrum'))) ||
|
||
(ing.id === 'biotin' && (miClean.includes('بیوتین') || miClean.includes('biotin'))) ||
|
||
(ing.id === 'taurin' && (miClean.includes('تورین') || miClean.includes('taurine'))) ||
|
||
(ing.id === 'salmon-oil' && (miClean.includes('سالمون') || miClean.includes('salmon') || miClean.includes('ماهی'))) ||
|
||
(ing.id === 'black-cumin' && (miClean.includes('سیاه دانه') || miClean.includes('زیره') || miClean.includes('cumin'))) ||
|
||
(ing.id === 'eggshell' && (miClean.includes('پوسته تخم مرغ') || miClean.includes('تخممرغ') || miClean.includes('eggshell'))) ||
|
||
(ing.id === 'hawthorn' && (miClean.includes('زالزالک') || miClean.includes('hawthorn'))) ||
|
||
(ing.id === 'l-carnitine' && (miClean.includes('کارنیتین') || miClean.includes('carnitine'))) ||
|
||
(ing.id === 'seaweed' && (miClean.includes('جلبک') || miClean.includes('seaweed'))) ||
|
||
(ing.id === 'hyaluronic' && (miClean.includes('هیالورونات') || miClean.includes('hyaluron'))) ||
|
||
(ing.id === 'calendula-sea-buckthorn' && (miClean.includes('کالاندولا') || miClean.includes('سنجد') || miClean.includes('خولان') || miClean.includes('calendula'))) ||
|
||
(ing.id === 'colloidal-silver' && miClean.includes('کلوئیدی')) ||
|
||
(ing.id === 'retinol-palmitate' && (miClean.includes('رتینول') || miClean.includes('پالمیتات'))) ||
|
||
(ing.id === 'grapefruit-seed' && miClean.includes('گریپ')) ||
|
||
(ing.id === 'vaseline' && miClean.includes('وازلین')) ||
|
||
(ing.id === 'panthenol' && miClean.includes('پانتنول')) ||
|
||
(ing.id === 'diatomaceous' && miClean.includes('دیاتومه')) ||
|
||
(ing.id === 'artichoke' && miClean.includes('کنگر')) ||
|
||
(ing.id === 'brewers-yeast' && (miClean.includes('مخمر') || miClean.includes('yeast'))) ||
|
||
(ing.id === 'willow-bark' && miClean.includes('بید')) ||
|
||
(ing.id === 'ginger' && miClean.includes('زنجبیل')) ||
|
||
(ing.id === 'bovine-serum' && miClean.includes('سرم')) ||
|
||
(ing.id === 'bovine-blood' && miClean.includes('خون')) ||
|
||
(ing.id === 'beef-fat' && miClean.includes('چربی')) ||
|
||
(ing.id === 'argan-oil' && miClean.includes('آرگان')) ||
|
||
(ing.id === 'rosehip-oil' && miClean.includes('گل رز')) ||
|
||
(ing.id === 'walnut-oil' && miClean.includes('گردو')) ||
|
||
(ing.id === 'polyglyceryl-caprate' && (miClean.includes('پلی گلیسریل') || miClean.includes('کاپرات'))) ||
|
||
(ing.id === 'carbomer' && miClean.includes('کربومر')) ||
|
||
(ing.id === 'dodecanoic' && (miClean.includes('دودکانوئیک') || miClean.includes('مارگوسا') || miClean.includes('insect')));
|
||
});
|
||
});
|
||
|
||
const isTargeted = termParam === ing.id;
|
||
return (
|
||
<div
|
||
key={ing.id}
|
||
id={`wiki-${ing.id}`}
|
||
className={`flex flex-col lg:flex-row items-center gap-16 p-6 rounded-[3rem] transition-all duration-500 ${isTargeted ? 'bg-canina-blue/5 border-2 border-canina-blue ring-4 ring-canina-blue/10 shadow-2xl' : ''} ${idx % 2 === 1 ? 'lg:flex-row-reverse' : ''}`}
|
||
>
|
||
{/* Content */}
|
||
<div className="lg:w-1/2 space-y-8">
|
||
<motion.div
|
||
initial={{ opacity: 0, x: idx % 2 === 1 ? 40 : -40 }}
|
||
whileInView={{ opacity: 1, x: 0 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.8 }}
|
||
>
|
||
<div className="flex items-center gap-4 mb-6">
|
||
<div className="w-14 h-14 rounded-3xl bg-medical-gray-900 flex items-center justify-center text-white shadow-xl">
|
||
<Beaker className="w-6 h-6" />
|
||
</div>
|
||
<h3 className="text-3xl font-black text-medical-gray-900">{ing.name}</h3>
|
||
</div>
|
||
|
||
<p className="text-lg text-medical-gray-600 leading-relaxed mb-8">
|
||
{ing.description}
|
||
</p>
|
||
|
||
<div className="grid grid-cols-1 gap-4 mb-10">
|
||
{ing.benefits.map((benefit, bIdx) => (
|
||
<div key={bIdx} className="flex items-start gap-4 p-4 bg-medical-gray-50 rounded-2xl border border-medical-gray-100">
|
||
<CheckCircle2 className="w-6 h-6 text-canina-blue flex-shrink-0" />
|
||
<span className="text-sm font-bold text-medical-gray-700">{benefit}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
|
||
{/* Products Linking */}
|
||
<div className="lg:w-1/2 relative">
|
||
<motion.div
|
||
initial={{ opacity: 0, scale: 0.9 }}
|
||
whileInView={{ opacity: 1, scale: 1 }}
|
||
viewport={{ once: true }}
|
||
className="bg-medical-gray-100/80 rounded-[3rem] p-8 sm:p-10 border border-medical-gray-200/60 relative overflow-hidden"
|
||
>
|
||
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60">
|
||
<div className="flex items-center gap-2">
|
||
<span className="w-2.5 h-2.5 rounded-full bg-canina-blue animate-pulse" />
|
||
<h4 className="text-xs sm:text-sm font-black text-medical-gray-900 font-vazir">موجود در محصولات کاتالوگ</h4>
|
||
</div>
|
||
<span className="text-[10px] font-black text-canina-blue bg-canina-blue/10 px-3 py-1 rounded-full font-vazir">
|
||
{hasIngredient.length} محصول
|
||
</span>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5 relative z-10">
|
||
{hasIngredient.length > 0 ? hasIngredient.map(p => (
|
||
<Link
|
||
key={p.id}
|
||
href={`/shop/${p.slug || p.id}`}
|
||
className="bg-white rounded-[2rem] p-5 shadow-lg border border-medical-gray-200/70 hover:border-canina-blue/40 hover:shadow-xl hover:scale-[1.03] transition-all cursor-pointer group flex flex-col justify-between"
|
||
>
|
||
<div className="aspect-square bg-medical-gray-50 rounded-2xl p-4 mb-4 flex items-center justify-center relative overflow-hidden">
|
||
<Image src={p.image} alt={p.name} width={96} height={96} className="max-h-24 w-auto object-contain group-hover:scale-110 transition-transform duration-500" unoptimized />
|
||
</div>
|
||
<h4 className="text-xs font-black text-center text-medical-gray-900 group-hover:text-canina-blue transition-colors px-1 leading-snug font-vazir">{p.name}</h4>
|
||
</Link>
|
||
)) : (
|
||
<div className="col-span-full py-8 text-center">
|
||
<p className="text-medical-gray-400 font-bold italic mb-3">محصولی با این ماده مؤثره یافت نشد.</p>
|
||
<button
|
||
onClick={() => router.push('/shop')}
|
||
className="text-canina-blue font-black text-sm hover:underline"
|
||
>
|
||
مشاهده همه محصولات
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Decorative backdrop */}
|
||
<div className="absolute -bottom-20 -left-20 w-80 h-80 bg-canina-blue rounded-full blur-[100px] opacity-10" />
|
||
</motion.div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
);
|
||
})()}
|
||
|
||
{/* Quality Badge */}
|
||
<div className="mt-32 p-12 bg-medical-gray-900 rounded-[4rem] text-center text-white relative overflow-hidden">
|
||
<div className="absolute inset-0 opacity-10 mix-blend-overlay">
|
||
<div className="grid grid-cols-12 h-full w-full">
|
||
{Array.from({length: 120}).map((_, i) => (
|
||
<div key={i} className="border border-white/20" />
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="relative z-10 max-w-3xl mx-auto">
|
||
<h3 className="text-3xl lg:text-5xl font-black mb-8 leading-tight italic">تمام مواد اولیه ما دارای گواهینامه <br /> <span className="text-canina-blue">گرید دارویی اختصاصی</span> هستند.</h3>
|
||
<p className="text-white/60 text-lg mb-10">این یعنی استانداردی فراتر از مکملهای معمولی، مشابه استانداردهای تولید دارو در اتحادیه اروپا.</p>
|
||
<div className="flex justify-center gap-12">
|
||
<div className="flex flex-col items-center">
|
||
<div className="text-2xl font-black font-vazir text-canina-blue">۱۰۰٪</div>
|
||
<div className="text-[10px] font-bold uppercase tracking-widest text-white/40 mt-1">تست آزمایشگاهی</div>
|
||
</div>
|
||
<div className="flex flex-col items-center">
|
||
<div className="text-2xl font-black font-vazir">GMP</div>
|
||
<div className="text-[10px] font-bold uppercase tracking-widest text-white/40 mt-1">استاندارد تولید</div>
|
||
</div>
|
||
<div className="flex flex-col items-center">
|
||
<div className="text-2xl font-black font-vazir">ISO</div>
|
||
<div className="text-[10px] font-bold uppercase tracking-widest text-white/40 mt-1">کنترل کیفیت</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|