Compare commits

..

No commits in common. "27ef5979aab276cbca4718587f1dd9cba6c6b774" and "0d805b0eb9d1bbb137534d02a2252e2e14137153" have entirely different histories.

13 changed files with 324 additions and 554 deletions

View File

@ -88,6 +88,6 @@
"testEnvironment": "node" "testEnvironment": "node"
}, },
"prisma": { "prisma": {
"seed": "ts-node prisma/seed.ts" "seed": "ts-node prisma/seed.ts && ts-node prisma/seed-products.ts && ts-node prisma/seed-home.ts"
} }
} }

View File

@ -255,10 +255,7 @@ async function main() {
// 2. Seed Scientific Terms // 2. Seed Scientific Terms
console.log('Seeding Scientific Terms...'); console.log('Seeding Scientific Terms...');
let termsFilePath = path.join(process.cwd() + "/prisma", '..', '..', 'frontend', 'application', 'lib', 'data', 'scientificTerms.ts'); const termsFilePath = path.join(process.cwd() + "/prisma", '..', '..', 'frontend', 'application', 'lib', 'data', 'scientificTerms.ts');
if (!fs.existsSync(termsFilePath)) {
termsFilePath = path.join(process.cwd(), 'prisma', 'scientificTerms.ts');
}
if (fs.existsSync(termsFilePath)) { if (fs.existsSync(termsFilePath)) {
const termsContent = fs.readFileSync(termsFilePath, 'utf-8'); const termsContent = fs.readFileSync(termsFilePath, 'utf-8');
const termsJsCode = ts.transpile(termsContent, { const termsJsCode = ts.transpile(termsContent, {
@ -293,25 +290,7 @@ async function main() {
} }
} }
// 3. Seed Products & Categories console.log('Seeding completed successfully!');
console.log('Seeding Products & Categories...');
try {
const { main: seedProducts } = await import('./seed-products');
await seedProducts();
} catch (err) {
console.error('Failed to seed products:', err);
}
// 4. Seed Home Components & Testimonials
console.log('Seeding Home Components...');
try {
const { main: seedHome } = await import('./seed-home');
await seedHome();
} catch (err) {
console.error('Failed to seed home components:', err);
}
console.log('All Seeding completed successfully!');
} }

View File

@ -35,7 +35,17 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
} }
}, [fetchProfile, fetchSettings]); }, [fetchProfile, fetchSettings]);
// Remove full-page blocking screen to allow immediate render if (!isInitialized) {
return (
<div className="min-h-screen bg-medical-gray-50 flex flex-col items-center justify-center font-sans" dir="rtl">
<div className="flex flex-col items-center gap-4 text-center">
<div className="w-12 h-12 border-4 border-canina-blue border-t-transparent rounded-full animate-spin" />
<h2 className="text-xl font-black text-medical-gray-900 font-lalezar tracking-wide">در حال بارگذاری اطلاعات سایت...</h2>
<p className="text-sm text-medical-gray-500 font-shabnam">لطفاً شکیبا باشید</p>
</div>
</div>
);
}
// Derived currentView from pathname for Header // Derived currentView from pathname for Header
let currentView = "home"; let currentView = "home";
@ -104,7 +114,7 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
petName={advisorData?.name} petName={advisorData?.name}
isAdvisorContext={!!advisorData} isAdvisorContext={!!advisorData}
/> />
<Toaster position="top-center" expand={true} richColors closeButton /> <Toaster position="top-center" expand={true} richColors />
</> </>
); );
} }

View File

@ -104,7 +104,7 @@
html, body, #root { html, body, #root {
font-family: "Vazirmatn" !important; font-family: "Vazirmatn" !important;
@apply bg-medical-gray-50 text-medical-gray-900 antialiased max-w-[100vw]; @apply bg-medical-gray-50 text-medical-gray-900 antialiased overflow-x-hidden max-w-[100vw];
font-feature-settings: "ss01", "ss02", "cv01", "cv11"; font-feature-settings: "ss01", "ss02", "cv01", "cv11";
} }

View File

@ -1,4 +1,3 @@
import { Suspense } from "react";
import IngredientWiki from "../../components/IngredientWiki"; import IngredientWiki from "../../components/IngredientWiki";
import type { Metadata } from 'next'; import type { Metadata } from 'next';
@ -19,9 +18,5 @@ export const metadata: Metadata = {
}; };
export default function WikiPage() { export default function WikiPage() {
return ( return <IngredientWiki />;
<Suspense fallback={<div className="min-h-screen flex items-center justify-center font-vazir text-sm">در حال بارگذاری دانشنامه...</div>}>
<IngredientWiki />
</Suspense>
);
} }

View File

@ -1,6 +1,5 @@
"use client"; "use client";
import React, { useState, useMemo, useEffect } from "react"; import React, { useState, useMemo, useEffect } from "react";
import { toPersian } from "../lib/utils";
import { Product, PetType } from "../lib/data/products"; import { Product, PetType } from "../lib/data/products";
import { usePetStore } from "../lib/store/usePetStore"; import { usePetStore } from "../lib/store/usePetStore";
import { productService } from "../lib/services/productService"; import { productService } from "../lib/services/productService";
@ -161,53 +160,15 @@ const ArchiveProductCard: React.FC<{ product: Product }> = ({ product }) => {
))} ))}
</div> </div>
<div className="mt-auto flex items-center justify-between pt-4 border-t border-medical-gray-50 gap-2"> <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 text-sm sm:text-base">{product.price}</span> <span className="font-black text-medical-gray-900 font-vazir">{product.price}</span>
{(() => { <button
const cartItem = useCartStore.getState().items.find(i => i.product.id === product.id); onClick={handleAddToCart}
if (cartItem && cartItem.quantity > 0) { disabled={isAdding}
return ( 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"
<div >
onClick={(e) => { e.preventDefault(); e.stopPropagation(); }} {isAdding ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}
className="flex items-center gap-1 bg-canina-blue/10 border border-canina-blue/20 rounded-xl p-1" </button>
>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
useCartStore.getState().updateQuantity(product.id, cartItem.quantity + 1);
}}
className="w-7 h-7 rounded-lg bg-canina-blue text-white flex items-center justify-center font-bold text-xs"
>
+
</button>
<span className="w-5 text-center font-black text-canina-blue text-xs font-vazir">
{toPersian(cartItem.quantity)}
</span>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
useCartStore.getState().updateQuantity(product.id, cartItem.quantity - 1);
}}
className="w-7 h-7 rounded-lg bg-white text-medical-gray-700 flex items-center justify-center font-bold text-xs shadow-sm"
>
-
</button>
</div>
);
}
return (
<button
onClick={handleAddToCart}
disabled={isAdding}
className="px-3 py-2 rounded-xl bg-canina-blue text-white text-xs font-black flex items-center gap-1.5 hover:bg-canina-dark transition-all disabled:opacity-50 shadow-md shadow-canina-blue/20"
>
{isAdding ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Plus className="w-3.5 h-3.5" />}
<span>خرید</span>
</button>
);
})()}
</div> </div>
</div> </div>
</Link> </Link>
@ -234,12 +195,10 @@ export default function ArchivePage({
const [activeSymptoms, setActiveSymptoms] = useState<string[]>(initialSymptoms ? initialSymptoms.split(',') : []); const [activeSymptoms, setActiveSymptoms] = useState<string[]>(initialSymptoms ? initialSymptoms.split(',') : []);
const [searchQuery, setSearchQuery] = useState(initialSearch); const [searchQuery, setSearchQuery] = useState(initialSearch);
const [isUpdating, setIsUpdating] = useState(false); const [isUpdating, setIsUpdating] = useState(false);
const [isMobileFilterOpen, setIsMobileFilterOpen] = useState(false);
const [filteredProducts, setFilteredProducts] = useState<Product[]>([]); const [filteredProducts, setFilteredProducts] = useState<Product[]>([]);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [meta, setMeta] = useState({ total: 0, lastPage: 1 }); const [meta, setMeta] = useState({ total: 0, lastPage: 1 });
const [symptomSearch, setSymptomSearch] = useState("");
const [categories, setCategories] = useState<{ id: string; label: string; icon: React.ReactNode }[]>([]); const [categories, setCategories] = useState<{ id: string; label: string; icon: React.ReactNode }[]>([]);
const [symptoms, setSymptoms] = useState<string[]>([]); const [symptoms, setSymptoms] = useState<string[]>([]);
@ -365,54 +324,44 @@ export default function ArchivePage({
<div className="min-h-screen bg-medical-gray-50 pb-20 px-4 pt-10 font-vazir" dir="rtl"> <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"> <div className="max-w-7xl mx-auto">
{/* Standard Breadcrumb Navigation & Integrated Back Button */} {/* Mobile Navigation & Breadcrumbs */}
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60 font-vazir"> <div className="lg:hidden mb-10 space-y-4">
<div className="flex items-center gap-2 text-xs font-bold text-medical-gray-400 whitespace-nowrap"> <button
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => router.push('/')}>خانه</span> onClick={() => router.back()}
<ChevronLeft className="w-3 h-3 text-medical-gray-300" /> className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => { setSelectedCategory("all"); }}>کاتالوگ</span> >
{selectedCategory !== "all" && ( <ChevronRight className="w-5 h-5 font-vazir" />
<> <span>بازگشت</span>
<ChevronLeft className="w-3 h-3 text-medical-gray-300" /> </button>
<span className="text-canina-blue font-black">{CATEGORY_LABELS[selectedCategory] || selectedCategory}</span>
</>
)}
</div>
<div className="flex items-center gap-2"> <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">
<button <span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
onClick={() => setIsMobileFilterOpen(!isMobileFilterOpen)} <ChevronLeft className="w-2.5 h-2.5" />
className="lg:hidden flex items-center gap-1.5 bg-canina-blue text-white px-3 py-1.5 rounded-lg text-xs font-bold shadow-xs" <span className="text-canina-blue">فروشگاه تخصصی</span>
>
<Filter className="w-3.5 h-3.5" />
<span>فیلترها {activeSymptoms.length > 0 || selectedPet !== "all" || selectedCategory !== "all" ? "•" : ""}</span>
</button>
<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>
</div> </div>
<div className="flex flex-col lg:flex-row gap-8"> {/* 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>
{/* Sidebar Filters - Collapsible on Mobile */} <div className="flex flex-col lg:flex-row gap-10">
<aside className={`lg:w-72 flex-shrink-0 space-y-6 ${isMobileFilterOpen ? 'block' : 'hidden lg:block'}`}>
{/* 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="bg-white rounded-[2rem] p-6 border border-medical-gray-200 shadow-sm">
<div className="flex items-center justify-between mb-6"> <div className="flex items-center gap-2 mb-6">
<div className="flex items-center gap-2"> <Filter className="w-5 h-5 text-canina-blue" />
<Filter className="w-5 h-5 text-canina-blue" /> <h3 className="font-black text-medical-gray-900">فیلترهای تخصصی</h3>
<h3 className="font-black text-medical-gray-900">فیلترهای تخصصی</h3>
</div>
<button
onClick={() => setIsMobileFilterOpen(false)}
className="lg:hidden text-xs text-medical-gray-400 font-bold"
>
بستن ✕
</button>
</div> </div>
<div className="space-y-6"> <div className="space-y-6">
@ -444,7 +393,7 @@ export default function ArchivePage({
{categories.map(cat => ( {categories.map(cat => (
<button <button
key={cat.id} key={cat.id}
onClick={() => { setSelectedCategory(cat.id); setIsMobileFilterOpen(false); }} 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'}`} 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.icon}
@ -454,7 +403,7 @@ export default function ArchivePage({
</div> </div>
</div> </div>
{/* Symptoms Pill Tags with Search Field */} {/* Symptoms Pill Tags */}
<div> <div>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">جستجو بر اساس علائم</span> <span className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">جستجو بر اساس علائم</span>
@ -467,32 +416,21 @@ export default function ArchivePage({
</button> </button>
)} )}
</div> </div>
<div className="relative mb-3"> <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">
<input
type="text"
placeholder="جستجوی علائم..."
value={symptomSearch}
onChange={(e) => setSymptomSearch(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-xs outline-none focus:border-canina-blue font-vazir"
/>
</div>
<div className="flex flex-wrap gap-1.5 max-h-48 overflow-y-auto scrollbar-thin scrollbar-thumb-medical-gray-200 scrollbar-track-transparent pr-0.5">
{symptoms.length === 0 ? ( {symptoms.length === 0 ? (
<span className="text-[10px] text-medical-gray-400">در حال بارگذاری...</span> <span className="text-[10px] text-medical-gray-400">در حال بارگذاری...</span>
) : symptoms ) : symptoms.map(s => (
.filter(s => s.toLowerCase().includes(symptomSearch.toLowerCase())) <button
.map(s => ( key={s}
<button onClick={() => toggleSymptom(s)}
key={s} className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${activeSymptoms.includes(s)
onClick={() => toggleSymptom(s)} ? 'bg-canina-blue border-canina-blue text-white shadow-sm shadow-canina-blue/30'
className={`px-2.5 py-1 rounded-full text-[10px] font-bold transition-all border whitespace-nowrap ${activeSymptoms.includes(s) : 'bg-medical-gray-50 border-medical-gray-200 text-medical-gray-500 hover:border-canina-blue/40 hover:text-canina-blue'
? '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>
{s} ))}
</button>
))}
</div> </div>
</div> </div>
</div> </div>
@ -509,7 +447,7 @@ export default function ArchivePage({
{/* Main Content */} {/* Main Content */}
<main className="flex-1 relative"> <main className="flex-1 relative">
<div className="flex flex-col md:flex-row items-center justify-between mb-6 gap-4"> <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> <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"> <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" /> <Search className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
@ -523,43 +461,6 @@ export default function ArchivePage({
</div> </div>
</div> </div>
{/* Active Filters Bar with X Dismiss Cross Buttons */}
{(selectedCategory !== "all" || selectedPet !== "all" || activeSymptoms.length > 0 || searchQuery) && (
<div className="flex flex-wrap items-center gap-2 mb-6 bg-white p-4 rounded-2xl border border-medical-gray-200 shadow-sm font-vazir" dir="rtl">
<span className="text-xs font-black text-medical-gray-400 ml-2">فیلترهای فعال:</span>
{selectedCategory !== "all" && (
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
{CATEGORY_LABELS[selectedCategory] || selectedCategory}
<button onClick={() => setSelectedCategory("all")} className="hover:text-red-500 text-sm leading-none">✕</button>
</span>
)}
{selectedPet !== "all" && (
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
پت: {selectedPet}
<button onClick={() => setSelectedPet("all")} className="hover:text-red-500 text-sm leading-none">✕</button>
</span>
)}
{activeSymptoms.map(sym => (
<span key={sym} className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
علائم: {sym}
<button onClick={() => toggleSymptom(sym)} className="hover:text-red-500 text-sm leading-none">✕</button>
</span>
))}
{searchQuery && (
<span className="inline-flex items-center gap-1.5 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-xl text-xs font-black border border-canina-blue/20">
جستجو: {searchQuery}
<button onClick={() => setSearchQuery("")} className="hover:text-red-500 text-sm leading-none">✕</button>
</span>
)}
<button
onClick={() => { setSelectedCategory("all"); setSelectedPet("all"); setActiveSymptoms([]); setSearchQuery(""); }}
className="text-xs font-bold text-red-500 hover:underline mr-auto"
>
حذف همه فیلترها
</button>
</div>
)}
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{isUpdating ? ( {isUpdating ? (
<div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6"> <div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">

View File

@ -1,8 +1,7 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { motion } from "motion/react"; import { motion } from "motion/react";
import { ChevronRight, Calendar, User, ArrowLeft, Sparkles, BookOpen, Mail, Check } from "lucide-react"; import { ChevronRight, Calendar, User, ArrowLeft, Sparkles, BookOpen } from "lucide-react";
import { toast } from "sonner";
import { Product } from "../lib/data/products"; import { Product } from "../lib/data/products";
import { productService } from "../lib/services/productService"; import { productService } from "../lib/services/productService";
@ -32,23 +31,13 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
return ( return (
<div className="min-h-screen bg-medical-gray-50 pt-8 pb-20 px-4 font-vazir" dir="rtl"> <div className="min-h-screen bg-medical-gray-50 pt-8 pb-20 px-4 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
{/* Standard Breadcrumb Navigation & Integrated Back Button */} {/* Breadcrumbs */}
<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-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<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" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => router.push('/')}>خانه</span> <ChevronRight className="w-2.5 h-2.5" />
<ChevronRight className="w-3 h-3 text-medical-gray-300" /> <span className="cursor-pointer hover:text-canina-blue" onClick={() => setSelectedPost(null)}>مجله سلامت</span>
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => setSelectedPost(null)}>مجله سلامت</span> <ChevronRight className="w-2.5 h-2.5" />
<ChevronRight className="w-3 h-3 text-medical-gray-300" /> <span className="text-canina-blue">{selectedPost.title}</span>
<span className="text-canina-blue font-black">{selectedPost.title}</span>
</div>
<button
onClick={() => setSelectedPost(null)}
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>
<div className="grid lg:grid-cols-12 gap-12"> <div className="grid lg:grid-cols-12 gap-12">
@ -155,37 +144,29 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
return ( return (
<div className="min-h-screen bg-medical-gray-50 pt-8 pb-20 px-4 font-vazir" dir="rtl"> <div className="min-h-screen bg-medical-gray-50 pt-8 pb-20 px-4 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
{/* Breadcrumb Navigation & Integrated Back Button */} {/* Header */}
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60 font-vazir"> <div className="flex flex-col md:flex-row items-center justify-between mb-16 gap-6">
<div className="flex items-center gap-2 text-xs font-bold text-medical-gray-400"> <div className="text-right">
<span className="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => router.push('/')}>خانه</span> <div className="inline-flex items-center gap-2 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-full text-[10px] font-black uppercase tracking-widest mb-4">
<ChevronRight className="w-3 h-3 text-medical-gray-300" /> <BookOpen className="w-3 h-3" />
<span className="text-canina-blue font-black">مجله سلامت</span> Canina Science Blog
</div>
<h1 className="text-4xl lg:text-6xl font-black text-medical-gray-900 italic leading-tight">
مجله تخصصی <span className="text-canina-blue">سلامت پت‌ها</span>
</h1>
<p className="text-lg text-medical-gray-500 font-medium mt-4 max-w-xl">
آخرین یافته‌های علمی محققین کانینا آلمان در مورد تغذیه و سلامت پت‌ها.
</p>
</div> </div>
<button <button
onClick={() => router.push('/')} 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" className="px-8 py-3 bg-white border border-medical-gray-200 rounded-2xl text-medical-gray-700 shadow-sm flex items-center gap-2 font-black hover:bg-medical-gray-50 transition-all"
> >
<ChevronRight className="w-3.5 h-3.5" /> <ChevronRight className="w-5 h-5" />
<span>بازگشت</span> بازگشت به خانه
</button> </button>
</div> </div>
{/* Header */}
<div className="mb-10 text-right">
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-full text-xs font-black uppercase tracking-widest mb-3">
<BookOpen className="w-3.5 h-3.5" />
<span>Canina Science Blog</span>
</div>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-black text-medical-gray-900 leading-tight">
مجله تخصصی <span className="text-canina-blue">سلامت پت‌ها</span>
</h1>
<p className="text-sm sm:text-base text-medical-gray-500 font-medium mt-3 max-w-xl leading-relaxed">
آخرین یافته‌های علمی محققین کانینا آلمان در مورد تغذیه و سلامت پت‌ها.
</p>
</div>
{/* Featured Post */} {/* Featured Post */}
{blogs.length > 0 && ( {blogs.length > 0 && (
<div className="mb-20"> <div className="mb-20">
@ -276,79 +257,26 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</motion.div> </motion.div>
))} ))}
{/* Ultra-Premium Redesigned Newsletter / CTA Box */} {/* Newsletter / CTA Box */}
<motion.div <div className="bg-canina-blue rounded-[3rem] p-10 text-white relative overflow-hidden flex flex-col justify-center">
initial={{ opacity: 0, y: 30 }} <div className="absolute top-0 right-0 p-8 opacity-20">
whileInView={{ opacity: 1, y: 0 }} <Sparkles className="w-24 h-24" />
viewport={{ once: true }}
transition={{ duration: 0.7 }}
className="bg-gradient-to-br from-canina-blue via-canina-blue/95 to-medical-gray-900 rounded-[3rem] p-8 sm:p-14 text-white relative overflow-hidden font-vazir shadow-2xl border border-white/10"
dir="rtl"
>
{/* Decorative Glassmorphic Background Elements */}
<div className="absolute top-0 right-0 w-96 h-96 bg-canina-teal/15 rounded-full blur-[100px] pointer-events-none" />
<div className="absolute bottom-0 left-0 w-80 h-80 bg-canina-gold/10 rounded-full blur-[90px] pointer-events-none" />
<div className="absolute -top-12 -left-12 opacity-5 pointer-events-none select-none">
<span className="text-[180px] font-black italic tracking-tighter font-sans text-white">CANINA</span>
</div> </div>
<h3 className="text-3xl font-black mb-4 italic">مشترک خبرنامه علمی شوید</h3>
<div className="relative z-10 max-w-4xl mx-auto flex flex-col items-center text-center space-y-8"> <p className="text-white/80 mb-8 font-medium leading-relaxed">
ماهانه یک ایمیل حاوی مهم‌ترین نکات سلامت پت‌ها و کدهای تخفیف اختصاصی دریافت کنید.
{/* Top Premium Badge */} </p>
<div className="inline-flex items-center gap-2.5 px-4 py-2 bg-white/10 backdrop-blur-md rounded-full border border-white/20 shadow-inner"> <div className="flex gap-2">
<div className="w-6 h-6 rounded-lg bg-canina-gold text-canina-dark flex items-center justify-center font-black text-xs italic shadow-md"> <input
C type="email"
</div> placeholder="آدرس ایمیل شما"
<span className="text-xs font-black text-white/90 tracking-wider font-vazir"> className="flex-1 bg-white/10 border border-white/20 rounded-xl px-4 py-3 outline-none focus:bg-white/20 placeholder:text-white/40"
خبرنامه اختصاصی پژوهشگاه کانینا آلمان />
</span> <button className="bg-white text-canina-blue px-6 py-3 rounded-xl font-black">
<Sparkles className="w-3.5 h-3.5 text-canina-gold animate-pulse" /> عضویت
</div> </button>
{/* Headline & Description */}
<div className="space-y-4 max-w-2xl">
<h3 className="text-3xl sm:text-4xl lg:text-5xl font-black font-vazir text-white leading-tight">
مشترک <span className="text-transparent bg-clip-text bg-gradient-to-r from-canina-gold via-white to-canina-teal">خبرنامه علمی</span> شوید
</h3>
<p className="text-sm sm:text-base text-white/80 font-medium font-vazir leading-relaxed">
ماهانه یک ایمیل حاوی تازه‌ترین یافتـه‌های پزشکی، کاتالوگ‌های درمانی اختصاصی کانینا و کدهای تخفیف ویژه برای شما ارسال می‌شود.
</p>
</div>
{/* Main Interactive Floating Input Bar */}
<div className="w-full max-w-xl">
<form onSubmit={(e) => { e.preventDefault(); toast.success("عضویت شما در خبرنامه علمی با موفقیت ثبت شد!"); }} className="w-full bg-white/15 backdrop-blur-xl border border-white/25 p-2 rounded-2xl sm:rounded-full flex flex-col sm:flex-row items-stretch sm:items-center gap-2 sm:gap-3 shadow-2xl hover:border-canina-gold/40 transition-all group" dir="ltr">
<input
type="email"
required
placeholder="آدرس ایمیل شما (name@domain.com)..."
className="flex-1 bg-transparent border-none text-xs sm:text-sm outline-none text-white placeholder:text-white/45 px-3 sm:px-4 py-2.5 sm:py-0 font-sans text-left"
/>
<button
type="submit"
className="bg-canina-gold hover:bg-white text-canina-dark px-6 sm:px-8 py-3.5 rounded-xl sm:rounded-full font-black text-xs sm:text-sm transition-all duration-300 whitespace-nowrap shadow-xl hover:scale-105 flex items-center justify-center gap-2 font-vazir cursor-pointer flex-shrink-0"
dir="rtl"
>
<span>عضویت آنی</span>
<Mail className="w-4 h-4" />
</button>
</form>
</div>
{/* Bottom Feature Micro Badges */}
<div className="pt-2 flex flex-wrap items-center justify-center gap-6 text-xs text-white/70 font-bold font-vazir border-t border-white/10 w-full max-w-xl">
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-canina-gold" />
<span>بدون اسپم (حداکثر ۱ ایمیل در ماه)</span>
</div>
<div className="flex items-center gap-2">
<Check className="w-4 h-4 text-canina-gold" />
<span>امکان لغو عضویت با یک کلیک</span>
</div>
</div>
</div> </div>
</motion.div> </div>
</div> </div>
{/* Synergy Products Cross-sell */} {/* Synergy Products Cross-sell */}

View File

@ -147,112 +147,121 @@ export default function CheckoutPage() {
<span className="text-canina-blue">درگاه پرداخت امن و نهایی‌سازی</span> <span className="text-canina-blue">درگاه پرداخت امن و نهایی‌سازی</span>
</div> </div>
<div className="grid lg:grid-cols-12 gap-8 lg:gap-12"> <div className="grid lg:grid-cols-12 gap-12">
{/* Main Form */} {/* Main Form */}
<div className="lg:col-span-8 space-y-6 sm:space-y-8"> <div className="lg:col-span-8 space-y-8">
{/* Step 1: Shipping */} {/* Step 1: Shipping */}
<section className="bg-white rounded-[2rem] sm:rounded-[3rem] border border-medical-gray-200 p-5 sm:p-10 overflow-hidden relative"> <section className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 overflow-hidden relative">
<div className="absolute top-0 right-0 w-2.5 sm:w-3 h-full bg-canina-blue opacity-20" /> <div className="absolute top-0 right-0 w-3 h-full bg-canina-blue opacity-20" />
<div className="flex items-center gap-3 sm:gap-4 mb-6 sm:mb-10"> <div className="flex items-center gap-4 mb-10">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-medical-gray-900 text-white rounded-2xl flex items-center justify-center font-black text-sm sm:text-base">۱</div> <div className="w-12 h-12 bg-medical-gray-900 text-white rounded-2xl flex items-center justify-center font-black">۱</div>
<h2 className="text-xl sm:text-2xl font-black text-medical-gray-900 italic">اطلاعات ارسال</h2> <h2 className="text-2xl font-black text-medical-gray-900 italic">اطلاعات ارسال</h2>
</div> </div>
<div className="grid md:grid-cols-2 gap-4 sm:gap-6"> <div className="grid md:grid-cols-2 gap-6">
<div className="space-y-2"> <div className="space-y-2">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">نام و نام خانوادگی</label> <label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">نام و نام خانوادگی</label>
<input type="text" className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="مثلاً: پارسا آقایی" /> <input type="text" className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="مثلاً: پارسا آقایی" />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">شماره تماس</label> <label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">شماره تماس</label>
<input type="text" className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="۰۹۱۲XXXXXXX" /> <input type="text" className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20" placeholder="۰۹۱۲XXXXXXX" />
</div> </div>
<div className="md:col-span-2 space-y-2"> <div className="md:col-span-2 space-y-2">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">آدرس دقیق پستی</label> <label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block">آدرس دقیق پستی</label>
<textarea className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 sm:py-4 px-4 sm:px-6 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20 h-28 sm:h-32" placeholder="استان، شهر، خیابان..." /> <textarea className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20 h-32" placeholder="استان، شهر، خیابان..." />
</div> </div>
</div> </div>
</section> </section>
{/* Step 2: Payment */} {/* Step 2: Payment */}
<section className="bg-white rounded-[2rem] sm:rounded-[3rem] border border-medical-gray-200 p-5 sm:p-10 overflow-hidden relative"> <section className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 overflow-hidden relative">
<div className="absolute top-0 right-0 w-2.5 sm:w-3 h-full bg-medical-gray-900 opacity-20" /> <div className="absolute top-0 right-0 w-3 h-full bg-medical-gray-900 opacity-20" />
<div className="flex items-center gap-3 sm:gap-4 mb-6 sm:mb-10"> <div className="flex items-center gap-4 mb-10">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-medical-gray-900 text-white rounded-2xl flex items-center justify-center font-black text-sm sm:text-base">۲</div> <div className="w-12 h-12 bg-medical-gray-900 text-white rounded-2xl flex items-center justify-center font-black">۲</div>
<h2 className="text-xl sm:text-2xl font-black text-medical-gray-900 italic">شیوه پرداخت</h2> <h2 className="text-2xl font-black text-medical-gray-900 italic">شیوه پرداخت</h2>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4"> <div className="grid md:grid-cols-3 gap-4">
{[ {[
{ id: 'online', label: 'پرداخت آنلاین', desc: 'کارت‌های بانکی', icon: <CreditCard className="w-5 h-5 sm:w-6 sm:h-6" /> }, { id: 'online', label: 'پرداخت آنلاین', desc: 'کارت‌های بانکی', icon: <CreditCard className="w-6 h-6" /> },
{ id: 'wallet', label: 'اعتبار حساب', desc: 'شارژ شده اختصاصی', icon: <Wallet className="w-5 h-5 sm:w-6 sm:h-6" /> }, { id: 'wallet', label: 'اعتبار حساب', desc: 'شارژ شده اختصاصی', icon: <Wallet className="w-6 h-6" /> },
{ id: 'cod', label: 'پرداخت در محل', desc: 'فقط تهران', icon: <Truck className="w-5 h-5 sm:w-6 sm:h-6" /> } { id: 'cod', label: 'پرداخت در محل', desc: 'فقط تهران', icon: <Truck className="w-6 h-6" /> }
].map((pay) => ( ].map((pay) => (
<div <div
key={pay.id} key={pay.id}
onClick={async () => { onClick={async () => {
setPaymentMethod(pay.id); setPaymentMethod(pay.id);
try {
// In a real scenario, this would call api.post('/payment/init', { method: pay.id, amount: getTotal() })
// and redirect to the returned gatewayUrl.
} catch (err) {
console.error("Payment init failed");
}
}} }}
className={cn("p-4 sm:p-6 rounded-2xl sm:rounded-3xl border-2 cursor-pointer transition-all group flex sm:flex-col items-center sm:items-start gap-4 sm:gap-0", paymentMethod === pay.id ? "border-canina-blue bg-canina-blue/5" : "border-medical-gray-100 hover:border-canina-blue")} className={cn("p-6 rounded-3xl border-2 cursor-pointer transition-all group", paymentMethod === pay.id ? "border-canina-blue bg-canina-blue/5" : "border-medical-gray-100 hover:border-canina-blue")}
> >
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-medical-gray-50 rounded-xl sm:rounded-2xl flex items-center justify-center text-medical-gray-400 group-hover:text-canina-blue group-hover:bg-canina-blue/10 sm:mb-4 transition-all flex-shrink-0"> <div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-medical-gray-400 group-hover:text-canina-blue group-hover:bg-canina-blue/10 mb-4 transition-all">
{pay.icon} {pay.icon}
</div> </div>
<div> <h4 className="font-black text-sm text-medical-gray-900 mb-1">{pay.label}</h4>
<h4 className="font-black text-xs sm:text-sm text-medical-gray-900 mb-0.5 sm:mb-1">{pay.label}</h4> <p className="text-[10px] text-medical-gray-400 font-bold">{pay.desc}</p>
<p className="text-[10px] text-medical-gray-400 font-bold">{pay.desc}</p>
</div>
</div> </div>
))} ))}
</div> </div>
</section> </section>
{/* Step 3: Charity Section */} {/* Step 3: Charity Section */}
<section className="bg-white rounded-[2rem] sm:rounded-[3rem] border border-medical-gray-200 p-5 sm:p-10 overflow-hidden relative"> <section className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 overflow-hidden relative">
<div className="absolute top-0 right-0 w-2.5 sm:w-3 h-full bg-pink-500 opacity-20" /> <div className="absolute top-0 right-0 w-3 h-full bg-pink-500 opacity-20" />
<div className="flex items-center justify-between mb-6 sm:mb-8"> <div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-3 sm:gap-4"> <div className="flex items-center gap-4">
<div className="w-10 h-10 sm:w-12 sm:h-12 bg-pink-500 text-white rounded-2xl flex items-center justify-center flex-shrink-0"> <div className="w-12 h-12 bg-pink-500 text-white rounded-2xl flex items-center justify-center">
<Heart className="w-5 h-5 sm:w-6 sm:h-6 fill-white" /> <Heart className="w-6 h-6 fill-white" />
</div> </div>
<div> <div>
<h2 className="text-xl sm:text-2xl font-black text-medical-gray-900 italic">ردپای مهربانی</h2> <h2 className="text-2xl font-black text-medical-gray-900 italic">ردپای مهربانی</h2>
<p className="text-[10px] sm:text-xs font-bold text-pink-500 mt-0.5">سهم شما در حمایت از حیوانات بی‌پناه</p> <p className="text-xs font-bold text-pink-500 mt-1">سهم شما در حمایت از حیوانات بی‌پناه</p>
</div> </div>
</div> </div>
</div> </div>
<div className="bg-pink-50 rounded-[2rem] sm:rounded-[2.5rem] p-5 sm:p-8 border border-pink-100"> <div className="bg-pink-50 rounded-[2.5rem] p-8 border border-pink-100">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 sm:gap-6"> <div className="flex flex-wrap items-center justify-between gap-6">
<div className="flex-1"> <div className="flex-1 min-w-[280px]">
<h4 className="text-base sm:text-lg font-black text-medical-gray-900 italic mb-1 sm:mb-2">رند کردن مبلغ و کمک به پناهگاه</h4> <h4 className="text-lg font-black text-medical-gray-900 italic mb-2">رند کردن مبلغ و کمک به پناهگاه</h4>
<p className="text-xs sm:text-sm text-medical-gray-600 leading-relaxed font-medium"> مابقی مبلغ تا ۱۰,۰۰۰ تومان بعدی صرف تامین غذا و دارو برای حیوانات بی-سرپرست می‌شود.</p> <p className="text-sm text-medical-gray-600 leading-relaxed font-medium"> با انتخاب این گزینه، مابقی مبلغ تا ده هزار تومان بعدی یا ۱٪ از خرید شما (هر کدام بیشتر باشد) صرف تامین غذا و دارو برای حیوانات بی-سرپرست تحت حمایت کانینا می‌شود.</p>
<div className="mt-4 flex items-center gap-3 text-pink-600">
<ShieldCheck className="w-4 h-4" />
<span className="text-[10px] font-black uppercase tracking-widest">گزارش شفاف هزینه‌کرد در داشبورد شما</span>
</div>
</div> </div>
<button <button
onClick={handleCharityToggle} onClick={handleCharityToggle}
className={cn( className={cn(
"w-14 h-14 sm:w-20 sm:h-20 rounded-full flex items-center justify-center transition-all shadow-lg self-end sm:self-center", "w-20 h-20 rounded-full flex items-center justify-center transition-all shadow-xl hover:scale-110 active:scale-95",
useRoundUp ? "bg-pink-500 text-white shadow-pink-200" : "bg-white text-medical-gray-300 border-2 border-medical-gray-100" useRoundUp ? "bg-pink-500 text-white shadow-pink-200" : "bg-white text-medical-gray-300 border-2 border-medical-gray-100"
)} )}
> >
<PlusCircle className={cn("w-7 h-7 sm:w-10 sm:h-10", useRoundUp ? "rotate-45" : "rotate-0")} /> <PlusCircle className={cn("w-10 h-10", useRoundUp ? "rotate-45" : "rotate-0")} />
</button> </button>
</div> </div>
</div>
{useRoundUp && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="mt-6 pt-6 border-t border-pink-100 flex items-center justify-between"
>
<span className="text-sm font-black text-pink-600 italic">مبلغ اهدایی شما:</span>
<span className="text-lg font-black font-vazir text-pink-500">{toPersian(charityDonation.toLocaleString())} تومان</span>
</motion.div>
)}
<p className="mt-6 text-[10px] text-center text-medical-gray-400 font-bold">«با خرید این محصول، شما هم در درمان یک حیوان پناهگاهی سهیم شدید.»</p> {useRoundUp && (
</section> <motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="mt-6 pt-6 border-t border-pink-100 flex items-center justify-between"
>
<span className="text-sm font-black text-pink-600 italic">مبلغ اهدایی شما:</span>
<span className="text-lg font-black font-vazir text-pink-500">{toPersian(charityDonation.toLocaleString())} تومان</span>
</motion.div>
)}
</div>
<p className="mt-6 text-[10px] text-center text-medical-gray-400 font-bold">«با خرید این محصول، شما هم در درمان یک حیوان پناهگاهی سهیم شدید.»</p>
</section>
</div> </div>
{/* Sidebar Summary */} {/* Sidebar Summary */}

View File

@ -29,7 +29,7 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
}; };
return ( return (
<footer className="bg-medical-gray-900 text-white pt-24 pb-36 sm:pb-12 font-shabnam relative" dir="rtl"> <footer className="bg-medical-gray-900 text-white pt-24 pb-12 font-shabnam relative" dir="rtl">
{/* Floating Back-to-Top Button */} {/* Floating Back-to-Top Button */}
{showScroll && ( {showScroll && (
<button <button

View File

@ -124,44 +124,45 @@ export default function Header({
<> <>
<AuthModal isOpen={isAuthModalOpen} onClose={() => setIsAuthModalOpen(false)} /> <AuthModal isOpen={isAuthModalOpen} onClose={() => setIsAuthModalOpen(false)} />
<div className="sticky top-0 z-50 w-full shadow-sm"> <div className="bg-canina-gold text-canina-dark text-xs font-black py-2.5 text-center font-vazir tracking-wider flex items-center justify-center gap-2">
<div className="bg-canina-gold text-canina-dark text-xs font-black py-2 text-center font-vazir tracking-wider flex items-center justify-center gap-2"> <span>🚚</span>
<span>🚚</span> <span>{getText('shipping_notice', "ارسال رایگان برای سفارش‌های بالای ۱۵۰ هزار تومان")}</span>
<span>{getText('shipping_notice', "ارسال رایگان برای سفارش‌های بالای ۱۵۰ هزار تومان")}</span> </div>
</div>
<header className="bg-white/95 backdrop-blur-md border-b border-medical-gray-100"> <header className="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-medical-gray-100 shadow-sm">
<div className="max-w-7xl mx-auto h-16 sm:h-20 md:h-24 flex items-center justify-between gap-1 sm:gap-4 px-2 sm:px-6 lg:px-8" dir="rtl"> <div className="max-w-7xl mx-auto py-2 min-[470px]:py-0 min-[470px]:h-24 flex flex-col min-[470px]:flex-row min-[470px]:items-center justify-between gap-2 min-[470px]:gap-4 px-3 sm:px-6 lg:px-8" dir="rtl">
{/* Logo & Mobile Toggle Area */} {/* Logo & Mobile Toggle Area */}
<div className="flex items-center gap-1.5 sm:gap-2 min-w-0"> <div className="flex items-center justify-between min-[470px]:justify-start gap-2 w-full min-[470px]:w-auto">
{/* Mobile Menu Toggle */} <div className="flex items-center gap-2">
<button {/* Mobile Menu Toggle (visible below 800px) */}
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} <button
className="min-[800px]:hidden p-1.5 sm:p-2 rounded-xl text-medical-gray-600 hover:bg-medical-gray-50 transition-all flex-shrink-0" onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="منو" className="min-[800px]:hidden p-2 rounded-xl text-medical-gray-600 hover:bg-medical-gray-50 transition-all flex-shrink-0"
> aria-label="منو"
{isMobileMenuOpen ? <X className="w-5 h-5 sm:w-6 sm:h-6" /> : <Menu className="w-5 h-5 sm:w-6 sm:h-6" />} >
</button> {isMobileMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
</button>
{/* Logo Section */} {/* Logo Section */}
<Link <Link
href="/" href="/"
className="flex items-center gap-1.5 sm:gap-3 cursor-pointer group min-w-0" className="flex items-center gap-2 sm:gap-3 cursor-pointer group"
onClick={() => setIsMobileMenuOpen(false)} onClick={() => setIsMobileMenuOpen(false)}
> >
<div className="w-8 h-8 sm:w-12 sm:h-12 bg-canina-blue rounded-xl sm:rounded-2xl flex items-center justify-center text-white font-bold text-base sm:text-2xl group-hover:bg-medical-gray-900 transition-all shadow-md sm:shadow-xl shadow-canina-blue/20 italic flex-shrink-0">C</div> <div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue rounded-2xl flex items-center justify-center text-white font-bold text-lg sm:text-2xl group-hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20 italic flex-shrink-0">C</div>
<div className="flex flex-col justify-center min-w-0"> <div className="flex flex-col justify-center gap-0.5 sm:gap-1">
<span className="text-canina-blue font-black text-xs sm:text-2xl tracking-tighter italic font-sans flex items-center gap-1 leading-none whitespace-nowrap"> <span className="text-canina-blue font-black text-base sm:text-2xl tracking-tighter italic font-sans flex items-center gap-1.5 sm:gap-2 leading-none whitespace-nowrap">
Canina Canina
<span className="text-[10px] sm:text-sm not-italic font-medium border-r border-medical-gray-200 pr-1 font-vazir"> <span className="text-xs sm:text-sm not-italic font-medium border-r-2 border-medical-gray-200 pr-1.5 sm:pr-2 font-vazir">
{getText('brand_name_fa', "ایران")} {getText('brand_name_fa', "ایران")}
</span>
</span> </span>
</span> <span className="text-[8px] sm:text-[9px] text-medical-gray-400 font-bold uppercase tracking-wider font-vazir leading-none whitespace-nowrap">
<span className="text-[7px] sm:text-[9px] text-medical-gray-400 font-bold uppercase tracking-wider font-vazir leading-tight whitespace-nowrap mt-0.5"> {getText('brand_subtitle', "نماینده رسمی Canina Pharma GmbH آلمان")}
نماینده رسمی <span className="block sm:inline text-[6px] sm:text-[9px]">CANINA PHARMA GMBH</span> </span>
</span> </div>
</div> </Link>
</Link> </div>
</div> </div>
{/* Navigation Items: Centered on XL screens (1224px+) */} {/* Navigation Items: Centered on XL screens (1224px+) */}
@ -248,17 +249,15 @@ export default function Header({
<div className="flex items-center gap-2 sm:gap-4 flex-shrink-0 justify-end h-auto md:h-16 pl-1 sm:pl-2"> <div className="flex items-center gap-2 sm:gap-4 flex-shrink-0 justify-end h-auto md:h-16 pl-1 sm:pl-2">
{/* Elastic Search */} {/* Elastic Search */}
{/* Elastic Search */} <div className="relative flex items-center justify-end z-20">
<div className="relative flex items-center justify-end z-30">
<AnimatePresence> <AnimatePresence>
{isSearchFocused && ( {isSearchFocused && (
<motion.div <motion.div
initial={{ width: 0, opacity: 0 }} initial={{ width: 0, opacity: 0 }}
animate={{ width: 220, opacity: 1 }} animate={{ width: 260, opacity: 1 }}
exit={{ width: 0, opacity: 0 }} exit={{ width: 0, opacity: 0 }}
transition={{ type: "spring", damping: 25, stiffness: 220 }} transition={{ type: "spring", damping: 25, stiffness: 220 }}
className="absolute left-full sm:right-0 top-1/2 -translate-y-1/2 bg-white border border-canina-blue/30 rounded-2xl shadow-2xl overflow-hidden h-10 sm:h-12 flex items-center pr-10 pl-3 z-30" className="absolute right-0 top-1/2 -translate-y-1/2 bg-white border border-canina-blue/30 border-l rounded-2xl shadow-xl shadow-canina-blue/5 overflow-hidden h-10 sm:h-12 flex items-center pr-10 pl-3 z-25"
style={{ transformOrigin: "right center" }}
> >
<form onSubmit={handleSearch} className="w-full flex items-center"> <form onSubmit={handleSearch} className="w-full flex items-center">
<input <input
@ -511,7 +510,6 @@ export default function Header({
))} ))}
</div> </div>
</header> </header>
</div>
{/* Mobile Drawer Menu */} {/* Mobile Drawer Menu */}
<AnimatePresence> <AnimatePresence>

View File

@ -65,10 +65,8 @@ export default function IngredientWiki() {
const el = document.getElementById(`wiki-${termParam}`); const el = document.getElementById(`wiki-${termParam}`);
if (el) { if (el) {
setTimeout(() => { setTimeout(() => {
const yOffset = -120; el.scrollIntoView({ behavior: 'smooth', block: 'center' });
const y = el.getBoundingClientRect().top + window.pageYOffset + yOffset; }, 100);
window.scrollTo({ top: y, behavior: 'smooth' });
}, 200);
} }
} }
}, [termParam, ingredientsWiki]); }, [termParam, ingredientsWiki]);
@ -77,21 +75,28 @@ export default function IngredientWiki() {
<div className="bg-white py-12 px-4 overflow-hidden font-vazir" dir="rtl"> <div className="bg-white py-12 px-4 overflow-hidden font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
{/* Standard Breadcrumb Navigation & Integrated Back Button */} {/* Mobile Navigation & Breadcrumbs */}
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60 font-vazir" dir="rtl"> <div className="lg:hidden mb-12 space-y-4">
<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 <button
onClick={() => router.push('/')} onClick={() => router.back()}
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" className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
> >
<ChevronRight className="w-3.5 h-3.5" /> <ChevronRight className="w-5 h-5" />
<span>بازگشت</span> <span>بازگشت</span>
</button> </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>
<div className="flex flex-col items-center text-center mb-20"> <div className="flex flex-col items-center text-center mb-20">
@ -224,29 +229,21 @@ export default function IngredientWiki() {
initial={{ opacity: 0, scale: 0.9 }} initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }} whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }} 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" className="bg-medical-gray-100 rounded-[4rem] p-12 relative overflow-hidden"
> >
<div className="flex items-center justify-between mb-8 pb-4 border-b border-medical-gray-200/60"> <div className="absolute top-0 right-0 p-8">
<div className="flex items-center gap-2"> <div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-[0.3em]">موجود در محصولات</div>
<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>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5 relative z-10"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6 relative z-10">
{hasIngredient.length > 0 ? hasIngredient.map(p => ( {hasIngredient.length > 0 ? hasIngredient.map(p => (
<Link <Link
key={p.id} key={p.id}
href={`/shop/${p.slug || 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" className="bg-white rounded-[2.5rem] p-6 shadow-xl hover:scale-105 transition-transform cursor-pointer group block"
> >
<div className="aspect-square bg-medical-gray-50 rounded-2xl p-4 mb-4 flex items-center justify-center"> <img src={p.image} alt={p.name} className="w-24 h-24 object-contain mx-auto mb-4" referrerPolicy="no-referrer" />
<img src={p.image} alt={p.name} className="max-h-24 w-auto object-contain group-hover:scale-110 transition-transform duration-500" 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>
<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> </Link>
)) : ( )) : (
<div className="col-span-full py-8 text-center"> <div className="col-span-full py-8 text-center">

View File

@ -161,66 +161,66 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
setItemQuantity(suggestedQty); setItemQuantity(suggestedQty);
}, [calculation?.duration]); }, [calculation?.duration]);
if (isLoading) return ( if (isLoading) return <div className="min-h-screen flex items-center justify-center">Loading...</div>;
<div className="min-h-screen bg-medical-gray-50 p-6 max-w-7xl mx-auto font-vazir" dir="rtl">
<div className="animate-pulse space-y-6">
<div className="h-8 bg-medical-gray-200 rounded-2xl w-48" />
<div className="grid md:grid-cols-12 gap-8">
<div className="md:col-span-5 h-80 bg-white border border-medical-gray-200 rounded-[2.5rem]" />
<div className="md:col-span-7 space-y-4">
<div className="h-10 bg-medical-gray-200 rounded-2xl w-3/4" />
<div className="h-6 bg-medical-gray-100 rounded-xl w-1/2" />
<div className="h-24 bg-medical-gray-100 rounded-2xl w-full" />
</div>
</div>
</div>
</div>
);
if (!product || !fullProduct || !calculation) return <div className="min-h-screen flex items-center justify-center">محصول یافت نشد</div>; if (!product || !fullProduct || !calculation) return <div className="min-h-screen flex items-center justify-center">محصول یافت نشد</div>;
return ( return (
<div className="min-h-screen bg-medical-gray-50 pt-2 pb-36 sm:pb-20 px-4 sm:px-6 lg:px-8 font-vazir" dir="rtl"> <div className="min-h-screen bg-medical-gray-50 pt-2 pb-20 px-4 md:px-0" dir="rtl">
<div className="max-w-7xl mx-auto w-full"> <div className="max-w-7xl mx-auto">
{/* Standard Breadcrumb Navigation & Integrated Back Button */} {/* Mobile Header with 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 justify-between mb-6 md:hidden">
<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="cursor-pointer hover:text-canina-blue transition-colors" onClick={() => router.push('/shop')}>فروشگاه</span>
<ChevronLeft className="w-3 h-3 text-medical-gray-300" />
<span className="text-canina-blue font-black">{product.nameFa || product.name}</span>
</div>
<button <button
onClick={() => router.back()} onClick={() => router.back()}
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" className="p-3 bg-white border border-medical-gray-200 rounded-2xl text-medical-gray-700 shadow-sm flex items-center gap-2 font-vazir text-sm font-bold"
> >
<ChevronRight className="w-3.5 h-3.5" /> <ChevronRight className="w-5 h-5" />
<span>بازگشت</span> بازگشت
</button> </button>
<div className="text-[10px] font-black text-canina-blue bg-canina-blue/5 px-4 py-2 rounded-xl font-vazir whitespace-nowrap">
کانینا ایران
</div>
</div> </div>
{/* Breadcrumbs */}
<nav className="hidden md:flex items-center gap-2 text-sm font-semibold text-medical-gray-600 mb-10 overflow-x-auto whitespace-nowrap py-3 border-b border-medical-gray-100">
<button
onClick={() => router.push('/')}
className="hover:text-canina-blue transition-colors font-vazir cursor-pointer"
>
خانه
</button>
<ChevronLeft className="w-3.5 h-3.5 flex-shrink-0 text-medical-gray-300" />
<button
onClick={() => router.push(`/shop?category=${product.categorySlug}`)}
className="hover:text-canina-blue cursor-pointer font-vazir"
>
{product.category}
</button>
<ChevronLeft className="w-3.5 h-3.5 flex-shrink-0 text-medical-gray-300" />
<span className="text-canina-blue font-vazir whitespace-nowrap font-bold">{product.name}</span>
</nav>
{/* Global Single Grid Layout - Aligns Sticky Buy Box at the Top */} {/* Global Single Grid Layout - Aligns Sticky Buy Box at the Top */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-start w-full"> <div className="grid lg:grid-cols-12 gap-12 items-start">
{/* Right/Main Content Column (lg:col-span-8) */} {/* Right/Main Content Column (lg:col-span-8) */}
<div className="w-full lg:col-span-8 space-y-12"> <div className="lg:col-span-8 space-y-12">
{/* Above the Fold Grid */} {/* Above the Fold Grid */}
<div className="grid grid-cols-1 md:grid-cols-12 gap-8 md:gap-12 items-center md:items-start text-center md:text-right font-vazir w-full" dir="rtl"> <div className="grid md:grid-cols-12 gap-12 items-start">
{/* Right Column: Product Image Frame (md:col-span-5) */} {/* Right Column: Product Image Frame (md:col-span-5) */}
<div className="md:col-span-5 w-full mx-auto max-w-sm md:max-w-none"> <div className="md:col-span-5 w-full">
<motion.div <motion.div
initial={{ opacity: 0, scale: 0.95 }} initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }} animate={{ opacity: 1, scale: 1 }}
className="bg-white rounded-[2.5rem] border border-medical-gray-200 shadow-xl relative group overflow-hidden h-[300px] sm:h-[380px] flex items-center justify-center p-6 sm:p-8" className="bg-white rounded-[2.5rem] border border-medical-gray-200 shadow-xl relative group overflow-hidden h-[380px] flex items-center justify-center p-8"
> >
<div className="absolute top-4 left-4 sm:top-6 sm:left-6 flex flex-col gap-1.5 sm:gap-2 z-10 items-start"> <div className="absolute top-6 left-6 flex flex-col gap-2 z-10">
<div className="px-2.5 py-1 bg-green-500 text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest flex items-center gap-1 font-vazir shadow-sm"> <div className="px-3 py-1 bg-green-500 text-white rounded-full text-[10px] font-black uppercase tracking-widest flex items-center gap-1 font-vazir shadow-sm">
<CheckCircle2 className="w-3 h-3" /> <CheckCircle2 className="w-3 h-3" />
موجود در انبار موجود در انبار
</div> </div>
<div className="px-2.5 py-1 bg-canina-blue text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm"> <div className="px-3 py-1 bg-canina-blue text-white rounded-full text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm">
گرید دارویی اختصاصی گرید دارویی اختصاصی
</div> </div>
</div> </div>
@ -228,15 +228,15 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
src={product.image} src={product.image}
alt={product.name} alt={product.name}
className="w-full h-full" className="w-full h-full"
imgClassName="max-h-[240px] sm:max-h-[300px] w-auto object-contain drop-shadow-2xl group-hover:scale-105 transition-transform duration-700 mx-auto my-auto" imgClassName="max-h-[300px] w-auto object-contain drop-shadow-2xl group-hover:scale-105 transition-transform duration-700 mx-auto my-auto"
/> />
</motion.div> </motion.div>
</div> </div>
{/* Left Column: Product Title & Description (md:col-span-7) */} {/* Left Column: Product Title & Description (md:col-span-7) */}
<div className="md:col-span-7 space-y-4 sm:space-y-6 flex flex-col items-center md:items-start"> <div className="md:col-span-7 space-y-6">
<div className="w-full flex flex-col items-center md:items-start"> <div>
<div className="flex flex-wrap justify-center md:justify-start items-center gap-2 sm:gap-3 mb-3 sm:mb-4"> <div className="flex flex-wrap items-center gap-3 mb-4">
<div className="px-3 py-1 bg-canina-blue text-white rounded-full text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm"> <div className="px-3 py-1 bg-canina-blue text-white rounded-full text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm">
استاندارد صنعتی آلمان استاندارد صنعتی آلمان
</div> </div>
@ -246,17 +246,17 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</div> </div>
)} )}
</div> </div>
<div className="flex flex-col gap-1.5 mb-4 text-center md:text-right w-full"> <div className="flex flex-col gap-2 mb-4">
<h1 dir="rtl" className="text-xl sm:text-2xl md:text-3xl lg:text-4xl font-black text-medical-gray-900 leading-tight font-vazir"> <h1 dir="rtl" className="text-2xl md:text-3xl lg:text-4xl font-black text-medical-gray-900 leading-tight font-vazir text-right">
{product.nameFa || product.name} {product.nameFa || product.name}
</h1> </h1>
{product.nameEn && ( {product.nameEn && (
<h2 dir="ltr" className="text-xs sm:text-base text-slate-400 font-bold italic font-sans text-center md:text-left"> <h2 dir="ltr" className="text-base md:text-lg text-slate-400 font-bold italic font-sans text-left">
{product.nameEn} {product.nameEn}
</h2> </h2>
)} )}
</div> </div>
<p className="text-base sm:text-xl text-canina-blue font-bold italic opacity-80 leading-relaxed max-w-2xl font-vazir mb-4 text-center md:text-right" dir="rtl"> <p className="text-xl text-canina-blue font-bold italic opacity-70 leading-relaxed max-w-2xl font-vazir mb-6 text-right" dir="rtl">
{isMounted && pets.length > 0 ? ( {isMounted && pets.length > 0 ? (
product.optimisticTemplate?.replace("[PetName]", activePet?.name || "").replace("[OnSet]", product.onSetOfAction || "به زودی") product.optimisticTemplate?.replace("[PetName]", activePet?.name || "").replace("[OnSet]", product.onSetOfAction || "به زودی")
) : ( ) : (
@ -264,11 +264,9 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
)} )}
</p> </p>
{fullProduct.shortDescription && ( {fullProduct.shortDescription && (
<div className="w-full text-right bg-canina-blue/5 border-r-4 border-canina-blue p-4 sm:p-6 rounded-2xl"> <p className="text-lg text-medical-gray-600 font-bold leading-relaxed max-w-3xl font-vazir border-r-4 border-canina-blue pr-6 py-2 bg-canina-blue/5 rounded-l-2xl">
<p className="text-sm sm:text-lg text-medical-gray-600 font-bold leading-relaxed font-vazir"> {fullProduct.shortDescription}
{fullProduct.shortDescription} </p>
</p>
</div>
)} )}
</div> </div>
</div> </div>
@ -381,8 +379,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<Clock className="w-6 h-6" /> <Clock className="w-6 h-6" />
</div> </div>
<div> <div>
<h3 className="text-lg sm:text-2xl font-black text-medical-gray-900 italic font-vazir whitespace-nowrap">ماشین حساب هوشمند مصرف</h3> <h3 className="text-2xl font-black text-medical-gray-900 italic font-vazir">ماشین حساب هوشمند مصرف</h3>
<p className="text-[11px] sm:text-xs text-medical-gray-400 font-bold font-vazir mt-0.5 sm:mt-1">تخمین دقیق دوز روزانه و ماندگاری هر بسته بر اساس مشخصات پت شما</p> <p className="text-xs text-medical-gray-400 font-bold font-vazir mt-1">تخمین دقیق دوز روزانه و ماندگاری هر بسته بر اساس مشخصات پت شما</p>
</div> </div>
</div> </div>
@ -435,18 +433,18 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
)} )}
{/* Ingredients Section */} {/* Ingredients Section */}
<section className="bg-white rounded-[2.5rem] border border-medical-gray-200 p-8 md:p-10 shadow-md space-y-8"> <section className="space-y-8">
<div className="flex items-center gap-4 border-b border-medical-gray-100 pb-6"> <div className="flex items-center gap-4">
<div className="w-12 h-12 bg-canina-blue text-white rounded-2xl flex items-center justify-center shadow-lg"> <div className="w-12 h-12 bg-canina-blue text-white rounded-2xl flex items-center justify-center shadow-lg">
<FlaskConical className="w-6 h-6" /> <FlaskConical className="w-6 h-6" />
</div> </div>
<h3 className="text-2xl md:text-3xl font-black text-medical-gray-900 italic font-vazir">ترکیبات و آنالیز علمی</h3> <h3 className="text-3xl font-black text-medical-gray-900 italic font-vazir">ترکیبات و آنالیز علمی</h3>
</div> </div>
<div className="space-y-8"> <div className="space-y-10">
{/* Ingredients Cards */} {/* Ingredients Cards */}
<div> <div className="bg-white rounded-[2.5rem] p-8 md:p-10 border border-medical-gray-200 shadow-md">
<h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-widest mb-4 font-vazir">مواد تشکیل‌دهنده برتر</h4> <h4 className="text-xs font-black text-medical-gray-400 uppercase tracking-widest mb-6 font-vazir">مواد تشکیل‌دهنده برتر</h4>
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{product.main_ingredients.map((ing, idx) => { {product.main_ingredients.map((ing, idx) => {
const termKey = termKeys.find(key => { const termKey = termKeys.find(key => {
@ -584,8 +582,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
)} )}
</div> </div>
{/* Sticky Sidebar (Clean Buy Box) - Hidden on mobile as mobile floating buy bar is active */} {/* Sticky Sidebar (Clean Buy Box) - Sticky starts at the top, level with the title */}
<div className="hidden lg:block lg:col-span-4 lg:sticky lg:top-36 space-y-8"> <div className="lg:col-span-4 lg:sticky lg:top-28 space-y-8">
<div className="bg-white rounded-[2.5rem] border-2 border-medical-gray-100 p-8 shadow-2xl relative overflow-hidden"> <div className="bg-white rounded-[2.5rem] border-2 border-medical-gray-100 p-8 shadow-2xl relative overflow-hidden">
<div className="absolute top-0 right-0 w-24 h-24 bg-canina-blue/5 rounded-full -mr-12 -mt-12" /> <div className="absolute top-0 right-0 w-24 h-24 bg-canina-blue/5 rounded-full -mr-12 -mt-12" />
@ -771,45 +769,6 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</div> </div>
)} )}
</AnimatePresence> </AnimatePresence>
{/* Mobile Floating Sticky Bottom Buy Bar */}
<div className="lg:hidden fixed bottom-0 left-0 right-0 z-40 bg-white border-t border-medical-gray-200 p-3 shadow-2xl flex items-center justify-between gap-3 font-vazir" dir="rtl">
<div>
<span className="text-[10px] text-medical-gray-400 font-bold block">قیمت نهایی</span>
<span className="text-lg font-black text-medical-gray-900 font-vazir">{toPersian(product.price)}</span>
</div>
<div className="flex items-center gap-2 flex-1 max-w-[240px]">
<div className="flex items-center gap-1 bg-medical-gray-50 border border-medical-gray-200 rounded-xl p-1 h-11">
<button
onClick={() => setItemQuantity(Math.max(1, itemQuantity - 1))}
className="w-7 h-7 flex items-center justify-center rounded-lg bg-white text-medical-gray-900 border border-medical-gray-200 font-bold text-xs"
>
-
</button>
<span className="w-5 text-center font-black text-medical-gray-900 text-xs font-vazir">
{toPersian(itemQuantity)}
</span>
<button
onClick={() => setItemQuantity(itemQuantity + 1)}
className="w-7 h-7 flex items-center justify-center rounded-lg bg-white text-medical-gray-900 border border-medical-gray-200 font-bold text-xs"
>
+
</button>
</div>
<button
onClick={() => {
addItem(product, itemQuantity, { quantity: calculation.dailyDose, unit: calculation.unit });
toast.success(`${toPersian(itemQuantity)} عدد به سبد خرید اضافه شد`);
}}
className="flex-1 bg-canina-blue text-white py-2.5 px-3 rounded-xl font-black text-xs hover:bg-canina-dark transition-all flex items-center justify-center gap-1.5 shadow-md shadow-canina-blue/20 whitespace-nowrap"
>
<ShoppingBag className="w-4 h-4" />
افزودن به سبد
</button>
</div>
</div>
</div> </div>
); );
} }

View File

@ -128,57 +128,51 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }} viewport={{ once: true }}
className="grid grid-cols-1 md:grid-cols-3 gap-4 sm:gap-6 mb-8 sm:mb-12" className="grid md:grid-cols-3 gap-6 mb-12"
> >
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between"> <div className="bg-white p-6 rounded-[2.5rem] border border-medical-gray-200/80 shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div> <div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0"> <div className="w-12 h-12 bg-canina-blue/10 rounded-2xl flex items-center justify-center text-canina-blue mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0"> <Pill className="w-6 h-6" />
<Pill className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">چرا ثبت شناسنامه؟</h3>
</div> </div>
<h3 className="text-lg font-black text-medical-gray-900 mb-2 font-vazir">چرا ثبت شناسنامه؟</h3>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir"> <p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
مکمل‌های دارویی کانینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه می‌کند. مکمل‌های دارویی کانینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه می‌کند تا حداکثر اثرگذاری ایجاد شود.
</p> </p>
</div> </div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir"> <div className="mt-4 pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" /> <Check className="w-3.5 h-3.5" />
تضمین ایمنی و عدم اوردوز تضمین ایمنی و عدم اوردوز
</div> </div>
</div> </div>
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between"> <div className="bg-white p-6 rounded-[2.5rem] border border-medical-gray-200/80 shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div> <div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0"> <div className="w-12 h-12 bg-canina-blue/10 rounded-2xl flex items-center justify-center text-canina-blue mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0"> <Activity className="w-6 h-6" />
<Activity className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">تطبیق علائم بالینی</h3>
</div> </div>
<h3 className="text-lg font-black text-medical-gray-900 mb-2 font-vazir">تطبیق علائم بالینی</h3>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir"> <p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
با انتخاب علائمی مثل لنگیدن یا ریزش مو، دقیق‌ترین راهکار مکمل آلمانی به همراه دلایل علمی به شما پیشنهاد می‌شود. با انتخاب علائمی مثل لنگیدن، ریزش مو، یا اسهال، موتور هوشمند ما دقیق‌ترین راهکار مکمل آلمانی مرتبط را به همراه دلایل علمی به شما پیشنهاد می‌دهد.
</p> </p>
</div> </div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir"> <div className="mt-4 pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" /> <Check className="w-3.5 h-3.5" />
پیشنهاد هدفمند و تخصصی پیشنهاد هدفمند و تخصصی
</div> </div>
</div> </div>
<div className="bg-white p-4 sm:p-6 rounded-2xl sm:rounded-[2.5rem] border border-medical-gray-200/80 shadow-md sm:shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between"> <div className="bg-white p-6 rounded-[2.5rem] border border-medical-gray-200/80 shadow-lg hover:shadow-xl transition-all group flex flex-col justify-between">
<div> <div>
<div className="flex items-center gap-3 sm:block mb-2 sm:mb-0"> <div className="w-12 h-12 bg-canina-blue/10 rounded-2xl flex items-center justify-center text-canina-blue mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm">
<div className="w-9 h-9 sm:w-12 sm:h-12 bg-canina-blue/10 rounded-xl sm:rounded-2xl flex items-center justify-center text-canina-blue sm:mb-4 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm flex-shrink-0"> <ShieldCheck className="w-6 h-6" />
<ShieldCheck className="w-5 h-5 sm:w-6 sm:h-6" />
</div>
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">پایش موجودی و یادآور</h3>
</div> </div>
<h3 className="text-lg font-black text-medical-gray-900 mb-2 font-vazir">پایش موجودی و یادآور</h3>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir"> <p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
زمان‌های مصرف مکمل‌ها تنظیم شده و سیستم قبل از اتمام دوره درمانی، هشدار شارژ مجدد ارسال خواهد کرد. پس از ایجاد شناسنامه، زمان‌های مصرف مکمل‌ها تنظیم شده و سیستم قبل از اتمام دوره درمانی، پیام هشدار شارژ مجدد به شما ارسال خواهد کرد.
</p> </p>
</div> </div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir"> <div className="mt-4 pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">
<Check className="w-3.5 h-3.5" /> <Check className="w-3.5 h-3.5" />
تکمیل منظم دوره درمان تکمیل منظم دوره درمان
</div> </div>