- 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
190 lines
10 KiB
TypeScript
190 lines
10 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 } from "lucide-react";
|
||
import { useSettingsStore } from "../lib/store/settingsStore";
|
||
import { productService } from "../lib/services/productService";
|
||
|
||
import { useRouter } from 'next/navigation';
|
||
|
||
export default function IngredientWiki() {
|
||
const router = useRouter();
|
||
const texts = useSettingsStore(state => state.texts);
|
||
const [ingredientsWiki, setIngredientsWiki] = useState<IngredientInfo[]>([]);
|
||
const [products, setProducts] = useState<Product[]>([]);
|
||
|
||
useEffect(() => {
|
||
productService.getProducts().then(data => setProducts(data));
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
const raw = texts.ingredients_wiki || texts.ingredients_wiki_text;
|
||
if (raw) {
|
||
try {
|
||
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||
if (Array.isArray(parsed)) {
|
||
setIngredientsWiki(parsed.map((item: any) => ({
|
||
id: item.id,
|
||
name: item.name,
|
||
description: item.description,
|
||
benefits: Array.isArray(item.benefits) ? item.benefits : []
|
||
})));
|
||
}
|
||
} catch (e) {
|
||
console.error("Failed to parse ingredients_wiki:", e);
|
||
}
|
||
}
|
||
}, [texts]);
|
||
|
||
return (
|
||
<div className="bg-white py-12 px-4 overflow-hidden font-vazir" dir="rtl">
|
||
<div className="max-w-7xl mx-auto">
|
||
|
||
{/* Mobile Navigation & Breadcrumbs */}
|
||
<div className="lg:hidden mb-12 space-y-4">
|
||
<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" />
|
||
<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" />
|
||
<span className="text-canina-blue">دانشنامه علمی</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Desktop Breadcrumbs */}
|
||
<div className="hidden lg:flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-12">
|
||
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
|
||
<ChevronLeft className="w-2.5 h-2.5" />
|
||
<span className="text-canina-blue">دانشنامه مواد نایاب و ارگانیک</span>
|
||
</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>
|
||
|
||
<div className="space-y-32">
|
||
{ingredientsWiki.map((ing, idx) => {
|
||
const hasIngredient = products.filter(p =>
|
||
p.main_ingredients?.some(mi => mi.toLowerCase().includes(ing.name.toLowerCase())) ||
|
||
p.main_ingredients?.some(mi => mi.toLowerCase().includes(ing.id.replace('-', ' ')))
|
||
);
|
||
|
||
return (
|
||
<div key={ing.id} className={`flex flex-col lg:flex-row items-center gap-16 ${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 rounded-[4rem] p-12 relative overflow-hidden"
|
||
>
|
||
<div className="absolute top-0 right-0 p-8">
|
||
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-[0.3em]">موجود در محصولات</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 relative z-10">
|
||
{hasIngredient.length > 0 ? hasIngredient.map(p => (
|
||
<div
|
||
key={p.id}
|
||
onClick={() => router.push(`/shop/${p.id}`)}
|
||
className="bg-white rounded-[2.5rem] p-6 shadow-xl hover:scale-105 transition-transform cursor-pointer group"
|
||
>
|
||
<img src={p.image} alt={p.name} className="w-24 h-24 object-contain mx-auto mb-4" referrerPolicy="no-referrer" />
|
||
<h4 className="text-sm font-black text-center text-medical-gray-900 group-hover:text-canina-blue transition-colors px-2">{p.name}</h4>
|
||
</div>
|
||
)) : (
|
||
<div className="col-span-full py-12 text-center text-medical-gray-400 font-bold italic">
|
||
اطلاعات محصولات مرتبط به زودی اضافه خواهد شد.
|
||
</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>
|
||
);
|
||
}
|