canina/frontend/application/components/IngredientWiki.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

190 lines
10 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 { 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>
);
}