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
This commit is contained in:
parsa aghaei 2026-07-11 15:40:49 +03:30
parent 804a596711
commit 7615aa0e51
74 changed files with 683 additions and 659 deletions

View File

@ -1,6 +1,6 @@
# نقشه جامع اتصال به بک‌بند (Comprehensive Backend Integration Map) 🏗️
# نقشه جامع اتصال به بک‌بند (Comprehensive Backend Integration Map) 🏗️
این سند حاوی معماری دقیق، فهرست کامل نقاط اتصال (API Endpoints)، کامنت‌های مکان‌نما در کد (TODO Markers)، و تعاریف رسمی تمامی تایپ‌های ورودی (Inputs) و خروجی (Outputs) پلتفرم درمانی و فروشگاهی کانینو ایران است.
این سند حاوی معماری دقیق، فهرست کامل نقاط اتصال (API Endpoints)، کامنت‌های مکان‌نما در کد (TODO Markers)، و تعاریف رسمی تمامی تایپ‌های ورودی (Inputs) و خروجی (Outputs) پلتفرم درمانی و فروشگاهی کانینا ایران است.
---

View File

@ -1,6 +1,6 @@
# طرح‌واره پایگاه داده کانینو ایران (Canino Iran Database Schema) 🗄️
# طرح‌واره پایگاه داده کانینا ایران (Canina Iran Database Schema) 🗄️
این سند ساختار دقیق جداول، فیلدها، نوع داده‌ها (Datatypes)، روابط بین موجودیت‌ها (ERD Relations) و ایندکس‌های پیشنهادی را برای راه‌اندازی پایگاه داده نهایی سیستم کانینو طراحی و ارائه می‌کند. جهت انعطاف‌پذیری توسعه، پیاده‌سازی هم بر اساس **پایگاه داده رابطه‌ای (PostgreSQL / MySQL)** و هم **پایگاه داده مستندمحور/سندمراقبتی (NoSQL - MongoDB / Firestore)** مدلسازی شده است.
این سند ساختار دقیق جداول، فیلدها، نوع داده‌ها (Datatypes)، روابط بین موجودیت‌ها (ERD Relations) و ایندکس‌های پیشنهادی را برای راه‌اندازی پایگاه داده نهایی سیستم کانینا طراحی و ارائه می‌کند. جهت انعطاف‌پذیری توسعه، پیاده‌سازی هم بر اساس **پایگاه داده رابطه‌ای (PostgreSQL / MySQL)** و هم **پایگاه داده مستندمحور/سندمراقبتی (NoSQL - MongoDB / Firestore)** مدلسازی شده است.
---
@ -63,7 +63,7 @@ CREATE TABLE wallet_transactions (
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- ۴. جدول کاتالوگ محصولات کانینو (products)
-- ۴. جدول کاتالوگ محصولات کانینا (products)
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
art_no VARCHAR(20) UNIQUE NOT NULL,
@ -250,7 +250,7 @@ CREATE INDEX idx_reminder_completions_ref ON reminder_completions(reminder_id, c
"reminders": [
{
"id": "REM-001",
"productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کانینو فیزیکی جهت کسر انبار پت
"productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کانینا فیزیکی جهت کسر انبار پت
"title": "مصرف قرص مفصل‌ساز Canhydrox",
"time": "08:30",
"frequency": "روزانه",

View File

@ -1,7 +1,7 @@
# پلتفرم کانینو ایران (Canino Iran Platform) 🐾
# پلتفرم کانینا ایران (Canina Iran Platform) 🐾
### لندینگ، فروشگاه تخصصی و پرونده سلامت الکترونیک پت (نمایندگی رسمی دارویی Canina Pharma)
پلتفرم **کانینو ایران** یک برنامه جامع تحت وب (SPA/PWA) مجهز به بردهای تعاملی و ابزارهای بهداشتی-دامپزشکی است که با هدف ارتقای سلامت حیوانات خانگی و دسترسی آسان‌تر به مکمل‌های دارویی گرید فوق‌ارگانیک و دارویی کمپانی والای **Canina pharma GmbH آلمان** توسعه یافته است.
پلتفرم **کانینا ایران** یک برنامه جامع تحت وب (SPA/PWA) مجهز به بردهای تعاملی و ابزارهای بهداشتی-دامپزشکی است که با هدف ارتقای سلامت حیوانات خانگی و دسترسی آسان‌تر به مکمل‌های دارویی گرید فوق‌ارگانیک و دارویی کمپانی والای **Canina pharma GmbH آلمان** توسعه یافته است.
---

View File

@ -1,4 +1,4 @@
import { PrismaClient } from '@prisma/client';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
@ -24,7 +24,7 @@ async function main() {
'<p>کلسیم یکی از مهم‌ترین مواد معدنی برای رشد ساختار استخوانی است. توله‌سگ‌ها در ماه‌های اول زندگی به کلسیم بیشتری نیاز دارند تا اسکلت‌بندی محکمی داشته باشند.</p>',
'',
'<h2>نسبت Ca:P (کلسیم به فسفر)</h2>',
'<p>نسبت ایده‌آل کلسیم به فسفر در رژیم توله‌سگ‌ها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت می‌تواند منجر به ناهنجاری‌های استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کانینو</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>',
'<p>نسبت ایده‌آل کلسیم به فسفر در رژیم توله‌سگ‌ها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت می‌تواند منجر به ناهنجاری‌های استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کانینا</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>',
'',
'<h2>نقش ویتامین D3 در جذب کلسیم</h2>',
'<p>ویتامین D3 (کوله‌کلسیفرول) جذب کلسیم از روده را تا ۳۰٪ افزایش می‌دهد. <strong>مصرف همزمان ویتامین D2 (ارگوکلسیفرول) با D3 مجاز نیست</strong> زیرا این دو با یکدیگر رقابت کرده و جذب مؤثر را کاهش می‌دهند.</p>',
@ -49,12 +49,12 @@ async function main() {
'<li><strong>B1 (تیامین):</strong> متابولیسم کربوهیدرات‌ها و عملکرد سیستم عصبی</li>',
'<li><strong>B2 (ریبوفلاوین):</strong> تولید انرژی و سلامت پوست</li>',
'<li><strong>B6 (پیریدوکسین):</strong> سنتز پروتئین و تولید گلبول قرمز</li>',
'<li><strong>B7 (بیوتین / ویتامین H):</strong> کراتین‌سازی مو و پنجه - <strong>Biotin-Tabs کانینو</strong> با ۱ میلیون میکروگرم بیوتین در کیلوگرم، قوی‌ترین دوز موجود در بازار است</li>',
'<li><strong>B7 (بیوتین / ویتامین H):</strong> کراتین‌سازی مو و پنجه - <strong>Biotin-Tabs کانینا</strong> با ۱ میلیون میکروگرم بیوتین در کیلوگرم، قوی‌ترین دوز موجود در بازار است</li>',
'<li><strong>B12 (کوبالامین):</strong> خونسازی و عملکرد عصبی</li>',
'</ul>',
'',
'<h2>نقش بیوتین در سلامت پوشش</h2>',
'<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانه‌های کلاسیک کمبود بیوتین هستند. قرص بیوتین کانینو با تأثیر از هفته چهارم، پوشش براق و پنجه‌های محکم را تضمین می‌کند.</p>',
'<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانه‌های کلاسیک کمبود بیوتین هستند. قرص بیوتین کانینا با تأثیر از هفته چهارم، پوشش براق و پنجه‌های محکم را تضمین می‌کند.</p>',
'',
'<h2>محصولات تقویت‌کننده پوست و مو</h2>',
'<ul>',

View File

@ -1,4 +1,4 @@
import { PrismaClient } from '@prisma/client';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
@ -39,7 +39,7 @@ async function main() {
vetName: 'دکتر علیرضا رضایی',
clinicName: 'کلینیک دامپزشکی پایتخت',
imageUrl: '/images/vets/vet1.webp',
quote: 'مکمل‌های مفصلی کانینو از نظر سرعت جذب و اثربخشی در سگ‌های نژاد بزرگ بی‌نظیر هستند. ما نتایج فوق‌العاده‌ای روی دیسپلازی هیپ مشاهده کردیم.',
quote: 'مکمل‌های مفصلی کانینا از نظر سرعت جذب و اثربخشی در سگ‌های نژاد بزرگ بی‌نظیر هستند. ما نتایج فوق‌العاده‌ای روی دیسپلازی هیپ مشاهده کردیم.',
rating: 5,
order: 1,
isActive: true,
@ -48,7 +48,7 @@ async function main() {
vetName: 'دکتر سارا شمس',
clinicName: 'بیمارستان دامپزشکی تهران',
imageUrl: '/images/vets/vet2.webp',
quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربه‌ها، قرص‌های مخمر و بیوتین کانینو را تجویز می‌کنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.',
quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربه‌ها، قرص‌های مخمر و بیوتین کانینا را تجویز می‌کنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.',
rating: 5,
order: 2,
isActive: true,

View File

@ -13,14 +13,6 @@ function slugify(text: string): string {
.replace(/^-|-$/g, '');
}
function cleanBrand(text: string): string {
return text
.replace(/کانینا/g, 'کانینو')
.replace(/کانی‌نا/g, 'کانینو')
.replace(/Canina/g, 'Canino')
.replace(/canina/g, 'canino');
}
function determineSuitableFor(name: string, description: string): string {
const text = (name + ' ' + description).toLowerCase();
const hasCat = text.includes('گربه') || text.includes('katzen') || text.includes('cat');
@ -41,22 +33,27 @@ function parseSize(size: string): { unit: string; packageSize: number } {
return { unit: 'g', packageSize: 100 };
}
async function findOrCreateCategory(slug: string): Promise<{ id: string; slug: string }> {
const CATEGORY_NAMES: Record<string, string> = {
'joints': 'مفاصل و استخوان',
'immune': 'تقویت سیستم ایمنی و گوارش',
'energy': 'ویتامین‌ها و انرژی‌بخش‌ها',
'special-care': 'مراقبت‌های ویژه (پوست، دندان و چشم)',
'general': 'تقویت عمومی',
'nutrition': 'تغذیه تخصصی',
'supplements': 'مکمل‌های غذایی و درمانی',
};
const name = CATEGORY_NAMES[slug] || slug;
return await prisma.category.upsert({
where: { slug },
update: { name },
create: { slug, name, description: name },
});
}
async function main() {
console.log('Seeding products from seed-products-data.json...');
// 1. Create default category
const category = await prisma.category.upsert({
where: { slug: 'supplements' },
update: {},
create: {
name: 'مکمل‌های غذایی و درمانی',
slug: 'supplements',
description: 'انواع مکمل‌های اورجینال کانینو آلمان',
metaTitle: 'خرید مکمل کانینو',
metaDescription: 'بهترین مکمل‌های کانینو'
}
});
// 2. Read JSON data
const dataPath = path.join(__dirname, 'seed-products-data.json');
if (!fs.existsSync(dataPath)) {
@ -64,16 +61,18 @@ async function main() {
process.exit(1);
}
const productsData = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
const productsData = JSON.parse(fs.readFileSync(dataPath, 'utf-8').replace(/^\ufeff/, ''));
let variantCount = 0;
for (const item of productsData) {
const baseName = cleanBrand(item.name);
const cleanDesc = cleanBrand(item.description);
const cleanIngredients = item.ingredients ? cleanBrand(item.ingredients) : '';
const cleanDosage = item.usage_and_dosage ? cleanBrand(item.usage_and_dosage) : '';
const baseName = item.name;
const cleanDesc = item.description;
const cleanIngredients = item.ingredients || '';
const cleanDosage = item.usage_and_dosage || '';
const suitableFor = determineSuitableFor(baseName, cleanDesc);
const baseSlug = slugify(baseName);
const categorySlug = item.category_slug || 'supplements';
const category = await findOrCreateCategory(categorySlug);
for (const variant of item.variants) {
const artNo = variant.art_no;
@ -135,7 +134,7 @@ async function main() {
// Seed ingredients (split by '،' or '، ')
await prisma.productIngredient.deleteMany({ where: { productId: product.id } });
if (cleanIngredients) {
const parts = cleanIngredients.split(/[،,]/).map(s => s.trim()).filter(Boolean);
const parts = cleanIngredients.split(/[،,]/).map((s: string) => s.trim()).filter(Boolean);
// Only take the first meaningful items (up to ~20)
const meaningful = parts.slice(0, 20);
for (const ing of meaningful) {
@ -171,16 +170,16 @@ async function main() {
// 3. Seed some Blogs
const blog1Content = [
'<p><strong>تغذیه صحیح سگ‌های بالغ</strong> یکی از مهم‌ترین عوامل در حفظ سلامت و افزایش طول عمر آن‌هاست. برند کانینو (Canino) با بیش از ۴۰ سال سابقه در تولید مکمل‌های دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>',
'<p><strong>تغذیه صحیح سگ‌های بالغ</strong> یکی از مهم‌ترین عوامل در حفظ سلامت و افزایش طول عمر آن‌هاست. برند کانینا (Canina) با بیش از ۴۰ سال سابقه در تولید مکمل‌های دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>',
'',
'<h2>اصول تغذیه سگ بالغ</h2>',
'<p>سگ‌های بالغ به رژیم غذایی متعادل حاوی پروتئین، چربی، کربوهیدرات، ویتامین‌ها و مواد معدنی نیاز دارند. نسبت Ca:P (کلسیم به فسفر) باید در محدوده ۱.۲:۱ تا ۱.۵:۱ باشد. هرگونه عدم تعادل در این نسبت می‌تواند منجر به مشکلات کلیوی و استخوانی شود.</p>',
'',
'<h2>نقش مکمل‌ها در رژیم غذایی</h2>',
'<p>حتی با بهترین رژیم غذایی، ممکن است برخی مواد مغذی به اندازه کافی تأمین نشوند. محصولات کانینو مانند <strong>Petvital Vitamin-Tabs</strong> (کمپلکس کامل A تا K3) و <strong>Biotin-Tabs</strong> (۱ میلیون میکروگرم بیوتین) نیازهای تغذیه‌ای را پوشش می‌دهند.</p>',
'<p>حتی با بهترین رژیم غذایی، ممکن است برخی مواد مغذی به اندازه کافی تأمین نشوند. محصولات کانینا مانند <strong>Petvital Vitamin-Tabs</strong> (کمپلکس کامل A تا K3) و <strong>Biotin-Tabs</strong> (۱ میلیون میکروگرم بیوتین) نیازهای تغذیه‌ای را پوشش می‌دهند.</p>',
'',
'<h2>اسیدهای چرب ضروری</h2>',
'<p>روغن سالمون کانینو (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج می‌شود و تمام ویتامین‌های حساس به حرارت را حفظ می‌کند. EPA پیش‌ماده رزولوین‌های ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل می‌دهد.</p>',
'<p>روغن سالمون کانینا (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج می‌شود و تمام ویتامین‌های حساس به حرارت را حفظ می‌کند. EPA پیش‌ماده رزولوین‌های ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل می‌دهد.</p>',
'',
'<h2>مراقبت از مفاصل</h2>',
'<p>با افزایش سن سگ، غضروف مفصلی تحلیل می‌رود. گلیکوزآمینوگلیکان‌های صدف لب سبز (GAG) با جذب مولکول‌های آب در ماتریکس غضروفی، خاصیت بافری مفاصل را بازیابی می‌کنند. <strong>CANHYDROX GAG</strong> و <strong>FLEXAN</strong> حاوی این ترکیبات حیاتی هستند.</p>',
@ -195,12 +194,12 @@ async function main() {
].join('\n');
const blog2Content = [
'<p><strong>کانینو (Canino)</strong> نماینده رسمی برند <strong>Canina pharma GmbH</strong> در ایران است. این شرکت آلمانی در سال ۱۹۸۴ توسط <strong>پتر و کریستین کرشن‌مایر</strong> در شهر برگیش گلادباخ تأسیس شد و به یکی از پیشگامان تولید مکمل‌های طبیعی دامپزشکی در اروپا تبدیل شده است.</p>',
'<p><strong>کانینا (Canina)</strong> نماینده رسمی برند <strong>Canina pharma GmbH</strong> در ایران است. این شرکت آلمانی در سال ۱۹۸۴ توسط <strong>پتر و کریستین کرشن‌مایر</strong> در شهر برگیش گلادباخ تأسیس شد و به یکی از پیشگامان تولید مکمل‌های طبیعی دامپزشکی در اروپا تبدیل شده است.</p>',
'',
'<h2>فلسفه Canina: "مادر طبیعت بهترین نسخه را می‌داند"</h2>',
'<p>تمام محصولات کانینا بر پایه مواد اولیه طبیعی و با فرآیندهای پیشرفته تولید می‌شوند. این شرکت دارای گواهی‌های معتبر <strong>IFS (International Featured Standard)</strong> و <strong>HACCP</strong> است و محصولات آن در بیش از ۴۰ کشور جهان توزیع می‌شود.</p>',
'',
'<h2>چرا مکمل‌های کانینو در ایران؟</h2>',
'<h2>چرا مکمل‌های کانینا در ایران؟</h2>',
'<ul>',
'<li><strong>کیفیت آلمانی:</strong> تمام محصولات در کارخانه برگیش گلادباخ تحت نظارت دامپزشکان تولید می‌شوند</li>',
'<li><strong>بدون مواد مصنوعی:</strong> فاقد رنگ، طعم و نگهدارنده مصنوعی</li>',
@ -215,7 +214,7 @@ async function main() {
'<p><strong>قلب و انرژی:</strong> Herz Vital (ال-کارنیتین و زالزالک)، Energy-Gel (ویتامین‌های گروه B)</p>',
'',
'<h2>تعهد به سلامت حیوانات</h2>',
'<p>کانینو به عنوان نماینده رسمی کانینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بسته‌بندی اصلی آلمان و بارکد اختصاصی هستند.</p>'
'<p>کانینا به عنوان نماینده رسمی کانینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بسته‌بندی اصلی آلمان و بارکد اختصاصی هستند.</p>'
].join('\n');
const blogs = [
@ -227,7 +226,7 @@ async function main() {
isPublished: true,
},
{
title: 'چرا مکمل‌های کانینو؟',
title: 'چرا مکمل‌های کانینا؟',
slug: 'why-canino-supplements',
content: blog2Content,
authorId: adminId,

View File

@ -1,4 +1,4 @@
import { PrismaClient } from '@prisma/client';
import { PrismaClient } from '@prisma/client';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
@ -47,7 +47,7 @@ async function main() {
const uiTexts = {
hero_badge: "از ۱۹۸۴ در خدمت سلامت حیوانات",
hero_title: "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی",
hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کانینو نماینده رسمی این برند در ایران است.",
hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کانینا نماینده رسمی این برند در ایران است.",
hero_btn_advisor: "دستیار سلامت پت",
hero_btn_products: "مشاهده محصولات",
hero_stat_founded: "۱۹۸۴ سال تأسیس",
@ -57,12 +57,12 @@ async function main() {
hero_image_title: "مکمل‌های تایید شده دامپزشکی با گواهی IFS",
hero_quality_standard: "استاندارد کیفی آلمان (IFS & HACCP)",
cta_title: "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟",
cta_subtitle: "تیم متخصص دامپزشکی کانینو ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.",
cta_subtitle: "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.",
cta_btn_free: "دریافت رژیم مکمل رایگان",
cta_btn_products: "ورود به محصولات تخصصی",
about_teaser_badge: "داستان ما از آلمان",
about_teaser_title: "Canina pharma GmbH میراثی از ۱۹۸۴",
about_teaser_desc: "شرکت Canina pharma GmbH در سال ۱۹۸۴ توسط پتر و کریستین کرشن‌مایر در شهر برگیش گلادباخ آلمان تأسیس شد. این شرکت با شعار «مادر طبیعت بهترین نسخه را می‌داند» از مواد اولیه طبیعی و تجدیدپذیر برای تولید مکمل‌های با گرید دارویی استفاده می‌کند. امروزه محصولات کانینا در بیش از ۴۰ کشور جهان توزیع می‌شود و نماینده رسمی آن در ایران با نام کانینو به ارائه محصولات اصل با پروانه دامپزشکی می‌پردازد.",
about_teaser_desc: "شرکت Canina pharma GmbH در سال ۱۹۸۴ توسط پتر و کریستین کرشن‌مایر در شهر برگیش گلادباخ آلمان تأسیس شد. این شرکت با شعار «مادر طبیعت بهترین نسخه را می‌داند» از مواد اولیه طبیعی و تجدیدپذیر برای تولید مکمل‌های با گرید دارویی استفاده می‌کند. امروزه محصولات کانینا در بیش از ۴۰ کشور جهان توزیع می‌شود و نماینده رسمی آن در ایران با نام کانینا به ارائه محصولات اصل با پروانه دامپزشکی می‌پردازد.",
about_teaser_feat1_title: "مواد اولیه نایاب",
about_teaser_feat1_desc: "استفاده از پودر صدف لب‌سبز اصل نیوزیلند (Perna canaliculus)، پیت طبیعی آلمان، آغوز و روغن‌های گیاهی ارگانیک با گرید دارویی.",
about_teaser_feat2_title: "فاقد مواد نگهدارنده",
@ -125,7 +125,7 @@ async function main() {
{
id: "biotin",
name: "بیوتین (ویتامین H / B7)",
description: "کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز. با دوز ۱,۰۰۰,۰۰۰ میکروگرم در کیلوگرم در محصولات کانینو، قوی‌ترین دوز موجود در بازار مکمل‌های دامپزشکی.",
description: "کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز. با دوز ۱,۰۰۰,۰۰۰ میکروگرم در کیلوگرم در محصولات کانینا، قوی‌ترین دوز موجود در بازار مکمل‌های دامپزشکی.",
benefits: [
"جلوگیری از ریزش مو",
"تقویت رنگدانه پوشش",

View File

@ -34,8 +34,8 @@ async function bootstrap() {
app.useGlobalFilters(new HttpExceptionFilter());
const config = new DocumentBuilder()
.setTitle('Canino Iran API')
.setDescription('API Documentation for Canino Iran Pet Health & Supplement Platform')
.setTitle('Canina Iran API')
.setDescription('API Documentation for Canina Iran Pet Health & Supplement Platform')
.setVersion('1.0.0')
.addBearerAuth()
.build();

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -1,7 +1,7 @@
# معرفی پروژه کانینو ایران (Canino Iran)
# معرفی پروژه کانینا ایران (Canina Iran)
## این پروژه چیست؟
سامانه «کانینو ایران» پلتفرم تخصصی معرفی، فروش و مدیریت مکمل‌های درمانی حیوانات خانگی با گرید دارویی است. این سامانه به عنوان درگاه آنلاین نماینده انحصاری کانینو آلمان در ایران فعالیت می‌کند. هدف اصلی پروژه، ارائه یک تجربه کاربری (UX) بسیار غنی، سریع و در کلاس جهانی برای خریداران، کلینیک‌های دامپزشکی (مشتریان B2B) و همچنین فراهم‌کردن ابزارهای هوشمند (مانند مشاوره هوشمند و دانشنامه ترکیبات دارویی) است.
سامانه «کانینا ایران» پلتفرم تخصصی معرفی، فروش و مدیریت مکمل‌های درمانی حیوانات خانگی با گرید دارویی است. این سامانه به عنوان درگاه آنلاین نماینده انحصاری کانینا آلمان در ایران فعالیت می‌کند. هدف اصلی پروژه، ارائه یک تجربه کاربری (UX) بسیار غنی، سریع و در کلاس جهانی برای خریداران، کلینیک‌های دامپزشکی (مشتریان B2B) و همچنین فراهم‌کردن ابزارهای هوشمند (مانند مشاوره هوشمند و دانشنامه ترکیبات دارویی) است.
## قابلیت‌های کلیدی سامانه
سامانه به گونه‌ای طراحی شده تا تمام نیازهای یک کسب‌وکار مدرن e-commerce را در کنار قابلیت‌های تخصصی حوزه سلامت حیوانات برآورده کند:

View File

@ -1,6 +1,6 @@
# راهنمای کاربری سیستم (User Guide)
# راهنمای کاربری سیستم (User Guide)
سیستم کانینو از نظر نوع مخاطب به دو دسته کلی B2C (مشتریان عادی) و B2B (کلینیک‌ها و فروشگاه‌ها) تقسیم می‌شود. علاوه بر این، نقش «ادمین» برای مدیریت سیستم وجود دارد.
سیستم کانینا از نظر نوع مخاطب به دو دسته کلی B2C (مشتریان عادی) و B2B (کلینیک‌ها و فروشگاه‌ها) تقسیم می‌شود. علاوه بر این، نقش «ادمین» برای مدیریت سیستم وجود دارد.
## ۱. مشتریان عادی (B2C Users)
مشتری عادی کسی است که وارد سایت می‌شود تا برای حیوان خانگی خود مکمل خریداری کند یا اطلاعات کسب کند.

View File

@ -1,6 +1,6 @@
# مستندات توسعه‌دهندگان (Developer Documentation)
# مستندات توسعه‌دهندگان (Developer Documentation)
به مستندات رسمی سامانه «کانینو ایران» خوش آمدید. این مستندات به منظور راهنمایی توسعه‌دهندگان، مهندسین دواپس و تیم فنی شرکت نوشته شده است و نباید در دسترس کاربران عمومی قرار گیرد.
به مستندات رسمی سامانه «کانینا ایران» خوش آمدید. این مستندات به منظور راهنمایی توسعه‌دهندگان، مهندسین دواپس و تیم فنی شرکت نوشته شده است و نباید در دسترس کاربران عمومی قرار گیرد.
در این دایرکتوری تمامی ساختارها، معماری‌ها، قوانین کدنویسی و مراحل انتشار (Deployment) به دقت تدوین شده‌اند تا سرعت 온‌بوردینگ (Onboarding) توسعه‌دهندگان جدید افزایش یافته و نگهداری کدهای قدیمی با کمترین ریسک انجام شود.

View File

@ -1,4 +1,4 @@
import { Link, useLocation, useNavigate } from 'react-router-dom';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import { Home, Users, ShoppingBag, ShoppingCart, Tag, Settings, LogOut, TrendingUp, FolderTree, FileText, BookOpen, Heart, Package, LayoutDashboard } from 'lucide-react';
const menuGroups = [
@ -67,7 +67,7 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) {
<aside className={`w-64 bg-white border-l border-gray-200 h-screen fixed lg:sticky top-0 flex flex-col font-vazir shadow-sm z-50 transform transition-transform duration-300 ease-in-out ${isOpen ? 'translate-x-0' : 'translate-x-full lg:translate-x-0'
}`}>
<div className="h-16 flex items-center justify-center border-b border-gray-200 shrink-0">
<h1 className="text-xl font-black text-purple-600">کانینو | ادمینپنل</h1>
<h1 className="text-xl font-black text-purple-600">کانینا | ادمینپنل</h1>
</div>
<nav className="flex-1 overflow-y-auto py-4 px-3 space-y-6">

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import { DollarSign, ShoppingCart, Users, Activity } from 'lucide-react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
import api from '../services/api';
@ -53,7 +53,7 @@ export default function Dashboard() {
<div className="space-y-6">
<div>
<h2 className="text-2xl font-black text-gray-900">داشبورد</h2>
<p className="text-gray-500 font-medium mt-1">خلاصهای از وضعیت فروشگاه کانینو</p>
<p className="text-gray-500 font-medium mt-1">خلاصهای از وضعیت فروشگاه کانینا</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">

View File

@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Lock, Mail, ChevronLeft } from 'lucide-react';
import api from '../services/api';
@ -36,7 +36,7 @@ export default function Login() {
ورود به پنل مدیریت
</h2>
<p className="mt-2 text-center text-sm text-gray-600 font-bold">
کانینو | لابراتوار تخصصی مکملهای درمانی حیوانات
کانینا | لابراتوار تخصصی مکملهای درمانی حیوانات
</p>
</div>

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import { Settings as SettingsIcon, Save, Truck, ShieldAlert, Percent, AlertCircle } from 'lucide-react';
import api from '../services/api';
import Spinner from '../components/ui/Spinner';
@ -57,7 +57,7 @@ export default function Settings() {
<SettingsIcon className="w-6 h-6 text-purple-600" />
تنظیمات فروشگاه
</h2>
<p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کانینو</p>
<p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کانینا</p>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect } from 'react';
import { Search, Plus, Edit2, Trash2, BookOpen, XCircle } from 'lucide-react';
import api from '../services/api';
import Spinner from '../components/ui/Spinner';
@ -100,7 +100,7 @@ export default function Wiki() {
<div>
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
<BookOpen className="w-6 h-6 text-purple-600" />
دانشنامه کانینو (Wiki)
دانشنامه کانینا (Wiki)
</h2>
<p className="text-gray-500 font-medium mt-1">مدیریت اصطلاحات علمی، مواد تشکیلدهنده و خواص درمانی</p>
</div>

View File

@ -3,3 +3,9 @@
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
# Brand Name
نام برند رسمی «**کانینا**» / «**Canina**» است (نه «کانینو» / «Canino»). در سرتاسر پروژه باید از Canina / کانینا استفاده شود.
- CSS class names: `canina-blue`, `canina-gold`, `canina-teal`, `canina-dark`
- Store/cookie names: `canina-user`, `canina-cart`, `canina-pets`
- URL `https://canino-iran.com` (domain name, بدون تغییر می‌ماند)

View File

@ -15,7 +15,7 @@ async function getBlog(slug: string) {
excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...',
image: b.imageUrl,
date: new Date(b.createdAt).toLocaleDateString('fa-IR'),
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینو',
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینا',
content: b.content
};
} catch (error) {
@ -41,7 +41,7 @@ export default async function BlogPostPage({ params }: { params: { slug: string
return (
<div className="min-h-[50vh] flex flex-col items-center justify-center font-vazir text-center" dir="rtl">
<h1 className="text-3xl font-black text-medical-gray-900 mb-4">مقالهای یافت نشد</h1>
<Link href="/blog" className="text-canino-blue font-bold flex items-center gap-2">
<Link href="/blog" className="text-canina-blue font-bold flex items-center gap-2">
<ChevronRight className="w-4 h-4" />
بازگشت به مجله سلامت
</Link>
@ -54,11 +54,11 @@ export default async function BlogPostPage({ params }: { params: { slug: string
<div className="max-w-7xl mx-auto">
{/* Breadcrumbs */}
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<Link href="/" className="hover:text-canino-blue transition-colors">خانه</Link>
<Link href="/" className="hover:text-canina-blue transition-colors">خانه</Link>
<ChevronRight className="w-2.5 h-2.5" />
<Link href="/blog" className="hover:text-canino-blue transition-colors">مجله سلامت</Link>
<Link href="/blog" className="hover:text-canina-blue transition-colors">مجله سلامت</Link>
<ChevronRight className="w-2.5 h-2.5" />
<span className="text-canino-blue">{selectedPost.title}</span>
<span className="text-canina-blue">{selectedPost.title}</span>
</div>
<div className="grid lg:grid-cols-12 gap-12">
@ -68,8 +68,8 @@ export default async function BlogPostPage({ params }: { params: { slug: string
<img src={selectedPost.image} alt={selectedPost.title} className="w-full h-full object-cover" />
</div>
<div className="p-12">
<div className="flex items-center gap-4 text-xs font-bold text-canino-blue mb-8">
<div className="bg-canino-blue/10 px-4 py-1.5 rounded-full uppercase tracking-widest">تحقیق بالینی</div>
<div className="flex items-center gap-4 text-xs font-bold text-canina-blue mb-8">
<div className="bg-canina-blue/10 px-4 py-1.5 rounded-full uppercase tracking-widest">تحقیق بالینی</div>
<div className="flex items-center gap-1">
<Calendar className="w-4 h-4" />
{selectedPost.date}
@ -79,7 +79,7 @@ export default async function BlogPostPage({ params }: { params: { slug: string
{selectedPost.title}
</h1>
<div className="prose prose-lg max-w-none text-medical-gray-600 leading-[2] text-justify space-y-6">
<p className="font-bold text-medical-gray-900 italic text-xl border-r-4 border-canino-blue pr-6 py-2">
<p className="font-bold text-medical-gray-900 italic text-xl border-r-4 border-canina-blue pr-6 py-2">
{selectedPost.excerpt}
</p>
<div className="whitespace-pre-line" dangerouslySetInnerHTML={{ __html: selectedPost.content }} />
@ -92,11 +92,11 @@ export default async function BlogPostPage({ params }: { params: { slug: string
</div>
<div>
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</div>
<div className="font-bold text-medical-gray-400">نویسنده کانینو</div>
<div className="font-bold text-medical-gray-400">نویسنده کانینا</div>
</div>
</div>
<div className="flex gap-4">
<button className="p-4 bg-medical-gray-100 rounded-2xl hover:bg-canino-blue hover:text-white transition-all text-medical-gray-400">
<button className="p-4 bg-medical-gray-100 rounded-2xl hover:bg-canina-blue hover:text-white transition-all text-medical-gray-400">
<Sparkles className="w-6 h-6" />
</button>
</div>
@ -106,7 +106,7 @@ export default async function BlogPostPage({ params }: { params: { slug: string
</div>
<div className="lg:col-span-4 space-y-10">
<div className="bg-canino-blue rounded-[3rem] p-10 text-white shadow-2xl relative overflow-hidden">
<div className="bg-canina-blue rounded-[3rem] p-10 text-white shadow-2xl relative overflow-hidden">
<div className="absolute top-0 left-0 p-8 opacity-10">
<Sparkles className="w-20 h-20" />
</div>

View File

@ -1,4 +1,4 @@
import BlogPage from "../../components/BlogPage";
import BlogPage from "../../components/BlogPage";
import type { Metadata } from 'next';
export const metadata: Metadata = {
@ -19,7 +19,7 @@ async function getBlogs() {
excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...',
image: b.imageUrl,
date: new Date(b.createdAt).toLocaleDateString('fa-IR'),
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینو',
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینا',
content: b.content
}));
} catch (error) {

View File

@ -7,10 +7,10 @@
--font-inter: "Inter", sans-serif;
/* Brand Colors */
--color-canino-blue: #1E4053;
--color-canino-gold: #F1B646;
--color-canino-teal: #9BC8CC;
--color-canino-dark: #060709;
--color-canina-blue: #1E4053;
--color-canina-gold: #F1B646;
--color-canina-teal: #9BC8CC;
--color-canina-dark: #060709;
/* Core UI color mappings (harmonies based on brand palette) */
--color-medical-gray-50: #FFFFFF; /* pure white main background */
@ -80,5 +80,5 @@
}
::-webkit-scrollbar-thumb:hover {
background: var(--color-canino-blue);
background: var(--color-canina-blue);
}

View File

@ -1,35 +1,35 @@
import type { Metadata } from 'next';
import type { Metadata } from 'next';
import './globals.css';
import ClientLayout from './ClientLayout';
export const metadata: Metadata = {
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || 'https://canino-iran.com'),
title: {
template: '%s | کانینو ایران',
default: 'کانینو ایران - مکمل‌های درمانی حیوانات خانگی',
template: '%s | کانینا ایران',
default: 'کانینا ایران - مکمل‌های درمانی حیوانات خانگی',
},
description: 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینو ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان.',
keywords: ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کانینو', 'داروی حیوانات', 'Canino Iran'],
authors: [{ name: 'Canino Iran' }],
creator: 'Canino Iran',
publisher: 'Canino Iran',
description: 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینا ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان.',
keywords: ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کانینا', 'داروی حیوانات', 'Canina Iran'],
authors: [{ name: 'Canina Iran' }],
creator: 'Canina Iran',
publisher: 'Canina Iran',
formatDetection: {
email: false,
address: false,
telephone: false,
},
openGraph: {
title: 'کانینو ایران - مکمل‌های درمانی حیوانات خانگی',
title: 'کانینا ایران - مکمل‌های درمانی حیوانات خانگی',
description: 'واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان',
url: 'https://canino-iran.com',
siteName: 'کانینو ایران',
siteName: 'کانینا ایران',
locale: 'fa_IR',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'کانینو ایران',
description: 'مکمل‌های درمانی حیوانات خانگی کانینو',
title: 'کانینا ایران',
description: 'مکمل‌های درمانی حیوانات خانگی کانینا',
},
robots: {
index: true,
@ -52,7 +52,7 @@ export default function RootLayout({
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'کانینو ایران',
name: 'کانینا ایران',
url: 'https://canino-iran.com',
logo: 'https://canina.de/media/fb/d5/47/1683116813/Logo.png',
contactPoint: {

View File

@ -36,9 +36,9 @@ export default async function Home() {
href="/shop"
className="bg-white p-12 rounded-[3.5rem] border border-medical-gray-200 shadow-sm hover:shadow-2xl hover:-translate-y-2 transition-all cursor-pointer group block"
>
<h3 className="text-3xl font-black text-medical-gray-900 mb-4 group-hover:text-canino-blue transition-colors italic">فروشگاه تخصصی</h3>
<h3 className="text-3xl font-black text-medical-gray-900 mb-4 group-hover:text-canina-blue transition-colors italic">فروشگاه تخصصی</h3>
<p className="text-medical-gray-500 mb-8 leading-relaxed">دسترسی به تمامی محصولات بر اساس علائم بالینی و نیازهای پت شما.</p>
<div className="flex items-center gap-2 text-canino-blue font-black tracking-widest uppercase text-xs">
<div className="flex items-center gap-2 text-canina-blue font-black tracking-widest uppercase text-xs">
کاتالوگ کامل محصولات
<span className="text-lg"></span>
</div>
@ -47,9 +47,9 @@ export default async function Home() {
href="/wiki"
className="bg-medical-gray-900 p-12 rounded-[3.5rem] text-white hover:shadow-2xl hover:-translate-y-2 transition-all cursor-pointer group block"
>
<h3 className="text-3xl font-black mb-4 group-hover:text-canino-blue transition-colors italic">دانشنامه علمی</h3>
<p className="text-white/60 mb-8 leading-relaxed">آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینو.</p>
<div className="flex items-center gap-2 text-canino-blue font-black tracking-widest uppercase text-xs">
<h3 className="text-3xl font-black mb-4 group-hover:text-canina-blue transition-colors italic">دانشنامه علمی</h3>
<p className="text-white/60 mb-8 leading-relaxed">آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینا.</p>
<div className="flex items-center gap-2 text-canina-blue font-black tracking-widest uppercase text-xs">
مطالعه مقالات تخصصی
<span className="text-lg"></span>
</div>
@ -61,21 +61,21 @@ export default async function Home() {
<section className="py-24 bg-white overflow-hidden">
<div className="max-w-7xl mx-auto px-4 grid lg:grid-cols-2 gap-16 lg:gap-24 items-center">
<div className="relative">
<div className="absolute -top-10 -right-10 w-40 h-40 bg-canino-blue/5 rounded-full blur-3xl" />
<div className="absolute -top-10 -right-10 w-40 h-40 bg-canina-blue/5 rounded-full blur-3xl" />
<img
src="/assets/images/regenerated_image_1779109861747.png"
alt="Laboratory"
className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%]"
/>
<div className="absolute -bottom-6 -left-6 bg-canino-blue text-white p-8 rounded-3xl shadow-xl z-20">
<div className="absolute -bottom-6 -left-6 bg-canina-blue text-white p-8 rounded-3xl shadow-xl z-20">
<div className="text-4xl font-black mb-1 italic">کیفیت</div>
<div className="text-xs uppercase tracking-widest font-bold opacity-80">استانداردهای فوقدارویی</div>
</div>
</div>
<div>
<div className="text-canino-blue text-xs font-bold uppercase tracking-[0.2em] mb-4">میراث ما از آلمان</div>
<div className="text-canina-blue text-xs font-bold uppercase tracking-[0.2em] mb-4">میراث ما از آلمان</div>
<h2 className="text-3xl lg:text-5xl font-black text-medical-gray-900 leading-[1.2] mb-12">
چرا برند آلمانی Canino مرجع دامپزشکان است؟
چرا برند آلمانی Canina مرجع دامپزشکان است؟
</h2>
<div className="space-y-6">
{[
@ -84,7 +84,7 @@ export default async function Home() {
{ title: 'تاییدیه اروپا', desc: 'مطابق با سخت‌گیرانه‌ترین استانداردهای ایمنی مواد غذایی و دارویی در اتحادیه اروپا.' }
].map((item, idx) => (
<div key={idx} className="flex gap-4 items-center">
<div className="w-12 h-12 rounded-2xl bg-medical-gray-50 flex items-center justify-center flex-shrink-0 text-canino-blue font-bold">
<div className="w-12 h-12 rounded-2xl bg-medical-gray-50 flex items-center justify-center flex-shrink-0 text-canina-blue font-bold">
{toPersian(idx + 1)}
</div>
<div>
@ -99,7 +99,7 @@ export default async function Home() {
</section>
{/* Call to Action */}
<section className="bg-canino-blue py-20 relative overflow-hidden">
<section className="bg-canina-blue py-20 relative overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="grid grid-cols-10 h-full w-full">
{Array.from({length: 100}).map((_, i) => (
@ -112,15 +112,15 @@ export default async function Home() {
میخواهید بدانید کدام محصول برای پت شما مناسبتر است؟
</h2>
<p className="text-white/80 text-lg mb-10 leading-relaxed">
تیم متخصص دامپزشکی کانینو ایران آماده پاسخگویی به سوالات شماست.
تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست.
</p>
<div className="flex flex-wrap justify-center gap-4">
<button className="bg-white text-canino-blue px-12 py-5 rounded-full font-black text-xl hover:scale-105 transition-transform shadow-2xl shadow-black/20">
<button className="bg-white text-canina-blue px-12 py-5 rounded-full font-black text-xl hover:scale-105 transition-transform shadow-2xl shadow-black/20">
دریافت رژیم مکمل رایگان
</button>
<Link
href="/shop"
className="bg-transparent border-2 border-white text-white px-12 py-5 rounded-full font-black text-xl hover:bg-white hover:text-canino-blue transition-all"
className="bg-transparent border-2 border-white text-white px-12 py-5 rounded-full font-black text-xl hover:bg-white hover:text-canina-blue transition-all"
>
پروانه دامپزشکی و اصالت کالا
</Link>

View File

@ -1,9 +1,9 @@
import SearchResultsPage from "../../components/SearchResultsPage";
import SearchResultsPage from "../../components/SearchResultsPage";
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'جستجوی محصولات',
description: 'جستجوی مکمل‌های درمانی حیوانات خانگی، داروها و مقالات سلامت در کانینو ایران.',
description: 'جستجوی مکمل‌های درمانی حیوانات خانگی، داروها و مقالات سلامت در کانینا ایران.',
};
export default async function SearchPage({ searchParams }: { searchParams: Promise<{ q?: string }> }) {

View File

@ -54,7 +54,7 @@ export default async function ShopProductPage({ params }: { params: Promise<{ sl
sku: product.artNo,
brand: {
'@type': 'Brand',
name: 'Canino'
name: 'Canina'
},
offers: {
'@type': 'Offer',

View File

@ -30,7 +30,7 @@ export default async function BlogPage({ params }: { params: { slug: string } })
return (
<div className="min-h-[50vh] flex flex-col items-center justify-center font-vazir text-center" dir="rtl">
<h1 className="text-3xl font-black text-medical-gray-900 mb-4">مقالهای یافت نشد</h1>
<Link href="/wiki" className="text-canino-blue font-bold flex items-center gap-2">
<Link href="/wiki" className="text-canina-blue font-bold flex items-center gap-2">
<ChevronRight className="w-4 h-4" />
بازگشت به دانشنامه
</Link>
@ -41,7 +41,7 @@ export default async function BlogPage({ params }: { params: { slug: string } })
return (
<div className="bg-white py-20 px-4 font-vazir" dir="rtl">
<div className="max-w-4xl mx-auto">
<Link href="/wiki" className="inline-flex items-center gap-2 text-medical-gray-400 hover:text-canino-blue transition-colors font-bold mb-8">
<Link href="/wiki" className="inline-flex items-center gap-2 text-medical-gray-400 hover:text-canina-blue transition-colors font-bold mb-8">
<ChevronRight className="w-5 h-5" />
بازگشت به مقالات
</Link>
@ -67,7 +67,7 @@ export default async function BlogPage({ params }: { params: { slug: string } })
</div>
<div
className="prose prose-lg prose-medical-gray max-w-none prose-headings:font-black prose-p:leading-relaxed prose-a:text-canino-blue"
className="prose prose-lg prose-medical-gray max-w-none prose-headings:font-black prose-p:leading-relaxed prose-a:text-canina-blue"
dangerouslySetInnerHTML={{ __html: blog.content }}
/>
</div>

View File

@ -1,9 +1,9 @@
import IngredientWiki from "../../components/IngredientWiki";
import IngredientWiki from "../../components/IngredientWiki";
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'دانشنامه ترکیبات دارویی',
description: 'اطلاعات کامل در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کانینو ایران.',
description: 'اطلاعات کامل در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کانینا ایران.',
};
export default function WikiPage() {

View File

@ -134,7 +134,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
>
<div className="bg-medical-gray-50 px-8 py-6 border-b border-medical-gray-100 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-canino-blue rounded-xl flex items-center justify-center text-white">
<div className="w-10 h-10 bg-canina-blue rounded-xl flex items-center justify-center text-white">
<MapPin className="w-5 h-5" />
</div>
<h3 className="text-xl font-black text-medical-gray-900 italic">
@ -159,7 +159,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.title}
onChange={e => setFormData({...formData, title: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20", errors.title ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20", errors.title ? "border-red-300" : "border-medical-gray-100")}
placeholder="مثال: منزل اصلی"
/>
{errors.title && <p className="text-[10px] text-red-500 font-bold pr-2">{errors.title}</p>}
@ -173,7 +173,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.receptorName}
onChange={e => setFormData({...formData, receptorName: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20", errors.receptorName ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20", errors.receptorName ? "border-red-300" : "border-medical-gray-100")}
placeholder="نام و نام‌خانوادگی..."
/>
{errors.receptorName && <p className="text-[10px] text-red-500 font-bold pr-2">{errors.receptorName}</p>}
@ -184,7 +184,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.phone}
onChange={e => setFormData({...formData, phone: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20 text-left", errors.phone ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20 text-left", errors.phone ? "border-red-300" : "border-medical-gray-100")}
placeholder="09120000000"
dir="ltr"
/>
@ -200,7 +200,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.province}
onChange={e => setFormData({...formData, province: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20", errors.province ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20", errors.province ? "border-red-300" : "border-medical-gray-100")}
placeholder="نام استان..."
/>
{errors.province && <p className="text-[10px] text-red-500 font-bold pr-2">{errors.province}</p>}
@ -211,7 +211,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.city}
onChange={e => setFormData({...formData, city: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20", errors.city ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20", errors.city ? "border-red-300" : "border-medical-gray-100")}
placeholder="نام شهر..."
/>
{errors.city && <p className="text-[10px] text-red-500 font-bold pr-2">{errors.city}</p>}
@ -225,7 +225,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
rows={2}
value={formData.detail}
onChange={e => setFormData({...formData, detail: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20 resize-none", errors.detail ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20 resize-none", errors.detail ? "border-red-300" : "border-medical-gray-100")}
placeholder="خیابان، کوچه، پلاک، واحد..."
/>
{errors.detail && <p className="text-[10px] text-red-500 font-bold pr-2">{errors.detail}</p>}
@ -238,7 +238,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
type="text"
value={formData.zipCode}
onChange={e => setFormData({...formData, zipCode: e.target.value})}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canino-blue/20 text-left", errors.zipCode ? "border-red-300" : "border-medical-gray-100")}
className={cn("w-full bg-medical-gray-50 border rounded-2xl py-3 px-5 outline-none font-bold transition-all focus:ring-2 focus:ring-canina-blue/20 text-left", errors.zipCode ? "border-red-300" : "border-medical-gray-100")}
placeholder="1234567890"
dir="ltr"
/>
@ -252,7 +252,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
onClick={() => setFormData({...formData, isDefault: !formData.isDefault})}
className={cn(
"w-6 h-6 rounded-lg border-2 flex items-center justify-center transition-all",
formData.isDefault ? "bg-canino-blue border-canino-blue text-white" : "border-medical-gray-200 text-transparent"
formData.isDefault ? "bg-canina-blue border-canina-blue text-white" : "border-medical-gray-200 text-transparent"
)}
>
<Check className="w-4 h-4" />
@ -272,7 +272,7 @@ export default function AddressModal({ isOpen, onClose, onSave, editingAddress }
<button
type="submit"
disabled={isSubmitting}
className="flex-[2] py-4 bg-canino-blue text-white rounded-2xl font-black text-sm flex items-center justify-center gap-3 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canino-blue/20 disabled:opacity-50 disabled:cursor-wait"
className="flex-[2] py-4 bg-canina-blue text-white rounded-2xl font-black text-sm flex items-center justify-center gap-3 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canina-blue/20 disabled:opacity-50 disabled:cursor-wait"
>
{isSubmitting ? (
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />

View File

@ -104,7 +104,7 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
className="group bg-white rounded-[2.5rem] border border-medical-gray-200 overflow-hidden hover:shadow-2xl transition-all cursor-pointer flex flex-col h-full relative"
>
{product.specialBadge && (
<div className="absolute top-4 right-4 z-10 bg-canino-blue text-white text-[9px] font-black uppercase tracking-widest px-3 py-1 rounded-full shadow-lg">
<div className="absolute top-4 right-4 z-10 bg-canina-blue text-white text-[9px] font-black uppercase tracking-widest px-3 py-1 rounded-full shadow-lg">
{product.specialBadge}
</div>
)}
@ -120,7 +120,7 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
)}
<div className="aspect-square bg-medical-gray-50 flex items-center justify-center p-8 overflow-hidden relative">
<SafeImage src={product.image} alt={product.name} className="w-full h-full object-contain group-hover:scale-110 transition-transform duration-700" />
<SafeImage src={product.image} alt={product.name} className="w-full h-full group-hover:scale-110 transition-transform duration-700" imgClassName="object-contain" />
<div className="absolute bottom-4 left-4 flex gap-2">
{(product.suitableFor === "سگ" || product.suitableFor === "هر دو") && (
<div className="w-7 h-7 bg-white rounded-lg flex items-center justify-center text-medical-gray-400 border border-medical-gray-100 shadow-sm">
@ -136,8 +136,8 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
</div>
<div className="p-6 flex flex-col flex-1">
<div className="text-[10px] font-bold text-canino-blue uppercase tracking-widest mb-2">{product.category}</div>
<h3 className="text-lg font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors mb-3 leading-tight">{product.name}</h3>
<div className="text-[10px] font-bold text-canina-blue uppercase tracking-widest mb-2">{product.category}</div>
<h3 className="text-lg font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors mb-3 leading-tight">{product.name}</h3>
<div className="flex flex-wrap gap-1 mb-6">
{product.symptoms.slice(0, 2).map((s, i) => (
@ -152,7 +152,7 @@ const ArchiveProductCard: React.FC<{ product: Product, onClick: (p: Product) =>
<button
onClick={handleAddToCart}
disabled={isAdding}
className="w-10 h-10 rounded-xl bg-medical-gray-50 text-canino-blue flex items-center justify-center group-hover:bg-canino-blue group-hover:text-white transition-all disabled:opacity-50"
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"
>
{isAdding ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}
</button>
@ -263,24 +263,24 @@ export default function ArchivePage({
<div className="lg:hidden mb-10 space-y-4">
<button
onClick={() => router.back()}
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canino-blue transition-colors"
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
>
<ChevronRight className="w-5 h-5 font-vazir" />
<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-canino-blue" onClick={() => router.push('/')}>کانینو</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">فروشگاه تخصصی</span>
<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-10">
<span className="cursor-pointer hover:text-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">کاتالوگ کامل محصولات</span>
<span className="text-canina-blue">کاتالوگ کامل محصولات</span>
</div>
<div className="flex flex-col lg:flex-row gap-10">
@ -289,7 +289,7 @@ export default function ArchivePage({
<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="flex items-center gap-2 mb-6">
<Filter className="w-5 h-5 text-canino-blue" />
<Filter className="w-5 h-5 text-canina-blue" />
<h3 className="font-black text-medical-gray-900">فیلترهای تخصصی</h3>
</div>
@ -306,7 +306,7 @@ export default function ArchivePage({
<button
key={pet.id}
onClick={() => setSelectedPet(pet.id as any)}
className={`py-2 rounded-xl text-[10px] font-black border transition-all flex flex-col items-center gap-1 ${selectedPet === pet.id ? 'bg-canino-blue border-canino-blue text-white shadow-lg shadow-canino-blue/20' : 'bg-white border-medical-gray-200 text-medical-gray-400'}`}
className={`py-2 rounded-xl text-[10px] font-black border transition-all flex flex-col items-center gap-1 ${selectedPet === pet.id ? 'bg-canina-blue border-canina-blue text-white shadow-lg shadow-canina-blue/20' : 'bg-white border-medical-gray-200 text-medical-gray-400'}`}
>
{pet.icon}
{pet.label}
@ -323,7 +323,7 @@ export default function ArchivePage({
<button
key={cat.id}
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-canino-blue border-canino-blue text-white' : 'bg-white border-medical-gray-100 text-medical-gray-600 hover:border-canino-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.label}
@ -352,8 +352,8 @@ export default function ArchivePage({
{/* Promo Card */}
<div className="bg-medical-gray-900 rounded-[2rem] p-6 text-white relative overflow-hidden group">
<div className="absolute -top-10 -left-10 w-32 h-32 bg-canino-blue rounded-full blur-3xl opacity-20 group-hover:opacity-40 transition-opacity" />
<h4 className="text-lg font-black italic mb-4 relative z-10 underline decoration-canino-blue underline-offset-8">مشاوره رایگان</h4>
<div className="absolute -top-10 -left-10 w-32 h-32 bg-canina-blue rounded-full blur-3xl opacity-20 group-hover:opacity-40 transition-opacity" />
<h4 className="text-lg font-black italic mb-4 relative z-10 underline decoration-canina-blue underline-offset-8">مشاوره رایگان</h4>
<p className="text-xs text-white/60 leading-relaxed mb-6 relative z-10">اگر نمیدانید کدام ترکیب برای پت شما مناسب است، همین حالا با دامپزشکان ما تماس بگیرید.</p>
<a href="tel:0218888" className="w-full bg-white text-medical-gray-900 py-3 rounded-xl text-xs font-black hover:scale-105 transition-transform relative z-10 flex items-center justify-center">شماره تماس: ۰۲۱-۸۸۸۸</a>
</div>
@ -362,7 +362,7 @@ export default function ArchivePage({
{/* Main Content */}
<main className="flex-1 relative">
<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-canino-blue">Canino</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">
<Search className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
<input
@ -370,20 +370,20 @@ export default function ArchivePage({
placeholder="جستجوی محصول..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-full py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canino-blue/20"
className="w-full bg-white border border-medical-gray-200 rounded-full py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
/>
</div>
</div>
<AnimatePresence mode="wait">
{isUpdating ? (
<div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{Array.from({ length: 6 }).map((_, i) => (
<div key="skeleton" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
{Array.from({ length: 8 }).map((_, i) => (
<ProductCardSkeleton key={i} />
))}
</div>
) : filteredProducts.length > 0 ? (
<div key="grid" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
<div key="grid" className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6">
<AnimatePresence mode="popLayout">
{filteredProducts.map((p: Product) => (
<ArchiveProductCard key={p.id} product={p} onClick={(p) => router.push(`/shop/${p.slug || p.id}`)} />
@ -405,7 +405,7 @@ export default function ArchivePage({
setActiveSymptoms([]);
setSearchQuery("");
}}
className="bg-canino-blue text-white px-8 py-3 rounded-xl font-black text-sm hover:scale-105 transition-transform shadow-lg shadow-canino-blue/20"
className="bg-canina-blue text-white px-8 py-3 rounded-xl font-black text-sm hover:scale-105 transition-transform shadow-lg shadow-canina-blue/20"
>
پاک کردن همه فیلترها و نمایش همه
</button>

View File

@ -181,7 +181,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
dir="rtl"
>
{/* Top highlight bar */}
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canino-blue to-indigo-500" />
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue to-indigo-500" />
<div className="p-8 relative">
{/* Close Button */}
@ -194,11 +194,11 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
{/* Title Header */}
<div className="flex flex-col items-center text-center mb-8 pt-4">
<div className="w-20 h-20 bg-canino-blue/10 rounded-3xl flex items-center justify-center mb-4 shadow-inner">
<ShieldCheck className="w-10 h-10 text-canino-blue" />
<div className="w-20 h-20 bg-canina-blue/10 rounded-3xl flex items-center justify-center mb-4 shadow-inner">
<ShieldCheck className="w-10 h-10 text-canina-blue" />
</div>
<h2 className="text-3xl font-black text-medical-gray-900 mb-2 italic">
ورود به دنیای کانینو
ورود به دنیای کانینا
</h2>
<p className="text-medical-gray-500 text-sm font-bold max-w-[280px]">
{view === "otp"
@ -227,7 +227,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 px-4 focus:ring-2 focus:ring-canino-blue/20 outline-none font-bold text-left tracking-widest"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 px-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-left tracking-widest"
/>
</div>
<div className="space-y-2">
@ -238,7 +238,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 px-4 focus:ring-2 focus:ring-canino-blue/20 outline-none text-left"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 px-4 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left"
/>
</div>
@ -246,14 +246,14 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="button"
onClick={() => setView("otp-phone")}
className="text-xs font-bold text-canino-blue hover:underline"
className="text-xs font-bold text-canina-blue hover:underline"
>
ورود با کد یکبار مصرف (OTP)
</button>
<button
type="button"
onClick={() => setView("register")}
className="text-xs font-bold text-canino-blue hover:underline"
className="text-xs font-bold text-canina-blue hover:underline"
>
حساب ندارید؟ ثبتنام
</button>
@ -262,7 +262,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="submit"
disabled={isLoading || !phoneNumber || !password}
className="w-full py-4 mt-4 bg-canino-blue text-white rounded-xl font-black hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-lg shadow-canino-blue/20 flex items-center justify-center gap-2 cursor-pointer"
className="w-full py-4 mt-4 bg-canina-blue text-white rounded-xl font-black hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-lg shadow-canina-blue/20 flex items-center justify-center gap-2 cursor-pointer"
>
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>ورود به حساب</>}
</button>
@ -286,7 +286,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canino-blue/20 outline-none text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm"
/>
</div>
<div className="space-y-1">
@ -296,7 +296,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={lastName}
onChange={(e) => setLastName(e.target.value)}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canino-blue/20 outline-none text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm"
/>
</div>
</div>
@ -309,7 +309,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canino-blue/20 outline-none text-left tracking-widest text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left tracking-widest text-sm"
/>
</div>
@ -320,7 +320,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canino-blue/20 outline-none text-left text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left text-sm"
/>
</div>
@ -331,7 +331,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canino-blue/20 outline-none text-left text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left text-sm"
/>
</div>
@ -339,7 +339,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="button"
onClick={() => setView("login")}
className="text-xs font-bold text-canino-blue hover:underline"
className="text-xs font-bold text-canina-blue hover:underline"
>
بازگشت به ورود
</button>
@ -348,7 +348,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="submit"
disabled={isLoading || !phoneNumber || !password || !firstName || !lastName}
className="w-full py-3 mt-2 bg-canino-blue text-white rounded-xl font-black hover:bg-indigo-700 disabled:opacity-50 transition-all flex items-center justify-center gap-2 cursor-pointer"
className="w-full py-3 mt-2 bg-canina-blue text-white rounded-xl font-black hover:bg-indigo-700 disabled:opacity-50 transition-all flex items-center justify-center gap-2 cursor-pointer"
>
{isLoading ? <RefreshCw className="w-4 h-4 animate-spin" /> : <>ثبتنام</>}
</button>
@ -370,7 +370,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="button"
onClick={() => setView("login")}
className="text-[10px] font-black text-canino-blue hover:underline"
className="text-[10px] font-black text-canina-blue hover:underline"
>
برگشت به صفحه ورود
</button>
@ -385,7 +385,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canino-blue/20 outline-none font-bold text-lg text-left tracking-widest"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-lg text-left tracking-widest"
/>
</div>
</div>
@ -393,7 +393,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="submit"
disabled={isLoading || phoneNumber.length < 11}
className="w-full py-5 bg-canino-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 cursor-pointer"
className="w-full py-5 bg-canina-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 cursor-pointer"
>
{isLoading ? (
<RefreshCw className="w-6 h-6 animate-spin" />
@ -422,7 +422,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="button"
onClick={() => setView("otp-phone")}
className="text-[10px] font-black text-canino-blue flex items-center gap-1 hover:underline"
className="text-[10px] font-black text-canina-blue flex items-center gap-1 hover:underline"
>
<ArrowRight className="w-3 h-3" />
تغییر شماره
@ -438,7 +438,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
value={otpCode}
onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-2xl text-center tracking-[0.5em]"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-2xl text-center tracking-[0.5em]"
/>
</div>
</div>
@ -453,7 +453,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
type="button"
onClick={handleResendOtp}
disabled={isLoading}
className="text-xs font-black text-canino-blue hover:underline flex items-center gap-1.5 justify-center mx-auto"
className="text-xs font-black text-canina-blue hover:underline flex items-center gap-1.5 justify-center mx-auto"
>
<RefreshCw className="w-3.5 h-3.5" />
ارسال مجدد کد تایید
@ -464,7 +464,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button
type="submit"
disabled={isLoading || otpCode.length < 5}
className="w-full py-5 bg-canino-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 cursor-pointer"
className="w-full py-5 bg-canina-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 cursor-pointer"
>
{isLoading ? (
<RefreshCw className="w-6 h-6 animate-spin" />

View File

@ -79,7 +79,7 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
</button>
{/* Sidebar Info */}
<div className="w-full md:w-80 bg-canino-blue p-10 text-white flex flex-col">
<div className="w-full md:w-80 bg-canina-blue p-10 text-white flex flex-col">
<div className="mb-10">
<div className="w-16 h-16 bg-white/20 rounded-2xl flex items-center justify-center mb-6">
<Building2 className="w-8 h-8" />
@ -113,14 +113,14 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
placeholder="جستجوی کد کالا یا نام محصول..."
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canino-blue/20"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-canina-blue/20"
/>
</div>
<button
onClick={handleAddAll}
disabled={totalItems === 0}
className="bg-medical-gray-900 text-white px-8 py-3 rounded-2xl font-black text-sm flex items-center gap-2 hover:bg-canino-blue transition-colors disabled:opacity-30"
className="bg-medical-gray-900 text-white px-8 py-3 rounded-2xl font-black text-sm flex items-center gap-2 hover:bg-canina-blue transition-colors disabled:opacity-30"
>
<ShoppingCart className="w-4 h-4" />
افزودن کلی ({totalItems} عدد)
@ -143,7 +143,7 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
{filteredProducts.map(product => (
<tr key={product.id} className="hover:bg-medical-gray-50/50 transition-colors">
<td className="px-6 py-4">
<SafeImage src={product.image} className="w-12 h-12 object-contain" alt={product.name} />
<SafeImage src={product.image} className="w-12 h-12" imgClassName="object-contain" alt={product.name} />
</td>
<td className="px-6 py-4">
<div className="font-black text-medical-gray-900">{product.name}</div>
@ -162,7 +162,7 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
value={quantities[product.id] || ""}
onChange={(e) => handleQuantityChange(product.id, e.target.value)}
placeholder="0"
className="w-20 bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-center font-mono font-bold focus:ring-2 focus:ring-canino-blue/20 outline-none"
className="w-20 bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-center font-mono font-bold focus:ring-2 focus:ring-canina-blue/20 outline-none"
/>
</td>
</tr>

View File

@ -33,11 +33,11 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
<div className="max-w-7xl mx-auto">
{/* 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-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronRight className="w-2.5 h-2.5" />
<span className="cursor-pointer hover:text-canino-blue" onClick={() => setSelectedPost(null)}>مجله سلامت</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => setSelectedPost(null)}>مجله سلامت</span>
<ChevronRight className="w-2.5 h-2.5" />
<span className="text-canino-blue">{selectedPost.title}</span>
<span className="text-canina-blue">{selectedPost.title}</span>
</div>
<div className="grid lg:grid-cols-12 gap-12">
@ -51,8 +51,8 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
<img src={selectedPost.image} alt={selectedPost.title} className="w-full h-full object-cover" />
</div>
<div className="p-12">
<div className="flex items-center gap-4 text-xs font-bold text-canino-blue mb-8">
<div className="bg-canino-blue/10 px-4 py-1.5 rounded-full uppercase tracking-widest">تحقیق بالینی</div>
<div className="flex items-center gap-4 text-xs font-bold text-canina-blue mb-8">
<div className="bg-canina-blue/10 px-4 py-1.5 rounded-full uppercase tracking-widest">تحقیق بالینی</div>
<div className="flex items-center gap-1">
<Calendar className="w-4 h-4" />
{selectedPost.date}
@ -62,7 +62,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
{selectedPost.title}
</h1>
<div className="prose prose-lg max-w-none text-medical-gray-600 leading-[2] text-justify space-y-6">
<p className="font-bold text-medical-gray-900 italic text-xl border-r-4 border-canino-blue pr-6 py-2">
<p className="font-bold text-medical-gray-900 italic text-xl border-r-4 border-canina-blue pr-6 py-2">
{selectedPost.excerpt}
</p>
<div className="whitespace-pre-line">
@ -77,11 +77,11 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div>
<div>
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</div>
<div className="font-bold text-medical-gray-400">تیم تحقیق و توسعه کانینو آلمان</div>
<div className="font-bold text-medical-gray-400">تیم تحقیق و توسعه کانینا آلمان</div>
</div>
</div>
<div className="flex gap-4">
<button className="p-4 bg-medical-gray-100 rounded-2xl hover:bg-canino-blue hover:text-white transition-all text-medical-gray-400">
<button className="p-4 bg-medical-gray-100 rounded-2xl hover:bg-canina-blue hover:text-white transition-all text-medical-gray-400">
<Sparkles className="w-6 h-6" />
</button>
</div>
@ -91,7 +91,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div>
<div className="lg:col-span-4 space-y-10">
<div className="bg-canino-blue rounded-[3rem] p-10 text-white shadow-2xl relative overflow-hidden">
<div className="bg-canina-blue rounded-[3rem] p-10 text-white shadow-2xl relative overflow-hidden">
<div className="absolute top-0 left-0 p-8 opacity-10">
<Sparkles className="w-20 h-20" />
</div>
@ -127,7 +127,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
<div className="w-16 h-16 rounded-2xl overflow-hidden shrink-0">
<img src={p.image} className="w-full h-full object-cover group-hover:scale-110 transition-transform" />
</div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors line-clamp-2">
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors line-clamp-2">
{p.title}
</div>
</div>
@ -147,15 +147,15 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
{/* Header */}
<div className="flex flex-col md:flex-row items-center justify-between mb-16 gap-6">
<div className="text-right">
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canino-blue/10 text-canino-blue rounded-full text-[10px] font-black uppercase tracking-widest mb-4">
<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">
<BookOpen className="w-3 h-3" />
Canino Science Blog
Canina Science Blog
</div>
<h1 className="text-4xl lg:text-6xl font-black text-medical-gray-900 italic leading-tight">
مجله تخصصی <span className="text-canino-blue">سلامت پتها</span>
مجله تخصصی <span className="text-canina-blue">سلامت پتها</span>
</h1>
<p className="text-lg text-medical-gray-500 font-medium mt-4 max-w-xl">
آخرین یافتههای علمی محققین کانینو آلمان در مورد تغذیه و سلامت پتها.
آخرین یافتههای علمی محققین کانینا آلمان در مورد تغذیه و سلامت پتها.
</p>
</div>
<button
@ -184,14 +184,14 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
/>
</div>
<div className="lg:w-1/2 p-12 flex flex-col justify-center">
<div className="flex items-center gap-4 text-xs font-bold text-canino-blue mb-6">
<div className="bg-canino-blue/10 px-3 py-1 rounded-full uppercase tracking-widest">تخصصی</div>
<div className="flex items-center gap-4 text-xs font-bold text-canina-blue mb-6">
<div className="bg-canina-blue/10 px-3 py-1 rounded-full uppercase tracking-widest">تخصصی</div>
<div className="flex items-center gap-1">
<Calendar className="w-3 h-3" />
{blogs[0].date}
</div>
</div>
<h2 className="text-3xl lg:text-4xl font-black text-medical-gray-900 mb-6 leading-tight group-hover:text-canino-blue transition-colors">
<h2 className="text-3xl lg:text-4xl font-black text-medical-gray-900 mb-6 leading-tight group-hover:text-canina-blue transition-colors">
{blogs[0].title}
</h2>
<p className="text-lg text-medical-gray-500 mb-8 leading-relaxed italic">
@ -204,10 +204,10 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div>
<div className="text-sm">
<div className="font-black text-medical-gray-900">{blogs[0].author}</div>
<div className="font-bold text-medical-gray-400">نویسنده کانینو</div>
<div className="font-bold text-medical-gray-400">نویسنده کانینا</div>
</div>
</div>
<div className="flex items-center gap-2 text-canino-blue font-black">
<div className="flex items-center gap-2 text-canina-blue font-black">
ادامه مطلب
<ArrowLeft className="w-5 h-5 group-hover:-translate-x-2 transition-transform" />
</div>
@ -237,13 +237,13 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
/>
</div>
<div className="p-8">
<div className="flex items-center gap-4 text-[10px] font-bold text-canino-blue mb-4">
<div className="flex items-center gap-4 text-[10px] font-bold text-canina-blue mb-4">
<div className="flex items-center gap-1">
<Calendar className="w-3 h-3" />
{post.date}
</div>
</div>
<h3 className="text-xl font-black text-medical-gray-900 mb-4 group-hover:text-canino-blue transition-colors">
<h3 className="text-xl font-black text-medical-gray-900 mb-4 group-hover:text-canina-blue transition-colors">
{post.title}
</h3>
<p className="text-sm text-medical-gray-500 mb-8 leading-relaxed line-clamp-2">
@ -258,7 +258,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
))}
{/* Newsletter / CTA Box */}
<div className="bg-canino-blue rounded-[3rem] p-10 text-white relative overflow-hidden flex flex-col justify-center">
<div className="bg-canina-blue rounded-[3rem] p-10 text-white relative overflow-hidden flex flex-col justify-center">
<div className="absolute top-0 right-0 p-8 opacity-20">
<Sparkles className="w-24 h-24" />
</div>
@ -272,7 +272,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
placeholder="آدرس ایمیل شما"
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"
/>
<button className="bg-white text-canino-blue px-6 py-3 rounded-xl font-black">
<button className="bg-white text-canina-blue px-6 py-3 rounded-xl font-black">
عضویت
</button>
</div>
@ -280,7 +280,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div>
{/* Synergy Products Cross-sell */}
<section className="mt-32 p-12 bg-canino-blue rounded-[4rem] text-white overflow-hidden relative shadow-2xl">
<section className="mt-32 p-12 bg-canina-blue rounded-[4rem] text-white overflow-hidden relative shadow-2xl">
<div className="absolute inset-0 opacity-20 pointer-events-none">
<div className="grid grid-cols-6 h-full w-full">
{Array.from({ length: 36 }).map((_, i) => (
@ -292,11 +292,11 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
<div className="flex-1">
<h3 className="text-3xl lg:text-4xl font-black italic mb-6">علم آلمانی در خدمت سلامت پت شما</h3>
<p className="text-white/80 mb-8 leading-relaxed max-w-xl">
تمامی مقالات این وبلاگ بر اساس کاتالوگهای رسمی و نتایج آزمایشگاهی کمپانی کانینو آلمان تدوین شده است.
تمامی مقالات این وبلاگ بر اساس کاتالوگهای رسمی و نتایج آزمایشگاهی کمپانی کانینا آلمان تدوین شده است.
</p>
<button
onClick={() => router.push('/shop')}
className="bg-white text-canino-blue px-8 py-4 rounded-2xl font-black hover:scale-105 transition-transform"
className="bg-white text-canina-blue px-8 py-4 rounded-2xl font-black hover:scale-105 transition-transform"
>
مشاهده محصولات تخصصی
</button>

View File

@ -69,7 +69,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
{/* Header */}
<div className="p-6 border-b border-medical-gray-100 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-medical-gray-50 rounded-xl flex items-center justify-center text-canino-blue">
<div className="w-10 h-10 bg-medical-gray-50 rounded-xl flex items-center justify-center text-canina-blue">
<ShoppingBag className="w-6 h-6" />
</div>
<h3 className="text-xl font-black text-medical-gray-900 italic">سبد خرید</h3>
@ -92,7 +92,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
onClose();
onShopNavigate?.();
}}
className="text-canino-blue font-black text-sm border-b-2 border-canino-blue pb-1 font-vazir"
className="text-canina-blue font-black text-sm border-b-2 border-canina-blue pb-1 font-vazir"
>
مشاهده محصولات تخصصی
</button>
@ -103,16 +103,16 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
{items.map((item) => (
<div key={item.product.id} className="flex gap-4 p-4 bg-medical-gray-50 rounded-3xl border border-medical-gray-100 group">
<div className="w-20 h-20 bg-white rounded-2xl p-2 flex-shrink-0 flex items-center justify-center shadow-sm">
<SafeImage src={item.product.image} alt={item.product.name} className="w-full h-full object-contain" />
<SafeImage src={item.product.image} alt={item.product.name} className="w-full h-full" imgClassName="object-contain" />
</div>
<div className="flex-1 min-w-0">
<h4 className="text-sm font-black text-medical-gray-900 truncate mb-1">{item.product.name}</h4>
<p className="text-[10px] text-canino-blue font-bold mb-3">{item.product.category}</p>
<p className="text-[10px] text-canina-blue font-bold mb-3">{item.product.category}</p>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2 bg-white rounded-lg border border-medical-gray-200 p-1">
<button
onClick={() => updateQuantity(item.product.id, item.quantity - 1)}
className="p-1 hover:text-canino-blue transition-colors"
className="p-1 hover:text-canina-blue transition-colors"
data-testid="minus-btn"
>
<Minus className="w-3 h-3" />
@ -120,7 +120,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
<span className="text-xs font-black min-w-[20px] text-center font-vazir">{toPersian(item.quantity)}</span>
<button
onClick={() => updateQuantity(item.product.id, item.quantity + 1)}
className="p-1 hover:text-canino-blue transition-colors"
className="p-1 hover:text-canina-blue transition-colors"
data-testid="plus-btn"
>
<Plus className="w-3 h-3" />
@ -184,15 +184,15 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="p-5 bg-gradient-to-br from-canino-blue/5 to-transparent border border-canino-blue/10 rounded-3xl"
className="p-5 bg-gradient-to-br from-canina-blue/5 to-transparent border border-canina-blue/10 rounded-3xl"
>
<div className="flex items-center gap-2 mb-4">
<Sparkles className="w-4 h-4 text-canino-blue animate-pulse" />
<Sparkles className="w-4 h-4 text-canina-blue animate-pulse" />
<span className="text-xs font-black text-medical-gray-900">پیشنهاد هوشمند برای جذب بهتر</span>
</div>
<div className="flex items-center gap-4">
<div className="w-16 h-16 bg-white rounded-2xl p-2 shrink-0 shadow-sm border border-canino-blue/5">
<SafeImage src={suggestedProduct.image} alt="" className="w-full h-full object-contain" />
<div className="w-16 h-16 bg-white rounded-2xl p-2 shrink-0 shadow-sm border border-canina-blue/5">
<SafeImage src={suggestedProduct.image} alt="" className="w-full h-full" imgClassName="object-contain" />
</div>
<div className="flex-1">
<h5 className="text-[10px] font-black text-medical-gray-900 mb-1">{suggestedProduct.name}</h5>
@ -200,7 +200,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
</div>
<button
onClick={() => addItem(suggestedProduct, 1)}
className="bg-canino-blue text-white w-8 h-8 rounded-full flex items-center justify-center hover:scale-110 transition-transform shadow-lg shadow-canino-blue/20"
className="bg-canina-blue text-white w-8 h-8 rounded-full flex items-center justify-center hover:scale-110 transition-transform shadow-lg shadow-canina-blue/20"
>
<Plus className="w-4 h-4" />
</button>
@ -226,11 +226,11 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
placeholder="CANINO2024"
value={couponCode}
onChange={(e) => setCouponCode(e.target.value)}
className={`w-full bg-white border ${couponStatus === 'error' ? 'border-red-300' : 'border-medical-gray-200'} rounded-2xl py-3 px-4 pr-10 text-sm font-bold focus:outline-none focus:ring-2 focus:ring-canino-blue/20 transition-all`}
className={`w-full bg-white border ${couponStatus === 'error' ? 'border-red-300' : 'border-medical-gray-200'} rounded-2xl py-3 px-4 pr-10 text-sm font-bold focus:outline-none focus:ring-2 focus:ring-canina-blue/20 transition-all`}
/>
<button
onClick={handleApplyCoupon}
className={`absolute left-2 top-1/2 -translate-y-1/2 px-4 py-1.5 rounded-xl text-[10px] font-black transition-all ${couponStatus === 'success' ? 'bg-green-600 text-white' : 'bg-medical-gray-900 text-white hover:bg-canino-blue'}`}
className={`absolute left-2 top-1/2 -translate-y-1/2 px-4 py-1.5 rounded-xl text-[10px] font-black transition-all ${couponStatus === 'success' ? 'bg-green-600 text-white' : 'bg-medical-gray-900 text-white hover:bg-canina-blue'}`}
>
{couponStatus === 'success' ? <CheckCircle2 className="w-3 h-3" /> : 'اعمال'}
</button>
@ -257,17 +257,17 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
{/* Subscription Toggle */}
<div
onClick={toggleSubscription}
className={`p-4 rounded-2xl border-2 transition-all cursor-pointer ${isSubscribed ? 'bg-canino-blue/5 border-canino-blue' : 'bg-white border-medical-gray-100 hover:border-canino-blue/30'}`}
className={`p-4 rounded-2xl border-2 transition-all cursor-pointer ${isSubscribed ? 'bg-canina-blue/5 border-canina-blue' : 'bg-white border-medical-gray-100 hover:border-canina-blue/30'}`}
>
<div className="flex items-center gap-3">
<div className={`w-10 h-10 rounded-xl flex items-center justify-center transition-colors ${isSubscribed ? 'bg-canino-blue text-white' : 'bg-medical-gray-50 text-medical-gray-300'}`}>
<div className={`w-10 h-10 rounded-xl flex items-center justify-center transition-colors ${isSubscribed ? 'bg-canina-blue text-white' : 'bg-medical-gray-50 text-medical-gray-300'}`}>
<ShieldCheck className="w-6 h-6" />
</div>
<div className="flex-1">
<h5 className="text-xs font-black text-medical-gray-900">فعالسازی سرویس تمدید خودکار (Refill)</h5>
<p className="text-[10px] text-medical-gray-500 font-medium">۵٪ تخفیف روی تمام فاکتور + ارسال اولویتدار</p>
</div>
<div className={`w-5 h-5 rounded-full border-2 flex items-center justify-center ${isSubscribed ? 'bg-canino-blue border-canino-blue' : 'border-medical-gray-200'}`}>
<div className={`w-5 h-5 rounded-full border-2 flex items-center justify-center ${isSubscribed ? 'bg-canina-blue border-canina-blue' : 'border-medical-gray-200'}`}>
{isSubscribed && <X className="w-3 h-3 text-white" />}
</div>
</div>
@ -287,7 +287,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
<div className="flex items-center justify-between border-t border-medical-gray-200 pt-4 px-2">
<span className="text-lg font-black text-medical-gray-900 italic">مجموع قابل پرداخت</span>
<div className="text-left">
<p className="text-2xl font-black text-canino-blue tracking-tighter leading-none font-vazir">{toPersian(getTotal().toLocaleString())}</p>
<p className="text-2xl font-black text-canina-blue tracking-tighter leading-none font-vazir">{toPersian(getTotal().toLocaleString())}</p>
<p className="text-[10px] text-medical-gray-400 font-bold">تومان</p>
</div>
</div>
@ -295,7 +295,7 @@ export default function CartDrawer({ isOpen, onClose, onCheckout, onShopNavigate
<button
onClick={onCheckout}
className="w-full bg-canino-blue text-white py-5 rounded-[2.5rem] font-black text-lg hover:shadow-2xl hover:shadow-canino-blue/20 transition-all flex items-center justify-center gap-3 group"
className="w-full bg-canina-blue text-white py-5 rounded-[2.5rem] font-black text-lg hover:shadow-2xl hover:shadow-canina-blue/20 transition-all flex items-center justify-center gap-3 group"
>
ثبت نهایی و تسویه حساب
<ArrowLeft className="w-5 h-5 group-hover:translate-x-[-4px] transition-transform" />

View File

@ -113,7 +113,7 @@ export default function CheckoutPage() {
<ShieldCheck className="w-12 h-12" />
</div>
<h2 className="text-2xl font-black text-medical-gray-900 italic">سبد خرید شما خالی است</h2>
<button onClick={() => router.push('/shop')} className="text-canino-blue font-black underline underline-offset-8">بازگشت به فروشگاه</button>
<button onClick={() => router.push('/shop')} className="text-canina-blue font-black underline underline-offset-8">بازگشت به فروشگاه</button>
</div>
</div>
);
@ -127,24 +127,24 @@ export default function CheckoutPage() {
<div className="lg:hidden mb-10 space-y-4">
<button
onClick={() => router.back()}
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canino-blue transition-colors"
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-canino-blue" onClick={() => router.push('/shop')}>سبد خرید</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/shop')}>سبد خرید</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">نهاییسازی سفارش</span>
<span className="text-canina-blue">نهاییسازی سفارش</span>
</div>
</div>
{/* Desktop Breadcrumbs (Hidden on Mobile) */}
<div className="hidden lg:flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-10">
<span className="cursor-pointer hover:text-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">درگاه پرداخت امن و نهاییسازی</span>
<span className="text-canina-blue">درگاه پرداخت امن و نهاییسازی</span>
</div>
<div className="grid lg:grid-cols-12 gap-12">
@ -152,7 +152,7 @@ export default function CheckoutPage() {
<div className="lg:col-span-8 space-y-8">
{/* Step 1: Shipping */}
<section className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 overflow-hidden relative">
<div className="absolute top-0 right-0 w-3 h-full bg-canino-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-4 mb-10">
<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-2xl font-black text-medical-gray-900 italic">اطلاعات ارسال</h2>
@ -161,15 +161,15 @@ export default function CheckoutPage() {
<div className="grid md:grid-cols-2 gap-6">
<div className="space-y-2">
<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-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canino-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 className="space-y-2">
<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-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canino-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 className="md:col-span-2 space-y-2">
<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-4 px-6 text-sm focus:outline-none focus:ring-2 focus:ring-canino-blue/20 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>
</section>
@ -199,9 +199,9 @@ export default function CheckoutPage() {
console.error("Payment init failed");
}
}}
className={cn("p-6 rounded-3xl border-2 cursor-pointer transition-all group", paymentMethod === pay.id ? "border-canino-blue bg-canino-blue/5" : "border-medical-gray-100 hover:border-canino-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-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-medical-gray-400 group-hover:text-canino-blue group-hover:bg-canino-blue/10 mb-4 transition-all">
<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}
</div>
<h4 className="font-black text-sm text-medical-gray-900 mb-1">{pay.label}</h4>
@ -230,7 +230,7 @@ export default function CheckoutPage() {
<div className="flex flex-wrap items-center justify-between gap-6">
<div className="flex-1 min-w-[280px]">
<h4 className="text-lg font-black text-medical-gray-900 italic mb-2">رند کردن مبلغ و کمک به پناهگاه</h4>
<p className="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>
@ -305,7 +305,7 @@ export default function CheckoutPage() {
<div className="flex justify-between items-end pt-4">
<span className="text-xl font-black italic">مبلغ نهایی</span>
<div className="text-left">
<p className="text-3xl font-black text-canino-blue leading-none font-vazir">{toPersian(getTotal().toLocaleString())}</p>
<p className="text-3xl font-black text-canina-blue leading-none font-vazir">{toPersian(getTotal().toLocaleString())}</p>
<p className="text-[10px] text-white/30 font-bold mt-1">تومان</p>
</div>
</div>
@ -330,7 +330,7 @@ export default function CheckoutPage() {
name="coupon"
type="text"
placeholder="کد تخفیف (مثلاً: CANINO2024)"
className="flex-1 bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-xs focus:ring-1 focus:ring-canino-blue outline-none"
className="flex-1 bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-xs focus:ring-1 focus:ring-canina-blue outline-none"
/>
<button type="submit" className="bg-white/10 px-4 py-3 rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-white/20 transition-all">اعمال</button>
</form>
@ -339,7 +339,7 @@ export default function CheckoutPage() {
{/* Refill Estimates */}
<div className="mt-10 p-6 bg-white/5 rounded-3xl border border-white/10 space-y-4">
<div className="flex items-center gap-3">
<Clock className="w-5 h-5 text-canino-blue" />
<Clock className="w-5 h-5 text-canina-blue" />
<h4 className="text-xs font-black uppercase tracking-widest font-vazir">تخمین اتمام مصرف (هوش مصنوعی)</h4>
</div>
<div className="space-y-2">
@ -353,7 +353,7 @@ export default function CheckoutPage() {
return (
<div key={item.product.id} className="flex items-center justify-between text-[10px] font-medium font-vazir">
<span className="text-white/40">{item.product.name}</span>
<span className="text-canino-blue">~ {toPersian(days)} روز دیگر</span>
<span className="text-canina-blue">~ {toPersian(days)} روز دیگر</span>
</div>
);
})}
@ -363,7 +363,7 @@ export default function CheckoutPage() {
<button
onClick={handleFinalize}
disabled={loading}
className="w-full bg-canino-blue text-white py-6 rounded-2xl font-black text-xl mt-10 hover:scale-[1.02] transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 disabled:opacity-50 disabled:cursor-not-allowed"
className="w-full bg-canina-blue text-white py-6 rounded-2xl font-black text-xl mt-10 hover:scale-[1.02] transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? (
<>

View File

@ -52,14 +52,14 @@ export class ErrorBoundary extends React.Component<Props, State> {
<button
onClick={this.handleRetry}
className="w-full bg-canino-blue text-white py-5 rounded-2xl font-black flex items-center justify-center gap-3 hover:scale-105 transition-all shadow-xl shadow-canino-blue/20"
className="w-full bg-canina-blue text-white py-5 rounded-2xl font-black flex items-center justify-center gap-3 hover:scale-105 transition-all shadow-xl shadow-canina-blue/20"
>
<RefreshCcw className="w-5 h-5" />
تلاش مجدد
</button>
<div className="mt-8 pt-8 border-t border-medical-gray-50 flex items-center justify-center gap-2">
<div className="w-8 h-8 bg-canino-blue rounded-xl flex items-center justify-center text-white font-bold text-xs italic">C</div>
<div className="w-8 h-8 bg-canina-blue rounded-xl flex items-center justify-center text-white font-bold text-xs italic">C</div>
<span className="text-[10px] font-black text-medical-gray-300 uppercase tracking-widest">Canina Pharma Support</span>
</div>
</div>

View File

@ -13,7 +13,7 @@ export const NotFoundPage = () => {
<div className="text-[15rem] font-black text-medical-gray-100 leading-none select-none">۴۰۴</div>
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-32 h-32 bg-white rounded-[3rem] shadow-2xl flex items-center justify-center">
<FileQuestion className="w-16 h-16 text-canino-blue" />
<FileQuestion className="w-16 h-16 text-canina-blue" />
</div>
</div>
</div>
@ -25,7 +25,7 @@ export const NotFoundPage = () => {
<button
onClick={() => router.push('/')}
className="bg-medical-gray-900 text-white px-10 py-5 rounded-2xl font-black flex items-center justify-center gap-3 mx-auto hover:bg-canino-blue transition-all shadow-2xl shadow-medical-gray-900/10"
className="bg-medical-gray-900 text-white px-10 py-5 rounded-2xl font-black flex items-center justify-center gap-3 mx-auto hover:bg-canina-blue transition-all shadow-2xl shadow-medical-gray-900/10"
>
<Home className="w-5 h-5" />
بازگشت به خانه
@ -45,13 +45,13 @@ export const ServerErrorPage = ({ onRetry }: { onRetry: () => void }) => {
<h1 className="text-4xl font-black text-medical-gray-900 mb-4">خطای داخلی سیستم</h1>
<p className="text-medical-gray-500 mb-12 font-bold text-lg">
ارتباط با دیتابیس کانینو با مشکل مواجه شده است. در حال بررسی موضوع هستیم.
ارتباط با دیتابیس کانینا با مشکل مواجه شده است. در حال بررسی موضوع هستیم.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={onRetry}
className="bg-canino-blue text-white px-10 py-5 rounded-2xl font-black flex items-center justify-center gap-3 hover:scale-105 transition-all shadow-xl shadow-canino-blue/20"
className="bg-canina-blue text-white px-10 py-5 rounded-2xl font-black flex items-center justify-center gap-3 hover:scale-105 transition-all shadow-xl shadow-canina-blue/20"
>
<RefreshCw className="w-5 h-5" />
تلاش مجدد

View File

@ -29,7 +29,7 @@ function ProductCard({ product, onClick }: { product: Product; key?: string | nu
viewport={{ once: true }}
transition={{ duration: 0.5 }}
onClick={() => onClick(product)}
className="group bg-white rounded-3xl border border-medical-gray-200 overflow-hidden hover:shadow-2xl hover:shadow-canino-blue/10 transition-all duration-500 flex flex-col h-full cursor-pointer relative"
className="group bg-white rounded-3xl border border-medical-gray-200 overflow-hidden hover:shadow-2xl hover:shadow-canina-blue/10 transition-all duration-500 flex flex-col h-full cursor-pointer relative"
>
{compatibility && (
<div className={`absolute top-16 right-4 z-10 text-[8px] font-black uppercase tracking-widest px-3 py-1 rounded-full shadow-md flex items-center gap-1 ${
@ -45,7 +45,8 @@ function ProductCard({ product, onClick }: { product: Product; key?: string | nu
<SafeImage
src={product.image}
alt={product.name}
className="w-full h-full object-contain group-hover:scale-105 transition-transform duration-500 drop-shadow-2xl"
className="w-full h-full group-hover:scale-105 transition-transform duration-500 drop-shadow-2xl"
imgClassName="object-contain"
/>
<div className="absolute top-4 right-4 px-3 py-1 bg-white/80 backdrop-blur-md rounded-full border border-medical-gray-200 text-[10px] font-bold text-medical-gray-500 uppercase tracking-widest">
{product.category}
@ -53,11 +54,11 @@ function ProductCard({ product, onClick }: { product: Product; key?: string | nu
{/* Hover Actions */}
<Link href={`/shop/${product.slug || product.id}`} className="absolute inset-0 z-10" />
<div className="absolute inset-0 bg-canino-blue/60 opacity-0 group-hover:opacity-100 backdrop-blur-sm transition-all duration-300 flex items-center justify-center gap-4">
<div className="w-12 h-12 rounded-full bg-white text-canino-blue flex items-center justify-center hover:scale-110 transition-transform shadow-lg">
<div className="absolute inset-0 bg-canina-blue/60 opacity-0 group-hover:opacity-100 backdrop-blur-sm transition-all duration-300 flex items-center justify-center gap-4">
<div className="w-12 h-12 rounded-full bg-white text-canina-blue flex items-center justify-center hover:scale-110 transition-transform shadow-lg">
<Eye className="w-5 h-5" />
</div>
<div className="w-12 h-12 rounded-full bg-canino-blue text-white flex items-center justify-center hover:scale-110 transition-transform shadow-lg border border-white/20">
<div className="w-12 h-12 rounded-full bg-canina-blue text-white flex items-center justify-center hover:scale-110 transition-transform shadow-lg border border-white/20">
<ShoppingCart className="w-5 h-5" />
</div>
</div>
@ -66,10 +67,10 @@ function ProductCard({ product, onClick }: { product: Product; key?: string | nu
{/* Content Area */}
<div className="p-8 flex flex-col flex-1">
<div className="flex items-start justify-between mb-4 gap-2">
<h3 className="text-xl font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors leading-tight">
<h3 className="text-xl font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors leading-tight">
{product.name}
</h3>
<ShieldCheck className="w-6 h-6 text-canino-blue flex-shrink-0" />
<ShieldCheck className="w-6 h-6 text-canina-blue flex-shrink-0" />
</div>
<p className="text-sm text-medical-gray-500 leading-relaxed mb-6 flex-1">
@ -78,13 +79,13 @@ function ProductCard({ product, onClick }: { product: Product; key?: string | nu
<div className="space-y-4 pt-4 border-t border-medical-gray-100">
<div className="flex items-center gap-3">
<div className="w-1 h-1 rounded-full bg-canino-blue" />
<div className="w-1 h-1 rounded-full bg-canina-blue" />
<span className="text-xs font-semibold text-medical-gray-700 italic">{product.benefits}</span>
</div>
<div className="flex items-center justify-between">
<div className="text-xl font-black text-medical-gray-900 font-vazir">{product.price}</div>
<button className="text-xs font-black text-canino-blue uppercase tracking-widest border-b-2 border-canino-blue pb-1 hover:text-medical-gray-900 hover:border-medical-gray-900 transition-all">
<button className="text-xs font-black text-canina-blue uppercase tracking-widest border-b-2 border-canina-blue pb-1 hover:text-medical-gray-900 hover:border-medical-gray-900 transition-all">
مشاهده جزییات
</button>
</div>
@ -122,19 +123,19 @@ export default function FeaturedProducts() {
<div className="max-w-7xl mx-auto px-4">
<div className="flex flex-col lg:flex-row items-end justify-between mb-16 gap-6">
<div className="lg:w-2/3">
<div className="text-canino-blue text-xs font-bold uppercase tracking-[0.2em] mb-4 font-vazir">بیشترین انتخاب توسط دامپزشکان</div>
<div className="text-canina-blue text-xs font-bold uppercase tracking-[0.2em] mb-4 font-vazir">بیشترین انتخاب توسط دامپزشکان</div>
<h2 className="text-3xl lg:text-5xl font-black text-medical-gray-900 leading-[1.2]">
محصولات برگزیده و راهکارهای <br />
<span className="italic text-canino-blue">درمان تخصصی</span>
<span className="italic text-canina-blue">درمان تخصصی</span>
</h2>
</div>
<div className="lg:w-1/3 text-left lg:text-right">
<p className="text-medical-gray-500 text-sm leading-relaxed mb-4">
محصولات دارویی کانینو با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شدهاند.
محصولات دارویی کانینا با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شدهاند.
</p>
<button
onClick={() => router.push('/shop')}
className="inline-flex items-center gap-2 text-canino-blue font-bold text-sm hover:translate-x-1 transition-transform rtl:hover:-translate-x-1"
className="inline-flex items-center gap-2 text-canina-blue font-bold text-sm hover:translate-x-1 transition-transform rtl:hover:-translate-x-1"
>
مشاهده تمامی محصولات
<span className="text-lg"></span>
@ -142,7 +143,7 @@ export default function FeaturedProducts() {
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-10">
{isLoading ? (
Array.from({ length: 3 }).map((_, i) => <ProductCardSkeleton key={i} />)
) : products.length > 0 ? (
@ -151,7 +152,7 @@ export default function FeaturedProducts() {
))
) : (
<div className="col-span-full py-16 px-8 flex flex-col items-center justify-center text-center bg-white rounded-[2.5rem] border border-medical-gray-200 shadow-xl max-w-lg mx-auto">
<AlertCircle className="w-12 h-12 text-canino-teal mb-4" />
<AlertCircle className="w-12 h-12 text-canina-teal mb-4" />
<h3 className="text-xl font-black text-medical-gray-900 mb-2 font-vazir">هیچ محصولی یافت نشد</h3>
<p className="text-sm text-medical-gray-500 font-medium font-vazir leading-relaxed">
در حال حاضر هیچ محصول برجستهای برای نمایش وجود ندارد. لطفاً در پنل ادمین محصولات برگزیده را تنظیم کنید.

View File

@ -16,10 +16,10 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
<div className="space-y-8">
<div className="flex items-center gap-4 cursor-pointer group" onClick={() => onNavigate("home")}>
<div className="w-16 h-16 bg-white rounded-2xl flex items-center justify-center p-2 group-hover:scale-105 transition-transform">
<img src="https://canina.de/media/fb/d5/47/1683116813/Logo.png" alt="Canino Logo" className="w-full h-auto" referrerPolicy="no-referrer" />
<img src="https://canina.de/media/fb/d5/47/1683116813/Logo.png" alt="Canina Logo" className="w-full h-auto" referrerPolicy="no-referrer" />
</div>
<div>
<h3 className="text-2xl font-black italic tracking-tighter">کانینو ایران</h3>
<h3 className="text-2xl font-black italic tracking-tighter">کانینا ایران</h3>
<p className="text-[10px] text-white/40 font-bold uppercase tracking-widest">نماینده رسمی در ایران</p>
</div>
</div>
@ -28,7 +28,7 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
</p>
<div className="flex gap-4">
{[Instagram, Globe].map((Icon, i) => (
<a key={i} href="#" className="w-10 h-10 bg-white/5 rounded-xl flex items-center justify-center hover:bg-canino-blue hover:text-white transition-all text-white/40">
<a key={i} href="#" className="w-10 h-10 bg-white/5 rounded-xl flex items-center justify-center hover:bg-canina-blue hover:text-white transition-all text-white/40">
<Icon className="w-5 h-5" />
</a>
))}
@ -37,26 +37,26 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
{/* Quick Links */}
<div className="space-y-8">
<h4 className="text-lg font-black text-canino-blue italic underline decoration-white/20 underline-offset-8">دسترسی سریع</h4>
<h4 className="text-lg font-black text-canina-blue italic underline decoration-white/20 underline-offset-8">دسترسی سریع</h4>
<ul className="space-y-4 text-sm font-bold text-white/60">
<li onClick={() => onShopNavigate()} className="hover:text-white hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group">
<div className="w-1.5 h-1.5 rounded-full bg-canino-blue group-hover:w-4 transition-all" />
<div className="w-1.5 h-1.5 rounded-full bg-canina-blue group-hover:w-4 transition-all" />
محصولات تخصصی ۲۰۲۴
</li>
<li onClick={() => onNavigate("blog")} className="hover:text-white hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group">
<div className="w-1.5 h-1.5 rounded-full bg-canino-blue group-hover:w-4 transition-all" />
<div className="w-1.5 h-1.5 rounded-full bg-canina-blue group-hover:w-4 transition-all" />
مجله سلامت پت (وبلاگ)
</li>
<li onClick={() => onNavigate("profile")} className="hover:text-white hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group">
<div className="w-1.5 h-1.5 rounded-full bg-canino-blue group-hover:w-4 transition-all" />
<div className="w-1.5 h-1.5 rounded-full bg-canina-blue group-hover:w-4 transition-all" />
شناسنامه پتها
</li>
<li onClick={() => onNavigate("wiki")} className="hover:text-white hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group">
<div className="w-1.5 h-1.5 rounded-full bg-canino-blue group-hover:w-4 transition-all" />
<div className="w-1.5 h-1.5 rounded-full bg-canina-blue group-hover:w-4 transition-all" />
دانشنامه ترکیبات
</li>
<li onClick={onB2BOpen} className="hover:text-canino-blue hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group text-blue-300">
<div className="w-1.5 h-1.5 rounded-full bg-canino-blue group-hover:w-4 transition-all" />
<li onClick={onB2BOpen} className="hover:text-canina-blue hover:translate-x-[-4px] transition-all cursor-pointer flex items-center gap-2 group text-blue-300">
<div className="w-1.5 h-1.5 rounded-full bg-canina-blue group-hover:w-4 transition-all" />
پنل سفارش عمده (B2B)
</li>
</ul>
@ -64,11 +64,11 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
{/* Location & Contact */}
<div className="space-y-8 lg:col-span-2">
<h4 className="text-lg font-black text-canino-blue italic underline decoration-white/20 underline-offset-8">اطلاعات تماس نمایندگی</h4>
<h4 className="text-lg font-black text-canina-blue italic underline decoration-white/20 underline-offset-8">اطلاعات تماس نمایندگی</h4>
<div className="grid md:grid-cols-2 gap-8">
<div className="space-y-6">
<div className="flex gap-4 group">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canino-blue group-hover:scale-110 transition-transform flex-shrink-0">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canina-blue group-hover:scale-110 transition-transform flex-shrink-0">
<Phone className="w-6 h-6" />
</div>
<div>
@ -77,7 +77,7 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
</div>
</div>
<div className="flex gap-4 group">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canino-blue group-hover:scale-110 transition-transform flex-shrink-0">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canina-blue group-hover:scale-110 transition-transform flex-shrink-0">
<Mail className="w-6 h-6" />
</div>
<div>
@ -88,12 +88,12 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
</div>
<div className="flex gap-4 group">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canino-blue group-hover:scale-110 transition-transform flex-shrink-0">
<div className="w-12 h-12 bg-white/5 rounded-2xl flex items-center justify-center text-canina-blue group-hover:scale-110 transition-transform flex-shrink-0">
<MapPin className="w-6 h-6" />
</div>
<div>
<p className="text-[10px] text-white/40 font-black uppercase mb-1">دفتر مرکزی</p>
<p className="text-sm font-bold leading-relaxed">تهران، جردن، خیابان سعیدی، ساختمان کانینو، طبقه ۵، واحد ۱۹</p>
<p className="text-sm font-bold leading-relaxed">تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹</p>
</div>
</div>
</div>
@ -108,14 +108,14 @@ export default function Footer({ onNavigate, onShopNavigate, onB2BOpen }: {
<p className="text-[10px] text-white/40 font-bold">تمامی محصولات دارای لیبل اصالت وزارت بهداشت و QR Code اختصاصی هستند.</p>
</div>
</div>
<div className="text-xs font-black italic text-white/20">اصالت آلمانی کانینو</div>
<div className="text-xs font-black italic text-white/20">اصالت آلمانی کانینا</div>
</div>
</div>
</div>
<div className="pt-12 border-t border-white/5 flex flex-col md:flex-row items-center justify-between gap-6 text-[10px] font-black text-white/20 uppercase tracking-[0.3em]">
<div>© ۲۰۲۶ کانینو ایران. تمامی حقوق محفوظ است.</div>
<div>© ۲۰۲۶ کانینا ایران. تمامی حقوق محفوظ است.</div>
<div className="flex gap-8 font-vazir">
<button onClick={() => onNavigate("home")} className="hover:text-white transition-colors">درباره ما</button>
<button onClick={() => onNavigate("home")} className="hover:text-white transition-colors">تماس با ما</button>

View File

@ -90,7 +90,7 @@ export default function Header({
<>
<AuthModal isOpen={isAuthModalOpen} onClose={() => setIsAuthModalOpen(false)} />
<div className="bg-canino-gold text-canino-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.5 text-center font-vazir tracking-wider flex items-center justify-center gap-2">
<span>🚚</span>
<span>ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان</span>
</div>
@ -115,9 +115,9 @@ export default function Header({
setIsMobileMenuOpen(false);
}}
>
<div className="w-12 h-12 bg-canino-blue rounded-2xl flex items-center justify-center text-white font-bold text-2xl group-hover:bg-medical-gray-900 transition-all shadow-xl shadow-canino-blue/20 italic">C</div>
<div className="w-12 h-12 bg-canina-blue rounded-2xl flex items-center justify-center text-white font-bold text-2xl group-hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20 italic">C</div>
<div className="flex flex-col">
<span className="text-canino-blue font-black text-2xl tracking-tighter leading-none italic font-inter">Canino <span className="text-sm not-italic font-medium border-l-2 border-medical-gray-100 pl-2 ml-2 font-vazir">ایران</span></span>
<span className="text-canina-blue font-black text-2xl tracking-tighter leading-none italic font-inter">Canina <span className="text-sm not-italic font-medium border-l-2 border-medical-gray-100 pl-2 ml-2 font-vazir">ایران</span></span>
<span className="text-[10px] text-medical-gray-400 font-bold uppercase tracking-widest leading-none mt-1.5 font-vazir">نماینده رسمی Canina Pharma GmbH آلمان</span>
</div>
</div>
@ -130,7 +130,7 @@ export default function Header({
onMouseEnter={() => setIsMegaMenuOpen(true)}
onMouseLeave={() => setIsMegaMenuOpen(false)}
>
<button className={`flex items-center justify-center gap-1.5 px-4 py-3 rounded-xl text-sm font-black transition-all whitespace-nowrap focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none min-h-[48px] ${isMegaMenuOpen ? 'bg-medical-gray-50 text-canino-blue' : 'text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canino-blue'} font-vazir`}>
<button className={`flex items-center justify-center gap-1.5 px-4 py-3 rounded-xl text-sm font-black transition-all whitespace-nowrap focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none min-h-[48px] ${isMegaMenuOpen ? 'bg-medical-gray-50 text-canina-blue' : 'text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canina-blue'} font-vazir`}>
راهکارهای درمانی
<ChevronDown className={`w-4 h-4 transition-transform duration-300 ${isMegaMenuOpen ? 'rotate-180' : ''}`} />
</button>
@ -153,7 +153,7 @@ export default function Header({
}}
>
<div className="flex items-center gap-4 mb-4">
<div className="p-3 bg-medical-gray-50 rounded-2xl text-canino-blue group-hover/item:bg-canino-blue group-hover/item:text-white transition-all shadow-sm">
<div className="p-3 bg-medical-gray-50 rounded-2xl text-canina-blue group-hover/item:bg-canina-blue group-hover/item:text-white transition-all shadow-sm">
{item.icon}
</div>
<h4 className="font-black text-medical-gray-900 text-sm font-vazir whitespace-nowrap">{item.title}</h4>
@ -162,7 +162,7 @@ export default function Header({
{item.solutions.map((sol, sIdx) => (
<li
key={sIdx}
className="text-[12px] text-medical-gray-400 hover:text-canino-blue hover:translate-x-[-4px] transition-all font-bold cursor-pointer font-vazir whitespace-nowrap"
className="text-[12px] text-medical-gray-400 hover:text-canina-blue hover:translate-x-[-4px] transition-all font-bold cursor-pointer font-vazir whitespace-nowrap"
onClick={(e) => {
e.stopPropagation();
onShopNavigate(item.id, sol);
@ -189,7 +189,7 @@ export default function Header({
<button
key={item.id}
onClick={item.action}
className={`px-4 py-3 rounded-xl text-sm font-black transition-all font-vazir whitespace-nowrap focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none min-h-[48px] ${currentView === item.id ? 'bg-canino-blue/5 text-canino-blue' : 'text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canino-blue'}`}
className={`px-4 py-3 rounded-xl text-sm font-black transition-all font-vazir whitespace-nowrap focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none min-h-[48px] ${currentView === item.id ? 'bg-canina-blue/5 text-canina-blue' : 'text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canina-blue'}`}
>
{item.label}
</button>
@ -208,7 +208,7 @@ export default function Header({
animate={{ width: 350, opacity: 1 }}
exit={{ width: 0, opacity: 0 }}
transition={{ type: "spring", damping: 20, stiffness: 200 }}
className="absolute right-0 top-1/2 -translate-y-1/2 bg-white border-2 border-canino-blue rounded-2xl shadow-xl overflow-hidden h-12 flex items-center pr-10"
className="absolute right-0 top-1/2 -translate-y-1/2 bg-white border-2 border-canina-blue rounded-2xl shadow-xl overflow-hidden h-12 flex items-center pr-10"
>
<form onSubmit={handleSearch} className="w-full flex items-center">
<input
@ -220,7 +220,7 @@ export default function Header({
placeholder="جستجوی محصولات، مقالات سلامت و..."
className="w-full bg-transparent px-4 py-2 text-[12px] font-bold outline-none font-vazir text-medical-gray-900"
/>
<button type="submit" className="px-4 py-2 bg-canino-blue text-white text-[10px] font-black hover:bg-medical-gray-900 transition-colors">
<button type="submit" className="px-4 py-2 bg-canina-blue text-white text-[10px] font-black hover:bg-medical-gray-900 transition-colors">
جستجو
</button>
</form>
@ -230,7 +230,7 @@ export default function Header({
<HeaderButton
variant={isSearchFocused ? "primary" : "secondary"}
className={cn("w-12 h-12 transition-all duration-300", isSearchFocused ? "z-30 bg-canino-blue text-white" : "")}
className={cn("w-12 h-12 transition-all duration-300", isSearchFocused ? "z-30 bg-canina-blue text-white" : "")}
onClick={() => setIsSearchFocused(!isSearchFocused)}
>
<Search className="w-5 h-5" />
@ -245,7 +245,7 @@ export default function Header({
className="flex items-center gap-2.5 px-4 py-2 hover:bg-white rounded-2xl cursor-pointer transition-all border border-transparent hover:border-medical-gray-200"
onClick={() => onNavigate("user-dashboard")}
>
<User className="w-5 h-5 text-canino-blue" />
<User className="w-5 h-5 text-canina-blue" />
<span className="text-[14px] font-black font-vazir text-medical-gray-900 leading-none">
{profile.firstName}
</span>
@ -259,16 +259,16 @@ export default function Header({
<div
className={cn(
"flex items-center gap-2.5 px-4 py-2 rounded-2xl transition-all cursor-pointer",
isPetSwitcherOpen ? "bg-canino-blue text-white shadow-lg shadow-canino-blue/20" : "text-canino-blue hover:bg-white"
isPetSwitcherOpen ? "bg-canina-blue text-white shadow-lg shadow-canina-blue/20" : "text-canina-blue hover:bg-white"
)}
onClick={() => setIsPetSwitcherOpen(!isPetSwitcherOpen)}
>
{activePet?.type === "گربه" ? (
<Cat className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canino-blue/60")} />
<Cat className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
) : (
<Dog className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canino-blue/60")} />
<Dog className={cn("w-5 h-5", isPetSwitcherOpen ? "text-white" : "text-canina-blue/60")} />
)}
<span className={cn("text-[14px] font-black font-vazir leading-none", isPetSwitcherOpen ? "text-white" : "text-canino-blue")}>
<span className={cn("text-[14px] font-black font-vazir leading-none", isPetSwitcherOpen ? "text-white" : "text-canina-blue")}>
{activePet?.name || "بدون پت"}
</span>
<ChevronDown className={cn("w-4 h-4 transition-transform", isPetSwitcherOpen ? "rotate-180" : "")} />
@ -289,7 +289,7 @@ export default function Header({
key={pet.id}
className={cn(
"w-full flex items-center justify-between p-3 rounded-xl transition-all group/item",
activePetId === pet.id ? "bg-canino-blue/5 text-canino-blue" : "hover:bg-medical-gray-50 text-medical-gray-600"
activePetId === pet.id ? "bg-canina-blue/5 text-canina-blue" : "hover:bg-medical-gray-50 text-medical-gray-600"
)}
>
<div
@ -302,7 +302,7 @@ export default function Header({
>
<div className={cn(
"w-8 h-8 rounded-lg flex items-center justify-center text-[11px] font-black transition-colors",
activePetId === pet.id ? "bg-canino-blue text-white" : "bg-medical-gray-100 text-medical-gray-400 group-hover/item:bg-medical-gray-200"
activePetId === pet.id ? "bg-canina-blue text-white" : "bg-medical-gray-100 text-medical-gray-400 group-hover/item:bg-medical-gray-200"
)}>
{pet.name[0]}
</div>
@ -318,7 +318,7 @@ export default function Header({
onNavigate({ view: "profile", subview: "detail" });
setIsPetSwitcherOpen(false);
}}
className="p-1.5 rounded-lg hover:bg-canino-blue hover:text-white transition-all text-medical-gray-300 hover:shadow-lg"
className="p-1.5 rounded-lg hover:bg-canina-blue hover:text-white transition-all text-medical-gray-300 hover:shadow-lg"
title="مشاهده شناسنامه سلامت"
>
<FileHeart className="w-4 h-4" />
@ -331,7 +331,7 @@ export default function Header({
<div className="pt-4 border-t border-medical-gray-100 space-y-1">
<button
onClick={() => { onNavigate({ view: "profile", subview: "add" }); setIsPetSwitcherOpen(false); }}
className="w-full flex items-center gap-3 p-3 text-canino-blue hover:bg-canino-blue/5 rounded-xl transition-all text-[12px] font-black font-vazir"
className="w-full flex items-center gap-3 p-3 text-canina-blue hover:bg-canina-blue/5 rounded-xl transition-all text-[12px] font-black font-vazir"
>
<PlusCircle className="w-5 h-5" />
ثبت همدم (Pet) جدید
@ -348,7 +348,7 @@ export default function Header({
className="w-full flex items-center gap-3 p-3 text-red-500 hover:bg-red-50 rounded-xl transition-all text-[12px] font-bold font-vazir mt-1"
>
<LogOut className="w-5 h-5" />
خروج از حساب کانینو
خروج از حساب کانینا
</button>
</div>
</motion.div>
@ -404,8 +404,8 @@ export default function Header({
>
<div className="flex items-center justify-between border-b border-medical-gray-100 pb-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-canino-blue rounded-xl flex items-center justify-center text-white font-bold text-xl italic">C</div>
<span className="text-canino-blue font-black text-xl italic font-inter">Canino</span>
<div className="w-10 h-10 bg-canina-blue rounded-xl flex items-center justify-center text-white font-bold text-xl italic">C</div>
<span className="text-canina-blue font-black text-xl italic font-inter">Canina</span>
</div>
<button
onClick={() => setIsMobileMenuOpen(false)}
@ -437,20 +437,20 @@ export default function Header({
{MENU_ITEMS.map((item, idx) => (
<div key={idx} className="py-1">
<div
className="text-[13px] font-bold text-medical-gray-800 font-vazir hover:text-canino-blue cursor-pointer flex items-center gap-2"
className="text-[13px] font-bold text-medical-gray-800 font-vazir hover:text-canina-blue cursor-pointer flex items-center gap-2"
onClick={() => {
onShopNavigate(item.id);
setIsMobileMenuOpen(false);
}}
>
<span className="text-canino-blue/80">{item.icon}</span>
<span className="text-canina-blue/80">{item.icon}</span>
<span>{item.title}</span>
</div>
<ul className="mt-1 space-y-1 mr-6">
{item.solutions.map((sol, sIdx) => (
<li
key={sIdx}
className="text-[11px] text-medical-gray-500 hover:text-canino-blue cursor-pointer py-1 font-vazir"
className="text-[11px] text-medical-gray-500 hover:text-canina-blue cursor-pointer py-1 font-vazir"
onClick={(e) => {
e.stopPropagation();
onShopNavigate(item.id, sol);
@ -481,7 +481,7 @@ export default function Header({
setIsMobileMenuOpen(false);
}}
className={`w-full text-right px-4 py-3 rounded-xl text-sm font-black transition-all font-vazir ${currentView === item.id
? 'bg-canino-blue/5 text-canino-blue'
? 'bg-canina-blue/5 text-canina-blue'
: 'text-medical-gray-600 hover:bg-medical-gray-50'
}`}
>

View File

@ -20,13 +20,13 @@ export default function HeaderButton({
badge,
icon
}: HeaderButtonProps) {
const baseStyles = "relative flex flex-col items-center justify-center rounded-xl transition-all duration-300 font-vazir select-none cursor-pointer overflow-visible focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none";
const baseStyles = "relative flex flex-col items-center justify-center rounded-xl transition-all duration-300 font-vazir select-none cursor-pointer overflow-visible focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none";
const variants = {
primary: "bg-canino-blue text-white hover:bg-medical-gray-900 shadow-lg shadow-canino-blue/20",
primary: "bg-canina-blue text-white hover:bg-medical-gray-900 shadow-lg shadow-canina-blue/20",
secondary: "bg-medical-gray-50 text-medical-gray-600 hover:bg-medical-gray-100",
outline: "border-2 border-medical-gray-100 text-medical-gray-700 hover:border-canino-blue hover:text-canino-blue",
ghost: "text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canino-blue"
outline: "border-2 border-medical-gray-100 text-medical-gray-700 hover:border-canina-blue hover:text-canina-blue",
ghost: "text-medical-gray-600 hover:bg-medical-gray-50 hover:text-canina-blue"
};
return (

View File

@ -22,7 +22,7 @@ function StatCounter({ target }: { target: number }) {
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 2.5, ease: "easeOut" }}
className="text-4xl lg:text-6xl font-black text-canino-blue font-vazir origin-right flex items-center"
className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir origin-right flex items-center"
>
<motion.span
animate={{ scale: [1, 1.1, 1] }}
@ -47,13 +47,13 @@ function Typewriter({ text }: { text: string }) {
}, [text]);
return (
<div className="text-4xl lg:text-6xl font-black text-canino-blue font-vazir flex flex-row-reverse items-center">
<div className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir flex flex-row-reverse items-center">
<span className="relative">
{toPersian(displayText)}
<motion.span
animate={{ opacity: [0, 1, 0] }}
transition={{ duration: 0.8, repeat: Infinity }}
className="absolute -left-1 top-0 h-full w-[3px] bg-canino-blue"
className="absolute -left-1 top-0 h-full w-[3px] bg-canina-blue"
/>
</span>
</div>
@ -68,7 +68,7 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
const title = banners.length > 0 ? banners[0].title : getText('hero_title', "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی");
const subtitle = banners.length > 0 ? banners[0].subtitle : getText(
'hero_desc',
'بیش از <span className="font-bold text-canino-blue">۴۰ سال</span> تجربه نوآورانه در تولید مکمل‌های درمانی با بالاترین استاندارد کیفی «گرید دارویی اختصاصی». راهکار هوشمند برای هر نیاز بالینی.'
'بیش از <span className="font-bold text-canina-blue">۴۰ سال</span> تجربه نوآورانه در تولید مکمل‌های درمانی با بالاترین استاندارد کیفی «گرید دارویی اختصاصی». راهکار هوشمند برای هر نیاز بالینی.'
);
const titleParts = title.split('\n');
@ -76,7 +76,7 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
<section className="relative overflow-hidden bg-white py-20 lg:py-32 border-b border-medical-gray-100">
{/* Background patterns */}
<div className="absolute top-0 left-0 w-full h-full opacity-[0.03] pointer-events-none select-none overflow-hidden">
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-canino-blue rounded-full blur-[120px] -mr-96 -mt-96" />
<div className="absolute top-0 right-0 w-[800px] h-[800px] bg-canina-blue rounded-full blur-[120px] -mr-96 -mt-96" />
<div className="absolute bottom-0 left-0 w-[600px] h-[600px] bg-medical-gray-500 rounded-full blur-[100px] -ml-40 -mb-40" />
</div>
@ -88,14 +88,14 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canino-blue/5 border border-canino-blue/10 rounded-full mb-6">
<span className="w-2 h-2 rounded-full bg-canino-blue animate-pulse" />
<span className="text-canino-blue text-xs font-bold uppercase tracking-widest leading-none">{getText('hero_badge', "تخصص دارویی از آلمان")}</span>
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canina-blue/5 border border-canina-blue/10 rounded-full mb-6">
<span className="w-2 h-2 rounded-full bg-canina-blue animate-pulse" />
<span className="text-canina-blue text-xs font-bold uppercase tracking-widest leading-none">{getText('hero_badge', "تخصص دارویی از آلمان")}</span>
</div>
<h1 className="text-4xl lg:text-7xl font-black text-medical-gray-900 leading-[1.1] mb-6">
{titleParts[0]} <br />
{titleParts[1] && <span className="text-canino-blue font-vazir">{titleParts[1]}</span>}
{titleParts[1] && <span className="text-canina-blue font-vazir">{titleParts[1]}</span>}
</h1>
<p
@ -113,14 +113,14 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
element.scrollIntoView({ behavior: 'smooth' });
}
}}
className="bg-medical-gray-900 text-white px-10 py-5 rounded-full font-bold text-lg hover:bg-canino-blue hover:shadow-2xl focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all flex items-center gap-2 group font-vazir min-h-[48px]"
className="bg-medical-gray-900 text-white px-10 py-5 rounded-full font-bold text-lg hover:bg-canina-blue hover:shadow-2xl focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all flex items-center gap-2 group font-vazir min-h-[48px]"
>
{getText('hero_btn_advisor', "دستیار سلامت پت")}
<ChevronLeft className="w-5 h-5 group-hover:-translate-x-1 transition-transform" />
</button>
<button
onClick={() => router.push('/shop')}
className="bg-white border-2 border-medical-gray-200 text-medical-gray-700 px-10 py-5 rounded-full font-bold text-lg hover:border-canino-blue hover:text-canino-blue focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all font-vazir min-h-[48px]"
className="bg-white border-2 border-medical-gray-200 text-medical-gray-700 px-10 py-5 rounded-full font-bold text-lg hover:border-canina-blue hover:text-canina-blue focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all font-vazir min-h-[48px]"
>
{getText('hero_btn_products', "مشاهده محصولات")}
</button>
@ -153,10 +153,10 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
className="absolute top-6 right-6 lg:top-8 lg:right-8 z-20 w-24 h-24 lg:w-28 lg:h-28 bg-white shadow-2xl rounded-full p-2 border-2 border-dashed border-canino-blue flex items-center justify-center text-center"
className="absolute top-6 right-6 lg:top-8 lg:right-8 z-20 w-24 h-24 lg:w-28 lg:h-28 bg-white shadow-2xl rounded-full p-2 border-2 border-dashed border-canina-blue flex items-center justify-center text-center"
>
<div className="flex flex-col items-center">
<span className="text-xl lg:text-2xl font-black text-canino-blue leading-none tracking-tighter">DE</span>
<span className="text-xl lg:text-2xl font-black text-canina-blue leading-none tracking-tighter">DE</span>
<span className="text-[7px] lg:text-[8px] font-bold text-medical-gray-500 uppercase tracking-widest mt-0.5 leading-tight">{getText('hero_quality_standard', "استاندارد کیفی آلمان")}</span>
</div>
</motion.div>
@ -183,7 +183,7 @@ export default function Hero({ banners = [] }: { banners?: any[] }) {
<div className="flex flex-col items-center justify-center text-center">
<div className="relative overflow-hidden group">
<motion.div
className="text-4xl lg:text-6xl font-black text-canino-blue font-vazir relative z-10"
className="text-4xl lg:text-6xl font-black text-canina-blue font-vazir relative z-10"
>
۱۰۰٪
</motion.div>

View File

@ -1,5 +1,5 @@
"use client";
import { useMemo, useState, useEffect } from "react";
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";
@ -16,21 +16,27 @@ export default function IngredientWiki() {
useEffect(() => {
productService.getProducts().then(data => setProducts(data));
fetch('http://localhost:4000/api/wiki')
.then(res => res.json())
.then(data => {
const mapped = data.map((item: any) => ({
id: item.key,
name: item.term,
description: item.definition,
benefits: item.keywords ? JSON.parse(item.keywords) : []
}));
setIngredientsWiki(mapped);
})
.catch(err => console.error("Failed to fetch wiki:", err));
}, []);
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">
@ -39,33 +45,33 @@ export default function IngredientWiki() {
<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-canino-blue transition-colors"
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-canino-blue" onClick={() => router.push('/')}>کانینو</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">دانشنامه علمی</span>
<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-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">دانشنامه مواد نایاب و ارگانیک</span>
<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-canino-blue/5 border border-canino-blue/10 rounded-full text-canino-blue text-xs font-black uppercase tracking-widest mb-6">
<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-canino-blue italic">نایاب و ارگانیک</span> کانینو
دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کانینا
</h2>
<p className="mt-6 text-lg text-medical-gray-500 max-w-2xl leading-relaxed">
ما از مواد اولیهای استفاده میکنیم که در سطح دارویی فرآوری شدهاند. در اینجا با قدرت بیولوژیک این ترکیبات آشنا شوید.
@ -103,7 +109,7 @@ export default function IngredientWiki() {
<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-canino-blue flex-shrink-0" />
<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>
))}
@ -131,7 +137,7 @@ export default function IngredientWiki() {
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-canino-blue transition-colors px-2">{p.name}</h4>
<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">
@ -141,7 +147,7 @@ export default function IngredientWiki() {
</div>
{/* Decorative backdrop */}
<div className="absolute -bottom-20 -left-20 w-80 h-80 bg-canino-blue rounded-full blur-[100px] opacity-10" />
<div className="absolute -bottom-20 -left-20 w-80 h-80 bg-canina-blue rounded-full blur-[100px] opacity-10" />
</motion.div>
</div>
</div>
@ -159,11 +165,11 @@ export default function IngredientWiki() {
</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-canino-blue">گرید دارویی اختصاصی</span> هستند.</h3>
<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-canino-blue">۱۰۰٪</div>
<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">

View File

@ -137,7 +137,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
dir="rtl"
>
{/* Top color indicator */}
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canino-blue to-indigo-500" />
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue to-indigo-500" />
{/* Close Button */}
<button
@ -149,15 +149,15 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
{/* Header info */}
<div className="text-center mb-8">
<div className="w-20 h-20 bg-canino-blue/10 rounded-[2.5rem] flex items-center justify-center mx-auto mb-6 shadow-inner">
<ShieldCheck className="w-10 h-10 text-canino-blue" />
<div className="w-20 h-20 bg-canina-blue/10 rounded-[2.5rem] flex items-center justify-center mx-auto mb-6 shadow-inner">
<ShieldCheck className="w-10 h-10 text-canina-blue" />
</div>
<h3 className="text-3xl font-black text-medical-gray-900 mb-2 italic">
ورود به کانینو
ورود به کانینا
</h3>
{isAdvisorContext ? (
<p className="text-medical-gray-500 font-bold leading-relaxed px-2 text-sm">
تحلیل سلامت <span className="text-canino-blue">{petName || "همدم شما"}</span> آماده است! برای مشاهده رژیم مکمل پیشنهادی و ذخیره شناسنامه، وارد شوید.
تحلیل سلامت <span className="text-canina-blue">{petName || "همدم شما"}</span> آماده است! برای مشاهده رژیم مکمل پیشنهادی و ذخیره شناسنامه، وارد شوید.
</p>
) : (
<p className="text-medical-gray-500 font-bold text-sm">برای دسترسی به پنل مدیریت سلامت، وارد شوید</p>
@ -187,7 +187,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canino-blue/20 focus:border-canino-blue outline-none font-bold text-lg text-left tracking-widest"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 focus:border-canina-blue outline-none font-bold text-lg text-left tracking-widest"
/>
</div>
</div>
@ -195,7 +195,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
<button
type="submit"
disabled={isLoading || phoneNumber.length < 11}
className="w-full py-5 bg-canino-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 cursor-pointer"
className="w-full py-5 bg-canina-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 cursor-pointer"
>
{isLoading ? (
<RefreshCw className="w-6 h-6 animate-spin" />
@ -222,7 +222,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
<button
type="button"
onClick={() => setStep("phone")}
className="text-[10px] font-black text-canino-blue flex items-center gap-1 hover:underline"
className="text-[10px] font-black text-canina-blue flex items-center gap-1 hover:underline"
>
<ArrowRight className="w-3 h-3" />
ویرایش شماره
@ -238,7 +238,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
value={otpCode}
onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canino-blue/20 focus:border-canino-blue outline-none font-black text-2xl text-center tracking-[0.5em]"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 focus:border-canina-blue outline-none font-black text-2xl text-center tracking-[0.5em]"
/>
</div>
<p className="text-[10px] text-medical-gray-400 font-bold text-center mt-2">
@ -256,7 +256,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
type="button"
onClick={handleResendOtp}
disabled={isLoading}
className="text-xs font-black text-canino-blue hover:underline flex items-center gap-1.5"
className="text-xs font-black text-canina-blue hover:underline flex items-center gap-1.5"
>
<RefreshCw className="w-3.5 h-3.5" />
ارسال مجدد کد تایید
@ -267,7 +267,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
<button
type="submit"
disabled={isLoading || otpCode.length < 5}
className="w-full py-5 bg-canino-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 cursor-pointer"
className="w-full py-5 bg-canina-blue text-white rounded-2xl font-black text-xl hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 cursor-pointer"
>
{isLoading ? (
<RefreshCw className="w-6 h-6 animate-spin" />

View File

@ -62,7 +62,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</head>
<body>
<div class="header">
<div class="logo">CANINO | کانینو</div>
<div class="logo">CANINO | کانینا</div>
<div>تاریخ: ${toPersian(new Date(order.date).toLocaleDateString('fa-IR'))}</div>
</div>
<div class="info">
@ -139,7 +139,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
{/* Header */}
<div className="bg-medical-gray-50 px-10 py-8 flex items-center justify-between border-b border-medical-gray-100">
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-canino-blue rounded-2xl flex items-center justify-center text-white shadow-lg">
<div className="w-14 h-14 bg-canina-blue rounded-2xl flex items-center justify-center text-white shadow-lg">
<Package className="w-7 h-7" />
</div>
<div>
@ -168,7 +168,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</div>
<div className="bg-medical-gray-50 p-4 rounded-2xl">
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">کد رهگیری</div>
<div className="text-sm font-mono font-bold text-canino-blue">{toPersian(order.trackingNumber)}</div>
<div className="text-sm font-mono font-bold text-canina-blue">{toPersian(order.trackingNumber)}</div>
</div>
<div className="bg-medical-gray-50 p-4 rounded-2xl">
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">زمان ثبت</div>
@ -182,12 +182,12 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
{/* Items List */}
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-6 flex items-center gap-2">
<ShoppingBag className="w-4 h-4 text-canino-blue" />
<ShoppingBag className="w-4 h-4 text-canina-blue" />
سبد محصولات خریده شده
</h4>
<div className="space-y-4">
{(order.items || []).map((item: any) => (
<div key={item.product.id} className="flex items-center justify-between p-4 border border-medical-gray-100 rounded-2xl hover:border-canino-blue transition-all">
<div key={item.product.id} className="flex items-center justify-between p-4 border border-medical-gray-100 rounded-2xl hover:border-canina-blue transition-all">
<div className="flex items-center gap-4">
<div className="w-16 h-16 bg-medical-gray-50 rounded-xl p-2 flex items-center justify-center shrink-0">
<SafeImage
@ -203,7 +203,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</div>
</div>
<div className="text-left">
<div className="text-lg font-black text-canino-blue italic">{toPersian((item.product.priceValue * item.quantity).toLocaleString())} <span className="text-[10px] not-italic">تومان</span></div>
<div className="text-lg font-black text-canina-blue italic">{toPersian((item.product.priceValue * item.quantity).toLocaleString())} <span className="text-[10px] not-italic">تومان</span></div>
</div>
</div>
))}
@ -214,7 +214,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
<div className="grid md:grid-cols-2 gap-8 pt-6 border-t border-medical-gray-100">
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-4 flex items-center gap-2">
<MapPin className="w-4 h-4 text-canino-blue" />
<MapPin className="w-4 h-4 text-canina-blue" />
اطلاعات ارسال
</h4>
<p className="text-xs font-bold text-medical-gray-500 leading-relaxed">
@ -223,7 +223,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</div>
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-4 flex items-center gap-2">
<CreditCard className="w-4 h-4 text-canino-blue" />
<CreditCard className="w-4 h-4 text-canina-blue" />
جزئیات پرداخت
</h4>
<div className="space-y-2">
@ -253,7 +253,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
<Download className="w-5 h-5" />
دانلود فاکتور رسمی
</button>
<button className="flex items-center justify-center w-14 h-14 bg-medical-gray-900 text-white rounded-2xl hover:bg-canino-blue transition-all shadow-lg shadow-black/10">
<button className="flex items-center justify-center w-14 h-14 bg-medical-gray-900 text-white rounded-2xl hover:bg-canina-blue transition-all shadow-lg shadow-black/10">
<Printer className="w-6 h-6" />
</button>
</div>

View File

@ -35,33 +35,33 @@ export default function OrderSuccess({ orderId }: { orderId: string }) {
className="bg-white rounded-[4rem] border border-medical-gray-200 p-12 text-center shadow-2xl relative overflow-hidden"
>
{/* Confetti-like background elements */}
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canino-blue via-green-500 to-canino-blue" />
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue via-green-500 to-canina-blue" />
<div className="w-24 h-24 bg-green-50 text-green-600 rounded-full flex items-center justify-center mx-auto mb-10 shadow-inner">
<CheckCircle2 className="w-12 h-12" />
</div>
<h2 className="text-4xl font-black text-medical-gray-900 italic mb-4">سفارش شما با موفقیت ثبت شد!</h2>
<p className="text-medical-gray-500 font-bold mb-10">شماره سفارش: <span className="text-canino-blue font-mono">{order.id}</span></p>
<p className="text-medical-gray-500 font-bold mb-10">شماره سفارش: <span className="text-canina-blue font-mono">{order.id}</span></p>
{/* Empathetic Message */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="p-8 bg-canino-blue/5 border border-canino-blue/10 rounded-[3rem] mb-12 text-right relative"
className="p-8 bg-canina-blue/5 border border-canina-blue/10 rounded-[3rem] mb-12 text-right relative"
>
<Sparkles className="absolute top-6 left-6 w-8 h-8 text-canino-blue opacity-20" />
<Sparkles className="absolute top-6 left-6 w-8 h-8 text-canina-blue opacity-20" />
<div className="flex items-center gap-4 mb-4">
<div className="w-10 h-10 bg-white rounded-2xl flex items-center justify-center text-canino-blue shadow-sm">
<div className="w-10 h-10 bg-white rounded-2xl flex items-center justify-center text-canina-blue shadow-sm">
<Heart className="w-6 h-6 fill-current" />
</div>
<h4 className="text-lg font-black text-canino-blue italic">خیالت راحت باشه!</h4>
<h4 className="text-lg font-black text-canina-blue italic">خیالت راحت باشه!</h4>
</div>
<p className="text-sm font-bold text-canino-blue/80 leading-relaxed">
<p className="text-sm font-bold text-canina-blue/80 leading-relaxed">
{activePet ? (
<>
انتخاب درستی برای <span className="text-canino-blue font-black">{activePet.name}</span> کردی.
انتخاب درستی برای <span className="text-canina-blue font-black">{activePet.name}</span> کردی.
{hasCanhydrox ? (
` مکمل Canhydrox با فرمول آلمانی‌اش دقیقاً همون چیزیه که استخوان‌های ${activePet.name} برای بازیگوشی دوباره بهش نیاز دارن.`
) : (
@ -94,13 +94,13 @@ export default function OrderSuccess({ orderId }: { orderId: string }) {
<div className="space-y-4">
<button
onClick={() => router.push('/track')}
className="w-full bg-medical-gray-900 text-white py-5 rounded-2xl font-black text-lg hover:bg-canino-blue transition-all"
className="w-full bg-medical-gray-900 text-white py-5 rounded-2xl font-black text-lg hover:bg-canina-blue transition-all"
>
مشاهده و پیگیری زنده سفارش
</button>
<button
onClick={() => router.push('/shop')}
className="flex items-center justify-center gap-2 w-full text-medical-gray-400 font-bold hover:text-canino-blue transition-colors"
className="flex items-center justify-center gap-2 w-full text-medical-gray-400 font-bold hover:text-canina-blue transition-colors"
>
<ChevronLeft className="w-4 h-4" />
بازگشت به فروشگاه

View File

@ -44,24 +44,24 @@ export default function OrderTracking() {
<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-canino-blue transition-colors"
className="flex items-center gap-2 text-medical-gray-500 font-bold hover:text-canina-blue transition-colors"
>
<ChevronRight className="w-5 h-5 font-vazir" />
<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-canino-blue" onClick={() => router.push('/')}>کانینو</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">پیگیری سفارش</span>
<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-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canino-blue">رهگیری هوشمند محموله</span>
<span className="text-canina-blue">رهگیری هوشمند محموله</span>
</div>
<div className="flex items-center justify-between mb-12">
@ -78,12 +78,12 @@ export default function OrderTracking() {
placeholder="شماره سفارش (CN-XXXXX) یا کد رهگیری پستی را وارد کنید..."
value={searchId}
onChange={(e) => setSearchId(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-6 text-sm focus:ring-2 focus:ring-canino-blue/20 outline-none font-mono"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-6 text-sm focus:ring-2 focus:ring-canina-blue/20 outline-none font-mono"
/>
</div>
<button
onClick={handleSearch}
className="bg-medical-gray-900 text-white px-10 py-4 rounded-2xl font-black italic hover:bg-canino-blue transition-all"
className="bg-medical-gray-900 text-white px-10 py-4 rounded-2xl font-black italic hover:bg-canina-blue transition-all"
>
رهگیری آنی
</button>
@ -97,7 +97,7 @@ export default function OrderTracking() {
<div className="flex items-center justify-between mb-12">
<div>
<p className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">کد رهگیری پستی</p>
<p className="text-sm font-mono font-bold text-canino-blue">{activeOrder.trackingNumber}</p>
<p className="text-sm font-mono font-bold text-canina-blue">{activeOrder.trackingNumber}</p>
</div>
<div className="text-left">
<p className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">تاریخ ثبت</p>
@ -110,7 +110,7 @@ export default function OrderTracking() {
{steps.map((step, i) => (
<div key={i} className={`relative flex items-center gap-8 ${step.status === 'pending' ? 'opacity-30' : ''}`}>
<div className={`w-12 h-12 rounded-2xl flex items-center justify-center z-10 shadow-sm transition-all ${step.status === 'completed' ? 'bg-green-600 text-white' : step.status === 'active' ? 'bg-canino-blue text-white ring-8 ring-canino-blue/10 scale-110' : 'bg-medical-gray-50 text-medical-gray-300 border border-medical-gray-100'}`}>
<div className={`w-12 h-12 rounded-2xl flex items-center justify-center z-10 shadow-sm transition-all ${step.status === 'completed' ? 'bg-green-600 text-white' : step.status === 'active' ? 'bg-canina-blue text-white ring-8 ring-canina-blue/10 scale-110' : 'bg-medical-gray-50 text-medical-gray-300 border border-medical-gray-100'}`}>
{step.status === 'completed' ? <CheckCircle2 className="w-6 h-6" /> : step.icon}
</div>
<div>
@ -136,13 +136,13 @@ export default function OrderTracking() {
</div>
<div className="mt-8 pt-6 border-t border-white/10 flex justify-between items-center font-black">
<span className="text-xs italic">مجموع فاکتور</span>
<span className="text-lg text-canino-blue">{activeOrder.total.toLocaleString()} تومان</span>
<span className="text-lg text-canina-blue">{activeOrder.total.toLocaleString()} تومان</span>
</div>
</div>
<div className="bg-white rounded-[2rem] p-6 border border-medical-gray-200">
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 bg-canino-blue/10 text-canino-blue rounded-xl flex items-center justify-center">
<div className="w-10 h-10 bg-canina-blue/10 text-canina-blue rounded-xl flex items-center justify-center">
<MapPin className="w-5 h-5" />
</div>
<h4 className="text-xs font-black italic">آدرس تحویل</h4>

View File

@ -285,7 +285,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
setView("add");
setStep(1);
}}
className="bg-canino-blue text-white px-8 py-4 rounded-[2rem] font-black shadow-xl shadow-canino-blue/20 hover:scale-105 transition-all flex items-center gap-3"
className="bg-canina-blue text-white px-8 py-4 rounded-[2rem] font-black shadow-xl shadow-canina-blue/20 hover:scale-105 transition-all flex items-center gap-3"
>
<Plus className="w-5 h-5" />
صدور شناسنامه جدید
@ -299,7 +299,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
whileHover={{ y: -5 }}
className="bg-white rounded-[3rem] border border-medical-gray-200 p-8 shadow-sm hover:shadow-2xl transition-all relative group"
>
<div className="w-24 h-24 bg-medical-gray-50 rounded-[2rem] flex items-center justify-center text-canino-blue mb-6 group-hover:bg-canino-blue group-hover:text-white transition-all shadow-inner">
<div className="w-24 h-24 bg-medical-gray-50 rounded-[2rem] flex items-center justify-center text-canina-blue mb-6 group-hover:bg-canina-blue group-hover:text-white transition-all shadow-inner">
{pet.type === "سگ" ? <Dog className="w-12 h-12" /> : <Cat className="w-12 h-12" />}
</div>
<h3 className="text-2xl font-black text-medical-gray-900 mb-1">{pet.name}</h3>
@ -318,7 +318,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
onClick={() => { setActivePet(pet.id); setView("detail"); }}
className="w-full py-4 bg-medical-gray-900 text-white rounded-2xl font-black hover:bg-canino-blue transition-all flex items-center justify-center gap-2 group-hover:shadow-lg"
className="w-full py-4 bg-medical-gray-900 text-white rounded-2xl font-black hover:bg-canina-blue transition-all flex items-center justify-center gap-2 group-hover:shadow-lg"
>
مشاهده شناسنامه سلامت
<ChevronLeft className="w-4 h-4" />
@ -390,7 +390,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Progress Bar */}
<div className="absolute top-0 left-0 w-full h-1.5 bg-medical-gray-100 font-vazir">
<motion.div
className="h-full bg-canino-blue"
className="h-full bg-canina-blue"
initial={{ width: "0%" }}
animate={{ width: `${(step / 3) * 100}%` }}
/>
@ -401,7 +401,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<h2 className="text-3xl font-black text-medical-gray-900">{view === "edit" ? "ویرایش شناسنامه" : "صدور شناسنامه سلامت"}</h2>
<p className="text-medical-gray-500 mt-2 font-medium">مرحله {toPersian(step)} از {toPersian(3)}: بروزرسانی اطلاعات تخصصی</p>
</div>
<div className="w-16 h-16 bg-canino-blue/10 rounded-2xl flex items-center justify-center text-canino-blue">
<div className="w-16 h-16 bg-canina-blue/10 rounded-2xl flex items-center justify-center text-canina-blue">
<ClipboardList className="w-8 h-8" />
</div>
</div>
@ -422,7 +422,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
type="text"
value={formData.name}
onChange={e => setFormData({ ...formData, name: e.target.value })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-lg"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-lg"
placeholder="مثلاً: لوسی"
/>
</div>
@ -431,14 +431,14 @@ export default function PetProfile({ initialView, advisorNeed }: {
<div className="grid grid-cols-2 gap-4">
<button
onClick={() => setFormData({ ...formData, type: "سگ" })}
className={`flex items-center justify-center gap-3 py-4 border-2 rounded-2xl transition-all ${formData.type === "سگ" ? 'border-canino-blue bg-canino-blue/5 text-canino-blue font-black' : 'border-medical-gray-200 text-medical-gray-400 font-bold'}`}
className={`flex items-center justify-center gap-3 py-4 border-2 rounded-2xl transition-all ${formData.type === "سگ" ? 'border-canina-blue bg-canina-blue/5 text-canina-blue font-black' : 'border-medical-gray-200 text-medical-gray-400 font-bold'}`}
>
<Dog className="w-6 h-6" />
سگ
</button>
<button
onClick={() => setFormData({ ...formData, type: "گربه" })}
className={`flex items-center justify-center gap-3 py-4 border-2 rounded-2xl transition-all ${formData.type === "گربه" ? 'border-canino-blue bg-canino-blue/5 text-canino-blue font-black' : 'border-medical-gray-200 text-medical-gray-400 font-bold'}`}
className={`flex items-center justify-center gap-3 py-4 border-2 rounded-2xl transition-all ${formData.type === "گربه" ? 'border-canina-blue bg-canina-blue/5 text-canina-blue font-black' : 'border-medical-gray-200 text-medical-gray-400 font-bold'}`}
>
<Cat className="w-6 h-6" />
گربه
@ -451,7 +451,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
type="text"
value={formData.breed}
onChange={e => setFormData({ ...formData, breed: e.target.value })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-bold"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold"
placeholder="آلمانی، پرشین، میکس و..."
/>
</div>
@ -473,7 +473,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
type="number"
value={formData.age || ""}
onChange={e => setFormData({ ...formData, age: parseInt(e.target.value) })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-lg"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-lg"
placeholder="۳"
/>
</div>
@ -484,7 +484,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
type="number"
value={formData.weight || ""}
onChange={e => setFormData({ ...formData, weight: parseFloat(e.target.value) })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-6 pl-12 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-lg"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-6 pl-12 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-lg"
/>
<Weight className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-medical-gray-400" />
</div>
@ -497,7 +497,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
key={level}
onClick={() => setFormData({ ...formData, activityLevel: level as any })}
className={`py-4 border-2 rounded-2xl transition-all text-sm font-black italic ${formData.activityLevel === level ? 'border-canino-blue bg-canino-blue/5 text-canino-blue shadow-lg shadow-canino-blue/10' : 'border-medical-gray-100 text-medical-gray-400'}`}
className={`py-4 border-2 rounded-2xl transition-all text-sm font-black italic ${formData.activityLevel === level ? 'border-canina-blue bg-canina-blue/5 text-canina-blue shadow-lg shadow-canina-blue/10' : 'border-medical-gray-100 text-medical-gray-400'}`}
>
{level}
</button>
@ -536,9 +536,9 @@ export default function PetProfile({ initialView, advisorNeed }: {
: [...current, condition]
})
}}
className={`flex items-center gap-4 p-4 border-2 rounded-2xl transition-all ${formData.medicalConditions.includes(condition) ? 'border-canino-blue bg-canino-blue/5 text-canino-blue' : 'border-medical-gray-50 text-medical-gray-500'}`}
className={`flex items-center gap-4 p-4 border-2 rounded-2xl transition-all ${formData.medicalConditions.includes(condition) ? 'border-canina-blue bg-canina-blue/5 text-canina-blue' : 'border-medical-gray-50 text-medical-gray-500'}`}
>
<div className={`w-6 h-6 rounded-lg flex items-center justify-center border ${formData.medicalConditions.includes(condition) ? 'bg-canino-blue border-canino-blue text-white' : 'border-medical-gray-200'}`}>
<div className={`w-6 h-6 rounded-lg flex items-center justify-center border ${formData.medicalConditions.includes(condition) ? 'bg-canina-blue border-canina-blue text-white' : 'border-medical-gray-200'}`}>
{formData.medicalConditions.includes(condition) && <ShieldCheck className="w-3.5 h-3.5" />}
</div>
<span className="font-black text-sm italic">{condition}</span>
@ -556,7 +556,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
else if (pets.length > 0) setView("index");
else router.back();
}}
className="absolute top-8 left-8 text-medical-gray-400 hover:text-canino-blue transition-colors text-[10px] font-black uppercase tracking-widest"
className="absolute top-8 left-8 text-medical-gray-400 hover:text-canina-blue transition-colors text-[10px] font-black uppercase tracking-widest"
>
انصراف
</button>
@ -572,7 +572,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
onClick={step === 3 ? handleSubmit : handleNext}
disabled={step === 1 && (!formData.name || !formData.type)}
className="flex-[2] bg-medical-gray-900 text-white py-4 rounded-2xl font-black flex items-center justify-center gap-2 disabled:opacity-50 hover:bg-canino-blue transition-all"
className="flex-[2] bg-medical-gray-900 text-white py-4 rounded-2xl font-black flex items-center justify-center gap-2 disabled:opacity-50 hover:bg-canina-blue transition-all"
>
{step === 3 ? (view === "edit" ? "ذخیره تغییرات" : "مشاهده پرونده سلامت") : "گام بعدی"}
<ChevronLeft className="w-5 h-5" />
@ -594,21 +594,21 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Navigation Bar */}
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">
<span className="cursor-pointer hover:text-canino-blue" onClick={() => setView("index")}>همدمهای من</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => setView("index")}>همدمهای من</span>
<ChevronLeft className="w-3 h-3" />
<span className="text-canino-blue">پرونده سلامت {activePet?.name}</span>
<span className="text-canina-blue">پرونده سلامت {activePet?.name}</span>
</div>
<div className="flex gap-3">
<button
onClick={() => setView("index")}
className="px-6 py-2.5 bg-white border border-medical-gray-200 rounded-xl text-[10px] font-black uppercase tracking-widest hover:border-canino-blue transition-all"
className="px-6 py-2.5 bg-white border border-medical-gray-200 rounded-xl text-[10px] font-black uppercase tracking-widest hover:border-canina-blue transition-all"
>
بازگشت به لیست
</button>
<button
onClick={startEdit}
className="px-6 py-2.5 bg-canino-blue text-white rounded-xl text-[10px] font-black uppercase tracking-widest shadow-lg shadow-canino-blue/20 hover:scale-105 transition-all flex items-center gap-2"
className="px-6 py-2.5 bg-canina-blue text-white rounded-xl text-[10px] font-black uppercase tracking-widest shadow-lg shadow-canina-blue/20 hover:scale-105 transition-all flex items-center gap-2"
>
<Edit3 className="w-3.5 h-3.5" />
ویرایش پرونده
@ -619,10 +619,10 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Profile Card */}
<section className="grid lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 bg-white rounded-[3.5rem] p-10 border border-medical-gray-200 shadow-xl flex flex-col md:flex-row gap-10 items-center relative overflow-hidden">
<div className="absolute top-0 left-0 w-32 h-32 bg-canino-blue/5 rounded-full blur-[60px] -translate-x-1/2 -translate-y-1/2" />
<div className="absolute top-0 left-0 w-32 h-32 bg-canina-blue/5 rounded-full blur-[60px] -translate-x-1/2 -translate-y-1/2" />
<div className="w-44 h-44 rounded-[2.5rem] bg-gradient-to-tr from-canino-blue to-blue-400 p-1 flex-shrink-0 shadow-2xl">
<div className="w-full h-full bg-white rounded-[2.2rem] flex items-center justify-center text-canino-blue">
<div className="w-44 h-44 rounded-[2.5rem] bg-gradient-to-tr from-canina-blue to-blue-400 p-1 flex-shrink-0 shadow-2xl">
<div className="w-full h-full bg-white rounded-[2.2rem] flex items-center justify-center text-canina-blue">
{activePet.type === "سگ" ? <Dog className="w-24 h-24" /> : <Cat className="w-24 h-24" />}
</div>
</div>
@ -652,7 +652,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<div className="flex flex-wrap gap-2">
{activePet.medicalConditions.map(c => (
<div key={c} className="bg-canino-blue text-white px-4 py-2 rounded-xl text-[10px] font-bold border border-white/10 flex items-center gap-2 shadow-sm">
<div key={c} className="bg-canina-blue text-white px-4 py-2 rounded-xl text-[10px] font-bold border border-white/10 flex items-center gap-2 shadow-sm">
<Stethoscope className="w-3 h-3" />
{c}
</div>
@ -661,7 +661,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
</div>
</div>
<div className="bg-canino-blue rounded-[3.5rem] p-10 text-white flex flex-col justify-between relative overflow-hidden shadow-2xl group">
<div className="bg-canina-blue rounded-[3.5rem] p-10 text-white flex flex-col justify-between relative overflow-hidden shadow-2xl group">
<div className="absolute top-0 right-0 p-8 opacity-20 group-hover:rotate-12 transition-transform duration-700">
<Activity className="w-16 h-16 text-white" />
</div>
@ -712,10 +712,10 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Refill & Stock Tracking */}
<section className="bg-white rounded-[3.5rem] p-10 border border-medical-gray-200 shadow-sm relative overflow-hidden">
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-canino-blue to-blue-300" />
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-canina-blue to-blue-300" />
<div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-3">
<Package className="w-8 h-8 text-canino-blue" />
<Package className="w-8 h-8 text-canina-blue" />
<h3 className="text-2xl font-black text-medical-gray-900 italic">پایش موجودی مکملها</h3>
</div>
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest hidden md:block">بروزرسانی لحظهای بر اساس مصرف</div>
@ -744,7 +744,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
</div>
<div className={cn(
"w-12 h-12 rounded-2xl flex items-center justify-center font-black text-xs",
isLow ? "bg-red-50 text-red-500 animate-pulse" : "bg-white text-canino-blue shadow-inner"
isLow ? "bg-red-50 text-red-500 animate-pulse" : "bg-white text-canina-blue shadow-inner"
)}>
{toPersian(Math.round(percentage))}%
</div>
@ -754,7 +754,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<motion.div
initial={{ width: 0 }}
animate={{ width: `${Math.min(100, Math.max(0, percentage))}%` }}
className={cn("h-full", isLow ? "bg-red-500" : "bg-canino-blue")}
className={cn("h-full", isLow ? "bg-red-500" : "bg-canina-blue")}
/>
</div>
@ -783,11 +783,11 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
key={tab.id}
onClick={() => setActivePetTab(tab.id as any)}
className={`pb-4 flex items-center gap-2 text-sm font-black transition-all relative ${activePetTab === tab.id ? "text-canino-blue" : "text-medical-gray-400 hover:text-medical-gray-600"}`}
className={`pb-4 flex items-center gap-2 text-sm font-black transition-all relative ${activePetTab === tab.id ? "text-canina-blue" : "text-medical-gray-400 hover:text-medical-gray-600"}`}
>
{tab.icon}
{tab.label}
{activePetTab === tab.id && <motion.div layoutId="petTab" className="absolute bottom-0 left-0 right-0 h-1 bg-canino-blue rounded-full" />}
{activePetTab === tab.id && <motion.div layoutId="petTab" className="absolute bottom-0 left-0 right-0 h-1 bg-canina-blue rounded-full" />}
</button>
))}
</div>
@ -798,7 +798,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<section>
<div className="flex items-center justify-between mb-8 px-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center text-canino-blue shadow-lg border border-medical-gray-100">
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center text-canina-blue shadow-lg border border-medical-gray-100">
<Star className="w-6 h-6" />
</div>
<h3 className="text-3xl font-black text-medical-gray-900 italic">توصیههای درمانی اختصاصی</h3>
@ -817,17 +817,17 @@ export default function PetProfile({ initialView, advisorNeed }: {
className="bg-white rounded-[2.5rem] p-6 border border-medical-gray-200 hover:shadow-2xl transition-all cursor-pointer group flex flex-col justify-between relative overflow-hidden"
>
{reason && (
<div className="absolute top-0 left-0 right-0 bg-canino-blue/10 py-2 px-4 text-[9px] font-black text-canino-blue text-center border-b border-canino-blue/10">
<div className="absolute top-0 left-0 right-0 bg-canina-blue/10 py-2 px-4 text-[9px] font-black text-canina-blue text-center border-b border-canina-blue/10">
{reason}
</div>
)}
<div className={cn("aspect-square bg-medical-gray-50 rounded-[1.5rem] p-6 mb-6 flex items-center justify-center overflow-hidden", reason ? "mt-8" : "")}>
<SafeImage src={p.image} alt={p.name} className="w-full h-full object-contain group-hover:scale-110 transition-transform duration-500" />
<SafeImage src={p.image} alt={p.name} className="w-full h-full group-hover:scale-110 transition-transform duration-500" imgClassName="object-contain" />
</div>
<div>
<h4 className="text-lg font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors mb-2 italic">{p.name}</h4>
<h4 className="text-lg font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors mb-2 italic">{p.name}</h4>
<p className="text-xs text-medical-gray-400 line-clamp-2 leading-relaxed mb-6 font-medium">{p.benefits}</p>
<button className="w-full py-3.5 bg-medical-gray-900 text-white rounded-xl text-[10px] font-black uppercase tracking-widest group-hover:bg-canino-blue transition-colors flex items-center justify-center gap-2">
<button className="w-full py-3.5 bg-medical-gray-900 text-white rounded-xl text-[10px] font-black uppercase tracking-widest group-hover:bg-canina-blue transition-colors flex items-center justify-center gap-2">
بررسی تخصصی
<ChevronLeft className="w-3.5 h-3.5" />
</button>
@ -842,7 +842,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<div className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 shadow-sm">
<div className="flex items-center justify-between mb-10">
<div className="flex items-center gap-3">
<Clock className="w-8 h-8 text-canino-blue" />
<Clock className="w-8 h-8 text-canina-blue" />
<h3 className="text-2xl font-black text-medical-gray-900 italic">یادآورهای فعال</h3>
</div>
<TrendingUp className="w-6 h-6 text-green-500" />
@ -863,7 +863,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
key={reminder.id}
className={cn(
"flex items-center justify-between p-5 rounded-2xl border transition-all group",
isCompleted ? "bg-green-50 border-green-200" : "bg-medical-gray-50 border-medical-gray-100 hover:border-canino-blue/30"
isCompleted ? "bg-green-50 border-green-200" : "bg-medical-gray-50 border-medical-gray-100 hover:border-canina-blue/30"
)}
>
<div className="flex items-center gap-4">
@ -871,7 +871,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
onClick={() => handleToggleReminder(reminder)}
className={cn(
"w-10 h-10 rounded-xl flex items-center justify-center shadow-inner transition-colors",
isCompleted ? "bg-green-500 text-white" : "bg-white text-medical-gray-300 hover:text-canino-blue"
isCompleted ? "bg-green-500 text-white" : "bg-white text-medical-gray-300 hover:text-canina-blue"
)}
>
{isCompleted ? <Check className="w-5 h-5" /> : <Clock className="w-5 h-5" />}
@ -892,7 +892,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
onClick={() => setIsAddingReminder(true)}
className="w-full mt-8 py-5 border-2 border-dashed border-medical-gray-200 rounded-2xl text-medical-gray-400 font-black hover:border-canino-blue hover:text-canino-blue transition-all flex items-center justify-center gap-2"
className="w-full mt-8 py-5 border-2 border-dashed border-medical-gray-200 rounded-2xl text-medical-gray-400 font-black hover:border-canina-blue hover:text-canina-blue transition-all flex items-center justify-center gap-2"
>
<Plus className="w-4 h-4" />
افزودن یادآور جدید
@ -902,7 +902,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Health Logs */}
<div className="bg-white rounded-[3rem] border border-medical-gray-200 p-10 shadow-sm">
<div className="flex items-center gap-3 mb-10">
<ClipboardList className="w-8 h-8 text-canino-blue" />
<ClipboardList className="w-8 h-8 text-canina-blue" />
<h3 className="text-2xl font-black text-medical-gray-900 italic">تایملاین سلامت</h3>
</div>
@ -919,7 +919,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
{toPersian(new Date(log.date).toLocaleDateString("fa-IR"))}
</div>
<div className="flex gap-2">
<div className="px-2 py-0.5 bg-canino-blue/10 text-canino-blue rounded-full text-[8px] font-black">{log.appetite}</div>
<div className="px-2 py-0.5 bg-canina-blue/10 text-canina-blue rounded-full text-[8px] font-black">{log.appetite}</div>
<div className="px-2 py-0.5 bg-green-500/10 text-green-500 rounded-full text-[8px] font-black">{log.energy}</div>
</div>
</div>
@ -933,7 +933,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
onClick={() => setIsAddingHealthLog(true)}
className="w-full mt-8 py-5 bg-canino-blue text-white rounded-2xl font-black hover:bg-medical-gray-900 transition-all shadow-xl shadow-canino-blue/20"
className="w-full mt-8 py-5 bg-canina-blue text-white rounded-2xl font-black hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20"
>
ثبت گزارش روزانه جدید
</button>
@ -958,7 +958,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
</div>
<div className="text-left">
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest">مجموع هزینه درمانی</div>
<div className="text-2xl font-black text-canino-blue">{toPersian(petOrders.reduce((a, b) => a + b.total, 0).toLocaleString())} <span className="text-xs italic">تومان</span></div>
<div className="text-2xl font-black text-canina-blue">{toPersian(petOrders.reduce((a, b) => a + b.total, 0).toLocaleString())} <span className="text-xs italic">تومان</span></div>
</div>
</div>
@ -968,7 +968,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<Package className="w-12 h-12" />
</div>
<p className="text-medical-gray-400 font-black text-xl italic">هنوز سفارشی برای {activePet.name} ثبت نکردهاید.</p>
<button onClick={() => router.push('/shop')} className="bg-canino-blue text-white px-10 py-4 rounded-2xl font-black hover:scale-105 transition-all">شروع اولین خرید</button>
<button onClick={() => router.push('/shop')} className="bg-canina-blue text-white px-10 py-4 rounded-2xl font-black hover:scale-105 transition-all">شروع اولین خرید</button>
</div>
) : (
<div className="space-y-5">
@ -984,10 +984,10 @@ export default function PetProfile({ initialView, advisorNeed }: {
>
{/* Info on Left (Text side) */}
<div className="flex-1 text-right">
<h4 className="text-xl font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors mb-2 italic">{item.product.name}</h4>
<h4 className="text-xl font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors mb-2 italic">{item.product.name}</h4>
<div className="flex flex-wrap gap-x-6 gap-y-2 items-center">
<div className="flex items-center gap-1.5 text-xs font-bold text-medical-gray-500">
<Calendar className="w-4 h-4 text-canino-blue/40" />
<Calendar className="w-4 h-4 text-canina-blue/40" />
{toPersian(new Date(order.date).toLocaleDateString("fa-IR", { year: 'numeric', month: 'long', day: 'numeric' }))}
</div>
<div className="flex items-center gap-1.5 px-3 py-1 bg-green-50 text-green-600 rounded-full text-[10px] font-black italic">
@ -1020,11 +1020,11 @@ export default function PetProfile({ initialView, advisorNeed }: {
{/* Seal of Authenticity */}
<div className="p-16 border-4 border-double border-medical-gray-200 rounded-[5rem] text-center max-w-4xl mx-auto opacity-40 grayscale hover:opacity-100 hover:grayscale-0 transition-all duration-1000">
<div className="flex justify-center mb-8">
<div className="w-20 h-20 border-4 border-canino-blue rounded-full flex items-center justify-center text-canino-blue font-black text-2xl rotate-12 shadow-2xl">آلمان</div>
<div className="w-20 h-20 border-4 border-canina-blue rounded-full flex items-center justify-center text-canina-blue font-black text-2xl rotate-12 shadow-2xl">آلمان</div>
</div>
<h4 className="text-2xl font-black text-medical-gray-900 mb-4 italic">ضمانت اصالت و سلامت کانینو آلمان</h4>
<h4 className="text-2xl font-black text-medical-gray-900 mb-4 italic">ضمانت اصالت و سلامت کانینا آلمان</h4>
<p className="text-sm text-medical-gray-500 font-medium leading-relaxed max-w-2xl mx-auto italic">
این گزارش توسط سیستم هوش مصنوعی کانینو و با انطباق کامل بر پروتکلهای درمانی Canina Pharma GmbH آلمان تولید شده است. تمامی مکملهای پیشنهادی دارای استاندارد دارویی (Pharmaceutical Grade) میباشند.
این گزارش توسط سیستم هوش مصنوعی کانینا و با انطباق کامل بر پروتکلهای درمانی Canina Pharma GmbH آلمان تولید شده است. تمامی مکملهای پیشنهادی دارای استاندارد دارویی (Pharmaceutical Grade) میباشند.
</p>
</div>
@ -1059,7 +1059,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
value={reminderForm.title}
onChange={e => setReminderForm({ ...reminderForm, title: e.target.value })}
placeholder="مثلاً: قرص مفاصل، کانهیدروکس"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-bold"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold"
/>
</div>
<div className="grid grid-cols-2 gap-4">
@ -1069,7 +1069,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
type="time"
value={reminderForm.time}
onChange={e => setReminderForm({ ...reminderForm, time: e.target.value })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black"
/>
</div>
<div>
@ -1077,7 +1077,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<select
value={reminderForm.frequency}
onChange={e => setReminderForm({ ...reminderForm, frequency: e.target.value as any })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-sm"
>
<option value="روزانه">روزانه</option>
<option value="هفتگی">هفتگی</option>
@ -1089,7 +1089,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<select
value={reminderForm.productId}
onChange={e => setReminderForm({ ...reminderForm, productId: e.target.value })}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-black text-sm"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-sm"
>
<option value="">هیچکدام</option>
{recommendedProducts.map(p => (
@ -1100,7 +1100,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
<button
onClick={handleReminderSubmit}
className="w-full py-5 bg-canino-blue text-white rounded-2xl font-black hover:bg-medical-gray-900 transition-all shadow-xl shadow-canino-blue/20 mt-4"
className="w-full py-5 bg-canina-blue text-white rounded-2xl font-black hover:bg-medical-gray-900 transition-all shadow-xl shadow-canina-blue/20 mt-4"
>
ثبت نهایی یادآور
</button>
@ -1142,7 +1142,7 @@ export default function PetProfile({ initialView, advisorNeed }: {
onClick={() => setLogForm({ ...logForm, appetite: opt as any })}
className={cn(
"py-3 border-2 rounded-xl text-xs font-black transition-all",
logForm.appetite === opt ? "border-canino-blue bg-canino-blue/10 text-canino-blue" : "border-medical-gray-100 text-medical-gray-400"
logForm.appetite === opt ? "border-canina-blue bg-canina-blue/10 text-canina-blue" : "border-medical-gray-100 text-medical-gray-400"
)}
>
{opt}
@ -1176,13 +1176,13 @@ export default function PetProfile({ initialView, advisorNeed }: {
value={logForm.note}
onChange={e => setLogForm({ ...logForm, note: e.target.value })}
placeholder="مشاهدات خود را برای بررسی دکتر سیستم اینجا بنویسید..."
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/20 outline-none font-bold text-sm resize-none"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-sm resize-none"
/>
</div>
<button
onClick={handleHealthLogSubmit}
className="w-full py-5 bg-medical-gray-900 text-white rounded-2xl font-black hover:bg-canino-blue transition-all shadow-xl mt-2"
className="w-full py-5 bg-medical-gray-900 text-white rounded-2xl font-black hover:bg-canina-blue transition-all shadow-xl mt-2"
>
ثبت نهایی گزارش
</button>

View File

@ -169,8 +169,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<ChevronRight className="w-5 h-5" />
بازگشت
</button>
<div className="text-[10px] font-black text-canino-blue bg-canino-blue/5 px-4 py-2 rounded-xl font-vazir whitespace-nowrap">
کانینو ایران
<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>
@ -178,19 +178,19 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<nav className="hidden md:flex items-center gap-2 text-xs font-bold text-medical-gray-400 mb-8 overflow-x-auto whitespace-nowrap py-2">
<button
onClick={() => router.push('/')}
className="hover:text-canino-blue transition-colors font-vazir cursor-pointer"
className="hover:text-canina-blue transition-colors font-vazir cursor-pointer"
>
خانه
</button>
<ChevronLeft className="w-3 h-3 flex-shrink-0" />
<button
onClick={() => router.push(`/shop?category=${product.category}`)}
className="hover:text-canino-blue cursor-pointer font-vazir"
onClick={() => router.push(`/shop?category=${product.categorySlug}`)}
className="hover:text-canina-blue cursor-pointer font-vazir"
>
{product.category}
</button>
<ChevronLeft className="w-3 h-3 flex-shrink-0" />
<span className="text-canino-blue font-vazir whitespace-nowrap">{product.name}</span>
<span className="text-canina-blue font-vazir whitespace-nowrap">{product.name}</span>
</nav>
<div className="grid lg:grid-cols-12 gap-12 items-start">
@ -198,7 +198,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<div className="lg:col-span-8 space-y-12">
<div>
<div className="flex flex-wrap items-center gap-3 mb-4">
<div className="px-3 py-1 bg-canino-blue text-white rounded-full text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap">
<div className="px-3 py-1 bg-canina-blue text-white rounded-full text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap">
استاندارد صنعتی آلمان
</div>
{product.specialBadge && (
@ -210,7 +210,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<h1 className="text-4xl lg:text-6xl font-black text-medical-gray-900 leading-tight mb-4 italic font-vazir">
{product.name}
</h1>
<p className="text-xl text-canino-blue font-bold italic opacity-70 leading-relaxed max-w-2xl font-vazir mb-6">
<p className="text-xl text-canina-blue font-bold italic opacity-70 leading-relaxed max-w-2xl font-vazir mb-6">
{pets.length > 0 ? (
product.optimisticTemplate?.replace("[PetName]", activePet?.name || "").replace("[OnSet]", product.onSetOfAction || "به زودی")
) : (
@ -218,17 +218,17 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
)}
</p>
{fullProduct.shortDescription && (
<p className="text-lg text-medical-gray-600 font-medium leading-relaxed max-w-3xl font-vazir border-r-4 border-canino-blue pr-6 py-2 bg-canino-blue/5 rounded-l-2xl">
<p className="text-lg text-medical-gray-600 font-medium leading-relaxed max-w-3xl font-vazir border-r-4 border-canina-blue pr-6 py-2 bg-canina-blue/5 rounded-l-2xl">
{fullProduct.shortDescription}
</p>
)}
</div>
{/* Key Benefits Section */}
{fullProduct.keyBenefits && (
{fullProduct.keyBenefits?.length > 0 && (
<section className="space-y-8">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-canino-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">
<Star className="w-6 h-6" />
</div>
<h3 className="text-3xl font-black text-medical-gray-900 italic font-vazir">چرا {fullProduct.name}؟</h3>
@ -238,8 +238,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
const Icon = ICON_MAP[benefit.icon] || CheckCircle2;
return (
<div key={i} className="bg-white border border-medical-gray-100 rounded-[2rem] p-8 shadow-sm hover:shadow-xl hover:-translate-y-1 transition-all group overflow-hidden relative">
<div className="absolute -top-10 -left-10 w-24 h-24 bg-canino-blue/5 rounded-full group-hover:scale-150 transition-transform duration-700" />
<div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-canino-blue mb-6 group-hover:bg-canino-blue group-hover:text-white transition-all">
<div className="absolute -top-10 -left-10 w-24 h-24 bg-canina-blue/5 rounded-full group-hover:scale-150 transition-transform duration-700" />
<div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-canina-blue mb-6 group-hover:bg-canina-blue group-hover:text-white transition-all">
<Icon className="w-6 h-6" />
</div>
<h4 className="text-xl font-black text-medical-gray-900 mb-2 font-vazir">{benefit.title}</h4>
@ -261,7 +261,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<CheckCircle2 className="w-3 h-3" />
موجود در انبار
</div>
<div className="px-3 py-1 bg-canino-blue/5 text-canino-blue rounded-full text-[10px] font-black uppercase tracking-widest border border-canino-blue/10 font-vazir whitespace-nowrap">
<div className="px-3 py-1 bg-canina-blue/5 text-canina-blue rounded-full text-[10px] font-black uppercase tracking-widest border border-canina-blue/10 font-vazir whitespace-nowrap">
گرید دارویی اختصاصی
</div>
</div>
@ -289,7 +289,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
{product.main_ingredients.map((ing, idx) => {
const termKey = termKeys.find(key => ing.includes(key));
return (
<div key={idx} className="bg-medical-gray-50 border border-medical-gray-100 px-5 py-3 rounded-2xl flex items-center gap-3 group hover:border-canino-blue/30 transition-all">
<div key={idx} className="bg-medical-gray-50 border border-medical-gray-100 px-5 py-3 rounded-2xl flex items-center gap-3 group hover:border-canina-blue/30 transition-all">
<span className="text-sm font-bold text-medical-gray-700 font-vazir">
{termKey ? (
<Tooltip termKey={termKey} onWikiNavigate={(id) => router.push(`/wiki?term=${id}`)}>
@ -297,7 +297,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</Tooltip>
) : ing}
</span>
<Sparkles className="w-3 h-3 text-canino-blue opacity-40 group-hover:opacity-100 transition-opacity" />
<Sparkles className="w-3 h-3 text-canina-blue opacity-40 group-hover:opacity-100 transition-opacity" />
</div>
);
})}
@ -305,24 +305,26 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</div>
{/* Analysis Cards Grid */}
{Object.keys(product.analysis).length > 0 && (
<div className="space-y-6">
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-4 font-vazir">تخمین اتمام بسته (هوش مصنوعی)</div>
<div className="grid grid-cols-2 gap-4">
{Object.entries(product.analysis).map(([key, value]) => (
<div key={key} className="bg-canino-blue text-white p-8 rounded-[2rem] border-b-2 border-white/20 shadow-xl group hover:scale-[1.02] transition-all duration-300">
<div key={key} className="bg-canina-blue text-white p-8 rounded-[2rem] border-b-2 border-white/20 shadow-xl group hover:scale-[1.02] transition-all duration-300">
<div className="text-[10px] font-black text-white/80 uppercase tracking-widest mb-3 font-vazir whitespace-nowrap">{key}</div>
<div className="text-3xl font-black font-vazir tracking-tighter text-white">{toPersian(value)}</div>
</div>
))}
</div>
</div>
)}
</div>
</section>
{/* Feeding Section */}
<section className="bg-canino-blue/5 border border-canino-blue/10 rounded-[3rem] p-10">
<section className="bg-canina-blue/5 border border-canina-blue/10 rounded-[3rem] p-10">
<div className="flex items-center gap-4 mb-8">
<div className="w-10 h-10 bg-canino-blue text-white rounded-xl flex items-center justify-center">
<div className="w-10 h-10 bg-canina-blue text-white rounded-xl flex items-center justify-center">
<CalendarDays className="w-6 h-6" />
</div>
<h3 className="text-2xl font-black text-medical-gray-900 italic font-vazir">توصیه غذایی و نحوه مصرف</h3>
@ -333,8 +335,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</section>
{/* Specialist Note */}
<section className="bg-white rounded-[3rem] p-10 border border-medical-gray-200">
{product.specialist && (
<section className="bg-white rounded-[3rem] p-10 border border-medical-gray-200">
<div className="flex flex-col md:flex-row gap-10 items-start">
<img
src={product.specialist.image}
@ -347,19 +349,19 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
مورد تأیید دامپزشکان
</div>
<h4 className="text-2xl font-black text-medical-gray-900 mb-1 font-vazir">{product.specialist.name}</h4>
<p className="text-sm font-bold text-canino-blue mb-6 font-vazir">{product.specialist.title}</p>
<p className="text-sm font-bold text-canina-blue mb-6 font-vazir">{product.specialist.title}</p>
<p className="text-base text-medical-gray-600 leading-relaxed italic font-vazir">
"{product.specialist.message}"
</p>
</div>
</div>
)}
</section>
)}
{/* Specialized Landing Banner */}
<section>
<div
className="relative bg-canino-blue rounded-[3rem] p-12 overflow-hidden group cursor-pointer"
className="relative bg-canina-blue rounded-[3rem] p-12 overflow-hidden group cursor-pointer"
onClick={() => toast.info("بزودی: صفحه فرود تخصصی این محصول در حال آماده‌سازی است")}
>
<div className="absolute top-0 right-0 w-full h-full bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-10" />
@ -372,7 +374,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
گزارشهای علمی، ویدیوهای آموزشی و تجربیات واقعی دیگر صاحبان پت در لندینگپیج اختصاصی این محصول.
</p>
</div>
<div className="bg-white text-canino-blue px-8 py-4 rounded-2xl font-black shadow-2xl hover:scale-105 transition-transform flex items-center gap-3">
<div className="bg-white text-canina-blue px-8 py-4 rounded-2xl font-black shadow-2xl hover:scale-105 transition-transform flex items-center gap-3">
ورود به آزمایشگاه علمی
<ArrowRight className="w-5 h-5 rotate-180" />
</div>
@ -381,20 +383,20 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</section>
{/* FAQ Section */}
{product.faqs && (
{product.faqs?.length > 0 && (
<section className="pt-10">
<div className="flex items-center gap-4 mb-10">
<div className="w-12 h-12 bg-blue-100 text-canino-blue rounded-2xl flex items-center justify-center">
<div className="w-12 h-12 bg-blue-100 text-canina-blue rounded-2xl flex items-center justify-center">
<Info className="w-6 h-6" />
</div>
<h3 className="text-3xl font-black text-medical-gray-900 italic font-vazir">پاسخ به ابهامات شما</h3>
</div>
<div className="grid md:grid-cols-1 gap-4">
{product.faqs.map((faq, i) => (
<details key={i} className="group bg-white border border-medical-gray-200 rounded-3xl overflow-hidden hover:border-canino-blue/30 transition-all">
<details key={i} className="group bg-white border border-medical-gray-200 rounded-3xl overflow-hidden hover:border-canina-blue/30 transition-all">
<summary className="flex items-center justify-between p-6 cursor-pointer list-none">
<span className="font-bold text-medical-gray-900 font-vazir">{faq.question}</span>
<ChevronDown className="w-5 h-5 text-canino-blue group-open:rotate-180 transition-transform" />
<ChevronDown className="w-5 h-5 text-canina-blue group-open:rotate-180 transition-transform" />
</summary>
<div className="px-6 pb-6 text-sm text-medical-gray-500 font-medium leading-relaxed font-vazir border-t border-medical-gray-50 pt-4">
{faq.answer}
@ -409,14 +411,14 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
{/* Sticky Sidebar */}
<div className="lg:col-span-4 lg:sticky lg:top-24 space-y-8">
<div className="bg-white rounded-[3rem] 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-canino-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" />
<div className="text-4xl font-black font-vazir text-medical-gray-900 tracking-tighter mb-4">
{toPersian(product.price)}
</div>
{/* Refill Auto-Calculator */}
<div className="bg-canino-blue rounded-[2rem] p-6 text-white mb-8 border-b-8 border-white/20 shadow-2xl">
<div className="bg-canina-blue rounded-[2rem] p-6 text-white mb-8 border-b-8 border-white/20 shadow-2xl">
<div className="flex items-center gap-2 mb-4 opacity-90">
<Clock className="w-4 h-4 text-white" />
<span className="text-[10px] font-bold uppercase tracking-widest font-vazir text-white">هوش مصنوعی تکرار خرید</span>
@ -437,18 +439,18 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<div className="bg-medical-gray-50 rounded-2xl p-6 border border-medical-gray-100 mb-8 space-y-6">
<div className="flex items-center justify-between">
<span className="text-[10px] font-black text-medical-gray-400 font-vazir">وزن پت (کیلوگرم)</span>
<span className="text-sm font-black text-canino-blue font-vazir">{toPersian(weight)}</span>
<span className="text-sm font-black text-canina-blue font-vazir">{toPersian(weight)}</span>
</div>
<input
type="range"
min="1" max="100"
value={weight}
onChange={(e) => setWeight(parseInt(e.target.value))}
className="w-full h-1.5 bg-medical-gray-200 rounded-lg appearance-none cursor-pointer accent-canino-blue"
className="w-full h-1.5 bg-medical-gray-200 rounded-lg appearance-none cursor-pointer accent-canina-blue"
/>
<div className="flex gap-2">
<button onClick={() => setPetType("young")} className={`flex-1 py-2 rounded-xl text-[10px] font-black transition-all ${petType === "young" ? 'bg-canino-blue text-white shadow-lg' : 'bg-white text-medical-gray-400'}`}>جوان</button>
<button onClick={() => setPetType("adult")} className={`flex-1 py-2 rounded-xl text-[10px] font-black transition-all ${petType === "adult" ? 'bg-canino-blue text-white shadow-lg' : 'bg-white text-medical-gray-400'}`}>بالغ</button>
<button onClick={() => setPetType("young")} className={`flex-1 py-2 rounded-xl text-[10px] font-black transition-all ${petType === "young" ? 'bg-canina-blue text-white shadow-lg' : 'bg-white text-medical-gray-400'}`}>جوان</button>
<button onClick={() => setPetType("adult")} className={`flex-1 py-2 rounded-xl text-[10px] font-black transition-all ${petType === "adult" ? 'bg-canina-blue text-white shadow-lg' : 'bg-white text-medical-gray-400'}`}>بالغ</button>
</div>
</div>
@ -457,7 +459,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<div className="flex items-center gap-4 bg-medical-gray-50 border border-medical-gray-100 rounded-2xl p-2 h-16 w-[40%]">
<button
onClick={() => setItemQuantity(Math.max(1, itemQuantity - 1))}
className="w-10 h-10 flex items-center justify-center rounded-xl bg-white text-medical-gray-900 border border-medical-gray-200 hover:bg-canino-blue hover:text-white hover:border-canino-blue transition-all shadow-sm"
className="w-10 h-10 flex items-center justify-center rounded-xl bg-white text-medical-gray-900 border border-medical-gray-200 hover:bg-canina-blue hover:text-white hover:border-canina-blue transition-all shadow-sm"
>
<Minus className="w-4 h-4" />
</button>
@ -466,7 +468,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</span>
<button
onClick={() => setItemQuantity(itemQuantity + 1)}
className="w-10 h-10 flex items-center justify-center rounded-xl bg-white text-medical-gray-900 border border-medical-gray-200 hover:bg-canino-blue hover:text-white hover:border-canino-blue transition-all shadow-sm"
className="w-10 h-10 flex items-center justify-center rounded-xl bg-white text-medical-gray-900 border border-medical-gray-200 hover:bg-canina-blue hover:text-white hover:border-canina-blue transition-all shadow-sm"
>
<Plus className="w-4 h-4" />
</button>
@ -478,7 +480,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
addItem(product, itemQuantity, { quantity: calculation.dailyDose, unit: calculation.unit });
toast.success(`${toPersian(itemQuantity)} عدد ${product.name} به سبد خرید اضافه شد`);
}}
className="w-[60%] flex items-center justify-center gap-1.5 px-4 bg-medical-gray-900 text-white rounded-2xl h-16 font-black text-sm hover:bg-canino-blue transition-all shadow-xl shadow-black/10 font-vazir whitespace-nowrap"
className="w-[60%] flex items-center justify-center gap-1.5 px-4 bg-medical-gray-900 text-white rounded-2xl h-16 font-black text-sm hover:bg-canina-blue transition-all shadow-xl shadow-black/10 font-vazir whitespace-nowrap"
>
<ShoppingBag className="w-5 h-5 mb-1" />
افزودن به سبد خرید
@ -491,14 +493,14 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
ضمانت اصالت محصول (Made in Germany)
</div>
<div className="flex items-center gap-2 text-[10px] font-bold text-medical-gray-400 font-vazir">
<Clock className="w-4 h-4 text-canino-blue" />
<Clock className="w-4 h-4 text-canina-blue" />
آماده ارسال (تحویل حداکثر ۴۸ ساعت)
</div>
</div>
</div>
{/* expected results box */}
{product.expectedResults && (
{product.expectedResults?.length > 0 && (
<div className="bg-white rounded-[2.5rem] border border-medical-gray-200 p-8">
<h4 className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-6 font-vazir">تغییرات قابل انتظار</h4>
<div className="space-y-4">
@ -506,7 +508,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
const Icon = ICON_MAP[res.icon] || Sparkles;
return (
<div key={i} className="flex items-center gap-4 group">
<div className="w-10 h-10 bg-medical-gray-50 rounded-xl flex items-center justify-center text-canino-blue group-hover:bg-canino-blue group-hover:text-white transition-all">
<div className="w-10 h-10 bg-medical-gray-50 rounded-xl flex items-center justify-center text-canina-blue group-hover:bg-canina-blue group-hover:text-white transition-all">
<Icon className="w-5 h-5" />
</div>
<span className="text-xs font-bold text-medical-gray-700 font-vazir">{res.text}</span>
@ -523,12 +525,12 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
{product.relatedProducts && product.relatedProducts.length > 0 && (
<section className="mt-32 pt-20 border-t border-medical-gray-200">
<div className="flex flex-col items-center text-center mb-16 px-4">
<div className="inline-flex items-center gap-2 px-4 py-2 bg-canino-blue/5 border border-canino-blue/10 rounded-full text-canino-blue text-xs font-black uppercase tracking-widest mb-6 font-vazir whitespace-nowrap">
<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 font-vazir whitespace-nowrap">
<Sparkles className="w-4 h-4" />
فرمولاسیون ترکیبی همافزا (Synergy Blend)
</div>
<h2 className="text-3xl lg:text-5xl font-black text-medical-gray-900 leading-tight">
اثربخشی <span className="text-canino-blue italic">دوبرابر</span> با ترکیب هوشمند
اثربخشی <span className="text-canina-blue italic">دوبرابر</span> با ترکیب هوشمند
</h2>
</div>
@ -546,20 +548,20 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
onClick={() => router.push(`/shop/${relProduct.id}`)}
>
<div className="w-40 h-40 bg-medical-gray-50 rounded-[2rem] p-4 flex items-center justify-center">
<SafeImage src={relProduct.image} alt={relProduct.name} className="w-full h-full object-contain drop-shadow-xl" />
<SafeImage src={relProduct.image} alt={relProduct.name} className="w-full h-full drop-shadow-xl" imgClassName="object-contain" />
</div>
<div className="flex-1 text-center md:text-right">
<h4 className="text-xl font-black text-medical-gray-900 mb-2">{relProduct.name}</h4>
<p className="text-sm text-medical-gray-500 mb-6">{relProduct.description}</p>
<div className="flex items-center justify-center md:justify-start gap-4">
<span className="text-lg font-black text-canino-blue">{relProduct.price}</span>
<span className="text-lg font-black text-canina-blue">{relProduct.price}</span>
<ArrowRight className="w-4 h-4 text-medical-gray-300" />
</div>
</div>
<div className="w-px h-24 bg-medical-gray-100 hidden md:block" />
<div className="flex items-center justify-center gap-1 group">
<span className="text-xs font-black text-medical-gray-400 group-hover:text-canino-blue transition-colors">مشاهده محصول مکمل</span>
<ChevronLeft className="w-4 h-4 text-medical-gray-300 group-hover:text-canino-blue group-hover:-translate-x-1 transition-all rtl:group-hover:translate-x-1" />
<span className="text-xs font-black text-medical-gray-400 group-hover:text-canina-blue transition-colors">مشاهده محصول مکمل</span>
<ChevronLeft className="w-4 h-4 text-medical-gray-300 group-hover:text-canina-blue group-hover:-translate-x-1 transition-all rtl:group-hover:translate-x-1" />
</div>
</motion.div>
);
@ -586,7 +588,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
exit={{ opacity: 0, scale: 0.9, y: 20 }}
className="bg-white w-full max-w-lg rounded-[3rem] p-10 relative z-10 shadow-2xl overflow-hidden"
>
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canino-blue via-blue-400 to-canino-blue" />
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue via-blue-400 to-canina-blue" />
<button
onClick={() => setShowRefillModal(false)}
className="absolute top-6 left-6 text-medical-gray-400 hover:text-medical-gray-600 transition-colors"
@ -595,13 +597,13 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
</button>
<div className="text-center">
<div className="w-20 h-20 bg-canino-blue/10 rounded-[2rem] flex items-center justify-center mx-auto mb-8">
<Bell className="w-10 h-10 text-canino-blue animate-bounce" />
<div className="w-20 h-20 bg-canina-blue/10 rounded-[2rem] flex items-center justify-center mx-auto mb-8">
<Bell className="w-10 h-10 text-canina-blue animate-bounce" />
</div>
<h3 className="text-3xl font-black text-medical-gray-900 mb-4 leading-tight italic">سیستم یادآوری هوشمند</h3>
<div className="bg-medical-gray-50 border border-medical-gray-100 rounded-3xl p-6 mb-8 text-right">
<p className="text-medical-gray-700 leading-relaxed font-medium font-vazir">
بر اساس وزن <span className="text-canino-blue font-bold">{toPersian(weight)} کیلوگرمی</span> {activePet ? `برای ${activePet.name}` : 'سگ شما'}، این بسته {toPersian(product.packageSize)} تایی دقیقاً <span className="text-canino-blue font-bold">{toPersian(calculation.duration)} روز</span> دیگر تمام میشود.
بر اساس وزن <span className="text-canina-blue font-bold">{toPersian(weight)} کیلوگرمی</span> {activePet ? `برای ${activePet.name}` : 'سگ شما'}، این بسته {toPersian(product.packageSize)} تایی دقیقاً <span className="text-canina-blue font-bold">{toPersian(calculation.duration)} روز</span> دیگر تمام میشود.
</p>
<div className="mt-4 flex items-center gap-2 text-xs font-bold text-medical-gray-500 font-vazir">
<ShieldCheck className="w-4 h-4 text-green-500" />
@ -612,7 +614,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
<div className="flex flex-col gap-3">
<button
onClick={() => setShowRefillModal(false)}
className="w-full bg-canino-blue text-white py-5 rounded-2xl font-black text-lg hover:shadow-xl hover:shadow-canino-blue/20 transition-all flex items-center justify-center gap-2"
className="w-full bg-canina-blue text-white py-5 rounded-2xl font-black text-lg hover:shadow-xl hover:shadow-canina-blue/20 transition-all flex items-center justify-center gap-2"
>
<CheckCircle2 className="w-5 h-5" />
بله، پیامک یادآوری فعال شود

View File

@ -32,17 +32,17 @@ export default function SafeImage({
<div className="absolute inset-0 opacity-[0.03] pointer-events-none">
<div className="grid grid-cols-6 h-full w-full">
{Array.from({length: 24}).map((_, i) => (
<div key={i} className="border border-canino-blue" />
<div key={i} className="border border-canina-blue" />
))}
</div>
</div>
<div className="w-16 h-16 bg-canino-blue rounded-2xl flex items-center justify-center text-white font-black text-3xl mb-4 shadow-xl shadow-canino-blue/20 italic transform -rotate-6">C</div>
<div className="w-16 h-16 bg-canina-blue rounded-2xl flex items-center justify-center text-white font-black text-3xl mb-4 shadow-xl shadow-canina-blue/20 italic transform -rotate-6">C</div>
<div className="relative">
<ImageOff className="w-5 h-5 text-medical-gray-200 mb-2" />
<Sparkles className="w-3 h-3 text-canino-blue absolute -top-1 -right-1 animate-pulse" />
<Sparkles className="w-3 h-3 text-canina-blue absolute -top-1 -right-1 animate-pulse" />
</div>
<span className="text-[9px] font-black text-canino-blue/60 uppercase tracking-[0.2em] font-vazir leading-relaxed">
<span className="text-[9px] font-black text-canina-blue/60 uppercase tracking-[0.2em] font-vazir leading-relaxed">
{fallbackText}
</span>
</div>
@ -53,7 +53,7 @@ export default function SafeImage({
<div className={cn("relative overflow-hidden group flex items-center justify-center", className)}>
{loading && (
<div className="absolute inset-0 bg-medical-gray-50 animate-pulse flex items-center justify-center z-10">
<Sparkles className="w-6 h-6 text-canino-blue/20" />
<Sparkles className="w-6 h-6 text-canina-blue/20" />
</div>
)}
<img

View File

@ -32,7 +32,7 @@ export default function SearchResultsPage({ query }: { query: string }) {
return (
<div className="min-h-screen bg-medical-gray-50 py-20 px-6 font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto">
<button onClick={() => router.back()} className="flex items-center gap-2 text-medical-gray-400 font-black mb-10 hover:text-canino-blue transition-colors">
<button onClick={() => router.back()} className="flex items-center gap-2 text-medical-gray-400 font-black mb-10 hover:text-canina-blue transition-colors">
<ArrowRight className="w-5 h-5 rotate-180" />
بازگشت
</button>
@ -40,7 +40,7 @@ export default function SearchResultsPage({ query }: { query: string }) {
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
<div>
<h1 className="text-4xl font-black text-medical-gray-900 italic mb-4">
نتایج جستجو برای: <span className="text-canino-blue">"{query}"</span>
نتایج جستجو برای: <span className="text-canina-blue">"{query}"</span>
</h1>
<p className="text-medical-gray-500 font-medium">
{results.length} محصول با معیارهای شما مطابقت دارد.
@ -65,7 +65,7 @@ export default function SearchResultsPage({ query }: { query: string }) {
key={product.id}
layoutId={product.id}
onClick={() => router.push(`/shop/${product.slug || product.id}`)}
className="bg-white rounded-[2.5rem] p-8 border border-medical-gray-200 group cursor-pointer hover:shadow-2xl hover:shadow-canino-blue/10 transition-all flex flex-col relative"
className="bg-white rounded-[2.5rem] p-8 border border-medical-gray-200 group cursor-pointer hover:shadow-2xl hover:shadow-canina-blue/10 transition-all flex flex-col relative"
>
<div className="relative aspect-square mb-8 bg-medical-gray-50 rounded-[2rem] overflow-hidden p-6 flex items-center justify-center">
<img
@ -91,8 +91,8 @@ export default function SearchResultsPage({ query }: { query: string }) {
</div>
<div className="flex-1">
<span className="text-[10px] font-black text-canino-blue uppercase tracking-widest mb-2 block">{product.category}</span>
<h3 className="text-xl font-black text-medical-gray-900 mb-2 leading-tight group-hover:text-canino-blue transition-colors">{product.name}</h3>
<span className="text-[10px] font-black text-canina-blue uppercase tracking-widest mb-2 block">{product.category}</span>
<h3 className="text-xl font-black text-medical-gray-900 mb-2 leading-tight group-hover:text-canina-blue transition-colors">{product.name}</h3>
<p className="text-xs text-medical-gray-400 line-clamp-2 leading-relaxed mb-6">{product.benefits}</p>
</div>
@ -100,7 +100,7 @@ export default function SearchResultsPage({ query }: { query: string }) {
<div>
<span className="text-lg font-black text-medical-gray-900">{product.price}</span>
</div>
<button className="bg-medical-gray-900 text-white w-10 h-10 rounded-xl flex items-center justify-center group-hover:bg-canino-blue transition-colors">
<button className="bg-medical-gray-900 text-white w-10 h-10 rounded-xl flex items-center justify-center group-hover:bg-canina-blue transition-colors">
<ChevronLeft className="w-5 h-5" />
</button>
</div>

View File

@ -95,12 +95,12 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
className="inline-flex items-center gap-2 px-4 py-2 bg-canino-blue/5 rounded-full mb-6"
className="inline-flex items-center gap-2 px-4 py-2 bg-canina-blue/5 rounded-full mb-6"
>
<Sparkle className="w-4 h-4 text-canino-blue" />
<span className="text-canino-blue text-xs font-black uppercase tracking-widest font-vazir">تکنولوژی پایش هوشمند</span>
<Sparkle className="w-4 h-4 text-canina-blue" />
<span className="text-canina-blue text-xs font-black uppercase tracking-widest font-vazir">تکنولوژی پایش هوشمند</span>
</motion.div>
<h2 className="text-4xl lg:text-5xl font-black text-medical-gray-900 mb-4 font-vazir italic">دستیار سلامت کانینو</h2>
<h2 className="text-4xl lg:text-5xl font-black text-medical-gray-900 mb-4 font-vazir italic">دستیار سلامت کانینا</h2>
<p className="text-medical-gray-600 font-bold text-lg font-vazir">فقط چند قدم تا صدور شناسنامه هوشمند و دریافت پیشنهادات تخصصی</p>
</div>
@ -108,7 +108,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
{/* Progress Indicator */}
<div className="absolute top-0 left-0 w-full h-2 bg-medical-gray-200">
<motion.div
className="h-full bg-canino-blue"
className="h-full bg-canina-blue"
initial={{ width: "0%" }}
animate={{ width: `${(step / 3) * 100}%` }}
transition={{ duration: 0.5 }}
@ -132,16 +132,16 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<div className="grid grid-cols-2 gap-4">
<button
onClick={() => setType("سگ")}
className={`flex flex-col items-center gap-4 p-8 rounded-[2.5rem] border-4 transition-all focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none ${type === "سگ" ? 'border-canino-blue bg-white shadow-xl shadow-canino-blue/10 scale-105' : 'border-transparent bg-white/50 text-medical-gray-400 hover:bg-white'}`}
className={`flex flex-col items-center gap-4 p-8 rounded-[2.5rem] border-4 transition-all focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none ${type === "سگ" ? 'border-canina-blue bg-white shadow-xl shadow-canina-blue/10 scale-105' : 'border-transparent bg-white/50 text-medical-gray-400 hover:bg-white'}`}
>
<Dog className={`w-12 h-12 ${type === "سگ" ? 'text-canino-blue' : 'text-current'}`} />
<Dog className={`w-12 h-12 ${type === "سگ" ? 'text-canina-blue' : 'text-current'}`} />
<span className="text-lg font-black font-vazir">سگ</span>
</button>
<button
onClick={() => setType("گربه")}
className={`flex flex-col items-center gap-4 p-8 rounded-[2.5rem] border-4 transition-all focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none ${type === "گربه" ? 'border-canino-blue bg-white shadow-xl shadow-canino-blue/10 scale-105' : 'border-transparent bg-white/50 text-medical-gray-400 hover:bg-white'}`}
className={`flex flex-col items-center gap-4 p-8 rounded-[2.5rem] border-4 transition-all focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none ${type === "گربه" ? 'border-canina-blue bg-white shadow-xl shadow-canina-blue/10 scale-105' : 'border-transparent bg-white/50 text-medical-gray-400 hover:bg-white'}`}
>
<Cat className={`w-12 h-12 ${type === "گربه" ? 'text-canino-blue' : 'text-current'}`} />
<Cat className={`w-12 h-12 ${type === "گربه" ? 'text-canina-blue' : 'text-current'}`} />
<span className="text-lg font-black font-vazir">گربه</span>
</button>
</div>
@ -154,7 +154,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
value={name}
onChange={e => setName(e.target.value)}
placeholder="لوسی، تدی..."
className="w-full bg-white border border-medical-gray-300 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/30 focus-visible:ring-4 focus-visible:ring-canino-blue/40 outline-none font-black text-lg font-vazir placeholder-medical-gray-500 text-medical-gray-900"
className="w-full bg-white border border-medical-gray-300 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/30 focus-visible:ring-4 focus-visible:ring-canina-blue/40 outline-none font-black text-lg font-vazir placeholder-medical-gray-500 text-medical-gray-900"
/>
</div>
<div className="space-y-2">
@ -164,7 +164,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
value={breed}
onChange={e => setBreed(e.target.value)}
placeholder="ژرمن، پرشین..."
className="w-full bg-white border border-medical-gray-300 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canino-blue/30 focus-visible:ring-4 focus-visible:ring-canino-blue/40 outline-none font-bold font-vazir placeholder-medical-gray-500 text-medical-gray-900"
className="w-full bg-white border border-medical-gray-300 rounded-2xl py-4 px-6 focus:ring-2 focus:ring-canina-blue/30 focus-visible:ring-4 focus-visible:ring-canina-blue/40 outline-none font-bold font-vazir placeholder-medical-gray-500 text-medical-gray-900"
/>
</div>
</div>
@ -172,7 +172,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<button
onClick={handleNext}
disabled={!name || !breed}
className="w-full py-6 rounded-3xl font-black text-lg flex items-center justify-center gap-3 font-vazir min-h-[48px] transition-all focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none disabled:bg-gray-200 disabled:text-gray-400 disabled:cursor-not-allowed disabled:shadow-none disabled:border-2 disabled:border-gray-300 bg-medical-gray-900 text-white hover:bg-canino-blue shadow-xl shadow-medical-gray-900/10"
className="w-full py-6 rounded-3xl font-black text-lg flex items-center justify-center gap-3 font-vazir min-h-[48px] transition-all focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none disabled:bg-gray-300 disabled:text-gray-500 disabled:cursor-not-allowed disabled:shadow-none disabled:border-2 disabled:border-gray-400 bg-medical-gray-900 text-white hover:bg-canina-blue shadow-xl shadow-medical-gray-900/10"
>
ثبت هویت و ادامه
<ChevronLeft className="w-5 h-5" />
@ -202,17 +202,17 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<div className="space-y-4">
<label className="block text-center text-sm font-black text-medical-gray-800 font-vazir">سن حیوان (سال)</label>
<div className="flex items-center gap-4 bg-white rounded-3xl p-2 border-2 border-medical-gray-200">
<button onClick={() => setAge(Math.max(0, age - 1))} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canino-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canino-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">-</button>
<span className="flex-1 text-center text-2xl font-black text-canino-blue font-vazir">{toPersian(age.toString())} <span className="text-sm font-bold text-medical-gray-400">سال</span></span>
<button onClick={() => setAge(age + 1)} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canino-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canino-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">+</button>
<button onClick={() => setAge(Math.max(0, age - 1))} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canina-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canina-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">-</button>
<span className="flex-1 text-center text-2xl font-black text-canina-blue font-vazir">{toPersian(age.toString())} <span className="text-sm font-bold text-medical-gray-400">سال</span></span>
<button onClick={() => setAge(age + 1)} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canina-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canina-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">+</button>
</div>
</div>
<div className="space-y-4">
<label className="block text-center text-sm font-black text-medical-gray-800 font-vazir">وزن حیوان (کیلوگرم)</label>
<div className="flex items-center gap-4 bg-white rounded-3xl p-2 border-2 border-medical-gray-200">
<button onClick={() => setWeight(Math.max(1, weight - 1))} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canino-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canino-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">-</button>
<span className="flex-1 text-center text-2xl font-black text-canino-blue font-vazir">{toPersian(weight.toString())} <span className="text-sm font-bold text-medical-gray-400">kg</span></span>
<button onClick={() => setWeight(weight + 1)} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canino-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canino-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">+</button>
<button onClick={() => setWeight(Math.max(1, weight - 1))} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canina-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canina-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">-</button>
<span className="flex-1 text-center text-2xl font-black text-canina-blue font-vazir">{toPersian(weight.toString())} <span className="text-sm font-bold text-medical-gray-400">kg</span></span>
<button onClick={() => setWeight(weight + 1)} className="w-12 h-12 flex items-center justify-center bg-medical-gray-50 rounded-xl text-medical-gray-900 hover:bg-canina-blue hover:text-white focus-visible:ring-2 focus-visible:ring-canina-blue focus-visible:outline-none transition-all shadow-sm font-black text-lg">+</button>
</div>
</div>
</div>
@ -224,7 +224,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<button
key={level}
onClick={() => setActivityLevel(level as any)}
className={`py-4 rounded-2xl border-2 transition-all font-black italic focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none min-h-[48px] ${activityLevel === level ? 'border-canino-blue bg-white text-canino-blue shadow-lg' : 'border-transparent bg-white/50 text-medical-gray-500 hover:bg-white'}`}
className={`py-4 rounded-2xl border-2 transition-all font-black italic focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none min-h-[48px] ${activityLevel === level ? 'border-canina-blue bg-white text-canina-blue shadow-lg' : 'border-transparent bg-white/50 text-medical-gray-500 hover:bg-white'}`}
>
{level}
</button>
@ -235,14 +235,14 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<div className="flex gap-4 pt-4">
<button
onClick={handleBack}
className="flex-1 py-6 bg-medical-gray-100 text-medical-gray-600 rounded-3xl font-black text-lg hover:bg-medical-gray-200 focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all flex items-center justify-center gap-3 font-vazir min-h-[48px]"
className="flex-1 py-6 bg-medical-gray-100 text-medical-gray-600 rounded-3xl font-black text-lg hover:bg-medical-gray-200 focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all flex items-center justify-center gap-3 font-vazir min-h-[48px]"
>
<ChevronRight className="w-5 h-5" />
قبلی
</button>
<button
onClick={handleNext}
className="flex-[2] py-6 bg-medical-gray-900 text-white rounded-3xl font-black text-lg hover:bg-canino-blue focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all shadow-xl shadow-medical-gray-900/10 flex items-center justify-center gap-3 font-vazir min-h-[48px]"
className="flex-[2] py-6 bg-medical-gray-900 text-white rounded-3xl font-black text-lg hover:bg-canina-blue focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all shadow-xl shadow-medical-gray-900/10 flex items-center justify-center gap-3 font-vazir min-h-[48px]"
>
گام نهایی سلامت
<ChevronLeft className="w-5 h-5" />
@ -273,12 +273,12 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
prev.includes(opt.condition) ? prev.filter(c => c !== opt.condition) : [...prev, opt.condition]
);
}}
className={`flex items-center gap-4 p-5 rounded-2xl border-2 transition-all text-right focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none min-h-[48px] ${medicalConditions.includes(opt.condition) ? 'border-canino-blue bg-white shadow-md' : 'border-transparent bg-white/50 text-medical-gray-600 hover:bg-white'}`}
className={`flex items-center gap-4 p-5 rounded-2xl border-2 transition-all text-right focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none min-h-[48px] ${medicalConditions.includes(opt.condition) ? 'border-canina-blue bg-white shadow-md' : 'border-transparent bg-white/50 text-medical-gray-600 hover:bg-white'}`}
>
<div className={`w-8 h-8 rounded-lg flex items-center justify-center border ${medicalConditions.includes(opt.condition) ? 'bg-canino-blue border-canino-blue text-white' : 'border-medical-gray-300 text-transparent'}`}>
<div className={`w-8 h-8 rounded-lg flex items-center justify-center border ${medicalConditions.includes(opt.condition) ? 'bg-canina-blue border-canina-blue text-white' : 'border-medical-gray-300 text-transparent'}`}>
<ShieldCheck className="w-5 h-5" />
</div>
<span className={`text-sm font-black font-vazir ${medicalConditions.includes(opt.condition) ? 'text-canino-blue' : 'text-medical-gray-900'}`}>{opt.label}</span>
<span className={`text-sm font-black font-vazir ${medicalConditions.includes(opt.condition) ? 'text-canina-blue' : 'text-medical-gray-900'}`}>{opt.label}</span>
</button>
))}
</div>
@ -286,14 +286,14 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<div className="flex gap-4 pt-4">
<button
onClick={handleBack}
className="flex-1 py-6 bg-medical-gray-100 text-medical-gray-600 rounded-3xl font-black text-lg hover:bg-medical-gray-200 focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all flex items-center justify-center gap-3 font-vazir min-h-[48px]"
className="flex-1 py-6 bg-medical-gray-100 text-medical-gray-600 rounded-3xl font-black text-lg hover:bg-medical-gray-200 focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all flex items-center justify-center gap-3 font-vazir min-h-[48px]"
>
<ChevronRight className="w-5 h-5" />
قبلی
</button>
<button
onClick={handleSubmit}
className="flex-[2] py-6 bg-canino-blue text-white rounded-3xl font-black text-lg hover:bg-indigo-700 focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none transition-all shadow-xl shadow-canino-blue/20 flex items-center justify-center gap-3 font-vazir min-h-[48px]"
className="flex-[2] py-6 bg-canina-blue text-white rounded-3xl font-black text-lg hover:bg-indigo-700 focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none transition-all shadow-xl shadow-canina-blue/20 flex items-center justify-center gap-3 font-vazir min-h-[48px]"
>
تکمیل و صدور شناسنامه
<ChevronLeft className="w-5 h-5" />

View File

@ -20,7 +20,7 @@ export default function Tooltip({ termKey, children, onWikiNavigate }: TooltipPr
return (
<span
className="relative inline-block group cursor-help border-b border-dotted border-canino-blue/40"
className="relative inline-block group cursor-help border-b border-dotted border-canina-blue/40"
onMouseEnter={() => setIsVisible(true)}
onMouseLeave={() => setIsVisible(false)}
>
@ -35,9 +35,9 @@ export default function Tooltip({ termKey, children, onWikiNavigate }: TooltipPr
className="absolute bottom-full left-1/2 -translate-x-1/2 mb-3 w-64 p-4 bg-medical-gray-900 text-white rounded-2xl shadow-2xl z-[100] text-sm"
dir="rtl"
>
<div className="flex items-center gap-2 mb-2 text-canino-blue">
<div className="flex items-center gap-2 mb-2 text-canina-blue">
<Info className="w-4 h-4" />
<span className="font-black text-[10px] uppercase tracking-widest">دانشنامه علمی کانینو</span>
<span className="font-black text-[10px] uppercase tracking-widest">دانشنامه علمی کانینا</span>
</div>
<h5 className="font-black mb-1">{termData.term}</h5>
<p className="text-white/70 text-xs leading-relaxed mb-3">
@ -46,7 +46,7 @@ export default function Tooltip({ termKey, children, onWikiNavigate }: TooltipPr
{termData.wikiId && (
<button
onClick={() => onWikiNavigate?.(termData.wikiId!)}
className="flex items-center gap-1.5 text-canino-blue hover:text-white transition-colors text-[10px] font-bold"
className="flex items-center gap-1.5 text-canina-blue hover:text-white transition-colors text-[10px] font-bold"
>
<span>مطالعه مقاله کامل</span>
<ExternalLink className="w-3 h-3" />

View File

@ -75,7 +75,7 @@ export default function TopUpModal({ isOpen, onClose, onConfirm }: TopUpModalPro
>
<div className="bg-medical-gray-50 px-8 py-6 border-b border-medical-gray-100 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-canino-blue rounded-xl flex items-center justify-center text-white">
<div className="w-10 h-10 bg-canina-blue rounded-xl flex items-center justify-center text-white">
<TrendingUp className="w-5 h-5" />
</div>
<h3 className="text-xl font-black text-medical-gray-900 italic">شارژ سریع کیف پول</h3>
@ -100,8 +100,8 @@ export default function TopUpModal({ isOpen, onClose, onConfirm }: TopUpModalPro
className={cn(
"px-6 py-3 rounded-2xl text-sm font-black transition-all border",
selectedPreset === preset.value
? "bg-canino-blue text-white border-canino-blue shadow-lg shadow-canino-blue/20"
: "bg-white text-medical-gray-700 border-medical-gray-100 hover:border-canino-blue"
? "bg-canina-blue text-white border-canina-blue shadow-lg shadow-canina-blue/20"
: "bg-white text-medical-gray-700 border-medical-gray-100 hover:border-canina-blue"
)}
>
{preset.label}
@ -118,7 +118,7 @@ export default function TopUpModal({ isOpen, onClose, onConfirm }: TopUpModalPro
type="text"
value={amount ? parseInt(amount).toLocaleString() : ""}
onChange={handleInputChange}
className="w-full bg-medical-gray-50 border border-medical-gray-100 rounded-3xl py-6 px-8 outline-none font-black text-2xl text-center text-medical-gray-900 transition-all focus:ring-4 focus:ring-canino-blue/10 focus:border-canino-blue italic"
className="w-full bg-medical-gray-50 border border-medical-gray-100 rounded-3xl py-6 px-8 outline-none font-black text-2xl text-center text-medical-gray-900 transition-all focus:ring-4 focus:ring-canina-blue/10 focus:border-canina-blue italic"
placeholder="۰"
/>
{amount && (
@ -128,14 +128,14 @@ export default function TopUpModal({ isOpen, onClose, onConfirm }: TopUpModalPro
</div>
<div className="bg-blue-50 border border-blue-100 rounded-2xl p-4 flex gap-3">
<Sparkles className="w-5 h-5 text-canino-blue shrink-0" />
<p className="text-[10px] font-bold text-canino-blue leading-relaxed">با شارژ کیف پول، از هدیههای هوشمند کانینو و اولویت در ارسال سفارشها بهرهمند شوید.</p>
<Sparkles className="w-5 h-5 text-canina-blue shrink-0" />
<p className="text-[10px] font-bold text-canina-blue leading-relaxed">با شارژ کیف پول، از هدیههای هوشمند کانینا و اولویت در ارسال سفارشها بهرهمند شوید.</p>
</div>
<button
type="submit"
disabled={loading || !amount}
className="w-full py-5 bg-medical-gray-900 text-white rounded-[2rem] font-black text-lg flex items-center justify-center gap-3 hover:bg-canino-blue transition-all shadow-xl shadow-black/10 disabled:opacity-50 disabled:cursor-not-allowed group"
className="w-full py-5 bg-medical-gray-900 text-white rounded-[2rem] font-black text-lg flex items-center justify-center gap-3 hover:bg-canina-blue transition-all shadow-xl shadow-black/10 disabled:opacity-50 disabled:cursor-not-allowed group"
>
{loading ? (
<div className="w-6 h-6 border-4 border-white/20 border-t-white rounded-full animate-spin" />

View File

@ -143,9 +143,9 @@ export default function UserDashboard() {
<div className="max-w-6xl mx-auto">
{/* Breadcrumb */}
<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-canino-blue" onClick={() => router.push('/')}>خانه</span>
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>خانه</span>
<ChevronRight className="w-2.5 h-2.5" />
<span className="text-canino-blue">پنل کاربری</span>
<span className="text-canina-blue">پنل کاربری</span>
</div>
<div className="grid lg:grid-cols-12 gap-8">
@ -153,7 +153,7 @@ export default function UserDashboard() {
<div className="lg:col-span-4 space-y-6">
<div className="bg-white rounded-[3rem] border border-medical-gray-200 p-8 shadow-xl">
<div className="flex items-center gap-4 mb-10">
<div className="w-16 h-16 bg-canino-blue rounded-3xl flex items-center justify-center text-white shadow-lg">
<div className="w-16 h-16 bg-canina-blue rounded-3xl flex items-center justify-center text-white shadow-lg">
<User className="w-8 h-8" />
</div>
<div>
@ -167,7 +167,7 @@ export default function UserDashboard() {
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as any)}
className={`w-full flex items-center gap-3 p-4 rounded-2xl transition-all font-bold ${activeTab === tab.id ? "bg-canino-blue text-white shadow-lg shadow-canino-blue/20" : "text-medical-gray-600 hover:bg-medical-gray-50"}`}
className={`w-full flex items-center gap-3 p-4 rounded-2xl transition-all font-bold ${activeTab === tab.id ? "bg-canina-blue text-white shadow-lg shadow-canina-blue/20" : "text-medical-gray-600 hover:bg-medical-gray-50"}`}
>
{tab.icon}
{tab.label}
@ -185,7 +185,7 @@ export default function UserDashboard() {
<div className="bg-medical-gray-900 rounded-[3rem] p-8 text-white relative overflow-hidden shadow-2xl">
<div className="absolute top-0 left-0 p-6 opacity-20">
<Wallet className="w-12 h-12 text-canino-blue" />
<Wallet className="w-12 h-12 text-canina-blue" />
</div>
<div className="relative z-10">
<div className="text-[10px] font-black uppercase tracking-widest text-white mb-2">موجودی کیف پول</div>
@ -196,7 +196,7 @@ export default function UserDashboard() {
<button
onClick={() => { setActiveTab("wallet"); setIsTopUpModalOpen(true); }}
disabled={isTopUpModalOpen}
className="mt-8 bg-canino-blue w-full py-4 rounded-2xl font-black hover:bg-white hover:text-canino-blue transition-all shadow-lg shadow-black/20 flex items-center justify-center gap-2"
className="mt-8 bg-canina-blue w-full py-4 rounded-2xl font-black hover:bg-white hover:text-canina-blue transition-all shadow-lg shadow-black/20 flex items-center justify-center gap-2"
>
شارژ کیف پول
</button>
@ -263,7 +263,7 @@ export default function UserDashboard() {
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all",
isEditing
? "bg-white border-canino-blue/30 focus:ring-2 focus:ring-canino-blue/20"
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
/>
@ -282,7 +282,7 @@ export default function UserDashboard() {
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all",
isEditing
? "bg-white border-canino-blue/30 focus:ring-2 focus:ring-canino-blue/20"
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
/>
@ -301,7 +301,7 @@ export default function UserDashboard() {
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all text-left",
isEditing
? "bg-white border-canino-blue/30 focus:ring-2 focus:ring-canino-blue/20"
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100"
)}
dir="ltr"
@ -322,7 +322,7 @@ export default function UserDashboard() {
className={cn(
"w-full border p-4 rounded-2xl font-bold outline-none transition-all text-left",
isEditing
? "bg-white border-canino-blue/30 focus:ring-2 focus:ring-canino-blue/20"
? "bg-white border-canina-blue/30 focus:ring-2 focus:ring-canina-blue/20"
: "bg-medical-gray-50 border-medical-gray-100 opacity-75 cursor-not-allowed"
)}
dir="ltr"
@ -336,7 +336,7 @@ export default function UserDashboard() {
<button
type="submit"
disabled={isSavingProfile}
className="bg-canino-blue text-white px-10 py-4 rounded-2xl font-black hover:bg-indigo-700 transition-all flex items-center gap-2 disabled:opacity-50"
className="bg-canina-blue text-white px-10 py-4 rounded-2xl font-black hover:bg-indigo-700 transition-all flex items-center gap-2 disabled:opacity-50"
>
{isSavingProfile && <span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />}
ذخیره تغییرات
@ -361,7 +361,7 @@ export default function UserDashboard() {
<button
type="button"
onClick={() => setIsEditing(true)}
className="bg-medical-gray-900 text-white px-10 py-4 rounded-2xl font-black hover:bg-canino-blue transition-all"
className="bg-medical-gray-900 text-white px-10 py-4 rounded-2xl font-black hover:bg-canina-blue transition-all"
>
ویرایش اطلاعات
</button>
@ -383,7 +383,7 @@ export default function UserDashboard() {
<div className="text-center py-20">
<ShoppingBag className="w-16 h-16 text-medical-gray-200 mx-auto mb-4" />
<p className="text-medical-gray-400 font-bold">هنوز سفارشی ثبت نکردهاید.</p>
<button onClick={() => router.push('/shop')} className="mt-6 text-canino-blue font-black underline underline-offset-8">برو به فروشگاه</button>
<button onClick={() => router.push('/shop')} className="mt-6 text-canina-blue font-black underline underline-offset-8">برو به فروشگاه</button>
</div>
) : (
<div className="space-y-4">
@ -395,15 +395,15 @@ export default function UserDashboard() {
key={order.id}
whileHover={{ scale: 1.01, x: -5 }}
onClick={() => setSelectedOrder(order)}
className="p-6 border border-medical-gray-100 rounded-[2.5rem] hover:border-canino-blue transition-all group cursor-pointer bg-white overflow-hidden relative"
className="p-6 border border-medical-gray-100 rounded-[2.5rem] hover:border-canina-blue transition-all group cursor-pointer bg-white overflow-hidden relative"
>
<div className="flex flex-wrap items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-canino-blue group-hover:bg-canino-blue group-hover:text-white transition-all shadow-sm">
<div className="w-12 h-12 bg-medical-gray-50 rounded-2xl flex items-center justify-center text-canina-blue group-hover:bg-canina-blue group-hover:text-white transition-all shadow-sm">
<Package className="w-6 h-6" />
</div>
<div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canino-blue transition-colors italic">سفارش {toPersian(order.id.toUpperCase())}</div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors italic">سفارش {toPersian(order.id.toUpperCase())}</div>
<div className="text-[10px] font-bold text-medical-gray-400 flex items-center gap-1">
<Calendar className="w-3 h-3 opacity-30" />
{toPersian(new Date(order.date).toLocaleDateString("fa-IR"))}
@ -413,7 +413,7 @@ export default function UserDashboard() {
<div className="text-left">
<div className="text-lg font-black text-medical-gray-900 italic">{toPersian(order.total.toLocaleString())} <span className="text-xs">تومان</span></div>
<div className="flex items-center gap-2 justify-end mt-1">
<span className={`text-[9px] font-black px-2 py-0.5 rounded-full uppercase tracking-tighter ${order.status === 'delivered' ? 'bg-green-50 text-green-600' : 'bg-canino-blue/5 text-canino-blue'}`}>
<span className={`text-[9px] font-black px-2 py-0.5 rounded-full uppercase tracking-tighter ${order.status === 'delivered' ? 'bg-green-50 text-green-600' : 'bg-canina-blue/5 text-canina-blue'}`}>
{order.status === 'delivered' ? 'تحویل شده' : 'ارسال شده'}
</span>
<ChevronRight className="w-4 h-4 text-medical-gray-300 -rotate-180" />
@ -434,7 +434,7 @@ export default function UserDashboard() {
<h3 className="text-2xl font-black text-medical-gray-900 italic">آدرسهای من</h3>
<button
onClick={handleAddClick}
className="px-6 py-3 bg-canino-blue text-white rounded-2xl font-black text-xs flex items-center gap-2 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canino-blue/10"
className="px-6 py-3 bg-canina-blue text-white rounded-2xl font-black text-xs flex items-center gap-2 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canina-blue/10"
>
<MapPin className="w-4 h-4" />
افزودن آدرس جدید
@ -455,12 +455,12 @@ export default function UserDashboard() {
animate={{ opacity: 1, y: 0 }}
className={cn(
"p-8 bg-white border rounded-[2.5rem] relative group transition-all",
addr.isDefault ? "border-canino-blue shadow-xl shadow-canino-blue/5" : "border-medical-gray-100 hover:border-medical-gray-200"
addr.isDefault ? "border-canina-blue shadow-xl shadow-canina-blue/5" : "border-medical-gray-100 hover:border-medical-gray-200"
)}
>
<div className="flex justify-between items-start mb-6">
<div className="flex items-center gap-4">
<div className={cn("w-12 h-12 rounded-2xl flex items-center justify-center transition-all", addr.isDefault ? "bg-canino-blue text-white shadow-lg" : "bg-medical-gray-50 text-canino-blue")}>
<div className={cn("w-12 h-12 rounded-2xl flex items-center justify-center transition-all", addr.isDefault ? "bg-canina-blue text-white shadow-lg" : "bg-medical-gray-50 text-canina-blue")}>
<MapPin className="w-6 h-6" />
</div>
<div>
@ -476,7 +476,7 @@ export default function UserDashboard() {
<div className="flex items-center gap-2">
<button
onClick={() => handleEditClick(addr)}
className="w-10 h-10 flex items-center justify-center rounded-xl bg-medical-gray-50 text-medical-gray-400 hover:bg-canino-blue hover:text-white transition-all shadow-sm"
className="w-10 h-10 flex items-center justify-center rounded-xl bg-medical-gray-50 text-medical-gray-400 hover:bg-canina-blue hover:text-white transition-all shadow-sm"
>
<Edit2 className="w-5 h-5" />
</button>
@ -495,11 +495,11 @@ export default function UserDashboard() {
<div className="flex flex-wrap items-center gap-6">
<div className="flex items-center gap-2">
<Phone className="w-4 h-4 text-canino-blue/40" />
<Phone className="w-4 h-4 text-canina-blue/40" />
<span className="text-xs font-bold text-medical-gray-500" dir="ltr">{toPersian(addr.phone)}</span>
</div>
<div className="flex items-center gap-2">
<Hash className="w-4 h-4 text-canino-blue/40" />
<Hash className="w-4 h-4 text-canina-blue/40" />
<span className="text-xs font-bold text-medical-gray-500" dir="ltr">{toPersian(addr.zipCode)}</span>
</div>
{!addr.isDefault && (
@ -512,7 +512,7 @@ export default function UserDashboard() {
toast.error("خطا در تغییر آدرس پیش‌فرض");
}
}}
className="mr-auto text-[10px] font-black text-canino-blue hover:text-medical-gray-900 uppercase tracking-widest whitespace-nowrap"
className="mr-auto text-[10px] font-black text-canina-blue hover:text-medical-gray-900 uppercase tracking-widest whitespace-nowrap"
>
انتخاب به عنوان پیشفرض
</button>
@ -542,7 +542,7 @@ export default function UserDashboard() {
</div>
{/* Main Balance Card */}
<div className="bg-gradient-to-br from-canino-blue to-blue-600 rounded-[3rem] p-12 text-white shadow-2xl shadow-canino-blue/20 relative overflow-hidden group">
<div className="bg-gradient-to-br from-canina-blue to-blue-600 rounded-[3rem] p-12 text-white shadow-2xl shadow-canina-blue/20 relative overflow-hidden group">
<div className="absolute top-0 right-0 p-12 opacity-10 group-hover:scale-110 transition-transform duration-700">
<Wallet className="w-48 h-48" />
</div>
@ -572,7 +572,7 @@ export default function UserDashboard() {
</div>
<button
onClick={() => setIsTopUpModalOpen(true)}
className="flex-1 md:w-40 h-16 bg-white text-canino-blue rounded-2xl font-black text-sm flex items-center justify-center gap-2 hover:bg-medical-gray-900 hover:text-white transition-all shadow-xl shadow-black/10 group/topup"
className="flex-1 md:w-40 h-16 bg-white text-canina-blue rounded-2xl font-black text-sm flex items-center justify-center gap-2 hover:bg-medical-gray-900 hover:text-white transition-all shadow-xl shadow-black/10 group/topup"
>
<ArrowUpCircle className="w-5 h-5 group-hover:-translate-y-1 transition-transform" />
شارژ آنی
@ -598,7 +598,7 @@ export default function UserDashboard() {
</div>
) : (
(profile?.transactions || []).map((trx) => (
<div key={trx.id} className="p-6 bg-white border border-medical-gray-100 rounded-[2rem] flex flex-wrap items-center justify-between gap-6 hover:shadow-lg hover:border-canino-blue/10 transition-all group">
<div key={trx.id} className="p-6 bg-white border border-medical-gray-100 rounded-[2rem] flex flex-wrap items-center justify-between gap-6 hover:shadow-lg hover:border-canina-blue/10 transition-all group">
<div className="flex items-center gap-4">
<div className={cn(
"w-12 h-12 rounded-2xl flex items-center justify-center transition-colors",

View File

@ -44,20 +44,20 @@ export default function VetGallery({ testimonials = [] }: { testimonials?: any[]
<div className="max-w-7xl mx-auto px-4">
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
<div className="max-w-2xl">
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canino-blue/10 text-canino-blue rounded-full text-[10px] font-black uppercase tracking-widest mb-4">
<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">
<Star className="w-3 h-3" />
Vet Insights
</div>
<h2 className="text-4xl md:text-5xl font-black text-medical-gray-900 italic leading-tight">
مشاوره ویدئویی <span className="text-canino-blue underline decoration-4 decoration-canino-blue/20 underline-offset-8">دوست دامپزشک پت شما</span>
مشاوره ویدئویی <span className="text-canina-blue underline decoration-4 decoration-canina-blue/20 underline-offset-8">دوست دامپزشک پت شما</span>
</h2>
<p className="text-lg text-medical-gray-500 font-medium mt-6">
متخصصین آلمانی کانینو مستقیماً با شما صحبت میکنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.
متخصصین آلمانی کانینا مستقیماً با شما صحبت میکنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.
</p>
</div>
<button
onClick={() => router.push('/videos')}
className="inline-flex items-center gap-2 text-canino-blue font-bold text-sm hover:translate-x-1 transition-transform rtl:hover:-translate-x-1"
className="inline-flex items-center gap-2 text-canina-blue font-bold text-sm hover:translate-x-1 transition-transform rtl:hover:-translate-x-1"
>
مشاهده همه ویدئوها
<Play className="w-4 h-4" />
@ -70,7 +70,7 @@ export default function VetGallery({ testimonials = [] }: { testimonials?: any[]
key={video.id}
whileHover={{ y: -8 }}
onClick={() => setSelectedVideo(video)}
className="w-full text-right block group cursor-pointer focus-visible:ring-4 focus-visible:ring-canino-blue/30 focus-visible:outline-none rounded-[2rem] p-2"
className="w-full text-right block group cursor-pointer focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none rounded-[2rem] p-2"
>
<div className="relative aspect-video rounded-[2rem] overflow-hidden mb-4 shadow-xl">
<div className="absolute inset-0 bg-medical-gray-900/20 group-hover:bg-transparent transition-colors z-10" />
@ -80,7 +80,7 @@ export default function VetGallery({ testimonials = [] }: { testimonials?: any[]
className="w-full h-full object-cover grayscale-[30%] group-hover:grayscale-0 transition-all duration-700"
/>
<div className="absolute inset-0 flex items-center justify-center z-20">
<div className="w-16 h-16 bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center text-canino-blue scale-90 group-hover:scale-100 group-hover:bg-white transition-all shadow-xl">
<div className="w-16 h-16 bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center text-canina-blue scale-90 group-hover:scale-100 group-hover:bg-white transition-all shadow-xl">
<Play className="w-6 h-6 ml-1" />
</div>
</div>
@ -89,11 +89,11 @@ export default function VetGallery({ testimonials = [] }: { testimonials?: any[]
<span>{video.duration || (index === 0 ? '۱:۴۵' : index === 1 ? '۲:۲۰' : '۳:۱۰')}</span>
</div>
</div>
<h4 className="text-lg font-black text-medical-gray-900 mb-2 group-hover:text-canino-blue transition-colors leading-tight font-vazir">
<h4 className="text-lg font-black text-medical-gray-900 mb-2 group-hover:text-canina-blue transition-colors leading-tight font-vazir">
{video.title || video.quote?.substring(0, 40) + '...'}
</h4>
<div className="flex items-center gap-2 text-medical-gray-500 font-bold text-sm font-vazir">
<ShieldCheck className="w-4 h-4 text-canino-blue" />
<ShieldCheck className="w-4 h-4 text-canina-blue" />
{video.doctor || video.vetName}
</div>
</motion.button>

View File

@ -69,12 +69,12 @@ export default function VideosPage() {
{/* Header */}
<div className="flex flex-col md:flex-row items-center justify-between mb-16 gap-6">
<div className="text-right">
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canino-blue/10 text-canino-blue rounded-full text-[10px] font-black uppercase tracking-widest mb-4">
<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">
<PlayCircle className="w-3 h-3" />
Video Academy
</div>
<h1 className="text-4xl lg:text-6xl font-black text-white italic leading-tight">
آکادمی ویدئویی <span className="text-canino-blue">کانینو</span>
آکادمی ویدئویی <span className="text-canina-blue">کانینا</span>
</h1>
</div>
<button
@ -117,7 +117,7 @@ export default function VideosPage() {
referrerPolicy="no-referrer"
/>
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-16 h-16 bg-canino-blue rounded-full flex items-center justify-center text-white shadow-2xl group-hover:scale-110 transition-transform">
<div className="w-16 h-16 bg-canina-blue rounded-full flex items-center justify-center text-white shadow-2xl group-hover:scale-110 transition-transform">
<PlayCircle className="w-10 h-10" />
</div>
</div>
@ -126,7 +126,7 @@ export default function VideosPage() {
</div>
</div>
<div className="px-4">
<h3 className="text-xl font-black text-white group-hover:text-canino-blue transition-colors mb-2">{video.title}</h3>
<h3 className="text-xl font-black text-white group-hover:text-canina-blue transition-colors mb-2">{video.title}</h3>
<div className="flex items-center gap-4 text-xs font-bold text-white/40">
<div className="flex items-center gap-1">
<User className="w-3 h-3" />
@ -173,7 +173,7 @@ export default function VideosPage() {
className="w-full h-full object-contain"
/>
<div className="absolute bottom-0 left-0 right-0 p-10 bg-gradient-to-t from-black/90 to-transparent">
<div className="flex items-center gap-2 text-canino-blue text-xs font-black mb-2 uppercase tracking-widest">
<div className="flex items-center gap-2 text-canina-blue text-xs font-black mb-2 uppercase tracking-widest">
<ShieldCheck className="w-4 h-4" />
Verified Insight
</div>

View File

@ -1,4 +1,4 @@
"use client";
"use client";
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import React from 'react';
@ -8,9 +8,9 @@ describe('Footer', () => {
it('renders footer brand text and standard layout elements', () => {
render(<Footer onNavigate={vi.fn()} onShopNavigate={vi.fn()} onB2BOpen={vi.fn()} />);
expect(screen.getByText('کانینو ایران')).toBeInTheDocument();
expect(screen.getByText('کانینا ایران')).toBeInTheDocument();
expect(screen.getByText('نماینده رسمی در ایران')).toBeInTheDocument();
expect(screen.getByText('تهران، جردن، خیابان سعیدی، ساختمان کانینو، طبقه ۵، واحد ۱۹')).toBeInTheDocument();
expect(screen.getByText('تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹')).toBeInTheDocument();
});
it('triggers onNavigate and onShopNavigate when quick links are clicked', () => {

View File

@ -54,7 +54,7 @@ describe('Header', () => {
/>
);
expect(screen.getByText('Canino')).toBeInTheDocument();
expect(screen.getByText('Canina')).toBeInTheDocument();
expect(screen.getByText('ایران')).toBeInTheDocument();
expect(screen.getByText('ورود / ثبت‌نام')).toBeInTheDocument();
});

View File

@ -108,7 +108,7 @@ export const PRODUCTS: Product[] = [
{
id: "canhydrox-gag",
artNo: "123490",
name: "Canino CANHYDROX GAG",
name: "Canina CANHYDROX GAG",
scientificTagline: "استاندارد طلایی ارتوپدی سگ‌های آلمان",
description: "ویژه سگ‌های بزرگ و سنگین‌وزن برای درمان بافت همبند، مفاصل، استخوان‌ها، تاندون‌ها و غضروف. هیدروکسی‌آپاتیت (کلسیم فسفات بیولوژیک) ساختار بلوری استخوان‌ها را بازسازی کرده و به تشکیل سریع‌تر کالوس استخوانی پس از جراحی‌ها کمک می‌کند. گلیکوزآمینوگلیکان‌های صدف لب‌سبز با جذب ملکول‌های آب به درون ماتریکس غضروفی، خاصیت الاستیسیته و بافری مفاصل را بازیابی می‌کنند.",
shortDescription: "قوی‌ترین فرمول ارتوپدی آلمان برای تقویت اسکلت‌بندی و رشد سالم استخوان‌ها در نژادهای بزرگ. هیدروکسی آپاتیت به همراه صدف لب‌سبز و سیلیکا، قوام ناخن‌ها، تاندون‌ها و مینای دندان‌ها را بهبود می‌بخشد.",
@ -173,7 +173,7 @@ export const PRODUCTS: Product[] = [
{
id: "immun-booster",
artNo: "140504",
name: "Canino Immun-Booster",
name: "Canina Immun-Booster",
scientificTagline: "سیستم دفاعی هوشمند بیولوژیک",
description: "خمیر آغوز متمرکز با دوز بالای ایمونوگلوبولین‌ها برای فعال‌سازی فوری سیستم ایمنی غیرفعال یا سرکوب‌شده. آغوز (اولین شیر پستانداران) حاوی IgG، IgA، IgM و لاکتوفرین است که سد دفاعی روده را تقویت کرده و از نفوذ پاتوژن‌ها جلوگیری می‌کند. ویتامین D3 تولید کاتلیسیدین (پپتید ضد میکروبی ذاتی) را تحریک کرده و ویتامین E به عنوان آنتی‌اکسیدان قوی از غشاهای سلولی محافظت می‌کند.",
shortDescription: "سپر دفاعی هوشمند؛ خمیر آغوز متمرکز برای فعال‌سازی فوری گلبول‌های سفید و تقویت توله‌ها و مادران باردار.",
@ -222,7 +222,7 @@ export const PRODUCTS: Product[] = [
{
id: "mikrosilber-zahngel",
artNo: "131454",
name: "Canino Mikrosilber Zahngel",
name: "Canina Mikrosilber Zahngel",
scientificTagline: "مراقبت آنتی‌سپتیک دهان با تکنولوژی نقره میکروسیمی",
description: "ژل دندانی حاوی ذرات نقره میکروسیلور با ساختار اسفنجی که به دلیل اندازه درشت جذب جریان خون نشده اما اثر آنتی‌باکتریال پایداری روی سطح لثه و مینا ایجاد می‌کند. بر خلاف نقره کلوئیدی معمولی، میکروسیلور رسوب سطحی طولانی‌مدت داشته و فلور طبیعی دهان را تخریب نمی‌کند. عصاره دانه گریپ‌فروت به عنوان مهارکننده تشکیل بیوفیلم باکتریایی عمل کرده و ویتامین C سنتز کلاژن لثه را تسریع می‌کند.",
shortDescription: "انقلاب در بهداشت دهان؛ ژل نقره میکروسیمی برای حذف باکتری‌های مولد جرم و بوی بد دهان بدون نیاز به بیهوشی.",
@ -270,7 +270,7 @@ export const PRODUCTS: Product[] = [
{
id: "ballaststoff-mix",
artNo: "140108",
name: "Canino Ballaststoff Mix",
name: "Canina Ballaststoff Mix",
scientificTagline: "بهینه‌سازی بیوم روده با فیبرهای گیاهی ارگانیک",
description: "ترکیب متعادل فیبرهای گیاهی از منابع فیبر سیب (پکتین)، یونجه، نخود فرنگی و هویج برای تنظیم سیستم گوارش و بهبود کیفیت دفع. پکتین سیب به عنوان یک پری‌بیوتیک طبیعی، بستر增殖 باکتری‌های مفید روده (لاکتوباسیلوس و بیفیدوباکتر) را فراهم کرده و فیبر یونجه حرکات پریستالتیک روده را تنظیم می‌کند.",
shortDescription: "راه‌کار نهایی مشکلات گوارشی؛ تنظیم‌کننده حرکات روده و کمک به تخلیه طبیعی غدد مقعدی با فیبر سیب.",
@ -310,7 +310,7 @@ export const PRODUCTS: Product[] = [
{
id: "lachs-ol",
artNo: "111803",
name: "Canino Lachs-Öl",
name: "Canina Lachs-Öl",
scientificTagline: "اسیدهای چرب ضروری با خلوص دارویی",
description: "روغن سالمون ۱۰۰٪ خالص نروژی حاوی اسیدهای چرب امگا ۳ (EPA و DHA) با روش پرس سرد (Cold Press) استخراج شده تا تمامی ویتامین‌های حساس به حرارت (A، D، E) حفظ شوند. EPA (ایکوزاپنتائنوئیک اسید) پیش‌ماده رزولوین‌ها و پروستاگلاندین‌های ضدالتهابی سری E3 بوده و DHA (دوکوزاهگزانوئیک اسید) ۳۰٪ وزن خشک مغز را تشکیل می‌دهد و برای بینایی و شناخت حیاتی است. نسبت EPA:DHA ۳:۲ بهینه جهت جذب سلولی در پت‌ها رعایت شده است.",
shortDescription: "اکسیر درخشش و سلامت؛ روغن سالمون نروژی با امگا ۳ غلیظ برای رفع خشکی پوست و ریزش مو.",
@ -348,14 +348,14 @@ export const PRODUCTS: Product[] = [
name: "دکتر ماری کونیگ",
title: "متخصص تغذیه دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
message: "روغن سالمون کانینو به روش پرس سرد تهیه شده تا تمامی ویتامین‌های حساس به حرارت حفظ شوند."
message: "روغن سالمون کانینا به روش پرس سرد تهیه شده تا تمامی ویتامین‌های حساس به حرارت حفظ شوند."
},
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
},
{
id: "herz-vital",
artNo: "111858",
name: "Canino Herz Vital",
name: "Canina Herz Vital",
scientificTagline: "محافظت تخصصی از میوکارد و سیستم گردش خون",
description: "مکمل تخصصی قلب حاوی ال-کارنیتین (۳۰,۰۰۰mg/kg) و عصاره زالزالک (Crataegus oxyacantha) برای تقویت عضله قلب در سگ‌ها و گربه‌های مسن و کاری. ال-کارنیتین اسیدهای چرب زنجیره بلند را به داخل میتوکندری کاردیومیوسیت‌ها منتقل کرده و ATP تولید می‌کند. زالزالک به عنوان مهارکننده ACE طبیعی، انقباض عروق کرونر را کاهش داده و ایسکمی میوکارد را بهبود می‌بخشد.",
shortDescription: "موتور تپنده زندگی؛ مکمل تخصصی حاوی ال-کارنیتین و زالزالک برای تقویت عضله قلب در پت‌های مسن و کاری.",
@ -393,7 +393,7 @@ export const PRODUCTS: Product[] = [
{
id: "energy-gel",
artNo: "111452",
name: "Canino Petvital Energy-Gel",
name: "Canina Petvital Energy-Gel",
scientificTagline: "تامین فوری گلوکز و ویتامین‌های متابولیک برای بازیابی توان",
description: "کمک‌درمانی تخصصی فرموله شده با دوز بالای ویتامین‌های گروه B (B1، B2، B6، B12) به عنوان کوآنزیم‌های چرخه کربس، گلوکز جهت تامین فوری ATP سلولی، ویتامین E به عنوان آنتی‌اکسیدان غشایی و منیزیم به عنوان کوفاکتور بیش از ۳۰۰ واکنش آنزیمی. مناسب برای بی‌اشتهایی، نقاهت جراحی، بارداری و شیردهی و مسابقات ورزشی.",
shortDescription: "منبع انرژی متمرکز و خوش‌خوراک؛ حاوی ویتامین‌های ب-کمپلکس و گلوکز برای بازگشت سریع انرژی در دوران نقاهت.",
@ -433,7 +433,7 @@ export const PRODUCTS: Product[] = [
{
id: "moor-tranke",
artNo: "112404",
name: "Canino Moor-Tränke",
name: "Canina Moor-Tränke",
scientificTagline: "اکسیر طبیعی بر پایه اسیدهای هومیک گیاهی",
description: "اکسیر طبیعی حاصل از تجزیه گیاهان در طول هزاران سال (پیت) با غلظت بالای اسیدهای هومیک. اسیدهای هومیک ساختار پلیمری با بار منفی دارند که سموم، قارچ‌ها و باکتری‌های مضر را در روده به دام انداخته و دفع می‌کنند. همچنین با ایجاد لایه کلوئیدی محافظ روی مخاط روده، التهاب را کاهش داده و اشتها را تحریک می‌کند.",
shortDescription: "سم‌زدای قدرتمند طبیعت؛ عصاره پیت حاوی اسیدهای هومیک برای پاکسازی روده از توکسین‌ها و تنظیم اشتها.",
@ -478,7 +478,7 @@ export const PRODUCTS: Product[] = [
{
id: "schwarz-kummel",
artNo: "112503",
name: "Canino Schwarz-Kümmel",
name: "Canina Schwarz-Kümmel",
scientificTagline: "درمان سنتی ارتقا یافته با تکنولوژی آلمانی",
description: "روغن سیاه دانه مصری ۱۰۰٪ خالص حاوی تیموکینون (Thymoquinone) با غلظت بالا که به روش پرس سرد استخراج شده است. تیموکینون با مهار مسیر NF-κB و کاهش تولید سایتوکاین‌های پیش‌التهابی (TNF-α، IL-6) اثر آنتی‌هیستامین و آنتی‌آلرژیک دارد. ترکیبات ساپونینی سیاه دانه باعث دفع طبیعی انگل‌های خارجی (کک و کنه) از طریق تغییر بوی پوست می‌شود.",
shortDescription: "درمان سنتی کهن؛ روغن سیاه دانه مصری با پرس سرد برای مقابله با آلرژی و دفع طبیعی پارازیت‌ها.",
@ -509,14 +509,14 @@ export const PRODUCTS: Product[] = [
name: "دکتر مونیخ",
title: "متخصص طب طبیعی دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
message: "روغن سیاه دانه مصری کانینو حاوی مقادیر بالایی اسیدهای چرب چند غیراشباع است."
message: "روغن سیاه دانه مصری کانینا حاوی مقادیر بالایی اسیدهای چرب چند غیراشباع است."
},
image: "https://www.canina.de/media/1b/83/7d/1715077272/Schwarz-Kuemmel-112503-V1-Canino-250ml_600x600.webp"
},
{
id: "eierschalenpulver",
artNo: "120208",
name: "Canino Eierschalenpulver",
name: "Canina Eierschalenpulver",
scientificTagline: "جایگزین طبیعی پودر استخوان برای رژیم BARF",
description: "پودر ۱۰۰٪ پوسته تخم مرغ آسیاب شده با ۳۶٪ کلسیم خالص. جایگزین پودر استخوان در رژیم‌های خام (BARF) برای سگ‌های دارای آلرژی به پروتئین گوشت. نسبت کلسیم به فسفر ۳۶۰:۱ نیاز کلسیم را بدون ایجاد عدم تعامل فسفر تأمین می‌کند.",
shortDescription: "منبع خالص کلسیم از پوسته تخم مرغ آسیاب شده برای تکمیل رژیم BARF و سلامت دندان‌ها و عضلات.",
@ -549,7 +549,7 @@ export const PRODUCTS: Product[] = [
{
id: "flexan",
artNo: "710003",
name: "Canino FLEXAN",
name: "Canina FLEXAN",
scientificTagline: "کلاژن خالص برای ترمیم غضروف و بافت همبند",
description: "پپتیدهای کلاژن هیدرولیز شده با ۹۴٪ پروتئین خالص که مستقیماً در ماتریکس غضروف مفصلی جذب شده و سنتز کلاژن نوع II را تحریک می‌کند. پودر صدف لب سبز گلیکوزآمینوگلیکان‌های ضروری را تأمین کرده و خاصیت ارتجاعی بافت همبند را بهبود می‌بخشد.",
shortDescription: "کلاژن هیدرولیز شده با صدف لب سبز برای بازسازی مفاصل و غضروف در توله‌ها و سگ‌های مسن.",
@ -588,7 +588,7 @@ export const PRODUCTS: Product[] = [
{
id: "petvital-gag",
artNo: "723201",
name: "Canino PETVITAL GAG",
name: "Canina PETVITAL GAG",
scientificTagline: "گلیکوزآمینوگلیکان‌های خالص برای سیستم حرکتی",
description: "تأمین گلیکوزآمینوگلیکان‌ها (GAG) جهت تثبیت تاندون‌ها، رباط‌ها و غضروف مفاصل. پودر صدف لب سبز با اسیدهای آمینه ضروری عملکرد بهینه سیستم حرکتی را تضمین کرده و متیونین به سنتز پروتئین‌های غضروفی کمک می‌کند.",
shortDescription: "پودر و قرص GAG با صدف لب سبز برای تثبیت تاندون‌ها، رباط‌ها و غضروف مفاصل.",
@ -627,7 +627,7 @@ export const PRODUCTS: Product[] = [
{
id: "velox-gelenkenergie",
artNo: "701902",
name: "Canino Velox Gelenkenergie",
name: "Canina Velox Gelenkenergie",
scientificTagline: "کنسانتره خالص صدف لب سبز نیوزیلند",
description: "۱۰۰٪ پودر گوشت صدف لب سبز نیوزیلندی (Perna canaliculus) با غلظت بالای گلیکوزآمینوگلیکان‌ها و اسیدهای چرب امگا ۳ اختصاصی (ETA). بازسازی مفاصل، رباط‌ها و غضروف را تسریع کرده و استقامت مفصلی توله‌های در حال رشد و سگ‌های پیر را افزایش می‌دهد.",
shortDescription: "کنسانتره خالص صدف لب سبز برای بازسازی سریع مفاصل و افزایش استقامت مفصلی.",
@ -661,7 +661,7 @@ export const PRODUCTS: Product[] = [
{
id: "arthro-tabletten",
artNo: "723003",
name: "Canino PETVITAL Arthro-Tabletten",
name: "Canina PETVITAL Arthro-Tabletten",
scientificTagline: "آنتی‌اکسیدان گیاهی برای متابولیسم استخوان",
description: "فرمول گیاهی با عصاره بید (Salix alba) و زنجبیل (Zingiber officinale) که به عنوان آنتی‌اکسیدان و ضدالتهاب طبیعی عمل کرده و خاصیت ارتجاعی استخوان را افزایش می‌دهد. متابولیسم استخوان را بهبود بخشیده و مفاصل ضعیف را تقویت می‌کند.",
shortDescription: "فرمول گیاهی بید و زنجبیل برای تقویت مفاصل ضعیف و بهبود متابولیسم استخوان.",
@ -696,7 +696,7 @@ export const PRODUCTS: Product[] = [
{
id: "biotin-tabs",
artNo: "702008",
name: "Canino PETVITAL Biotin-Tabs",
name: "Canina PETVITAL Biotin-Tabs",
scientificTagline: "دوز بالای بیوتین برای مو و پنجه‌های محکم",
description: "دوز بالای بیوتین (ویتامین H / B7) با ۱,۰۰۰,۰۰۰ میکروگرم در کیلوگرم برای جلوگیری از ریزش مو، تقویت رنگدانه‌های پوشش و محکم‌سازی پنجه‌ها. بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است.",
shortDescription: "قرص بیوتین فوق‌غلظت برای جلوگیری از ریزش مو، پوشش براق و پنجه‌های محکم.",
@ -735,7 +735,7 @@ export const PRODUCTS: Product[] = [
{
id: "mineral-tabs",
artNo: "723102",
name: "Canino PETVITAL MINERAL-Tabs",
name: "Canina PETVITAL MINERAL-Tabs",
scientificTagline: "انواع کلسیم برای تشکیل بافت استخوانی",
description: "ترکیب انواع مختلف کلسیم (کربنات کلسیم) به همراه مخمر آبجو و ویتامین D3 برای ذخیره‌سازی کلسیم در استخوان. حیاتی در دوره رشد، بارداری و شیردهی. هشدار: مصرف همزمان ویتامین D2 مجاز نیست.",
shortDescription: "کلسیم چندمنبعی با ویتامین D3 برای بارداری، شیردهی و توله‌های در حال رشد.",
@ -769,7 +769,7 @@ export const PRODUCTS: Product[] = [
{
id: "vitamin-tabs",
artNo: "712205",
name: "Canino PETVITAL VITAMIN-Tabs",
name: "Canina PETVITAL VITAMIN-Tabs",
scientificTagline: "کمپلکس کامل ویتامین‌های A تا K3",
description: "کمپلکس کامل ویتامین‌های A، B1 تا B12، D3، E و K3 از مخمر آبجو. اصلاح کمبود ویتامین، جلوگیری از خستگی، عدم تناسب و اختلالات رشد. ایده‌آل برای مادران باردار و شرایط استرس‌زا.",
shortDescription: "مولتی‌ویتامین کامل از A تا K برای رفع کمبودهای تغذیه‌ای و استرس.",
@ -801,7 +801,7 @@ export const PRODUCTS: Product[] = [
{
id: "bio-aktivator",
artNo: "712007",
name: "Canino PETVITAL Bio-Aktivator",
name: "Canina PETVITAL Bio-Aktivator",
scientificTagline: "سرم خون گاو برای تحریک اشتها و نقاهت",
description: "قطره‌های خوراکی حاوی سرم خون گاو که اشتها را تحریک کرده و روند بهبودی را در دوره نقاهت تسریع می‌کند. رفاه و هماهنگی متابولیسم را بهبود بخشیده و برای پت‌های بی‌اشتها یا پس از جراحی ایده‌آل است.",
shortDescription: "قطره سرم خون گاو برای تحریک اشتها و تسریع بهبودی در دوره نقاهت.",
@ -834,7 +834,7 @@ export const PRODUCTS: Product[] = [
{
id: "seealgen",
artNo: "130504",
name: "Canino Seealgen / Bio-Seealgenmehl",
name: "Canina Seealgen / Bio-Seealgenmehl",
scientificTagline: "جلبک دریایی ارگانیک غنی از ید و مواد معدنی",
description: "جلبک دریایی ارگانیک سرشار از ید، روی، لیزین و سلولز که رنگدانه‌های پوست، بینی و پوشش مو را پشتیبانی می‌کند. ید جزء حیاتی هورمون‌های تیروئیدی (T3 و T4) بوده و متابولیسم پایه را تنظیم می‌کند.",
shortDescription: "جلبک دریایی ارگانیک برای رنگدانه قوی، سلامت پوست و تامین ید طبیعی.",
@ -866,7 +866,7 @@ export const PRODUCTS: Product[] = [
{
id: "rinderblut-pulver",
artNo: "792016",
name: "Canino Rinderblut Pulver",
name: "Canina Rinderblut Pulver",
scientificTagline: "آهن و هموگلوبین خالص برای بازسازی خون",
description: "پودر خون کامل گاو خشک شده با ۹۲٪ پروتئین خام و آهن بالا. منبع ارزشمند هموگلوبین برای انتقال اکسیژن و رشد عضلات. مکمل عالی برای رژیم BARF جهت جبران خون از دست رفته و حمایت از سگ‌های ورزشی.",
shortDescription: "پودر خون گاو غنی از آهن برای رژیم BARF، نقاهت و سگ‌های ورزشی.",
@ -899,7 +899,7 @@ export const PRODUCTS: Product[] = [
{
id: "rinderfett-pulver",
artNo: "131235",
name: "Canino Rinderfett Pulver",
name: "Canina Rinderfett Pulver",
scientificTagline: "انرژی طبیعی از چربی گوشت گاو",
description: "پودر چربی گوشت گاو آب پز با ۷۲٪ چربی خالص و ۷۴۰ کیلوکالری انرژی. منبع عالی انرژی برای حیوانات لاغر، سگ‌های بسیار فعال و جبران کمبود چربی در وعده‌های خام.",
shortDescription: "پودر چربی گوشت گاو آب پز برای افزایش وزن و انرژی سگ‌های فعال.",
@ -932,7 +932,7 @@ export const PRODUCTS: Product[] = [
{
id: "schwarz-kummel-samen",
artNo: "131105",
name: "Canino Schwarz Kümmel Samen",
name: "Canina Schwarz Kümmel Samen",
scientificTagline: "دانه کامل سیاه دانه برای هضم و متابولیسم",
description: "دانه‌های کامل زیره سیاه مصری سرشار از اسیدهای چرب غیراشباع که هضم و متابولیسم را تنظیم کرده و سیستم دفاعی را تقویت می‌کند. برای تقویت عمومی و بهبود عملکرد بدن سگ.",
shortDescription: "دانه کامل سیاه دانه مصری برای تقویت هضم، متابولیسم و سیستم ایمنی.",
@ -966,7 +966,7 @@ export const PRODUCTS: Product[] = [
{
id: "marine-ol-mischung",
artNo: "153008",
name: "Canino Marine-Ölmischung PREMIUM",
name: "Canina Marine-Ölmischung PREMIUM",
scientificTagline: "ترکیب روغن‌های دریایی و گیاهی ممتاز",
description: "ترکیب هماهنگ روغن ماهی، روغن گردو، روغن آرگان و روغن دانه گل رز. روغن آرگان و گل رز به عنوان آنتی‌اکسیدان و ترمیم‌کننده سلولی عمل کرده و اسیدهای چرب امگا ۳ و ۶ را در تعادل بهینه تأمین می‌کنند.",
shortDescription: "ترکیب روغن‌های ممتاز دریایی و گیاهی برای تامین متعادل اسیدهای چرب.",
@ -999,7 +999,7 @@ export const PRODUCTS: Product[] = [
{
id: "taurin-fur-katzen",
artNo: "229505",
name: "Canino TAURIN Für Katzen",
name: "Canina TAURIN Für Katzen",
scientificTagline: "اسید آمینه ضروری برای قلب و بینایی گربه",
description: "تورین با غلظت ۷۰۰ گرم در کیلوگرم از مخمر آبجو. اسید آمینه ضروری شرطی برای گربه‌ها که بدن آن‌ها قادر به سنتز تورین نیست. کمبود تورین باعث دژنراسیون مرکزی شبکیه (نابینایی) و کاردیومیوپاتی متسع می‌شود.",
shortDescription: "مکمل تورین فوق‌غلظت برای پیشگیری از نابینایی و نارسایی قلبی در گربه‌ها.",
@ -1037,7 +1037,7 @@ export const PRODUCTS: Product[] = [
{
id: "welpenmilch",
artNo: "130702",
name: "Canino Welpenmilch",
name: "Canina Welpenmilch",
scientificTagline: "شیر کامل جایگزین مادر برای توله‌سگ‌ها",
description: "شیر کامل جایگزین شیر مادر با ۳۰٪ پروتئین، لاکتوز و روغن ماهی. غنی از تورین و ویتامین‌ها برای توله‌سگ‌های بی‌مادر از روز اول زندگی. ترکیب شبیه‌سازی شده با شیر سگ ماده.",
shortDescription: "شیر خشک مخصوص توله‌سگ‌های بی‌مادر با پروتئین و ویتامین بالا.",
@ -1061,14 +1061,14 @@ export const PRODUCTS: Product[] = [
name: "دکتر بکر",
title: "متخصص تولیدمثل دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
message: "شیر توله‌سگ کانینو نزدیک‌ترین ترکیب به شیر طبیعی سگ ماده را دارد."
message: "شیر توله‌سگ کانینا نزدیک‌ترین ترکیب به شیر طبیعی سگ ماده را دارد."
},
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
},
{
id: "welpenbrei",
artNo: "130603",
name: "Canino Welpenbrei",
name: "Canina Welpenbrei",
scientificTagline: "فرنی پروتئین بالا برای توله‌سگ‌های ۳ هفته به بالا",
description: "فرنی با ۲۷٪ پروتئین، غلات، گوشت و لبنیات برای پرورش سالم توله‌سگ از هفته سوم. هشدار: مصرف همزمان ویتامین D2 مجاز نیست.",
shortDescription: "فرنی پروتئین و ویتامین بالا برای شروع تغذیه کمکی توله‌سگ از هفته سوم.",
@ -1093,14 +1093,14 @@ export const PRODUCTS: Product[] = [
name: "دکتر کوهن",
title: "متخصص طب سنتی دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
message: "فرنی توله‌سگ کانینو انتقال نرم از شیر به غذای جامد را تضمین می‌کند."
message: "فرنی توله‌سگ کانینا انتقال نرم از شیر به غذای جامد را تضمین می‌کند."
},
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
},
{
id: "bio-insect-shocker",
artNo: "741304",
name: "Canino PETVITAL Bio-Insect Shocker",
name: "Canina PETVITAL Bio-Insect Shocker",
scientificTagline: "اسپری دفع‌کننده طبیعی کک و کنه",
description: "اسپری محیطی با دودکانوئیک اسید (۱۵ گرم در لیتر) و عصاره مارگوسا (چریش) که تخم‌ها و انگل‌های خارجی را به طور مؤثر از بین می‌برد. ۱۰۰٪ طبیعی و بدون مواد شیمیایی سمی.",
shortDescription: "اسپری دفع‌کننده محیطی کک، شپش و کنه با عصاره چریش.",
@ -1131,7 +1131,7 @@ export const PRODUCTS: Product[] = [
{
id: "novagard-augenpflege",
artNo: "NG0013",
name: "Canino NovaGard Green Augenpflege",
name: "Canina NovaGard Green Augenpflege",
scientificTagline: "قطره چشم ضدالتهاب با نقره کلوئیدی و هیالورونات",
description: "قطره چشمی استریل با هیالورونات سدیم (مرطوب‌کننده و محافظ قرنیه) و نقره کلوئیدی (ضدالتهاب و ضدعفونی‌کننده). ایده‌آل برای تمیز کردن چشم‌های گرفته و گریان.",
shortDescription: "قطره چشم ضدالتهاب برای تمیز کردن چشم‌های گریان و گرفته.",
@ -1162,7 +1162,7 @@ export const PRODUCTS: Product[] = [
{
id: "novagard-pfotenpflege",
artNo: "NG0016",
name: "Canino NovaGard Green Pfotenpflege",
name: "Canina NovaGard Green Pfotenpflege",
scientificTagline: "کرم ۱۰۰٪ طبیعی برای ترمیم پنجه‌های ترک خورده",
description: "کرم ۱۰۰٪ طبیعی با روغن پالپ سنجد دریایی (Sea Buckthorn)، روغن کالاندولا و پانتنول (پروویتامین B5) برای تسکین پوست خارش‌دار، التیام زخم‌ها و خراشیدگی پنجه در تابستان و زمستان.",
shortDescription: "کرم طبیعی پنجه با سنجد دریایی و کالاندولا برای زمستان و تابستان.",
@ -1193,7 +1193,7 @@ export const PRODUCTS: Product[] = [
{
id: "katzenmilch",
artNo: "230808",
name: "Canino Katzenmilch",
name: "Canina Katzenmilch",
scientificTagline: "شیر جایگزین کامل برای بچه‌گربه‌های بی‌مادر",
description: "غذای کامل جایگزین شیر مادر با ۳۰٪ پروتئین، لاکتوز، چربی نارگیل، روغن ماهی و ۱۰۰ میلی‌گرم تورین. مناسب بچه‌گربه‌های بی‌مادر از ۱ روزگی، گربه‌های مسن، بیمار و شیرده.",
shortDescription: "شیر خشک مخصوص بچه‌گربه‌های بی‌مادر با تورین بالا از بدو تولد.",
@ -1217,7 +1217,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر بکر",
title: "متخصص تولیدمثل دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
message: "شیر گربه کانینو با تورین بالا برای سلامت قلب و بینایی بچه‌گربه‌ها حیاتی است."
message: "شیر گربه کانینا با تورین بالا برای سلامت قلب و بینایی بچه‌گربه‌ها حیاتی است."
},
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
}

View File

@ -1,4 +1,4 @@
export interface ScientificTerm {
export interface ScientificTerm {
term: string;
definition: string;
wikiId?: string;
@ -42,7 +42,7 @@ export const SCIENTIFIC_TERMS: Record<string, ScientificTerm> = {
},
"نسبت Ca:P": {
term: "نسبت کلسیم به فسفر (Ca:P Ratio)",
definition: "نسبت ایده‌آل کلسیم به فسفر در رژیم حیوانات ۱.۲:۱ تا ۱.۵:۱ است. عدم تعادل این نسبت منجر به مشکلات کلیوی و استخوانی می‌شود. پودر پوسته تخم مرغ کانینو با ۳۶٪ کلسیم و ۰.۱٪ فسفر بهترین تنظیم‌کننده این نسبت است.",
definition: "نسبت ایده‌آل کلسیم به فسفر در رژیم حیوانات ۱.۲:۱ تا ۱.۵:۱ است. عدم تعادل این نسبت منجر به مشکلات کلیوی و استخوانی می‌شود. پودر پوسته تخم مرغ کانینا با ۳۶٪ کلسیم و ۰.۱٪ فسفر بهترین تنظیم‌کننده این نسبت است.",
wikiId: "nutrition"
},
"ویتامین D3": {
@ -52,17 +52,17 @@ export const SCIENTIFIC_TERMS: Record<string, ScientificTerm> = {
},
"BARF": {
term: "رژیم BARF (Biologically Appropriate Raw Food)",
definition: "رژیم غذایی خام متناسب با زیست‌شناسی حیوان که شامل گوشت خام، استخوان، اندام‌ها و سبزیجات است. مکمل‌های کانینو مانند Eierschalenpulver، Rinderblut Pulver و Rinderfett Pulver برای تکمیل این رژیم طراحی شده‌اند.",
definition: "رژیم غذایی خام متناسب با زیست‌شناسی حیوان که شامل گوشت خام، استخوان، اندام‌ها و سبزیجات است. مکمل‌های کانینا مانند Eierschalenpulver، Rinderblut Pulver و Rinderfett Pulver برای تکمیل این رژیم طراحی شده‌اند.",
wikiId: "nutrition"
},
"آغوز": {
term: "آغوز (Colostrum)",
definition: "اولین شیر پستانداران حاوی IgG, IgA, IgM و لاکتوفرین که سد دفاعی روده را تقویت کرده و ایمنی غیرفعال منتقل می‌کند. محصول Immun-Booster کانینو حاوی ۲۰٪ پودر آغوز است.",
definition: "اولین شیر پستانداران حاوی IgG, IgA, IgM و لاکتوفرین که سد دفاعی روده را تقویت کرده و ایمنی غیرفعال منتقل می‌کند. محصول Immun-Booster کانینا حاوی ۲۰٪ پودر آغوز است.",
wikiId: "immune"
},
"ال-کارنیتین": {
term: "ال-کارنیتین",
definition: "ماده‌ای شبه‌آمینواسید که اسیدهای چرب زنجیره بلند را به داخل میتوکندری کاردیومیوسیت‌ها منتقل کرده و ATP تولید می‌کند. محصول Herz Vital کانینو حاوی ۳۰,۰۰۰mg/kg ال-کارنیتین است.",
definition: "ماده‌ای شبه‌آمینواسید که اسیدهای چرب زنجیره بلند را به داخل میتوکندری کاردیومیوسیت‌ها منتقل کرده و ATP تولید می‌کند. محصول Herz Vital کانینا حاوی ۳۰,۰۰۰mg/kg ال-کارنیتین است.",
wikiId: "heart"
},
"زالزالک": {
@ -72,7 +72,7 @@ export const SCIENTIFIC_TERMS: Record<string, ScientificTerm> = {
},
"بیوتین": {
term: "بیوتین (ویتامین H / B7)",
definition: "کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز. کمبود آن منجر به ریزش مو و شکنندگی پنجه می‌شود. قرص Biotin-Tabs کانینو با ۱,۰۰۰,۰۰۰ میکروگرم در کیلوگرم قوی‌ترین دوز موجود است.",
definition: "کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز. کمبود آن منجر به ریزش مو و شکنندگی پنجه می‌شود. قرص Biotin-Tabs کانینا با ۱,۰۰۰,۰۰۰ میکروگرم در کیلوگرم قوی‌ترین دوز موجود است.",
wikiId: "skin"
},
"هیدروکسی آپاتیت": {
@ -82,7 +82,7 @@ export const SCIENTIFIC_TERMS: Record<string, ScientificTerm> = {
},
"EPA/DHA": {
term: "EPA و DHA",
definition: "ایکوزاپنتائنوئیک اسید (EPA) پیش‌ماده رزولوین‌های ضدالتهابی و دوکوزاهگزانوئیک اسید (DHA) ۳۰٪ وزن خشک مغز را تشکیل می‌دهد. نسبت ۳:۲ EPA:DHA در روغن سالمون کانینو بهینه‌سازی شده است.",
definition: "ایکوزاپنتائنوئیک اسید (EPA) پیش‌ماده رزولوین‌های ضدالتهابی و دوکوزاهگزانوئیک اسید (DHA) ۳۰٪ وزن خشک مغز را تشکیل می‌دهد. نسبت ۳:۲ EPA:DHA در روغن سالمون کانینا بهینه‌سازی شده است.",
wikiId: "omega3"
}
};

View File

@ -1,6 +1,16 @@
import api from './api';
import { PRODUCTS, Product, PetType } from "../data/products";
const CATEGORY_SLUG_TO_NAME: Record<string, string> = {
'joints': 'مفاصل و استخوان',
'immune': 'تقویت سیستم ایمنی و گوارش',
'energy': 'ویتامین‌ها و انرژی‌بخش‌ها',
'special-care': 'مراقبت‌های ویژه (پوست، دندان و چشم)',
'general': 'تقویت عمومی',
'nutrition': 'تغذیه تخصصی',
'supplements': 'مکمل‌های غذایی و درمانی',
};
export class ProductService {
private static instance: ProductService;
@ -34,7 +44,7 @@ export class ProductService {
shortDescription: data.shortDescription,
price: data.priceDisplay || `${data.priceValue.toLocaleString('fa-IR')} تومان`,
priceValue: Number(data.priceValue),
category: data.category?.name || data.category || data.categorySlug || '',
category: data.category?.name || data.category || CATEGORY_SLUG_TO_NAME[data.categorySlug] || data.categorySlug || '',
categorySlug: data.categorySlug,
unit: data.unit,
packageSize: data.packageSize,
@ -71,7 +81,7 @@ export class ProductService {
const params = new URLSearchParams();
if (filters?.category && filters.category !== "all") params.append('category', filters.category);
if (filters?.petType && filters.petType !== "all") params.append('petType', filters.petType);
if (filters?.query) params.append('query', filters.query);
if (filters?.query) params.append('search', filters.query);
try {
const response = await api.get(`/products?${params.toString()}`);

View File

@ -33,7 +33,7 @@ describe('settingsStore', () => {
it('should fetch settings successfully and map array to object', async () => {
const mockUiTexts = [
{ key: 'hero_title', value: 'Welcome to Canino' },
{ key: 'hero_title', value: 'Welcome to Canina' },
{ key: 'hero_desc', value: 'Best supplements' },
];
const mockTerms = [
@ -54,7 +54,7 @@ describe('settingsStore', () => {
await store.fetchSettings();
const state = useSettingsStore.getState();
expect(state.texts['hero_title']).toBe('Welcome to Canino');
expect(state.texts['hero_title']).toBe('Welcome to Canina');
expect(state.texts['hero_desc']).toBe('Best supplements');
expect(state.scientificTerms['mussel']).toEqual(mockTerms[0]);
expect(state.isLoading).toBe(false);

View File

@ -165,6 +165,6 @@ export const useCartStore = create<CartStore>()(
},
getTotal: () => get().getSubtotal() - get().getDiscount() + get().charityDonation,
}),
{ name: "canino-cart" }
{ name: "canina-cart" }
)
);

View File

@ -212,6 +212,6 @@ export const usePetStore = create<PetStore>()(
set({ pets: mappedPets, activePetId: get().activePetId && mappedPets.some(p => p.id === get().activePetId) ? get().activePetId : (mappedPets[0]?.id || null) });
},
}),
{ name: "canino-pets" }
{ name: "canina-pets" }
)
);

View File

@ -191,6 +191,6 @@ export const useUserStore = create<UserStore>()(
}
},
}),
{ name: "canino-user" }
{ name: "canina-user" }
)
);

View File

@ -1,6 +1,6 @@
# Application Backend Integration & Refactoring Plan
This plan details the migration of the CaninoIran frontend application from using mock data to communicating entirely with the backend APIs, adding email/password authentication, and resolving issues with the pet profile forms.
This plan details the migration of the CaninaIran frontend application from using mock data to communicating entirely with the backend APIs, adding email/password authentication, and resolving issues with the pet profile forms.
## User Review Required
> [!IMPORTANT]

View File

@ -1,5 +1,5 @@
{
"name": "Canino Iran - Official Representative",
"name": "Canina Iran - Official Representative",
"description": "The official representative of Canina pharma GmbH in Iran. Specialist in veterinary supplements and pharmaceutical-grade pet care products since 1984.",
"requestFramePermissions": [],
"majorCapabilities": [

View File

@ -7,7 +7,7 @@
"dev:backend": "cd backend && npm run start:dev",
"dev:frontend": "cd frontend/application && npm run dev",
"dev:admin": "cd frontend/admin-panel && npm run dev",
"dev": "node scripts/start-dev.js"
"dev": "node scripts/start-dev.js",
"build:backend": "cd backend && npm run build",
"build:frontend": "cd frontend/application && npm run build",
"build:admin": "cd frontend/admin-panel && npm run build",