Compare commits

..

No commits in common. "8d1b786a24be715b2e51c1d6bb3ef998b064a427" and "897b4d61ec7016dc7b0ce14c007d5cda35c7cad4" have entirely different histories.

80 changed files with 484 additions and 865 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 @@
# طرح‌واره پایگاه داده کنینا ایران (Canina 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 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
); );
-- ۴. جدول کاتالوگ محصولات کنینا (products) -- ۴. جدول کاتالوگ محصولات کانینا (products)
CREATE TABLE products ( CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
art_no VARCHAR(20) UNIQUE NOT NULL, art_no VARCHAR(20) UNIQUE NOT NULL,
@ -250,7 +250,7 @@ CREATE INDEX idx_reminder_completions_ref ON reminder_completions(reminder_id, c
"reminders": [ "reminders": [
{ {
"id": "REM-001", "id": "REM-001",
"productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کنینا فیزیکی جهت کسر انبار پت "productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کانینا فیزیکی جهت کسر انبار پت
"title": "مصرف قرص مفصل‌ساز Canhydrox", "title": "مصرف قرص مفصل‌ساز Canhydrox",
"time": "08:30", "time": "08:30",
"frequency": "روزانه", "frequency": "روزانه",

View File

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

View File

@ -24,7 +24,7 @@ async function main() {
'<p>کلسیم یکی از مهم‌ترین مواد معدنی برای رشد ساختار استخوانی است. توله‌سگ‌ها در ماه‌های اول زندگی به کلسیم بیشتری نیاز دارند تا اسکلت‌بندی محکمی داشته باشند.</p>', '<p>کلسیم یکی از مهم‌ترین مواد معدنی برای رشد ساختار استخوانی است. توله‌سگ‌ها در ماه‌های اول زندگی به کلسیم بیشتری نیاز دارند تا اسکلت‌بندی محکمی داشته باشند.</p>',
'', '',
'<h2>نسبت Ca:P (کلسیم به فسفر)</h2>', '<h2>نسبت Ca:P (کلسیم به فسفر)</h2>',
'<p>نسبت ایده‌آل کلسیم به فسفر در رژیم توله‌سگ‌ها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت می‌تواند منجر به ناهنجاری‌های استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کنینا</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>', '<p>نسبت ایده‌آل کلسیم به فسفر در رژیم توله‌سگ‌ها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت می‌تواند منجر به ناهنجاری‌های استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کانینا</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>',
'', '',
'<h2>نقش ویتامین D3 در جذب کلسیم</h2>', '<h2>نقش ویتامین D3 در جذب کلسیم</h2>',
'<p>ویتامین D3 (کوله‌کلسیفرول) جذب کلسیم از روده را تا ۳۰٪ افزایش می‌دهد. <strong>مصرف همزمان ویتامین D2 (ارگوکلسیفرول) با D3 مجاز نیست</strong> زیرا این دو با یکدیگر رقابت کرده و جذب مؤثر را کاهش می‌دهند.</p>', '<p>ویتامین D3 (کوله‌کلسیفرول) جذب کلسیم از روده را تا ۳۰٪ افزایش می‌دهد. <strong>مصرف همزمان ویتامین D2 (ارگوکلسیفرول) با D3 مجاز نیست</strong> زیرا این دو با یکدیگر رقابت کرده و جذب مؤثر را کاهش می‌دهند.</p>',
@ -49,12 +49,12 @@ async function main() {
'<li><strong>B1 (تیامین):</strong> متابولیسم کربوهیدرات‌ها و عملکرد سیستم عصبی</li>', '<li><strong>B1 (تیامین):</strong> متابولیسم کربوهیدرات‌ها و عملکرد سیستم عصبی</li>',
'<li><strong>B2 (ریبوفلاوین):</strong> تولید انرژی و سلامت پوست</li>', '<li><strong>B2 (ریبوفلاوین):</strong> تولید انرژی و سلامت پوست</li>',
'<li><strong>B6 (پیریدوکسین):</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>', '<li><strong>B12 (کوبالامین):</strong> خونسازی و عملکرد عصبی</li>',
'</ul>', '</ul>',
'', '',
'<h2>نقش بیوتین در سلامت پوشش</h2>', '<h2>نقش بیوتین در سلامت پوشش</h2>',
'<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانه‌های کلاسیک کمبود بیوتین هستند. قرص بیوتین کنینا با تأثیر از هفته چهارم، پوشش براق و پنجه‌های محکم را تضمین می‌کند.</p>', '<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانه‌های کلاسیک کمبود بیوتین هستند. قرص بیوتین کانینا با تأثیر از هفته چهارم، پوشش براق و پنجه‌های محکم را تضمین می‌کند.</p>',
'', '',
'<h2>محصولات تقویت‌کننده پوست و مو</h2>', '<h2>محصولات تقویت‌کننده پوست و مو</h2>',
'<ul>', '<ul>',

View File

@ -39,7 +39,7 @@ export async function main() {
vetName: 'دکتر علیرضا رضایی', vetName: 'دکتر علیرضا رضایی',
clinicName: 'کلینیک دامپزشکی پایتخت', clinicName: 'کلینیک دامپزشکی پایتخت',
imageUrl: '/assets/images/regenerated_image_1779109861747.png', imageUrl: '/assets/images/regenerated_image_1779109861747.png',
quote: 'مکمل‌های مفصلی کنینا از نظر سرعت جذب و اثربخشی در سگ‌های نژاد بزرگ بی‌نظیر هستند. ما نتایج فوق‌العاده‌ای روی دیسپلازی هیپ مشاهده کردیم.', quote: 'مکمل‌های مفصلی کانینا از نظر سرعت جذب و اثربخشی در سگ‌های نژاد بزرگ بی‌نظیر هستند. ما نتایج فوق‌العاده‌ای روی دیسپلازی هیپ مشاهده کردیم.',
rating: 5, rating: 5,
order: 1, order: 1,
isActive: true, isActive: true,
@ -48,7 +48,7 @@ export async function main() {
vetName: 'دکتر سارا شمس', vetName: 'دکتر سارا شمس',
clinicName: 'بیمارستان دامپزشکی تهران', clinicName: 'بیمارستان دامپزشکی تهران',
imageUrl: '/assets/images/regenerated_image_1779109861747.png', imageUrl: '/assets/images/regenerated_image_1779109861747.png',
quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربه‌ها، قرص‌های مخمر و بیوتین کنینا را تجویز می‌کنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.', quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربه‌ها، قرص‌های مخمر و بیوتین کانینا را تجویز می‌کنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.',
rating: 5, rating: 5,
order: 2, order: 2,
isActive: true, isActive: true,

View File

@ -1,8 +1,8 @@
[ [
{ {
"name": "Canina Ballaststoff Mix (فیبر میکس کنینا)", "name": "Canina Ballaststoff Mix (فیبر میکس کانینا)",
"category_slug": "immune", "category_slug": "immune",
"description": "فیبر میکس کنینا حاوی منابع فیبر گیاهی از سیب، یونجه، نخود فرنگی و هویج است که به طور روزانه رژیم غذایی خام پت را تقویت می‌کند. فیبرها برای فلور پایدار روده مهم هستند؛ به عنوان پری‌بیوتیک، آن‌ها به عنوان غذا برای باکتری‌های روده بزرگ عمل می‌کنند. اجزای گیاهی، همی‌سلولز، سلولز، لیگنین و مواد معدنی طبیعی مانند منیزیم و پتاسیم را فراهم می‌کنند. فیبر میکس کنینا را می‌توان به هر نوع غذایی اضافه کرد. حتی رژیم‌های غذایی خام و غذاهای خانگی اغلب فاقد فیبری هستند که حرکت طبیعی روده را تحریک کرده و مدفوع را حجیم‌تر می‌کند. این فیبرها می‌توانند تأثیر مثبتی بر حرکات دودی روده، مدفوع و تخلیه غدد مقعدی داشته باشند. مانان الیگوساکارید و بتا گلوکان از دیواره سلولی مخمر سیستم ایمنی روده را تقویت می‌کنند. بتا گلوکان‌ها به عنوان منبع انرژی برای باکتری‌های روده بزرگ عمل می‌کنند و توسط آن‌ها به اسیدهای چرب زنجیره کوتاه تبدیل می‌شوند که به نوبه خود به عنوان ماده مغذی برای سلول‌های دیواره روده عمل می‌کنند.", "description": "فیبر میکس کانینا حاوی منابع فیبر گیاهی از سیب، یونجه، نخود فرنگی و هویج است که به طور روزانه رژیم غذایی خام پت را تقویت می‌کند. فیبرها برای فلور پایدار روده مهم هستند؛ به عنوان پری‌بیوتیک، آن‌ها به عنوان غذا برای باکتری‌های روده بزرگ عمل می‌کنند. اجزای گیاهی، همی‌سلولز، سلولز، لیگنین و مواد معدنی طبیعی مانند منیزیم و پتاسیم را فراهم می‌کنند. فیبر میکس کانینا را می‌توان به هر نوع غذایی اضافه کرد. حتی رژیم‌های غذایی خام و غذاهای خانگی اغلب فاقد فیبری هستند که حرکت طبیعی روده را تحریک کرده و مدفوع را حجیم‌تر می‌کند. این فیبرها می‌توانند تأثیر مثبتی بر حرکات دودی روده، مدفوع و تخلیه غدد مقعدی داشته باشند. مانان الیگوساکارید و بتا گلوکان از دیواره سلولی مخمر سیستم ایمنی روده را تقویت می‌کنند. بتا گلوکان‌ها به عنوان منبع انرژی برای باکتری‌های روده بزرگ عمل می‌کنند و توسط آن‌ها به اسیدهای چرب زنجیره کوتاه تبدیل می‌شوند که به نوبه خود به عنوان ماده مغذی برای سلول‌های دیواره روده عمل می‌کنند.",
"short_description": "فیبر گیاهی پری‌بیوتیک برای تنظیم فلور روده و بهبود گوارش سگ و گربه.", "short_description": "فیبر گیاهی پری‌بیوتیک برای تنظیم فلور روده و بهبود گوارش سگ و گربه.",
"ingredients": "تفاله سیب، پودر یونجه سبز، فیبر نخود فرنگی، تفاله هویج، کیک بذر کتان، کمپلکس الیگوساکارید و بتا-گلوکان، مخمر آبجو، کنگر فرنگی، خاک دیاتومه، روغن کلزا، کربنات کلسیم.", "ingredients": "تفاله سیب، پودر یونجه سبز، فیبر نخود فرنگی، تفاله هویج، کیک بذر کتان، کمپلکس الیگوساکارید و بتا-گلوکان، مخمر آبجو، کنگر فرنگی، خاک دیاتومه، روغن کلزا، کربنات کلسیم.",
"usage_and_dosage": "گرم به ازای هر کیلوگرم وزن بدن، حداکثر 15 گرم در روز.", "usage_and_dosage": "گرم به ازای هر کیلوگرم وزن بدن، حداکثر 15 گرم در روز.",
@ -34,9 +34,9 @@
] ]
}, },
{ {
"name": "Canina Eierschalenpulver (پودر پوسته تخم مرغ کنینا)", "name": "Canina Eierschalenpulver (پودر پوسته تخم مرغ کانینا)",
"category_slug": "energy", "category_slug": "energy",
"description": "پودر پوسته تخم مرغ کنینا نه تنها کلسیم معدنی مهم مورد نیاز برای متابولیسم استخوان، سلامت دندان‌ها و فعالیت عضلات را تأمین می‌کند، بلکه سایر مواد معدنی طبیعی مانند منیزیم، پتاسیم، سدیم، آهن، مس و روی را نیز تأمین می‌کند. از آنجایی که پودر پوسته تخم مرغ کنینا ریز آسیاب شده است، به خوبی تحمل می‌شود و بنابراین جذب کلسیم بسیار بالا است. پودر پوسته تخم مرغ کنینا یک جایگزین با کیفیت بالا برای پودر استخوان گوشت برای سگ‌هایی است که به پروتئین‌های گوشتی مانند گوشت گاو، مرغ یا خوک حساسیت دارند. پودر پوسته تخم مرغ کنینا به دلیل فسفر کم و کلسیم بالا، به ویژه برای تکمیل وعده‌های غذایی گوشتی خام غنی از فسفر و کم کلسیم یا آماده‌سازی‌های گوشتی پخته شده مناسب است.", "description": "پودر پوسته تخم مرغ کانینا نه تنها کلسیم معدنی مهم مورد نیاز برای متابولیسم استخوان، سلامت دندان‌ها و فعالیت عضلات را تأمین می‌کند، بلکه سایر مواد معدنی طبیعی مانند منیزیم، پتاسیم، سدیم، آهن، مس و روی را نیز تأمین می‌کند. از آنجایی که پودر پوسته تخم مرغ کانینا ریز آسیاب شده است، به خوبی تحمل می‌شود و بنابراین جذب کلسیم بسیار بالا است. پودر پوسته تخم مرغ کانینا یک جایگزین با کیفیت بالا برای پودر استخوان گوشت برای سگ‌هایی است که به پروتئین‌های گوشتی مانند گوشت گاو، مرغ یا خوک حساسیت دارند. پودر پوسته تخم مرغ کانینا به دلیل فسفر کم و کلسیم بالا، به ویژه برای تکمیل وعده‌های غذایی گوشتی خام غنی از فسفر و کم کلسیم یا آماده‌سازی‌های گوشتی پخته شده مناسب است.",
"short_description": "تامین‌کننده کلسیم ارگانیک و طبیعی مناسب رژیم خام گوشتی.", "short_description": "تامین‌کننده کلسیم ارگانیک و طبیعی مناسب رژیم خام گوشتی.",
"ingredients": "100% پوسته تخم مرغ آسیاب شده. خاکستر خام 96%، کلسیم 36%، فسفر 0.1%.", "ingredients": "100% پوسته تخم مرغ آسیاب شده. خاکستر خام 96%، کلسیم 36%، فسفر 0.1%.",
"usage_and_dosage": "0.2 گرم به ازای هر کیلوگرم وزن بدن در روز.", "usage_and_dosage": "0.2 گرم به ازای هر کیلوگرم وزن بدن در روز.",
@ -51,9 +51,9 @@
] ]
}, },
{ {
"name": "Canina FLEXAN (فلکسان کنینا)", "name": "Canina FLEXAN (فلکسان کانینا)",
"category_slug": "joints", "category_slug": "joints",
"description": "فلکسان کنینا به طور طبیعی از سیستم اسکلتی عضلانی سگ شما پشتیبانی می‌کند. مفاصل متحرک، استخوان‌های پایدار، تحرک و تناسب اندام - پپتیدهای کلاژن زیست‌فعال، بلوک‌های سازنده اولیه بدن هستند. کلاژن پروتئین ساختاری اصلی بافت همبند است. نشان داده شده است که تأمین هدفمند هیدرولیز کلاژن، سلول‌های غضروف را فعال می‌کند و بنابراین به طور بهینه از بازسازی غضروف مفاصل پشتیبانی کرده و روند تخریب آن را کند می‌کند. همچنین سلول‌های تشکیل‌دهنده استخوان را تحریک کرده و بافت استخوان را از نظر پایداري، انعطاف‌پذیري، ماده و چگالی بهبود می‌بخشد. کلاژن زیست‌فعال موجود در مواد اولیه طبیعی با منشأ حیوانی تولید می‌شود. پپتیدهای کلاژن با فراهمی زیستی عالی مشخص می‌شوند و تقریباً بدون از دست رفتن توسط بدن جذب می‌شوند. پودر گوشت صدف لب سبز از صدف لب سبز نیوزیلند بلوک‌های ساختمانی ارزشمندی (گلیکوزآمینوگلیکان‌ها) را برای غضروف مفصل فراهم می‌کند و تمام بافت همبند را تقویت می‌کند. پپتیدهای کلاژن زیست‌فعال و پودر گوشت صدف لب سبز به صورت هم‌افزایی با هم کار می‌کنند و تأثیر را بر کل سیستم اسکلتی عضلانی بهینه می‌کنند.", "description": "فلکسان کانینا به طور طبیعی از سیستم اسکلتی عضلانی سگ شما پشتیبانی می‌کند. مفاصل متحرک، استخوان‌های پایدار، تحرک و تناسب اندام - پپتیدهای کلاژن زیست‌فعال، بلوک‌های سازنده اولیه بدن هستند. کلاژن پروتئین ساختاری اصلی بافت همبند است. نشان داده شده است که تأمین هدفمند هیدرولیز کلاژن، سلول‌های غضروف را فعال می‌کند و بنابراین به طور بهینه از بازسازی غضروف مفاصل پشتیبانی کرده و روند تخریب آن را کند می‌کند. همچنین سلول‌های تشکیل‌دهنده استخوان را تحریک کرده و بافت استخوان را از نظر پایداري، انعطاف‌پذیري، ماده و چگالی بهبود می‌بخشد. کلاژن زیست‌فعال موجود در مواد اولیه طبیعی با منشأ حیوانی تولید می‌شود. پپتیدهای کلاژن با فراهمی زیستی عالی مشخص می‌شوند و تقریباً بدون از دست رفتن توسط بدن جذب می‌شوند. پودر گوشت صدف لب سبز از صدف لب سبز نیوزیلند بلوک‌های ساختمانی ارزشمندی (گلیکوزآمینوگلیکان‌ها) را برای غضروف مفصل فراهم می‌کند و تمام بافت همبند را تقویت می‌کند. پپتیدهای کلاژن زیست‌فعال و پودر گوشت صدف لب سبز به صورت هم‌افزایی با هم کار می‌کنند و تأثیر را بر کل سیستم اسکلتی عضلانی بهینه می‌کنند.",
"short_description": "پپتیدهای کلاژن زیست‌فعال برای بازسازی غضروف و بهبود تحرک سگ.", "short_description": "پپتیدهای کلاژن زیست‌فعال برای بازسازی غضروف و بهبود تحرک سگ.",
"ingredients": "90% کلاژن هیدرولیز شده، 10% پودر گوشت صدف لب سبز.", "ingredients": "90% کلاژن هیدرولیز شده، 10% پودر گوشت صدف لب سبز.",
"usage_and_dosage": "2 گرم به ازای هر 10 کیلوگرم وزن بدن، حداکثر 15 گرم در روز.", "usage_and_dosage": "2 گرم به ازای هر 10 کیلوگرم وزن بدن، حداکثر 15 گرم در روز.",
@ -68,7 +68,7 @@
] ]
}, },
{ {
"name": "Canina HERZ VITAL (هرز ویتال کنینا)", "name": "Canina HERZ VITAL (هرز ویتال کانینا)",
"category_slug": "general", "category_slug": "general",
"description": "سگ‌ها و گربه‌های مسن اغلب از نارسایی قلبی رنج می‌برند. ال-کارنیتین می‌تواند بر تأمین انرژی قلب و عضلات اسکلتی تأثیر مثبت بگذارد. این ماده می‌تواند نشاط، انگیزه و رفاه سگ/گربه شما را افزایش دهد. ال-کارنیتین می‌تواند عملکرد فیزیولوژیکی قلب را تقویت کند.", "description": "سگ‌ها و گربه‌های مسن اغلب از نارسایی قلبی رنج می‌برند. ال-کارنیتین می‌تواند بر تأمین انرژی قلب و عضلات اسکلتی تأثیر مثبت بگذارد. این ماده می‌تواند نشاط، انگیزه و رفاه سگ/گربه شما را افزایش دهد. ال-کارنیتین می‌تواند عملکرد فیزیولوژیکی قلب را تقویت کند.",
"short_description": "تقویت‌کننده طبیعی کارکرد ماهیچه قلب برای سگ و گربه مسن.", "short_description": "تقویت‌کننده طبیعی کارکرد ماهیچه قلب برای سگ و گربه مسن.",
@ -85,9 +85,9 @@
] ]
}, },
{ {
"name": "Canina IMMUN-BOOSTER (ایمون بوستر کنینا)", "name": "Canina IMMUN-BOOSTER (ایمون بوستر کانینا)",
"category_slug": "immune", "category_slug": "immune",
"description": "بازیابی و نقاهت تغذیه‌ای > چگالی انرژی بالا، غلظت بالای مواد مغذی ضروری و مواد تشکیل‌دهنده با قابلیت هضم بالا. تقویت‌کننده سیستم ایمنی کنینا انرژی قابل هضم و در دسترس، ویتامین‌های با غلظت بالا و ایمونوگلوبولین‌های آغوز را برای سگ‌ها و گربه‌ها فراهم می‌کند. این اولین شیری است که مادر در طول و بعد از تولد تولید می‌کند. این شیر سرشار از لاکتوفرین و لیزوزیم است. تقویت‌کننده سیستم ایمنی کنینا از سیستم دفاعی بدن پشتیبانی می‌کند و مرحله بهبودی حیوانات را، به ویژه در حین و بعد از فعالیت‌های بدنی مانند زایمان (حیوان مادر و همچنین توله سگ‌ها و بچه گربه‌ها)، تمرین، ورزش و آزمایش، بهینه می‌کند. میکروب تشکیل‌دهنده اسید لاکتیک، انتروکوک فاسیوم، در تقویت‌کننده سیستم ایمنی کنینا، کلونیزاسیون سریع با لاکتوباسیل‌های مهم را تضمین می‌کند. این باکتری‌ها برای فلور روده سالم و متعادل و در نتیجه برای سیستم ایمنی پایدار روده ضروری هستند. اتصال میکروب‌های منفی به مخاط روده خنثی می‌شود. این محصول یک خمیر خوشمزه است که سگ‌ها و گربه‌ها از آن لذت می‌برند. این محصول از توله سگ‌ها/بچه گربه‌ها تا گربه‌های مسن مناسب است. برای حمایت از سلامت و عملکرد، این محصول می‌تواند جیره غذایی روزانه را افزایش دهد. این خمیر همچنین می‌تواند در مراحل خاصی از زندگی که غذای روزانه به طور مطلوب نیازهای بالای حیوان را برآورده نمی‌کند، تجویز شود.", "description": "بازیابی و نقاهت تغذیه‌ای > چگالی انرژی بالا، غلظت بالای مواد مغذی ضروری و مواد تشکیل‌دهنده با قابلیت هضم بالا. تقویت‌کننده سیستم ایمنی کانینا انرژی قابل هضم و در دسترس، ویتامین‌های با غلظت بالا و ایمونوگلوبولین‌های آغوز را برای سگ‌ها و گربه‌ها فراهم می‌کند. این اولین شیری است که مادر در طول و بعد از تولد تولید می‌کند. این شیر سرشار از لاکتوفرین و لیزوزیم است. تقویت‌کننده سیستم ایمنی کانینا از سیستم دفاعی بدن پشتیبانی می‌کند و مرحله بهبودی حیوانات را، به ویژه در حین و بعد از فعالیت‌های بدنی مانند زایمان (حیوان مادر و همچنین توله سگ‌ها و بچه گربه‌ها)، تمرین، ورزش و آزمایش، بهینه می‌کند. میکروب تشکیل‌دهنده اسید لاکتیک، انتروکوک فاسیوم، در تقویت‌کننده سیستم ایمنی کانینا، کلونیزاسیون سریع با لاکتوباسیل‌های مهم را تضمین می‌کند. این باکتری‌ها برای فلور روده سالم و متعادل و در نتیجه برای سیستم ایمنی پایدار روده ضروری هستند. اتصال میکروب‌های منفی به مخاط روده خنثی می‌شود. این محصول یک خمیر خوشمزه است که سگ‌ها و گربه‌ها از آن لذت می‌برند. این محصول از توله سگ‌ها/بچه گربه‌ها تا گربه‌های مسن مناسب است. برای حمایت از سلامت و عملکرد، این محصول می‌تواند جیره غذایی روزانه را افزایش دهد. این خمیر همچنین می‌تواند در مراحل خاصی از زندگی که غذای روزانه به طور مطلوب نیازهای بالای حیوان را برآورده نمی‌کند، تجویز شود.",
"short_description": "خمیر انرژی‌بخش و ایمن‌ساز حاوی آغوز و پروبیوتیک فعال.", "short_description": "خمیر انرژی‌بخش و ایمن‌ساز حاوی آغوز و پروبیوتیک فعال.",
"ingredients": "روغن ها و چربی های گیاهی، پودر آغوز 20%، شکر انگور.", "ingredients": "روغن ها و چربی های گیاهی، پودر آغوز 20%، شکر انگور.",
"usage_and_dosage": "توله سگ ها: 0.25 میلی لیتر. سگ های متوسط: 0.5 تا 1 میلی لیتر. گربه ها: 0.25 میلی لیتر.", "usage_and_dosage": "توله سگ ها: 0.25 میلی لیتر. سگ های متوسط: 0.5 تا 1 میلی لیتر. گربه ها: 0.25 میلی لیتر.",
@ -102,7 +102,7 @@
] ]
}, },
{ {
"name": "Canina Katzenmilch (شیر گربه کنینا)", "name": "Canina Katzenmilch (شیر گربه کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "غذای کامل جایگزین شیر مادر با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت. غذا با تمام ویتامین‌ها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای بچه‌گربه‌ها از ۱ روزگی، برای تغذیه بچه‌گربه‌های بی‌مادر، اگر تولید شیر مادر کافی نیست، برای توله‌های بزرگ، برای آماده‌سازی و در طول شیردهی، به عنوان مکمل برای گربه‌های مولد، به عنوان مکمل برای گربه‌های مسن و بیمار. فرمول این شیر بر اساس شیر طبیعی گربه مادر تهیه شده است.", "description": "غذای کامل جایگزین شیر مادر با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت. غذا با تمام ویتامین‌ها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای بچه‌گربه‌ها از ۱ روزگی، برای تغذیه بچه‌گربه‌های بی‌مادر، اگر تولید شیر مادر کافی نیست، برای توله‌های بزرگ، برای آماده‌سازی و در طول شیردهی، به عنوان مکمل برای گربه‌های مولد، به عنوان مکمل برای گربه‌های مسن و بیمار. فرمول این شیر بر اساس شیر طبیعی گربه مادر تهیه شده است.",
"short_description": "شیر خشک غنی از تورین جایگزین کامل شیر مادر برای بچه‌گربه‌ها.", "short_description": "شیر خشک غنی از تورین جایگزین کامل شیر مادر برای بچه‌گربه‌ها.",
@ -119,9 +119,9 @@
] ]
}, },
{ {
"name": "Canina Lachsol (روغن ماهی سالمون کنینا)", "name": "Canina Lachsol (روغن ماهی سالمون کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "روغن ماهی سالمون کنینا از روغن ماهی سالمون ۱۰۰٪ خالص با کیفیت غذایی ساخته شده و سرشار از اسیدهای چرب چند غیراشباع (اسیدهای چرب امگا، EPA و DPA) است. از آنجایی که این اسیدهای چرب نمی‌توانند توسط خود سگ‌ها و گربه‌ها تولید شوند، باید از منابع خارجی در غذای آنها تأمین شوند. آنها برای متابولیسم روان ضروری و حیاتی هستند. روغن ماهی سالمون کنینا از بازسازی پوست و رشد مو پشتیبانی می‌کند و کل فرآیندهای متابولیکی بدن را هماهنگ می‌کند. صرف نظر از نوع خوراک، روغن ماهی سالمون کنینا غذای حیوان شما را به عنوان یک ماده خوراکی با کیفیت بالا بهینه می‌کند.", "description": "روغن ماهی سالمون کانینا از روغن ماهی سالمون ۱۰۰٪ خالص با کیفیت غذایی ساخته شده و سرشار از اسیدهای چرب چند غیراشباع (اسیدهای چرب امگا، EPA و DPA) است. از آنجایی که این اسیدهای چرب نمی‌توانند توسط خود سگ‌ها و گربه‌ها تولید شوند، باید از منابع خارجی در غذای آنها تأمین شوند. آنها برای متابولیسم روان ضروری و حیاتی هستند. روغن ماهی سالمون کانینا از بازسازی پوست و رشد مو پشتیبانی می‌کند و کل فرآیندهای متابولیکی بدن را هماهنگ می‌کند. صرف نظر از نوع خوراک، روغن ماهی سالمون کانینا غذای حیوان شما را به عنوان یک ماده خوراکی با کیفیت بالا بهینه می‌کند.",
"short_description": "روغن سالمون ۱۰۰٪ خالص برای براقیت پوست و مو و تنظیم متابولیسم.", "short_description": "روغن سالمون ۱۰۰٪ خالص برای براقیت پوست و مو و تنظیم متابولیسم.",
"ingredients": "100% روغن طبیعی ماهی سالمون.", "ingredients": "100% روغن طبیعی ماهی سالمون.",
"usage_and_dosage": "2 میلی لیتر به ازای هر 10 کیلوگرم وزن بدن روزانه.", "usage_and_dosage": "2 میلی لیتر به ازای هر 10 کیلوگرم وزن بدن روزانه.",
@ -136,7 +136,7 @@
] ]
}, },
{ {
"name": "Canina Marine-Olmischung PREMIUM (روغن دریایی پریمیوم کنینا)", "name": "Canina Marine-Olmischung PREMIUM (روغن دریایی پریمیوم کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "روغن دریایی پریمیوم، ترکیبی هماهنگ و ویژه از روغن‌های خوراکی با کیفیت بالا است که در اثرات مثبت خود بر کل ارگانیسم، یکدیگر را به طور بهینه تکمیل می‌کنند. روغن دریایی امگا ۳ طبیعی (کنترل شده با آفت‌کش) سرشار از اسیدهای چرب اشباع نشده EPA و DHA است که برای سگ‌ها و گربه‌ها ضروری هستند. این اسیدهای چرب باید با غذا تأمین شوند، زیرا حیوانات نمی‌توانند خودشان آن‌ها را تولید کنند. ویتامین‌هایی مانند آ و د ۳ که به طور طبیعی در این محصول وجود دارند، متابولیسم استخوان و پوست را پشتیبانی می‌کنند. این محصول سرشار از آنتی‌اکسیدان‌های طبیعی است. روغن گردو، روغن دانه گل رز و روغن آرگان سرشار از ویتامین E هستند که از سلول‌ها محافظت و بازسازی می‌کند و رادیکال‌های آزاد و مضر را جذب می‌کند. ویتامین آ حاصل از روغن دانه گل رز تأثیر مثبتی بر پوست و غشاهای مخاطی دارد و به ویژه برای بینایی و رشد مهم است. روغن آرگان از دانه‌های درخت آرگان به دست می‌آید. روغن آرگان علاوه بر طیف متعادلی از اسیدهای چرب، حاوی مواد گیاهی ثانویه مانند فیتواسترول‌ها و اسکوالن است که تأثیر مثبتی بر متابولیسم سگ‌ها و گربه‌ها دارند. صرف نظر از نوع خوراک، ترکیب روغن دریایی پریمیوم تمام وعده‌های غذایی حیوان را بهبود می‌بخشد. این محصول از کمبود مواد مغذی در وعده‌های غذایی خام (ویتامین آ، ایی، د ۳ و اسیدهای چرب امگا ۳) جلوگیری می‌کند.", "description": "روغن دریایی پریمیوم، ترکیبی هماهنگ و ویژه از روغن‌های خوراکی با کیفیت بالا است که در اثرات مثبت خود بر کل ارگانیسم، یکدیگر را به طور بهینه تکمیل می‌کنند. روغن دریایی امگا ۳ طبیعی (کنترل شده با آفت‌کش) سرشار از اسیدهای چرب اشباع نشده EPA و DHA است که برای سگ‌ها و گربه‌ها ضروری هستند. این اسیدهای چرب باید با غذا تأمین شوند، زیرا حیوانات نمی‌توانند خودشان آن‌ها را تولید کنند. ویتامین‌هایی مانند آ و د ۳ که به طور طبیعی در این محصول وجود دارند، متابولیسم استخوان و پوست را پشتیبانی می‌کنند. این محصول سرشار از آنتی‌اکسیدان‌های طبیعی است. روغن گردو، روغن دانه گل رز و روغن آرگان سرشار از ویتامین E هستند که از سلول‌ها محافظت و بازسازی می‌کند و رادیکال‌های آزاد و مضر را جذب می‌کند. ویتامین آ حاصل از روغن دانه گل رز تأثیر مثبتی بر پوست و غشاهای مخاطی دارد و به ویژه برای بینایی و رشد مهم است. روغن آرگان از دانه‌های درخت آرگان به دست می‌آید. روغن آرگان علاوه بر طیف متعادلی از اسیدهای چرب، حاوی مواد گیاهی ثانویه مانند فیتواسترول‌ها و اسکوالن است که تأثیر مثبتی بر متابولیسم سگ‌ها و گربه‌ها دارند. صرف نظر از نوع خوراک، ترکیب روغن دریایی پریمیوم تمام وعده‌های غذایی حیوان را بهبود می‌بخشد. این محصول از کمبود مواد مغذی در وعده‌های غذایی خام (ویتامین آ، ایی، د ۳ و اسیدهای چرب امگا ۳) جلوگیری می‌کند.",
"short_description": "روغن دریایی امگا ۳ غنی از روغن آرگان و گل رز برای پوست و رشد.", "short_description": "روغن دریایی امگا ۳ غنی از روغن آرگان و گل رز برای پوست و رشد.",
@ -153,7 +153,7 @@
] ]
}, },
{ {
"name": "Canina Moortranke (عصاره پیت کنینا - مایع)", "name": "Canina Moortranke (عصاره پیت کانینا - مایع)",
"category_slug": "immune", "category_slug": "immune",
"description": "مواد هومیک موجود در عصاره پیت، از غشاهای مخاطی دستگاه گوارش محافظت کرده و از سیستم ایمنی روده، چه در حیوانات جوان و چه در حیوانات بالغ، پشتیبانی می‌کنند. عصاره پیت برای حیوانات خانگی یک ماده خوراکی طبیعی بدون افزودنی و بدون مواد نگهدارنده است. موارد استفاده: برای تحریک دستگاه گوارش، تغییر غلظت مدفوع، نفخ یا پس از درمان‌های آنتی‌بیوتیکی، برای تحریک اشتها، برای تقویت رشد و تقویت سیستم ایمنی، برای تقویت باروری در حیوانات نر و ماده، برای تحریک خون‌سازی و برای اتصال و حذف مواد مضر.", "description": "مواد هومیک موجود در عصاره پیت، از غشاهای مخاطی دستگاه گوارش محافظت کرده و از سیستم ایمنی روده، چه در حیوانات جوان و چه در حیوانات بالغ، پشتیبانی می‌کنند. عصاره پیت برای حیوانات خانگی یک ماده خوراکی طبیعی بدون افزودنی و بدون مواد نگهدارنده است. موارد استفاده: برای تحریک دستگاه گوارش، تغییر غلظت مدفوع، نفخ یا پس از درمان‌های آنتی‌بیوتیکی، برای تحریک اشتها، برای تقویت رشد و تقویت سیستم ایمنی، برای تقویت باروری در حیوانات نر و ماده، برای تحریک خون‌سازی و برای اتصال و حذف مواد مضر.",
"short_description": "عصاره طبیعی پیت غنی از اسید هومیک برای تنظیم فلور گوارشی.", "short_description": "عصاره طبیعی پیت غنی از اسید هومیک برای تنظیم فلور گوارشی.",
@ -303,9 +303,9 @@
] ]
}, },
{ {
"name": "Canina Rinderblut Pulver (پودر خون گاو کنینا)", "name": "Canina Rinderblut Pulver (پودر خون گاو کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "پودر خون گاو کنینا منبع ارزشمندی از رنگدانه قرمز خون (هموگلوبین) است که حاوی آهن به عنوان اتم مرکزی است. آهن اکسیژن را به خون منتقل می‌کند. سایر مواد معدنی که به طور طبیعی در پودر خون گاو وجود دارند عبارتند از کلسیم، فسفر، سدیم، پتاسیم، منیزیم، مس، منگنز و روی. علاوه بر این، خون گاو حاوی پروتئین‌هایی است که به نوبه خود از اسیدهای آمینه تشکیل شده‌اند که برای رشد ماده ژنتیکی در هر سلول بدن مورد نیاز هستند. افزودن پودر خون گاو کنینا به ویژه برای سگ‌ها و گربه‌هایی که با گوشت تازه (B.A.R.F.) تغذیه می‌شوند توصیه می‌شود زیرا گوشت خام دیگر حاوی خون نیست. به دلیل محتوای پروتئین طبیعی بالا، پودر خون گاو کنینا باعث رشد عضلات می‌شود. پودر خون گاو کنینا از ایجاد شکل بدنی هماهنگ در طول مرحله رشد پشتیبانی می‌کند. سگ‌ها و گربه‌هایی که در حال گذراندن دوره نقاهت هستند یا تحت فشار خاصی قرار دارند از مصرف پودر خون گاو کنینا سود می‌برند: این پودر از قدرت، استقامت و رفاه پشتیبانی می‌کند و عملکرد را بهبود می‌بخشد.", "description": "پودر خون گاو کانینا منبع ارزشمندی از رنگدانه قرمز خون (هموگلوبین) است که حاوی آهن به عنوان اتم مرکزی است. آهن اکسیژن را به خون منتقل می‌کند. سایر مواد معدنی که به طور طبیعی در پودر خون گاو وجود دارند عبارتند از کلسیم، فسفر، سدیم، پتاسیم، منیزیم، مس، منگنز و روی. علاوه بر این، خون گاو حاوی پروتئین‌هایی است که به نوبه خود از اسیدهای آمینه تشکیل شده‌اند که برای رشد ماده ژنتیکی در هر سلول بدن مورد نیاز هستند. افزودن پودر خون گاو کانینا به ویژه برای سگ‌ها و گربه‌هایی که با گوشت تازه (B.A.R.F.) تغذیه می‌شوند توصیه می‌شود زیرا گوشت خام دیگر حاوی خون نیست. به دلیل محتوای پروتئین طبیعی بالا، پودر خون گاو کانینا باعث رشد عضلات می‌شود. پودر خون گاو کانینا از ایجاد شکل بدنی هماهنگ در طول مرحله رشد پشتیبانی می‌کند. سگ‌ها و گربه‌هایی که در حال گذراندن دوره نقاهت هستند یا تحت فشار خاصی قرار دارند از مصرف پودر خون گاو کانینا سود می‌برند: این پودر از قدرت، استقامت و رفاه پشتیبانی می‌کند و عملکرد را بهبود می‌بخشد.",
"short_description": "منبع آهن طبیعی هموگلوبین و اسیدهای آمینه برای سگ و گربه بارف.", "short_description": "منبع آهن طبیعی هموگلوبین و اسیدهای آمینه برای سگ و گربه بارف.",
"ingredients": "100% پودر خون گاو خشک شده.", "ingredients": "100% پودر خون گاو خشک شده.",
"usage_and_dosage": "0.3 گرم به ازای هر کیلوگرم وزن بدن روزانه، حداکثر 12 گرم.", "usage_and_dosage": "0.3 گرم به ازای هر کیلوگرم وزن بدن روزانه، حداکثر 12 گرم.",
@ -327,9 +327,9 @@
] ]
}, },
{ {
"name": "Canina Rinderfett Pulver (پودر چربی گوشت گاو کنینا)", "name": "Canina Rinderfett Pulver (پودر چربی گوشت گاو کانینا)",
"category_slug": "energy", "category_slug": "energy",
"description": "پودر چربی گوشت گاو کنینا یک منبع انرژی طبیعی از چربی گوشت گاو آب‌پز و آبگوشت حاصل از آن، بدون افزودن شکر است. سگ‌ها و گربه‌ها می‌توانند انرژی چربی را از این چربی حیوانی، منحصراً چربی گاو، تبدیل کرده و برای بدن خود استفاده کنند. حیوانات جوان در حال رشد که با وجود خوردن غذای کافی، لاغر هستند و وزن کم می‌کنند، بدنشان را برای نمایش آماده می‌کنند. حیوانات باردار و شیرده از کالری چربی سود می‌برند، همچنین در مورد تغذیه توله سگ‌هایشان. برای سگ‌هایی که از نظر جسمی بسیار فعال هستند، پودر چربی گوشت گاو کنینا باید به عنوان یک منبع انرژی طبیعی برای قدرت و استقامت در وعده‌های غذایی روزانه آنها گنجانده شود. پودر چربی گوشت گاو کنینا می‌تواند به حیوانات حساس به طعم و بدخوران کمک کند تا اشتهای خود را افزایش دهند زیرا چربی در انتقال طعم عالی است. علاوه بر این، پودر چربی گوشت گاو کنینا یک منبع عالی چربی حیوانی برای بهینه‌سازی وعده‌های غذایی خام است.", "description": "پودر چربی گوشت گاو کانینا یک منبع انرژی طبیعی از چربی گوشت گاو آب‌پز و آبگوشت حاصل از آن، بدون افزودن شکر است. سگ‌ها و گربه‌ها می‌توانند انرژی چربی را از این چربی حیوانی، منحصراً چربی گاو، تبدیل کرده و برای بدن خود استفاده کنند. حیوانات جوان در حال رشد که با وجود خوردن غذای کافی، لاغر هستند و وزن کم می‌کنند، بدنشان را برای نمایش آماده می‌کنند. حیوانات باردار و شیرده از کالری چربی سود می‌برند، همچنین در مورد تغذیه توله سگ‌هایشان. برای سگ‌هایی که از نظر جسمی بسیار فعال هستند، پودر چربی گوشت گاو کانینا باید به عنوان یک منبع انرژی طبیعی برای قدرت و استقامت در وعده‌های غذایی روزانه آنها گنجانده شود. پودر چربی گوشت گاو کانینا می‌تواند به حیوانات حساس به طعم و بدخوران کمک کند تا اشتهای خود را افزایش دهند زیرا چربی در انتقال طعم عالی است. علاوه بر این، پودر چربی گوشت گاو کانینا یک منبع عالی چربی حیوانی برای بهینه‌سازی وعده‌های غذایی خام است.",
"short_description": "پودر چربی طبیعی گاو جهت افزایش سریع وزن و اشتهاآور پت‌های بدخوراک.", "short_description": "پودر چربی طبیعی گاو جهت افزایش سریع وزن و اشتهاآور پت‌های بدخوراک.",
"ingredients": "72% چربی گوشت گاو خشک شده، 28% عصاره گوشت گاو.", "ingredients": "72% چربی گوشت گاو خشک شده، 28% عصاره گوشت گاو.",
"usage_and_dosage": "نصف قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن، حداکثر 3 قاشق چایخوری روزانه.", "usage_and_dosage": "نصف قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن، حداکثر 3 قاشق چایخوری روزانه.",
@ -344,9 +344,9 @@
] ]
}, },
{ {
"name": "Canina Schwarz Kummel Samen (سیاه دانه مصری کنینا)", "name": "Canina Schwarz Kummel Samen (سیاه دانه مصری کانینا)",
"category_slug": "immune", "category_slug": "immune",
"description": "دانه‌های زیره سیاه کنینا غنی از اسیدهای چرب غیراشباع چندگانه مانند اسید لینولئیک هستند و همچنین حاوی روغن‌های ضروری و مواد تلخ مانند نیژلین می‌باشند. آنها می‌توانند تأثیر تنظیم‌کننده‌ای بر متابولیسم و هضم داشته باشند. آنها می‌توانند تأثیر مثبتی بر سلامت و عملکرد سگ شما داشته باشند و سیستم دفاعی بدن را تقویت کنند. به دلیل عطر تند و آجیلی، پذیرش دانه‌های زیره سیاه کنینا عموماً بسیار خوب است. برای سگ‌های باردار و شیرده استفاده نشود.", "description": "دانه‌های زیره سیاه کانینا غنی از اسیدهای چرب غیراشباع چندگانه مانند اسید لینولئیک هستند و همچنین حاوی روغن‌های ضروری و مواد تلخ مانند نیژلین می‌باشند. آنها می‌توانند تأثیر تنظیم‌کننده‌ای بر متابولیسم و هضم داشته باشند. آنها می‌توانند تأثیر مثبتی بر سلامت و عملکرد سگ شما داشته باشند و سیستم دفاعی بدن را تقویت کنند. به دلیل عطر تند و آجیلی، پذیرش دانه‌های زیره سیاه کانینا عموماً بسیار خوب است. برای سگ‌های باردار و شیرده استفاده نشود.",
"short_description": "دانه‌های سیاه دانه مصری جهت تقویت سیستم ایمنی و دفع انگل‌های گوارشی.", "short_description": "دانه‌های سیاه دانه مصری جهت تقویت سیستم ایمنی و دفع انگل‌های گوارشی.",
"ingredients": "100% دانه های سیاه دانه مصری.", "ingredients": "100% دانه های سیاه دانه مصری.",
"usage_and_dosage": "1 قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن روزانه، حداکثر 4 قاشق چایخوری.", "usage_and_dosage": "1 قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن روزانه، حداکثر 4 قاشق چایخوری.",
@ -361,7 +361,7 @@
] ]
}, },
{ {
"name": "Canina Seelgen Tabletten (قرص جلبک دریایی کنینا)", "name": "Canina Seelgen Tabletten (قرص جلبک دریایی کانینا)",
"category_slug": "special-care", "category_slug": "special-care",
"description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست می‌آید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانه‌های پوشش، بینی و پنجه‌ها را پشتیبانی می‌کند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه می‌کند؛ سلولز و مانیتول هضم را پشتیبانی می‌کنند. محتوای بالای ویتامین‌ها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش می‌دهد.", "description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست می‌آید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانه‌های پوشش، بینی و پنجه‌ها را پشتیبانی می‌کند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه می‌کند؛ سلولز و مانیتول هضم را پشتیبانی می‌کنند. محتوای بالای ویتامین‌ها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش می‌دهد.",
"short_description": "قرص جلبک دریایی ارگانیک جهت تیره‌سازی پیگمنت بینی، پنجه و براقیت مو.", "short_description": "قرص جلبک دریایی ارگانیک جهت تیره‌سازی پیگمنت بینی، پنجه و براقیت مو.",
@ -385,7 +385,7 @@
] ]
}, },
{ {
"name": "Canina Bio-Seelgenmehl (پودر جلبک دریایی ارگانیک کنینا)", "name": "Canina Bio-Seelgenmehl (پودر جلبک دریایی ارگانیک کانینا)",
"category_slug": "special-care", "category_slug": "special-care",
"description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست می‌آید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانه‌های پوشش، بینی و پنجه‌ها را پشتیبانی می‌کند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه می‌کند؛ سلولز و مانیتول هضم را پشتیبانی می‌کنند. محتوای بالای ویتامین‌ها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش می‌دهد.", "description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست می‌آید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانه‌های پوشش، بینی و پنجه‌ها را پشتیبانی می‌کند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه می‌کند؛ سلولز و مانیتول هضم را پشتیبانی می‌کنند. محتوای بالای ویتامین‌ها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش می‌دهد.",
"short_description": "پودر خالص جلبک دریایی ارگانیک برای تقویت پیگمنت‌های تیره و غده تیروئید.", "short_description": "پودر خالص جلبک دریایی ارگانیک برای تقویت پیگمنت‌های تیره و غده تیروئید.",
@ -402,7 +402,7 @@
] ]
}, },
{ {
"name": "Canina TAURIN Fur Katzen (پودر تورین مخصوص گربه‌ها کنینا)", "name": "Canina TAURIN Fur Katzen (پودر تورین مخصوص گربه‌ها کانینا)",
"category_slug": "special-care", "category_slug": "special-care",
"description": "تورین یک اسید آمینه مبتنی بر گوگرد است که در تمام سلول‌های بدن حیوانات یافت می‌شود. گربه‌ها نمی‌توانند خود تورین تولید کنند. تورین برای آنها ضروری (حیاتی) است و بنابراین باید با غذا تأمین شود. تورین دارای اثر سوخت و ساز است، سیستم ایمنی را تقویت می‌کند، از بینایی و عملکرد قلب پشتیبانی می‌کند و پوست و پوشش را بهبود می‌بخشد. مواد معدنی و آنزیم‌های ارزشمندی را فراهم می‌کند، مخمر آبجو موجود در این محصول، ویتامین‌های گروه بی که تأثیر مثبتی بر سوخت و ساز بدن دارند و سیستم ایمنی را تقویت می‌کنند.", "description": "تورین یک اسید آمینه مبتنی بر گوگرد است که در تمام سلول‌های بدن حیوانات یافت می‌شود. گربه‌ها نمی‌توانند خود تورین تولید کنند. تورین برای آنها ضروری (حیاتی) است و بنابراین باید با غذا تأمین شود. تورین دارای اثر سوخت و ساز است، سیستم ایمنی را تقویت می‌کند، از بینایی و عملکرد قلب پشتیبانی می‌کند و پوست و پوشش را بهبود می‌بخشد. مواد معدنی و آنزیم‌های ارزشمندی را فراهم می‌کند، مخمر آبجو موجود در این محصول، ویتامین‌های گروه بی که تأثیر مثبتی بر سوخت و ساز بدن دارند و سیستم ایمنی را تقویت می‌کنند.",
"short_description": "پودر تورین ۱۰۰٪ خالص و مخمر آبجو برای سلامت قلب و بینایی گربه‌ها.", "short_description": "پودر تورین ۱۰۰٪ خالص و مخمر آبجو برای سلامت قلب و بینایی گربه‌ها.",
@ -419,7 +419,7 @@
] ]
}, },
{ {
"name": "Canina Velox Gelenkenergie (ولوکس ژلنک‌انرژی کنینا)", "name": "Canina Velox Gelenkenergie (ولوکس ژلنک‌انرژی کانینا)",
"category_slug": "joints", "category_slug": "joints",
"description": "قدرت متمرکز صدف لب سبز نیوزیلندی برای سیستم اسکلتی عضلانی و عملکرد دوست چهارپای شما! این محصول برای تأمین با کیفیت بالای گلیکوزآمینوگلیکان‌ها به سیستم اسکلتی عضلانی استفاده می‌شود که در صدف لب سبز نیوزیلندی موجود است. گگ‌ها، مانند سولفات کندرویتین، سولفات هپاران و اسید هیالورونیک، ساختارهای بافت همبند مانند تاندون‌ها، رباط‌ها، غضروف مفاصل و دیسک‌های بین مهره‌ای را تثبیت و بازسازی می‌کنند. عملکرد دوست چهارپای شما بهبود می‌یابد و در نتیجه سلامت آنها را ارتقا می‌دهد. اسیدهای چرب امگا طبیعی به طور کلی سهم ارزشمندی در متابولیسم کلی و به طور خاص در متابولیسم مفاصل دارند. ظرفیت بافری غضروف مفصلی در عملکرد فیزیولوژیکی آن پشتیبانی می‌شود.", "description": "قدرت متمرکز صدف لب سبز نیوزیلندی برای سیستم اسکلتی عضلانی و عملکرد دوست چهارپای شما! این محصول برای تأمین با کیفیت بالای گلیکوزآمینوگلیکان‌ها به سیستم اسکلتی عضلانی استفاده می‌شود که در صدف لب سبز نیوزیلندی موجود است. گگ‌ها، مانند سولفات کندرویتین، سولفات هپاران و اسید هیالورونیک، ساختارهای بافت همبند مانند تاندون‌ها، رباط‌ها، غضروف مفاصل و دیسک‌های بین مهره‌ای را تثبیت و بازسازی می‌کنند. عملکرد دوست چهارپای شما بهبود می‌یابد و در نتیجه سلامت آنها را ارتقا می‌دهد. اسیدهای چرب امگا طبیعی به طور کلی سهم ارزشمندی در متابولیسم کلی و به طور خاص در متابولیسم مفاصل دارند. ظرفیت بافری غضروف مفصلی در عملکرد فیزیولوژیکی آن پشتیبانی می‌شود.",
"short_description": "پودر ۱۰۰٪ خالص صدف لب‌سبز نیوزیلندی برای بازسازی مفاصل و تاندون‌ها.", "short_description": "پودر ۱۰۰٪ خالص صدف لب‌سبز نیوزیلندی برای بازسازی مفاصل و تاندون‌ها.",
@ -436,9 +436,9 @@
] ]
}, },
{ {
"name": "Canina Welpenbrei (سرلاک توله سگ - ولپن‌برای کنینا)", "name": "Canina Welpenbrei (سرلاک توله سگ - ولپن‌برای کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "فرنی توله سگ کنینا پرورش سالم توله سگ‌های شما را ارتقا می‌دهد. طیف گسترده‌ای از پروتئین‌ها، ترکیب مناسب مواد مغذی و فیبر و محتوای بالای مواد معدنی، عناصر کمیاب و ویتامین‌ها، این خوراک را به یک محصول برتر تبدیل می‌کند. از آنجایی که فقط شیر توله سگ کنینا باید در طول ۳ هفته اول به توله سگ‌ها داده شود، فرنی توله سگ کنینا را می‌توان از این مرحله شروع کرد. توله سگ‌ها هنوز باید شیر توله سگ دریافت کنند و این مقدار فقط باید از ۶ هفتگی کاهش یابد. رشد بهینه دندان‌ها و سیستم اسکلتی تضمین شود. تجویز همزمان ویتامین دی ۲ مجاز نیست.", "description": "فرنی توله سگ کانینا پرورش سالم توله سگ‌های شما را ارتقا می‌دهد. طیف گسترده‌ای از پروتئین‌ها، ترکیب مناسب مواد مغذی و فیبر و محتوای بالای مواد معدنی، عناصر کمیاب و ویتامین‌ها، این خوراک را به یک محصول برتر تبدیل می‌کند. از آنجایی که فقط شیر توله سگ کانینا باید در طول ۳ هفته اول به توله سگ‌ها داده شود، فرنی توله سگ کانینا را می‌توان از این مرحله شروع کرد. توله سگ‌ها هنوز باید شیر توله سگ دریافت کنند و این مقدار فقط باید از ۶ هفتگی کاهش یابد. رشد بهینه دندان‌ها و سیستم اسکلتی تضمین شود. تجویز همزمان ویتامین دی ۲ مجاز نیست.",
"short_description": "غذای کمکی توله سگ از ۳ هفتگی سرشار از کلسیم برای رشد اسکلتی.", "short_description": "غذای کمکی توله سگ از ۳ هفتگی سرشار از کلسیم برای رشد اسکلتی.",
"ingredients": "غلات، گوشت و فرآورده های فرعی حیوانی، فرآورده های فرعی گیاهی، شیر و محصولات لبنی، مخمر.", "ingredients": "غلات، گوشت و فرآورده های فرعی حیوانی، فرآورده های فرعی گیاهی، شیر و محصولات لبنی، مخمر.",
"usage_and_dosage": "1 قسمت فرنی با 3 قسمت آب گرم مخلوط شود. از سن 3 تا 6 هفتگی.", "usage_and_dosage": "1 قسمت فرنی با 3 قسمت آب گرم مخلوط شود. از سن 3 تا 6 هفتگی.",
@ -453,7 +453,7 @@
] ]
}, },
{ {
"name": "Canina Welpenmilch (شیر خشک توله سگ کنینا)", "name": "Canina Welpenmilch (شیر خشک توله سگ کانینا)",
"category_slug": "nutrition", "category_slug": "nutrition",
"description": "شیر مخصوص توله سگ با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت تغذیه با تمام ویتامین‌ها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای توله سگ‌ها از ۱ روزگی، برای تغذیه توله سگ‌های بی مادر - اگر تولید شیر مادر کافی نیست - برای توله‌های بزرگ - برای آماده‌سازی و در طول شیردهی - به عنوان مکمل برای سگ‌های کار و پرورش - به عنوان مکمل برای سگ‌های مسن و بیمار. طرز تهیه: بر اساس شیر طبیعی سگ مادر، نوشیدنی‌های شیر را با ۴ قسمت وزنی آب (۸۰٪) و ۱ قسمت وزنی شیر توله سگ (۲۰٪) آماده کنید.", "description": "شیر مخصوص توله سگ با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت تغذیه با تمام ویتامین‌ها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای توله سگ‌ها از ۱ روزگی، برای تغذیه توله سگ‌های بی مادر - اگر تولید شیر مادر کافی نیست - برای توله‌های بزرگ - برای آماده‌سازی و در طول شیردهی - به عنوان مکمل برای سگ‌های کار و پرورش - به عنوان مکمل برای سگ‌های مسن و بیمار. طرز تهیه: بر اساس شیر طبیعی سگ مادر، نوشیدنی‌های شیر را با ۴ قسمت وزنی آب (۸۰٪) و ۱ قسمت وزنی شیر توله سگ (۲۰٪) آماده کنید.",
"short_description": "شیر خشک غنی از پروتئین جایگزین کامل شیر مادر مخصوص توله سگ‌ها.", "short_description": "شیر خشک غنی از پروتئین جایگزین کامل شیر مادر مخصوص توله سگ‌ها.",
@ -494,9 +494,9 @@
] ]
}, },
{ {
"name": "Canina Mikrosilber Zahngel (ژل دندان میکروسیلور کنینا)", "name": "Canina Mikrosilber Zahngel (ژل دندان میکروسیلور کانینا)",
"category_slug": "special-care", "category_slug": "special-care",
"description": "ژل دندانی میکروسیلور کنینا با عصاره دانه گریپ فروت مشکلات اصلی بهداشت دهان و دندان در سگ‌ها و گربه‌ها، مانند پلاک، جرم و التهاب لثه را برطرف می‌کند. اثر تمیزکنندگی دندان بر اساس فرمولاسیونی از میکروسیلور و عصاره دانه گریپ فروت است که به خوبی تحمل می‌شود. در صورت استفاده منظم، تأثیر واقعی بر تشکیل جرم جدید دارد. مصرف آن بی خطر است. بیوفلاونوئیدهای موجود در عصاره دانه گریپ فروت دارای اثر آنتی‌اکسیدانی هستند. آنها به محافظت از دندان‌ها در برابر حملات باکتری‌های پلاک کمک می‌کنند. ویتامین سی موجود در این محصول از سلامت لثه‌ها پشتیبانی می‌کند و اسیدهای آمینه و چرب عصاره دانه گریپ فروت، حل شدن پلاک دندان را تقویت می‌کنند.", "description": "ژل دندانی میکروسیلور کانینا با عصاره دانه گریپ فروت مشکلات اصلی بهداشت دهان و دندان در سگ‌ها و گربه‌ها، مانند پلاک، جرم و التهاب لثه را برطرف می‌کند. اثر تمیزکنندگی دندان بر اساس فرمولاسیونی از میکروسیلور و عصاره دانه گریپ فروت است که به خوبی تحمل می‌شود. در صورت استفاده منظم، تأثیر واقعی بر تشکیل جرم جدید دارد. مصرف آن بی خطر است. بیوفلاونوئیدهای موجود در عصاره دانه گریپ فروت دارای اثر آنتی‌اکسیدانی هستند. آنها به محافظت از دندان‌ها در برابر حملات باکتری‌های پلاک کمک می‌کنند. ویتامین سی موجود در این محصول از سلامت لثه‌ها پشتیبانی می‌کند و اسیدهای آمینه و چرب عصاره دانه گریپ فروت، حل شدن پلاک دندان را تقویت می‌کنند.",
"short_description": "ژل دندان تخصصی برای از بین بردن پلاک، تارتار و بوی بد دهان.", "short_description": "ژل دندان تخصصی برای از بین بردن پلاک، تارتار و بوی بد دهان.",
"ingredients": "آب، پلی گلیسریل-4-کاپرات، کربومر، نقره میکروسیلور، عصاره دانه گریپ فروت، ویتامین C.", "ingredients": "آب، پلی گلیسریل-4-کاپرات، کربومر، نقره میکروسیلور، عصاره دانه گریپ فروت، ویتامین C.",
"usage_and_dosage": "روزانه یک بار ترجیحا عصرها روی لثه و قسمت بیرونی دندان ها مالیده شود.", "usage_and_dosage": "روزانه یک بار ترجیحا عصرها روی لثه و قسمت بیرونی دندان ها مالیده شود.",
@ -513,7 +513,7 @@
{ {
"name": "Canina Nova Gard Green Augenpflege (قطره تمیزکننده چشم نوواگارد گرین)", "name": "Canina Nova Gard Green Augenpflege (قطره تمیزکننده چشم نوواگارد گرین)",
"category_slug": "special-care", "category_slug": "special-care",
"description": "مراقبت صحیح از چشم‌ها و گوش‌ها برای سلامت و رفاه سگ‌ها و گربه‌ها بسیار مهم است. آبریزش یا گرفتگی چشم، مانند خارش گوش‌ها، به ویژه در گربه‌ها به طور کلی و در سگ‌هایی با گوش‌های افتاده، یک مشکل روزمره است. پیشگیری با یک محصول مراقبتی طبیعی، ملایم و مؤثر که به طور مؤثر از درمان دامپزشکی نیز پشتیبانی می‌کند. مراقبت از چشم کنینا (برای سگ‌ها و گربه‌ها) چشم‌های گرفته/گریان حیوانات (به علاوه ناحیه چشم) را تمیز و مراقبت می‌کند. با چکاندن قطره در چشم، چشم‌های تحریک شده تسکین می‌یابند. این محصول را می‌توان برای مراقبت روزانه از چشم استفاده کرد و از چسبندگی و سوزش مجدد جلوگیری می‌کند. استفاده نوآورانه از نقره کلوئیدی از التهاب جلوگیری می‌کند.", "description": "مراقبت صحیح از چشم‌ها و گوش‌ها برای سلامت و رفاه سگ‌ها و گربه‌ها بسیار مهم است. آبریزش یا گرفتگی چشم، مانند خارش گوش‌ها، به ویژه در گربه‌ها به طور کلی و در سگ‌هایی با گوش‌های افتاده، یک مشکل روزمره است. پیشگیری با یک محصول مراقبتی طبیعی، ملایم و مؤثر که به طور مؤثر از درمان دامپزشکی نیز پشتیبانی می‌کند. مراقبت از چشم کانینا (برای سگ‌ها و گربه‌ها) چشم‌های گرفته/گریان حیوانات (به علاوه ناحیه چشم) را تمیز و مراقبت می‌کند. با چکاندن قطره در چشم، چشم‌های تحریک شده تسکین می‌یابند. این محصول را می‌توان برای مراقبت روزانه از چشم استفاده کرد و از چسبندگی و سوزش مجدد جلوگیری می‌کند. استفاده نوآورانه از نقره کلوئیدی از التهاب جلوگیری می‌کند.",
"short_description": "قطره استریل حاوی نقره کلوئیدی جهت رفع التهاب و ترشحات چشم پت.", "short_description": "قطره استریل حاوی نقره کلوئیدی جهت رفع التهاب و ترشحات چشم پت.",
"ingredients": "آب، هیالورونات سدیم، نقره کلوئیدی، رتینول پالمیتات.", "ingredients": "آب، هیالورونات سدیم، نقره کلوئیدی، رتینول پالمیتات.",
"usage_and_dosage": "چند قطره روزانه روی کیسه ملتحمه چشم ریخته شود. اطراف چشم تمیز شود.", "usage_and_dosage": "چند قطره روزانه روی کیسه ملتحمه چشم ریخته شود. اطراف چشم تمیز شود.",

View File

@ -455,16 +455,16 @@ export async function main() {
// 3. Seed some Blogs // 3. Seed some Blogs
const blog1Content = [ const blog1Content = [
'<p><strong>تغذیه صحیح سگ‌های بالغ</strong> یکی از مهم‌ترین عوامل در حفظ سلامت و افزایش طول عمر آن‌هاست. برند کنینا (Canina) با بیش از ۴۰ سال سابقه در تولید مکمل‌های دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>', '<p><strong>تغذیه صحیح سگ‌های بالغ</strong> یکی از مهم‌ترین عوامل در حفظ سلامت و افزایش طول عمر آن‌هاست. برند کانینا (Canina) با بیش از ۴۰ سال سابقه در تولید مکمل‌های دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>',
'', '',
'<h2>اصول تغذیه سگ بالغ</h2>', '<h2>اصول تغذیه سگ بالغ</h2>',
'<p>سگ‌های بالغ به رژیم غذایی متعادل حاوی پروتئین، چربی، کربوهیدرات، ویتامین‌ها و مواد معدنی نیاز دارند. نسبت Ca:P (کلسیم به فسفر) باید در محدوده ۱.۲:۱ تا ۱.۵:۱ باشد. هرگونه عدم تعادل در این نسبت می‌تواند منجر به مشکلات کلیوی و استخوانی شود.</p>', '<p>سگ‌های بالغ به رژیم غذایی متعادل حاوی پروتئین، چربی، کربوهیدرات، ویتامین‌ها و مواد معدنی نیاز دارند. نسبت Ca:P (کلسیم به فسفر) باید در محدوده ۱.۲:۱ تا ۱.۵:۱ باشد. هرگونه عدم تعادل در این نسبت می‌تواند منجر به مشکلات کلیوی و استخوانی شود.</p>',
'', '',
'<h2>نقش مکمل‌ها در رژیم غذایی</h2>', '<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>', '<h2>اسیدهای چرب ضروری</h2>',
'<p>روغن سالمون کنینا (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج می‌شود و تمام ویتامین‌های حساس به حرارت را حفظ می‌کند. EPA پیش‌ماده رزولوین‌های ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل می‌دهد.</p>', '<p>روغن سالمون کانینا (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج می‌شود و تمام ویتامین‌های حساس به حرارت را حفظ می‌کند. EPA پیش‌ماده رزولوین‌های ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل می‌دهد.</p>',
'', '',
'<h2>مراقبت از مفاصل</h2>', '<h2>مراقبت از مفاصل</h2>',
'<p>با افزایش سن سگ، غضروف مفصلی تحلیل می‌رود. گلیکوزآمینوگلیکان‌های صدف لب سبز (GAG) با جذب مولکول‌های آب در ماتریکس غضروفی، خاصیت بافری مفاصل را بازیابی می‌کنند. <strong>CANHYDROX GAG</strong> و <strong>FLEXAN</strong> حاوی این ترکیبات حیاتی هستند.</p>', '<p>با افزایش سن سگ، غضروف مفصلی تحلیل می‌رود. گلیکوزآمینوگلیکان‌های صدف لب سبز (GAG) با جذب مولکول‌های آب در ماتریکس غضروفی، خاصیت بافری مفاصل را بازیابی می‌کنند. <strong>CANHYDROX GAG</strong> و <strong>FLEXAN</strong> حاوی این ترکیبات حیاتی هستند.</p>',
@ -479,12 +479,12 @@ export async function main() {
].join('\n'); ].join('\n');
const blog2Content = [ const blog2Content = [
'<p><strong>کنینا (Canina)</strong> نماینده رسمی برند <strong>Canina pharma GmbH</strong> در ایران است. این شرکت آلمانی در سال ۱۹۸۴ توسط <strong>پتر و کریستین کرشن‌مایر</strong> در شهر برگیش گلادباخ تأسیس شد و به یکی از پیشگامان تولید مکمل‌های طبیعی دامپزشکی در اروپا تبدیل شده است.</p>', '<p><strong>کانینا (Canina)</strong> نماینده رسمی برند <strong>Canina pharma GmbH</strong> در ایران است. این شرکت آلمانی در سال ۱۹۸۴ توسط <strong>پتر و کریستین کرشن‌مایر</strong> در شهر برگیش گلادباخ تأسیس شد و به یکی از پیشگامان تولید مکمل‌های طبیعی دامپزشکی در اروپا تبدیل شده است.</p>',
'', '',
'<h2>فلسفه Canina: "مادر طبیعت بهترین نسخه را می‌داند"</h2>', '<h2>فلسفه Canina: "مادر طبیعت بهترین نسخه را می‌داند"</h2>',
'<p>تمام محصولات کنینا بر پایه مواد اولیه طبیعی و با فرآیندهای پیشرفته تولید می‌شوند. این شرکت دارای گواهی‌های معتبر <strong>IFS (International Featured Standard)</strong> و <strong>HACCP</strong> است و محصولات آن در بیش از ۴۰ کشور جهان توزیع می‌شود.</p>', '<p>تمام محصولات کانینا بر پایه مواد اولیه طبیعی و با فرآیندهای پیشرفته تولید می‌شوند. این شرکت دارای گواهی‌های معتبر <strong>IFS (International Featured Standard)</strong> و <strong>HACCP</strong> است و محصولات آن در بیش از ۴۰ کشور جهان توزیع می‌شود.</p>',
'', '',
'<h2>چرا مکمل‌های کنینا در ایران؟</h2>', '<h2>چرا مکمل‌های کانینا در ایران؟</h2>',
'<ul>', '<ul>',
'<li><strong>کیفیت آلمانی:</strong> تمام محصولات در کارخانه برگیش گلادباخ تحت نظارت دامپزشکان تولید می‌شوند</li>', '<li><strong>کیفیت آلمانی:</strong> تمام محصولات در کارخانه برگیش گلادباخ تحت نظارت دامپزشکان تولید می‌شوند</li>',
'<li><strong>بدون مواد مصنوعی:</strong> فاقد رنگ، طعم و نگهدارنده مصنوعی</li>', '<li><strong>بدون مواد مصنوعی:</strong> فاقد رنگ، طعم و نگهدارنده مصنوعی</li>',
@ -499,7 +499,7 @@ export async function main() {
'<p><strong>قلب و انرژی:</strong> Herz Vital (ال-کارنیتین و زالزالک)، Energy-Gel (ویتامین‌های گروه B)</p>', '<p><strong>قلب و انرژی:</strong> Herz Vital (ال-کارنیتین و زالزالک)، Energy-Gel (ویتامین‌های گروه B)</p>',
'', '',
'<h2>تعهد به سلامت حیوانات</h2>', '<h2>تعهد به سلامت حیوانات</h2>',
'<p>کنینا به عنوان نماینده رسمی کنینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بسته‌بندی اصلی آلمان و بارکد اختصاصی هستند.</p>', '<p>کانینا به عنوان نماینده رسمی کانینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بسته‌بندی اصلی آلمان و بارکد اختصاصی هستند.</p>',
].join('\n'); ].join('\n');
const blogs = [ const blogs = [
@ -511,7 +511,7 @@ export async function main() {
isPublished: true, isPublished: true,
}, },
{ {
title: 'چرا مکمل‌های کنینا؟', title: 'چرا مکمل‌های کانینا؟',
slug: 'why-canino-supplements', slug: 'why-canino-supplements',
content: blog2Content, content: blog2Content,
authorId: adminId, authorId: adminId,

View File

@ -24,7 +24,7 @@ const UI_TEXTS: Record<string, string> = {
"nav_pet_switcher_title": "تغییر پت یا مدیریت حساب", "nav_pet_switcher_title": "تغییر پت یا مدیریت حساب",
"nav_register_pet": "ثبت همدم (Pet) جدید", "nav_register_pet": "ثبت همدم (Pet) جدید",
"nav_wallet_orders": "کیف پول و سفارشات", "nav_wallet_orders": "کیف پول و سفارشات",
"nav_logout": "خروج از حساب کنینا", "nav_logout": "خروج از حساب کانینا",
"nav_login": "ورود / ثبت‌نام", "nav_login": "ورود / ثبت‌نام",
"nav_cart": "سبد خرید", "nav_cart": "سبد خرید",
@ -44,7 +44,7 @@ const UI_TEXTS: Record<string, string> = {
// === Smart Advisor === // === Smart Advisor ===
"advisor_badge": "تکنولوژی پایش هوشمند", "advisor_badge": "تکنولوژی پایش هوشمند",
"advisor_title": "دستیار سلامت کنینا", "advisor_title": "دستیار سلامت کانینا",
"advisor_subtitle": "فقط چند قدم تا صدور شناسنامه هوشمند و دریافت پیشنهادات تخصصی", "advisor_subtitle": "فقط چند قدم تا صدور شناسنامه هوشمند و دریافت پیشنهادات تخصصی",
"advisor_step1_title": "گام اول: هویت بصری", "advisor_step1_title": "گام اول: هویت بصری",
"advisor_step1_desc": "همدم شما رو با چه اسمی صدا می‌زنید؟", "advisor_step1_desc": "همدم شما رو با چه اسمی صدا می‌زنید؟",
@ -69,7 +69,7 @@ const UI_TEXTS: Record<string, string> = {
"featured_badge": "بیشترین انتخاب توسط دامپزشکان", "featured_badge": "بیشترین انتخاب توسط دامپزشکان",
"featured_title_line1": "محصولات برگزیده و راهکارهای", "featured_title_line1": "محصولات برگزیده و راهکارهای",
"featured_title_line2": "درمان تخصصی", "featured_title_line2": "درمان تخصصی",
"featured_desc": "محصولات دارویی کنینا با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شده‌اند.", "featured_desc": "محصولات دارویی کانینا با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شده‌اند.",
"featured_view_all": "مشاهده تمامی محصولات", "featured_view_all": "مشاهده تمامی محصولات",
"product_view_details": "مشاهده جزییات", "product_view_details": "مشاهده جزییات",
"featured_no_products_title": "هیچ محصولی یافت نشد", "featured_no_products_title": "هیچ محصولی یافت نشد",
@ -79,7 +79,7 @@ const UI_TEXTS: Record<string, string> = {
"videos_badge": "Vet Insights", "videos_badge": "Vet Insights",
"videos_title": "مشاوره ویدئویی", "videos_title": "مشاوره ویدئویی",
"videos_title_highlight": "دوست دامپزشک پت شما", "videos_title_highlight": "دوست دامپزشک پت شما",
"videos_desc": "متخصصین آلمانی کنینا مستقیماً با شما صحبت می‌کنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.", "videos_desc": "متخصصین آلمانی کانینا مستقیماً با شما صحبت می‌کنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.",
"videos_view_all": "مشاهده همه ویدئوها", "videos_view_all": "مشاهده همه ویدئوها",
// === Navigation Cards (Home Page) === // === Navigation Cards (Home Page) ===
@ -87,7 +87,7 @@ const UI_TEXTS: Record<string, string> = {
"nav_card_shop_desc": "دسترسی به تمامی محصولات بر اساس علائم بالینی و نیازهای پت شما.", "nav_card_shop_desc": "دسترسی به تمامی محصولات بر اساس علائم بالینی و نیازهای پت شما.",
"nav_card_shop_cta": "کاتالوگ کامل محصولات", "nav_card_shop_cta": "کاتالوگ کامل محصولات",
"nav_card_wiki_title": "دانشنامه علمی", "nav_card_wiki_title": "دانشنامه علمی",
"nav_card_wiki_desc": "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کنینا.", "nav_card_wiki_desc": "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینا.",
"nav_card_wiki_cta": "مطالعه مقالات تخصصی", "nav_card_wiki_cta": "مطالعه مقالات تخصصی",
// === About Section === // === About Section ===
@ -102,12 +102,12 @@ const UI_TEXTS: Record<string, string> = {
// === CTA Section === // === CTA Section ===
"cta_title": "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟", "cta_title": "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟",
"cta_desc": "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست.", "cta_desc": "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست.",
"cta_btn_primary": "دریافت رژیم مکمل رایگان", "cta_btn_primary": "دریافت رژیم مکمل رایگان",
"cta_btn_secondary": "پروانه دامپزشکی و اصالت کالا", "cta_btn_secondary": "پروانه دامپزشکی و اصالت کالا",
// === Footer === // === Footer ===
"footer_brand_title": "کنینا ایران", "footer_brand_title": "کانینا ایران",
"footer_brand_subtitle": "نماینده رسمی در ایران", "footer_brand_subtitle": "نماینده رسمی در ایران",
"footer_brand_desc": "تدارک هوشمندانه سلامت برای همراهان وفادار شما. واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان با سابقه ۴۰ سال نوآوری.", "footer_brand_desc": "تدارک هوشمندانه سلامت برای همراهان وفادار شما. واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان با سابقه ۴۰ سال نوآوری.",
"footer_links_title": "دسترسی سریع", "footer_links_title": "دسترسی سریع",
@ -122,11 +122,11 @@ const UI_TEXTS: Record<string, string> = {
"footer_email_label": "مکاتبات رسمی", "footer_email_label": "مکاتبات رسمی",
"footer_email": "info@canino-iran.com", "footer_email": "info@canino-iran.com",
"footer_address_label": "دفتر مرکزی", "footer_address_label": "دفتر مرکزی",
"footer_address": "تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹", "footer_address": "تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹",
"footer_auth_title": "اصالت کالا تضمین می‌شود", "footer_auth_title": "اصالت کالا تضمین می‌شود",
"footer_auth_desc": "تمامی محصولات دارای لیبل اصالت وزارت بهداشت و QR Code اختصاصی هستند.", "footer_auth_desc": "تمامی محصولات دارای لیبل اصالت وزارت بهداشت و QR Code اختصاصی هستند.",
"footer_auth_badge": "اصالت آلمانی کنینا", "footer_auth_badge": "اصالت آلمانی کانینا",
"footer_copyright": "© ۲۰۲۶ کنینا ایران. تمامی حقوق محفوظ است.", "footer_copyright": "© ۲۰۲۶ کانینا ایران. تمامی حقوق محفوظ است.",
"footer_about": "درباره ما", "footer_about": "درباره ما",
"footer_contact": "تماس با ما", "footer_contact": "تماس با ما",
"footer_privacy": "حریم خصوصی", "footer_privacy": "حریم خصوصی",

View File

@ -53,7 +53,7 @@ async function main() {
const uiTexts = { const uiTexts = {
hero_badge: "از ۱۹۸۴ در خدمت سلامت حیوانات", hero_badge: "از ۱۹۸۴ در خدمت سلامت حیوانات",
hero_title: "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی", hero_title: "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی",
hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کنینا نماینده رسمی این برند در ایران است.", hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کانینا نماینده رسمی این برند در ایران است.",
hero_btn_advisor: "دستیار سلامت پت", hero_btn_advisor: "دستیار سلامت پت",
hero_btn_products: "مشاهده محصولات", hero_btn_products: "مشاهده محصولات",
hero_stat_founded: "۱۹۸۴ سال تأسیس", hero_stat_founded: "۱۹۸۴ سال تأسیس",
@ -63,12 +63,12 @@ async function main() {
hero_image_title: "مکمل‌های تایید شده دامپزشکی با گواهی IFS", hero_image_title: "مکمل‌های تایید شده دامپزشکی با گواهی IFS",
hero_quality_standard: "استاندارد کیفی آلمان (IFS & HACCP)", hero_quality_standard: "استاندارد کیفی آلمان (IFS & HACCP)",
cta_title: "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟", cta_title: "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟",
cta_subtitle: "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.", cta_subtitle: "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.",
cta_btn_free: "دریافت رژیم مکمل رایگان", cta_btn_free: "دریافت رژیم مکمل رایگان",
cta_btn_products: "ورود به محصولات تخصصی", cta_btn_products: "ورود به محصولات تخصصی",
about_teaser_badge: "داستان ما از آلمان", about_teaser_badge: "داستان ما از آلمان",
about_teaser_title: "Canina pharma GmbH – میراثی از ۱۹۸۴", 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_title: "مواد اولیه نایاب",
about_teaser_feat1_desc: "استفاده از پودر صدف لب‌سبز اصل نیوزیلند (Perna canaliculus)، پیت طبیعی آلمان، آغوز و روغن‌های گیاهی ارگانیک با گرید دارویی.", about_teaser_feat1_desc: "استفاده از پودر صدف لب‌سبز اصل نیوزیلند (Perna canaliculus)، پیت طبیعی آلمان، آغوز و روغن‌های گیاهی ارگانیک با گرید دارویی.",
about_teaser_feat2_title: "فاقد مواد نگهدارنده", about_teaser_feat2_title: "فاقد مواد نگهدارنده",

View File

@ -339,7 +339,7 @@ export class SmsService {
{ {
id: config.otpBodyId, id: config.otpBodyId,
title: 'کد تایید ورود و ثبت‌نام (OTP)', title: 'کد تایید ورود و ثبت‌نام (OTP)',
body: 'کد ورود به کنینا: {0}', body: 'کد ورود به کانینا: {0}',
assigned: 'otp', assigned: 'otp',
}, },
{ {

View File

@ -100,7 +100,7 @@ export class ContactService {
{ {
key: 'address_info', key: 'address_info',
title: 'نشانی دفتر مرکزی', title: 'نشانی دفتر مرکزی',
value: 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹', value: 'تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹',
icon: 'map-pin', icon: 'map-pin',
order: 3, order: 3,
}, },

View File

@ -65,7 +65,7 @@ export class PaymentService {
callbackUrl, callbackUrl,
orderId: order.id, orderId: order.id,
mobile: order.user?.mobile || undefined, mobile: order.user?.mobile || undefined,
description: `پرداخت سفارش ${order.trackingNumber || ''} - پت‌شاپ کنینا`, description: `پرداخت سفارش ${order.trackingNumber || ''} - پت‌شاپ کانینا`,
}; };
// Create a pending PaymentTransaction in database // Create a pending PaymentTransaction in database
@ -159,7 +159,7 @@ export class PaymentService {
amountRials, amountRials,
callbackUrl, callbackUrl,
mobile: user.mobile || undefined, mobile: user.mobile || undefined,
description: `شارژ کیف پول - پت شاپ کنینا`, description: `شارژ کیف پول - پت شاپ کانینا`,
}; };
const transaction = await this.prisma.paymentTransaction.create({ const transaction = await this.prisma.paymentTransaction.create({

View File

@ -136,7 +136,7 @@ export class ZibalService implements IPaymentGateway {
merchant, merchant,
amount: params.amountRials, amount: params.amountRials,
callbackUrl: params.callbackUrl, callbackUrl: params.callbackUrl,
description: params.description || 'پرداخت سفارش در پت شاپ کنینا', description: params.description || 'پرداخت سفارش در پت شاپ کانینا',
orderId: params.orderId, orderId: params.orderId,
mobile: params.mobile, mobile: params.mobile,
nationalCode: params.nationalCode, nationalCode: params.nationalCode,

View File

@ -36,7 +36,7 @@ export class PrescriptionsService {
mobile: cleanPhone, mobile: cleanPhone,
role: 'Customer', role: 'Customer',
firstName: data.petName ? `سرپرست ${data.petName}` : 'کاربر', firstName: data.petName ? `سرپرست ${data.petName}` : 'کاربر',
lastName: 'کنینا', lastName: 'کانینا',
}, },
}); });
} }

View File

@ -1,5 +1,5 @@
import { ApiPropertyOptional } from '@nestjs/swagger'; import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, IsEmail, MinLength } from 'class-validator'; import { IsOptional, IsString, IsEmail } from 'class-validator';
export class UpdateProfileDto { export class UpdateProfileDto {
@ApiPropertyOptional({ description: 'نام کاربر' }) @ApiPropertyOptional({ description: 'نام کاربر' })
@ -21,15 +21,4 @@ export class UpdateProfileDto {
@IsOptional() @IsOptional()
@IsString() @IsString()
mobile?: string; mobile?: string;
@ApiPropertyOptional({ description: 'رمز عبور جدید' })
@IsOptional()
@IsString()
@MinLength(6, { message: 'رمز عبور باید حداقل ۶ کاراکتر باشد' })
password?: string;
@ApiPropertyOptional({ description: 'رمز عبور فعلی (در صورت وجود)' })
@IsOptional()
@IsString()
currentPassword?: string;
} }

View File

@ -1,13 +1,6 @@
import { import { Injectable } from '@nestjs/common';
Injectable,
BadRequestException,
NotFoundException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client'; import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service'; import { PrismaService } from '../prisma/prisma.service';
import * as bcrypt from 'bcryptjs';
import { normalizeMobile } from '../common/utils/phone.utils';
import { UpdateProfileDto } from './dto/update-profile.dto';
export interface UserAddressInput { export interface UserAddressInput {
title: string; title: string;
@ -56,13 +49,7 @@ export class UsersService {
}, },
}); });
if (dbUser) { if (dbUser) return dbUser;
const { password, ...safeUser } = dbUser;
return {
...safeUser,
hasPassword: !!password,
};
}
return { return {
id: '12345678-1234-1234-1234-123456789012', id: '12345678-1234-1234-1234-123456789012',
@ -77,13 +64,12 @@ export class UsersService {
orders: [], orders: [],
addresses: [], addresses: [],
walletTransactions: [], walletTransactions: [],
hasPassword: true,
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date(),
}; };
} }
const user = await this.prisma.user.findUnique({ return this.prisma.user.findUnique({
where: { id }, where: { id },
include: { include: {
pets: { pets: {
@ -112,70 +98,12 @@ export class UsersService {
}, },
}, },
}); });
if (!user) return null;
const { password, ...safeUser } = user;
return {
...safeUser,
hasPassword: !!password,
};
} }
async update(id: string, dto: UpdateProfileDto) { async update(id: string, data: Prisma.UserUpdateInput) {
const user = await this.prisma.user.findUnique({ where: { id } }); return this.prisma.user.update({
if (!user) {
throw new NotFoundException('کاربر یافت نشد');
}
const updateData: Prisma.UserUpdateInput = {};
if (dto.firstName !== undefined) updateData.firstName = dto.firstName.trim();
if (dto.lastName !== undefined) updateData.lastName = dto.lastName.trim();
if (dto.mobile !== undefined) {
const normalizedMobile = normalizeMobile(dto.mobile);
if (normalizedMobile && normalizedMobile !== user.mobile) {
const existing = await this.prisma.user.findUnique({
where: { mobile: normalizedMobile },
});
if (existing && existing.id !== id) {
throw new BadRequestException('این شماره موبایل قبلاً توسط کاربر دیگری ثبت شده است');
}
updateData.mobile = normalizedMobile;
}
}
if (dto.email !== undefined) {
const normalizedEmail = dto.email ? dto.email.trim().toLowerCase() : null;
if (normalizedEmail && normalizedEmail !== user.email) {
const existing = await this.prisma.user.findUnique({
where: { email: normalizedEmail },
});
if (existing && existing.id !== id) {
throw new BadRequestException('این آدرس ایمیل قبلاً توسط کاربر دیگری ثبت شده است');
}
}
updateData.email = normalizedEmail;
}
if (dto.password && dto.password.trim().length >= 6) {
// If user already has a password set, require and verify currentPassword
if (user.password) {
if (!dto.currentPassword) {
throw new BadRequestException('برای تغییر رمز عبور، وارد کردن رمز عبور فعلی الزامی است');
}
const isCurrentMatch = await bcrypt.compare(dto.currentPassword.trim(), user.password);
if (!isCurrentMatch) {
throw new BadRequestException('رمز عبور فعلی اشتباه است');
}
}
updateData.password = await bcrypt.hash(dto.password.trim(), 10);
}
const updatedUser = await this.prisma.user.update({
where: { id }, where: { id },
data: updateData, data,
include: { include: {
pets: true, pets: true,
orders: { orders: {
@ -189,12 +117,6 @@ export class UsersService {
walletTransactions: true, walletTransactions: true,
}, },
}); });
const { password, ...safeUser } = updatedUser;
return {
...safeUser,
hasPassword: !!password,
};
} }
async addAddress(userId: string, data: UserAddressInput) { async addAddress(userId: string, data: UserAddressInput) {

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@ -143,7 +143,7 @@ This document defines the strict integration contract between the NestJS backend
"authorName": "دکتر علیرضا محمدی", "authorName": "دکتر علیرضا محمدی",
"roleTitle": "دامپزشک و متخصص جراحی", "roleTitle": "دامپزشک و متخصص جراحی",
"avatarUrl": "https://example.com/avatar.jpg", "avatarUrl": "https://example.com/avatar.jpg",
"content": "فرمولاسیون کنهیدروکس کنینا در بهبودی پاهای O شکل سگ‌های نژاد بزرگ معجزه می‌کند.", "content": "فرمولاسیون کنهیدروکس کانینا در بهبودی پاهای O شکل سگ‌های نژاد بزرگ معجزه می‌کند.",
"rating": 5, "rating": 5,
"isFeatured": true, "isFeatured": true,
"isActive": true, "isActive": true,
@ -233,9 +233,9 @@ This document defines the strict integration contract between the NestJS backend
- **Response (200 OK)**: - **Response (200 OK)**:
```json ```json
{ {
"defaultMetaTitle": "کنینا ایران | مکمل‌های دارویی آلمانی حیوانات خانگی", "defaultMetaTitle": "کانینا ایران | مکمل‌های دارویی آلمانی حیوانات خانگی",
"defaultMetaDescription": "نمایندگی رسمی محصولات کنینا فارما آلمان", "defaultMetaDescription": "نمایندگی رسمی محصولات کانینا فارما آلمان",
"keywords": "مکمل سگ, مکمل گربه, کنهیدروکس, کنینا", "keywords": "مکمل سگ, مکمل گربه, کنهیدروکس, کانینا",
"canonicalBaseUrl": "https://caninairan.com", "canonicalBaseUrl": "https://caninairan.com",
"ogImageUrl": "https://caninairan.com/og-default.jpg" "ogImageUrl": "https://caninairan.com/og-default.jpg"
} }

View File

@ -98,7 +98,7 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) {
<aside className={`w-64 bg-white border-l border-gray-200 h-screen fixed lg:fixed lg:right-0 lg:top-0 lg:bottom-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' <aside className={`w-64 bg-white border-l border-gray-200 h-screen fixed lg:fixed lg:right-0 lg:top-0 lg:bottom-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"> <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> </div>
<nav className="flex-1 overflow-y-auto py-4 px-3 space-y-6"> <nav className="flex-1 overflow-y-auto py-4 px-3 space-y-6">

View File

@ -67,7 +67,7 @@ export default function Dashboard() {
<div className="space-y-6"> <div className="space-y-6">
<div> <div>
<h2 className="text-2xl font-black text-gray-900">داشبورد</h2> <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>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">

View File

@ -162,7 +162,7 @@ export default function IngredientsManager() {
<FlaskConical className="w-6 h-6 text-purple-600" /> <FlaskConical className="w-6 h-6 text-purple-600" />
مدیریت ترکیبات و دانشنامه علمی (Scientific Wiki) مدیریت ترکیبات و دانشنامه علمی (Scientific Wiki)
</h2> </h2>
<p className="text-gray-500 font-medium mt-1">مدیریت مواد موثره، ترکیبات دارویی و خواص درمانی محصولات کنینا</p> <p className="text-gray-500 font-medium mt-1">مدیریت مواد موثره، ترکیبات دارویی و خواص درمانی محصولات کانینا</p>
</div> </div>
<button <button
onClick={() => openModal()} onClick={() => openModal()}

View File

@ -94,7 +94,7 @@ export default function Login() {
ورود به پنل مدیریت ورود به پنل مدیریت
</h2> </h2>
<p className="mt-2 text-center text-sm text-gray-600 font-bold"> <p className="mt-2 text-center text-sm text-gray-600 font-bold">
کنینا | لابراتوار تخصصی مکمل‌های درمانی حیوانات کانینا | لابراتوار تخصصی مکمل‌های درمانی حیوانات
</p> </p>
</div> </div>

View File

@ -478,7 +478,7 @@ export default function MediaManager() {
type="text" type="text"
value={seoFormData.altText} value={seoFormData.altText}
onChange={(e) => setSeoFormData({ ...seoFormData, altText: e.target.value })} onChange={(e) => setSeoFormData({ ...seoFormData, altText: e.target.value })}
placeholder="مثال: عکس مکمل کانیدروکس گپ کنینا" placeholder="مثال: عکس مکمل کانیدروکس گپ کانینا"
className="w-full px-3 py-2 border rounded-xl text-sm" className="w-full px-3 py-2 border rounded-xl text-sm"
/> />
</div> </div>

View File

@ -186,7 +186,7 @@ export default function Orders() {
const paymentMethodText = orderToPrint.paymentMethod === 'wallet' ? 'پرداخت از کیف پول الکترونیک' : 'پرداخت آنلاین از درگاه شتاب'; const paymentMethodText = orderToPrint.paymentMethod === 'wallet' ? 'پرداخت از کیف پول الکترونیک' : 'پرداخت آنلاین از درگاه شتاب';
const itemsHtml = items.map((item: OrderItem) => { const itemsHtml = items.map((item: OrderItem) => {
const pName = item.product?.nameFa || item.product?.name || item.name || 'محصول کنینا'; const pName = item.product?.nameFa || item.product?.name || item.name || 'محصول کانینا';
const pImg = item.product?.imageUrl || item.product?.image || '/products/product-placeholder.png'; const pImg = item.product?.imageUrl || item.product?.image || '/products/product-placeholder.png';
const pPrice = Number(item.product?.priceValue || item.priceValue || 0); const pPrice = Number(item.product?.priceValue || item.priceValue || 0);
const rowTotal = pPrice * (item.quantity || 1); const rowTotal = pPrice * (item.quantity || 1);
@ -210,7 +210,7 @@ export default function Orders() {
<html dir="rtl" lang="fa"> <html dir="rtl" lang="fa">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>فاکتور رسمی کنینا - ${trackingCode}</title> <title>فاکتور رسمی کانینا - ${trackingCode}</title>
<style> <style>
@font-face { @font-face {
font-family: 'Vazirmatn'; font-family: 'Vazirmatn';
@ -238,7 +238,7 @@ export default function Orders() {
<div class="invoice-card"> <div class="invoice-card">
<div class="header"> <div class="header">
<div> <div>
<div class="logo-text">CANINA | کنینا</div> <div class="logo-text">CANINA | کانینا</div>
<div class="sub-logo">پنل مدیریت سفارشات آلمان</div> <div class="sub-logo">پنل مدیریت سفارشات آلمان</div>
</div> </div>
<div style="text-align: left;"> <div style="text-align: left;">
@ -303,7 +303,7 @@ export default function Orders() {
<div class="footer"> <div class="footer">
این فاکتور رسمی به صورت سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/> این فاکتور رسمی به صورت سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/>
پشتیبانی کنینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir پشتیبانی کانینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
</div> </div>
</div> </div>
@ -581,7 +581,7 @@ export default function Orders() {
</h4> </h4>
<div className="space-y-3"> <div className="space-y-3">
{(selectedOrder.orderItems || selectedOrder.items || []).map((item: OrderItem, idx: number) => { {(selectedOrder.orderItems || selectedOrder.items || []).map((item: OrderItem, idx: number) => {
const pName = item.product?.nameFa || item.product?.name || item.name || 'محصول کنینا'; const pName = item.product?.nameFa || item.product?.name || item.name || 'محصول کانینا';
const pImg = item.product?.imageUrl || item.product?.image || '/products/product-placeholder.png'; const pImg = item.product?.imageUrl || item.product?.image || '/products/product-placeholder.png';
const pPrice = Number(item.product?.priceValue || item.priceValue || 0); const pPrice = Number(item.product?.priceValue || item.priceValue || 0);
const qty = item.quantity || 1; const qty = item.quantity || 1;

View File

@ -241,8 +241,8 @@ export default function Products() {
buyPrice: formData.buyPrice ? Number(formData.buyPrice) : 0, buyPrice: formData.buyPrice ? Number(formData.buyPrice) : 0,
wholesalePrice: formData.wholesalePrice ? Number(formData.wholesalePrice) : null, wholesalePrice: formData.wholesalePrice ? Number(formData.wholesalePrice) : null,
slug: derivedSlug, slug: derivedSlug,
metaTitle: formData.metaTitle.trim() || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کنینا`, metaTitle: formData.metaTitle.trim() || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کانینا`,
metaDescription: formData.metaDescription.trim() || formData.shortDescription || 'خرید آنلاین مکمل اصل کنینا آلمان با بالاترین کیفیت بالینی...', metaDescription: formData.metaDescription.trim() || formData.shortDescription || 'خرید آنلاین مکمل اصل کانینا آلمان با بالاترین کیفیت بالینی...',
canonicalUrl: formData.canonicalUrl.trim() || `/shop/${derivedSlug}` canonicalUrl: formData.canonicalUrl.trim() || `/shop/${derivedSlug}`
}; };
@ -918,8 +918,8 @@ export default function Products() {
<div className={activeTab === 'seo' ? 'block' : 'hidden'}> <div className={activeTab === 'seo' ? 'block' : 'hidden'}>
{(() => { {(() => {
const derivedSlug = formData.slug || slugify(formData.nameEn); const derivedSlug = formData.slug || slugify(formData.nameEn);
const derivedMetaTitle = formData.metaTitle || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کنینا`; const derivedMetaTitle = formData.metaTitle || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کانینا`;
const derivedMetaDescription = formData.metaDescription || (formData.shortDescription || 'خرید آنلاین مکمل اصل کنینا آلمان با بالاترین کیفیت بالینی و ضمانت اصالت فیزیکی...'); const derivedMetaDescription = formData.metaDescription || (formData.shortDescription || 'خرید آنلاین مکمل اصل کانینا آلمان با بالاترین کیفیت بالینی و ضمانت اصالت فیزیکی...');
const derivedCanonicalUrl = formData.canonicalUrl || `/shop/${derivedSlug}`; const derivedCanonicalUrl = formData.canonicalUrl || `/shop/${derivedSlug}`;
return ( return (

View File

@ -101,7 +101,7 @@ export default function Reports() {
onClick={() => { onClick={() => {
if (!reportData) return; if (!reportData) return;
const rows = [ const rows = [
['گزارش کلی سیستم کنینا ایران'], ['گزارش کلی سیستم کانینا ایران'],
['درآمد کل (تومان)', overview?.totalRevenue || 0], ['درآمد کل (تومان)', overview?.totalRevenue || 0],
['تعداد سفارشات', overview?.totalOrders || 0], ['تعداد سفارشات', overview?.totalOrders || 0],
['تعداد کاربران', overview?.totalUsers || 0], ['تعداد کاربران', overview?.totalUsers || 0],

View File

@ -8,9 +8,9 @@ import type { SeoSettings } from '../types/admin';
export default function SeoSettingsPage() { export default function SeoSettingsPage() {
const [seo, setSeo] = useState<SeoSettings>({ const [seo, setSeo] = useState<SeoSettings>({
defaultMetaTitle: 'کنینا ایران | مکمل‌های دارویی آلمانی حیوانات خانگی', defaultMetaTitle: 'کانینا ایران | مکمل‌های دارویی آلمانی حیوانات خانگی',
defaultMetaDescription: 'نمایندگی رسمی محصولات کنینا فارما آلمان در ایران', defaultMetaDescription: 'نمایندگی رسمی محصولات کانینا فارما آلمان در ایران',
keywords: 'مکمل سگ, مکمل گربه, کنهیدروکس, کنینا', keywords: 'مکمل سگ, مکمل گربه, کنهیدروکس, کانینا',
canonicalBaseUrl: 'https://caninairan.com', canonicalBaseUrl: 'https://caninairan.com',
ogImageUrl: 'https://caninairan.com/og-default.jpg', ogImageUrl: 'https://caninairan.com/og-default.jpg',
}); });

View File

@ -29,7 +29,7 @@ export default function Settings() {
SOCIAL_WHATSAPP: '09120000000', SOCIAL_WHATSAPP: '09120000000',
SOCIAL_INSTAGRAM: 'https://instagram.com/canina_iran', SOCIAL_INSTAGRAM: 'https://instagram.com/canina_iran',
SOCIAL_TELEGRAM: 'https://t.me/canina_iran', SOCIAL_TELEGRAM: 'https://t.me/canina_iran',
CONTACT_ADDRESS: 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹', CONTACT_ADDRESS: 'تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹',
BRAND_LOGO_URL: '/logo.png', BRAND_LOGO_URL: '/logo.png',
ENAMAD_CODE: '', ENAMAD_CODE: '',
THEME_PRIMARY_COLOR: '#7c3aed', THEME_PRIMARY_COLOR: '#7c3aed',
@ -66,7 +66,7 @@ export default function Settings() {
SOCIAL_WHATSAPP: response.data.data.SOCIAL_WHATSAPP || '09120000000', SOCIAL_WHATSAPP: response.data.data.SOCIAL_WHATSAPP || '09120000000',
SOCIAL_INSTAGRAM: response.data.data.SOCIAL_INSTAGRAM || 'https://instagram.com/canina_iran', SOCIAL_INSTAGRAM: response.data.data.SOCIAL_INSTAGRAM || 'https://instagram.com/canina_iran',
SOCIAL_TELEGRAM: response.data.data.SOCIAL_TELEGRAM || 'https://t.me/canina_iran', SOCIAL_TELEGRAM: response.data.data.SOCIAL_TELEGRAM || 'https://t.me/canina_iran',
CONTACT_ADDRESS: response.data.data.CONTACT_ADDRESS || 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹', CONTACT_ADDRESS: response.data.data.CONTACT_ADDRESS || 'تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹',
BRAND_LOGO_URL: response.data.data.BRAND_LOGO_URL || '/logo.png', BRAND_LOGO_URL: response.data.data.BRAND_LOGO_URL || '/logo.png',
ENAMAD_CODE: response.data.data.ENAMAD_CODE || '', ENAMAD_CODE: response.data.data.ENAMAD_CODE || '',
THEME_PRIMARY_COLOR: response.data.data.THEME_PRIMARY_COLOR || '#7c3aed', THEME_PRIMARY_COLOR: response.data.data.THEME_PRIMARY_COLOR || '#7c3aed',
@ -105,7 +105,7 @@ export default function Settings() {
<SettingsIcon className="w-6 h-6 text-purple-600" /> <SettingsIcon className="w-6 h-6 text-purple-600" />
تنظیمات فروشگاه تنظیمات فروشگاه
</h2> </h2>
<p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کنینا</p> <p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کانینا</p>
</div> </div>
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
<Link <Link
@ -212,7 +212,7 @@ export default function Settings() {
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-200"> <div className="flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-200">
<div> <div>
<h4 className="font-bold text-gray-900 text-sm">کارت به کارت (واریز مستقیم)</h4> <h4 className="font-bold text-gray-900 text-sm">کارت به کارت (واریز مستقیم)</h4>
<p className="text-xs text-gray-500 mt-0.5">واریز به شماره کارت/شبا رسمی کنینا</p> <p className="text-xs text-gray-500 mt-0.5">واریز به شماره کارت/شبا رسمی کانینا</p>
</div> </div>
<label className="relative inline-flex items-center cursor-pointer"> <label className="relative inline-flex items-center cursor-pointer">
<input <input

View File

@ -1344,7 +1344,7 @@ export default function SmsSettingsPage() {
required required
value={newPatternTitle} value={newPatternTitle}
onChange={(e) => setNewPatternTitle(e.target.value)} onChange={(e) => setNewPatternTitle(e.target.value)}
placeholder="مثلاً: تایید سفارش کنینا" placeholder="مثلاً: تایید سفارش کانینا"
className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-purple-500 text-sm font-bold" className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-purple-500 text-sm font-bold"
/> />
</div> </div>
@ -1372,7 +1372,7 @@ export default function SmsSettingsPage() {
required required
value={newPatternBody} value={newPatternBody}
onChange={(e) => setNewPatternBody(e.target.value)} onChange={(e) => setNewPatternBody(e.target.value)}
placeholder="کاربر گرامی، سفارش {0} با مبلغ {1} تومان در کنینا ثبت شد." placeholder="کاربر گرامی، سفارش {0} با مبلغ {1} تومان در کانینا ثبت شد."
className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-purple-500 text-sm font-medium leading-relaxed" className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-purple-500 text-sm font-medium leading-relaxed"
/> />
</div> </div>

View File

@ -182,7 +182,7 @@ export default function UITexts() {
مدیریت محتوا و بنرهای صفحات (Page Builder) مدیریت محتوا و بنرهای صفحات (Page Builder)
</h1> </h1>
<p className="text-sm text-gray-500 font-bold mt-1"> <p className="text-sm text-gray-500 font-bold mt-1">
ویرایش زنده متون، تصاویر بنر، لینک دکمه‌ها و عناوین تمام صفحات سایت کنینا ویرایش زنده متون، تصاویر بنر، لینک دکمه‌ها و عناوین تمام صفحات سایت کانینا
</p> </p>
</div> </div>
</div> </div>

View File

@ -173,7 +173,7 @@ export default function Videos() {
مدیریت ویدئوها و آکادمی آموزشی مدیریت ویدئوها و آکادمی آموزشی
</h1> </h1>
<p className="text-sm text-gray-500 font-bold mt-1"> <p className="text-sm text-gray-500 font-bold mt-1">
آپلود مستقیم ویدئو/کاور یا درج کد آیفرم آپارات/یوتیوب برای مشاوره ویدئویی دامپزشکان کنینا آپلود مستقیم ویدئو/کاور یا درج کد آیفرم آپارات/یوتیوب برای مشاوره ویدئویی دامپزشکان کانینا
</p> </p>
</div> </div>
<button <button

View File

@ -134,7 +134,7 @@ export default function Wiki() {
<div> <div>
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2"> <h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
<BookOpen className="w-6 h-6 text-purple-600" /> <BookOpen className="w-6 h-6 text-purple-600" />
دانشنامه کنینا (Wiki) دانشنامه کانینا (Wiki)
</h2> </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

@ -5,7 +5,7 @@ This version has breaking changes — APIs, conventions, and file structure may
<!-- END:nextjs-agent-rules --> <!-- END:nextjs-agent-rules -->
# Brand Name # Brand Name
نام برند رسمی «**کنینا**» / «**Canina**» است (نه «کانینو» / «Canino»). در سرتاسر پروژه باید از Canina / کنینا استفاده شود. نام برند رسمی «**کانینا**» / «**Canina**» است (نه «کانینو» / «Canino»). در سرتاسر پروژه باید از Canina / کانینا استفاده شود.
- CSS class names: `canina-blue`, `canina-gold`, `canina-teal`, `canina-dark` - CSS class names: `canina-blue`, `canina-gold`, `canina-teal`, `canina-dark`
- Store/cookie names: `canina-user`, `canina-cart`, `canina-pets` - Store/cookie names: `canina-user`, `canina-cart`, `canina-pets`
- URL `https://canino-iran.com` (domain name, بدون تغییر می‌ماند) - URL `https://canino-iran.com` (domain name, بدون تغییر می‌ماند)

View File

@ -92,7 +92,7 @@ export default function HomeClient({ initialData }: HomeClientProps) {
{getText('nav_card_wiki_title', "دانشنامه علمی")} {getText('nav_card_wiki_title', "دانشنامه علمی")}
</h3> </h3>
<p className="text-medical-gray-600 mb-8 leading-relaxed font-shabnam"> <p className="text-medical-gray-600 mb-8 leading-relaxed font-shabnam">
{getText('nav_card_wiki_desc', "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کنینا.")} {getText('nav_card_wiki_desc', "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینا.")}
</p> </p>
<div className="flex items-center gap-2 text-emerald-700 font-black tracking-widest uppercase text-xs font-vazir"> <div className="flex items-center gap-2 text-emerald-700 font-black tracking-widest uppercase text-xs font-vazir">
{getText('nav_card_wiki_cta', "مطالعه مقالات تخصصی")} {getText('nav_card_wiki_cta', "مطالعه مقالات تخصصی")}
@ -109,7 +109,7 @@ export default function HomeClient({ initialData }: HomeClientProps) {
<div className="absolute -top-10 -right-10 w-40 h-40 bg-canina-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" />
<Image <Image
src="/assets/images/regenerated_image_1779109861747.png" src="/assets/images/regenerated_image_1779109861747.png"
alt="آزمایشگاه تخصصی تولید مکمل‌های دارویی کنینا آلمان" alt="آزمایشگاه تخصصی تولید مکمل‌های دارویی کانینا آلمان"
className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%] w-full" className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%] w-full"
width={640} width={640}
height={425} height={425}
@ -172,7 +172,7 @@ export default function HomeClient({ initialData }: HomeClientProps) {
{getText('cta_title', "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟")} {getText('cta_title', "می‌خواهید بدانید کدام محصول برای پت شما مناسب‌تر است؟")}
</h2> </h2>
<p className="text-white/80 text-lg mb-10 leading-relaxed font-shabnam"> <p className="text-white/80 text-lg mb-10 leading-relaxed font-shabnam">
{getText('cta_desc', "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست.")} {getText('cta_desc', "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست.")}
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
<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 font-shabnam"> <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 font-shabnam">

View File

@ -3,15 +3,15 @@ import { ShieldCheck, History, Award, CheckCircle } from "lucide-react";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "درباره ما - میراث ۴۰ ساله کانیتا آلمان در ایران", title: "درباره ما - میراث ۴۰ ساله کانیتا آلمان در ایران",
description: "داستان کنینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکمل‌های فوق‌تخصصی دامپزشکی با گرید دارویی اختصاصی.", description: "داستان کانینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکمل‌های فوق‌تخصصی دامپزشکی با گرید دارویی اختصاصی.",
alternates: { alternates: {
canonical: "/about", canonical: "/about",
}, },
openGraph: { openGraph: {
title: "درباره ما - کنینا ایران", title: "درباره ما - کانینا ایران",
description: "داستان کنینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکمل‌های فوق‌تخصصی دامپزشکی.", description: "داستان کانینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکمل‌های فوق‌تخصصی دامپزشکی.",
url: "https://canina-iran.com/about", url: "https://canina-iran.com/about",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }
@ -29,7 +29,7 @@ export default function AboutPage() {
داستان ما از ۱۹۸۴ داستان ما از ۱۹۸۴
</span> </span>
<h1 className="text-4xl lg:text-5xl font-black text-medical-gray-900 leading-tight"> <h1 className="text-4xl lg:text-5xl font-black text-medical-gray-900 leading-tight">
درباره <span className="text-canina-blue italic">کنینا ایران</span> درباره <span className="text-canina-blue italic">کانینا ایران</span>
</h1> </h1>
<p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed"> <p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed">
میراث علمی و تعهد ما به تدارک هوشمندانه سلامت برای همراهان وفادار شما. میراث علمی و تعهد ما به تدارک هوشمندانه سلامت برای همراهان وفادار شما.
@ -50,7 +50,7 @@ export default function AboutPage() {
{/* Narrative Section */} {/* Narrative Section */}
<div className="space-y-8 text-medical-gray-700 leading-relaxed"> <div className="space-y-8 text-medical-gray-700 leading-relaxed">
<p> <p>
امروز محصولات کنینا در بیش از ۴۰ کشور جهان توزیع می‌شود. کنینا ایران به عنوان نماینده رسمی این برند، با هدف ارتقای کیفیت زندگی حیوانات خانگی و دسترسی آسان جامعه دامپزشکی و دارندگان حیوانات به این مکمل‌های ارزشمند، فعالیت خود را آغاز نموده است. تمامی محصولات با بسته‌بندی اصلی آلمان و دارای برچسب اصالت سازمان دامپزشکی ارائه می‌شوند. امروز محصولات کانینا در بیش از ۴۰ کشور جهان توزیع می‌شود. کانینا ایران به عنوان نماینده رسمی این برند، با هدف ارتقای کیفیت زندگی حیوانات خانگی و دسترسی آسان جامعه دامپزشکی و دارندگان حیوانات به این مکمل‌های ارزشمند، فعالیت خود را آغاز نموده است. تمامی محصولات با بسته‌بندی اصلی آلمان و دارای برچسب اصالت سازمان دامپزشکی ارائه می‌شوند.
</p> </p>
</div> </div>

View File

@ -18,7 +18,7 @@ async function getBlog(slug: string) {
excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...', excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...',
image: b.imageUrl, image: b.imageUrl,
date: new Date(b.createdAt).toLocaleDateString('fa-IR'), 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 content: b.content
}; };
} catch (error) { } catch (error) {
@ -32,9 +32,9 @@ export const revalidate = 60; // ensure SSR dynamic revalidation works correctly
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> { export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
const { slug } = await params; const { slug } = await params;
const blog = await getBlog(slug); const blog = await getBlog(slug);
if (!blog) return { title: 'مقاله یافت نشد | کنینا ایران' }; if (!blog) return { title: 'مقاله یافت نشد | کانینا ایران' };
const title = `${blog.title} | مجله سلامت کنینا`; const title = `${blog.title} | مجله سلامت کانینا`;
const description = blog.excerpt.substring(0, 150).trim(); const description = blog.excerpt.substring(0, 150).trim();
return { return {
@ -48,7 +48,7 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
description, description,
images: [blog.image], images: [blog.image],
url: `/blog/${slug}`, url: `/blog/${slug}`,
siteName: "کنینا ایران", siteName: "کانینا ایران",
type: "article", type: "article",
} }
}; };
@ -112,7 +112,7 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
</div> </div>
<div> <div>
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</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> </div>
<div className="flex gap-4"> <div className="flex gap-4">

View File

@ -2,16 +2,16 @@ import BlogPage from "../../components/BlogPage";
import type { Metadata } from 'next'; import type { Metadata } from 'next';
export const metadata: Metadata = { export const metadata: Metadata = {
title: "مجله سلامت حیوانات خانگی و مقالات علمی - کنینا ایران", title: "مجله سلامت حیوانات خانگی و مقالات علمی - کانینا ایران",
description: "آخرین مقالات، آموزش‌های دامپزشکی و اخبار علمی روز دنیا در زمینه نگهداری، تغذیه تخصصی و سلامت سگ و گربه.", description: "آخرین مقالات، آموزش‌های دامپزشکی و اخبار علمی روز دنیا در زمینه نگهداری، تغذیه تخصصی و سلامت سگ و گربه.",
alternates: { alternates: {
canonical: "/blog", canonical: "/blog",
}, },
openGraph: { openGraph: {
title: "مجله سلامت حیوانات خانگی - کنینا ایران", title: "مجله سلامت حیوانات خانگی - کانینا ایران",
description: "آخرین مقالات، آموزش‌ها و اخبار علمی در زمینه نگهداری، تغذیه و سلامت سگ و گربه.", description: "آخرین مقالات، آموزش‌ها و اخبار علمی در زمینه نگهداری، تغذیه و سلامت سگ و گربه.",
url: "https://canina-iran.com/blog", url: "https://canina-iran.com/blog",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }

View File

@ -3,15 +3,15 @@ import CatalogClient from "./CatalogClient";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "کاتالوگ محصولات Canina - راهنمای مکمل‌های درمانی سگ و گربه", title: "کاتالوگ محصولات Canina - راهنمای مکمل‌های درمانی سگ و گربه",
description: "کاتالوگ جامع محصولات آلمانی کنینا شامل راهنمای ترکیبات، گرید دارویی، دوز مصرفی و موارد درمان بالینی مفصل، پوست و مو و رشد پت‌ها.", description: "کاتالوگ جامع محصولات آلمانی کانینا شامل راهنمای ترکیبات، گرید دارویی، دوز مصرفی و موارد درمان بالینی مفصل، پوست و مو و رشد پت‌ها.",
alternates: { alternates: {
canonical: "/catalog", canonical: "/catalog",
}, },
openGraph: { openGraph: {
title: "کاتالوگ رسمی مکمل‌های درمانی Canina Pharma Germany", title: "کاتالوگ رسمی مکمل‌های درمانی Canina Pharma Germany",
description: "دانلود و مشاهده آنلاین کاتالوگ مکمل‌های دارویی حیوانات خانگی کنینا آلمان", description: "دانلود و مشاهده آنلاین کاتالوگ مکمل‌های دارویی حیوانات خانگی کانینا آلمان",
url: "https://canina-iran.com/catalog", url: "https://canina-iran.com/catalog",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }

View File

@ -2,16 +2,16 @@ import type { Metadata } from "next";
import ContactFormClient from "@/components/ContactFormClient"; import ContactFormClient from "@/components/ContactFormClient";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "تماس با ما - نمایندگی رسمی مکمل‌های کنینا آلمان در ایران", title: "تماس با ما - نمایندگی رسمی مکمل‌های کانینا آلمان در ایران",
description: "راه‌های ارتباطی، تلفن تماس ویژه، آدرس دفتر مرکزی و فرم تماس مستقیم با نمایندگی انحصاری کانیتا آلمان در ایران.", description: "راه‌های ارتباطی، تلفن تماس ویژه، آدرس دفتر مرکزی و فرم تماس مستقیم با نمایندگی انحصاری کانیتا آلمان در ایران.",
alternates: { alternates: {
canonical: "/contact", canonical: "/contact",
}, },
openGraph: { openGraph: {
title: "تماس با ما - کنینا ایران", title: "تماس با ما - کانینا ایران",
description: "راه‌های ارتباطی با نمایندگی رسمی مکمل‌های دامپزشکی کنینا در ایران.", description: "راه‌های ارتباطی با نمایندگی رسمی مکمل‌های دامپزشکی کانینا در ایران.",
url: "https://canina-iran.com/contact", url: "https://canina-iran.com/contact",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }
@ -28,7 +28,7 @@ export default function ContactPage() {
پاسخگوی شما هستیم پاسخگوی شما هستیم
</span> </span>
<h1 className="text-4xl lg:text-5xl font-black text-medical-gray-900 leading-tight"> <h1 className="text-4xl lg:text-5xl font-black text-medical-gray-900 leading-tight">
تماس با <span className="text-canina-blue italic">کنینا ایران</span> تماس با <span className="text-canina-blue italic">کانینا ایران</span>
</h1> </h1>
<p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed"> <p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed">
جهت مشاوره تخصصی، خرید عمده و پیگیری سفارشات با ما در ارتباط باشید. جهت مشاوره تخصصی، خرید عمده و پیگیری سفارشات با ما در ارتباط باشید.

View File

@ -22,10 +22,10 @@ export async function generateMetadata(): Promise<Metadata> {
} }
const siteUrl = seoSettings?.canonicalBaseUrl || process.env.NEXT_PUBLIC_SITE_URL || 'https://canina-iran.com'; const siteUrl = seoSettings?.canonicalBaseUrl || process.env.NEXT_PUBLIC_SITE_URL || 'https://canina-iran.com';
const titleDefault = seoSettings?.defaultMetaTitle || 'کنینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی'; const titleDefault = seoSettings?.defaultMetaTitle || 'کانینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی';
const descriptionDefault = seoSettings?.defaultMetaDescription || 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کنینا ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان.'; const descriptionDefault = seoSettings?.defaultMetaDescription || 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینا ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان.';
let keywordsList: string[] = ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کنینا', 'داروی حیوانات', 'Canina Iran']; let keywordsList: string[] = ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کانینا', 'داروی حیوانات', 'Canina Iran'];
if (seoSettings?.keywords) { if (seoSettings?.keywords) {
if (Array.isArray(seoSettings.keywords)) { if (Array.isArray(seoSettings.keywords)) {
keywordsList = seoSettings.keywords; keywordsList = seoSettings.keywords;
@ -39,7 +39,7 @@ export async function generateMetadata(): Promise<Metadata> {
return { return {
metadataBase: new URL(siteUrl), metadataBase: new URL(siteUrl),
title: { title: {
template: '%s | کنینا ایران', template: '%s | کانینا ایران',
default: titleDefault, default: titleDefault,
}, },
description: descriptionDefault, description: descriptionDefault,
@ -59,7 +59,7 @@ export async function generateMetadata(): Promise<Metadata> {
title: titleDefault, title: titleDefault,
description: descriptionDefault, description: descriptionDefault,
url: siteUrl, url: siteUrl,
siteName: 'کنینا ایران', siteName: 'کانینا ایران',
locale: 'fa_IR', locale: 'fa_IR',
type: 'website', type: 'website',
images: [ images: [
@ -99,7 +99,7 @@ export default function RootLayout({
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Organization', '@type': 'Organization',
name: 'کنینا ایران', name: 'کانینا ایران',
url: 'https://canina-iran.com', url: 'https://canina-iran.com',
logo: 'https://canina.de/media/fb/d5/47/1683116813/Logo.png', logo: 'https://canina.de/media/fb/d5/47/1683116813/Logo.png',
contactPoint: { contactPoint: {

View File

@ -2,16 +2,16 @@ import type { Metadata } from "next";
import HomeClient from "./HomeClient"; import HomeClient from "./HomeClient";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "کنینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی", title: "کانینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی",
description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما. کنینا ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان با پروانه رسمی دامپزشکی.", description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینا ایران واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان با پروانه رسمی دامپزشکی.",
alternates: { alternates: {
canonical: "/", canonical: "/",
}, },
openGraph: { openGraph: {
title: "کنینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی", title: "کانینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی",
description: "واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان", description: "واردکننده انحصاری مکمل‌های درمانی با گرید دارویی اختصاصی از آلمان",
url: "https://canina-iran.com", url: "https://canina-iran.com",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
images: [ images: [
@ -19,13 +19,13 @@ export const metadata: Metadata = {
url: "/assets/images/regenerated_image_1779109861747.png", url: "/assets/images/regenerated_image_1779109861747.png",
width: 1200, width: 1200,
height: 630, height: 630,
alt: "کنینا ایران - مکمل‌های درمانی حیوانات خانگی", alt: "کانینا ایران - مکمل‌های درمانی حیوانات خانگی",
} }
] ]
}, },
twitter: { twitter: {
card: "summary_large_image", card: "summary_large_image",
title: "کنینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی", title: "کانینا ایران - مکمل‌های درمانی حیوانات خانگی با گرید دارویی اختصاصی",
description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما.", description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما.",
images: ["/assets/images/regenerated_image_1779109861747.png"], images: ["/assets/images/regenerated_image_1779109861747.png"],
} }

View File

@ -211,7 +211,7 @@ function VerifyContent() {
{orderDetails?.trackingNumber && ( {orderDetails?.trackingNumber && (
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-medical-gray-500 font-bold">کد پیگیری سفارش کنینا:</span> <span className="text-medical-gray-500 font-bold">کد پیگیری سفارش کانینا:</span>
<span className="font-mono font-black text-canina-blue text-sm dir-ltr"> <span className="font-mono font-black text-canina-blue text-sm dir-ltr">
{orderDetails.trackingNumber} {orderDetails.trackingNumber}
</span> </span>

View File

@ -2,16 +2,16 @@ import type { Metadata } from "next";
import { Shield } from "lucide-react"; import { Shield } from "lucide-react";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "حریم خصوصی کاربران - کنینا ایران", title: "حریم خصوصی کاربران - کانینا ایران",
description: "سیاست‌های حفاظت از اطلاعات شخصی کاربران، امنیت داده‌های پزشکی و پرونده‌های درمانی پت در وب‌سایت کنینا ایران.", description: "سیاست‌های حفاظت از اطلاعات شخصی کاربران، امنیت داده‌های پزشکی و پرونده‌های درمانی پت در وب‌سایت کانینا ایران.",
alternates: { alternates: {
canonical: "/privacy", canonical: "/privacy",
}, },
openGraph: { openGraph: {
title: "حریم خصوصی کاربران - کنینا ایران", title: "حریم خصوصی کاربران - کانینا ایران",
description: "سیاست‌های حفاظت از اطلاعات شخصی کاربران در وب‌سایت کنینا ایران.", description: "سیاست‌های حفاظت از اطلاعات شخصی کاربران در وب‌سایت کانینا ایران.",
url: "https://canina-iran.com/privacy", url: "https://canina-iran.com/privacy",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }
@ -31,7 +31,7 @@ export default function PrivacyPage() {
حریم خصوصی کاربران حریم خصوصی کاربران
</h1> </h1>
<p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed"> <p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed">
تعهد ما به امنیت داده‌ها و اطلاعات شخصی ثبت شده در وب‌سایت کنینا ایران. تعهد ما به امنیت داده‌ها و اطلاعات شخصی ثبت شده در وب‌سایت کانینا ایران.
</p> </p>
</div> </div>
@ -54,7 +54,7 @@ export default function PrivacyPage() {
<section className="space-y-4"> <section className="space-y-4">
<h3 className="text-xl font-black text-medical-gray-900">۳. امنیت داده‌ها</h3> <h3 className="text-xl font-black text-medical-gray-900">۳. امنیت داده‌ها</h3>
<p> <p>
تمامی اطلاعات حساس کاربران با استفاده از پروتکل‌های امنیتی استاندارد و بستر امن HTTPS رمزگذاری شده و بر روی سرورهای ابری محافظت شده ذخیره می‌گردند. تیم فنی کنینا متعهد به پایش مداوم و به‌روزرسانی سیستم‌های امنیتی جهت جلوگیری از دسترسی‌های غیرمجاز است. تمامی اطلاعات حساس کاربران با استفاده از پروتکل‌های امنیتی استاندارد و بستر امن HTTPS رمزگذاری شده و بر روی سرورهای ابری محافظت شده ذخیره می‌گردند. تیم فنی کانینا متعهد به پایش مداوم و به‌روزرسانی سیستم‌های امنیتی جهت جلوگیری از دسترسی‌های غیرمجاز است.
</p> </p>
</section> </section>

View File

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

View File

@ -11,13 +11,13 @@ export async function generateMetadata(
if (!product) { if (!product) {
return { return {
title: 'خرید مکمل درمانی پت | کنینا ایران', title: 'خرید مکمل درمانی پت | کانینا ایران',
}; };
} }
const nameFa = product.nameFa || product.name; const nameFa = product.nameFa || product.name;
const nameEn = product.nameEn || ""; const nameEn = product.nameEn || "";
const title = nameFa.includes("Canina") ? nameFa : `${nameFa} (${nameEn}) | برند کنینا آلمان`; const title = nameFa.includes("Canina") ? nameFa : `${nameFa} (${nameEn}) | برند کانینا آلمان`;
const description = (product.shortDescription || product.description || '').substring(0, 150).trim(); const description = (product.shortDescription || product.description || '').substring(0, 150).trim();
const rawKeywords = (product as unknown as Record<string, unknown>).keywords; const rawKeywords = (product as unknown as Record<string, unknown>).keywords;
const keywords = typeof rawKeywords === 'string' ? rawKeywords.split(',') : product.main_ingredients; const keywords = typeof rawKeywords === 'string' ? rawKeywords.split(',') : product.main_ingredients;
@ -31,7 +31,7 @@ export async function generateMetadata(
description, description,
images: [product.image], images: [product.image],
url: `/shop/${resolvedParams.slug}`, url: `/shop/${resolvedParams.slug}`,
siteName: "کنینا ایران", siteName: "کانینا ایران",
type: "website", type: "website",
}, },
alternates: { alternates: {
@ -74,7 +74,7 @@ export default async function ShopProductPage({ params }: { params: Promise<{ sl
itemCondition: 'https://schema.org/NewCondition', itemCondition: 'https://schema.org/NewCondition',
seller: { seller: {
'@type': 'Organization', '@type': 'Organization',
name: 'کنینا ایران' name: 'کانینا ایران'
} }
} }
}; };

View File

@ -2,16 +2,16 @@ import type { Metadata } from "next";
import ArchivePage from "../../components/ArchivePage"; import ArchivePage from "../../components/ArchivePage";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "فروشگاه تخصصی مکمل‌های دارویی - کنینا ایران", title: "فروشگاه تخصصی مکمل‌های دارویی - کانینا ایران",
description: "خرید آنلاین انواع مکمل‌های درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامین‌ها و مراقبت‌های ویژه سگ و گربه با تضمین اصالت و گواهی سلامت دامپزشکی.", description: "خرید آنلاین انواع مکمل‌های درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامین‌ها و مراقبت‌های ویژه سگ و گربه با تضمین اصالت و گواهی سلامت دامپزشکی.",
alternates: { alternates: {
canonical: "/shop", canonical: "/shop",
}, },
openGraph: { openGraph: {
title: "فروشگاه تخصصی مکمل‌های دارویی - کنینا ایران", title: "فروشگاه تخصصی مکمل‌های دارویی - کانینا ایران",
description: "خرید آنلاین انواع مکمل‌های درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامین‌ها و مراقبت‌های ویژه سگ و گربه.", description: "خرید آنلاین انواع مکمل‌های درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامین‌ها و مراقبت‌های ویژه سگ و گربه.",
url: "https://canina-iran.com/shop", url: "https://canina-iran.com/shop",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }

View File

@ -4,8 +4,8 @@ import EnamadBadge from '@/components/EnamadBadge';
import { ShieldCheck, Award, FileCheck, CheckCircle2, Building2 } from 'lucide-react'; import { ShieldCheck, Award, FileCheck, CheckCircle2, Building2 } from 'lucide-react';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'نمادهای اعتماد و مجوزهای رسمی | کنینا ایران', title: 'نمادهای اعتماد و مجوزهای رسمی | کانینا ایران',
description: 'مشاهده نماد اعتماد الکترونیکی (اینماد)، مجوزهای سازمان دامپزشکی کشور و گواهینامه‌های اصالت کالاهای کنینا ایران.', description: 'مشاهده نماد اعتماد الکترونیکی (اینماد)، مجوزهای سازمان دامپزشکی کشور و گواهینامه‌های اصالت کالاهای کانینا ایران.',
}; };
export default function TrustSealsPage() { export default function TrustSealsPage() {
@ -19,7 +19,7 @@ export default function TrustSealsPage() {
color: 'from-teal-500 to-emerald-600', color: 'from-teal-500 to-emerald-600',
}, },
{ {
title: 'پروانه بهداشتی واردات محصولات کنینا', title: 'پروانه بهداشتی واردات محصولات کانینا',
authority: 'سازمان دامپزشکی کل کشور', authority: 'سازمان دامپزشکی کل کشور',
code: 'IVC-8840192', code: 'IVC-8840192',
status: 'تایید شده رسمی', status: 'تایید شده رسمی',
@ -56,7 +56,7 @@ export default function TrustSealsPage() {
تضمین اصالت و اطمینان خرید تضمین اصالت و اطمینان خرید
</div> </div>
<h1 className="text-3xl md:text-5xl font-extrabold tracking-tight mb-4 leading-tight"> <h1 className="text-3xl md:text-5xl font-extrabold tracking-tight mb-4 leading-tight">
نمادهای اعتماد و مجوزهای قانونی کنینا نمادهای اعتماد و مجوزهای قانونی کانینا
</h1> </h1>
<p className="text-teal-100 text-base md:text-lg leading-relaxed"> <p className="text-teal-100 text-base md:text-lg leading-relaxed">
تمام کلیه مکمل‌ها، ویتامین‌ها و داروها به صورت مستقیم از کمپانی Canina Pharma آلمان وارد شده و دارای کلیه مجوزهای رسمی سازمان دامپزشکی و نمادهای تجارت الکترونیک می‌باشند. تمام کلیه مکمل‌ها، ویتامین‌ها و داروها به صورت مستقیم از کمپانی Canina Pharma آلمان وارد شده و دارای کلیه مجوزهای رسمی سازمان دامپزشکی و نمادهای تجارت الکترونیک می‌باشند.
@ -101,13 +101,13 @@ export default function TrustSealsPage() {
<section className="bg-white rounded-2xl p-8 border border-gray-100 shadow-sm mb-12"> <section className="bg-white rounded-2xl p-8 border border-gray-100 shadow-sm mb-12">
<h2 className="text-xl font-extrabold text-gray-900 mb-6 flex items-center gap-2"> <h2 className="text-xl font-extrabold text-gray-900 mb-6 flex items-center gap-2">
<CheckCircle2 className="w-6 h-6 text-teal-600" /> <CheckCircle2 className="w-6 h-6 text-teal-600" />
تعهدات کنینا ایران به مشتریان تعهدات کانینا ایران به مشتریان
</h2> </h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="p-4 rounded-xl bg-teal-50/50 border border-teal-100"> <div className="p-4 rounded-xl bg-teal-50/50 border border-teal-100">
<h3 className="font-bold text-teal-900 mb-2">۱۰۰٪ گارانتی اصالت کالا</h3> <h3 className="font-bold text-teal-900 mb-2">۱۰۰٪ گارانتی اصالت کالا</h3>
<p className="text-xs text-teal-700 leading-relaxed"> <p className="text-xs text-teal-700 leading-relaxed">
تمامی مکمل‌ها دارای هولوگرام اصلی کمپانی کنینا آلمان و تاریخ انقضای معتبر و بروز می‌باشند. تمامی مکمل‌ها دارای هولوگرام اصلی کمپانی کانینا آلمان و تاریخ انقضای معتبر و بروز می‌باشند.
</p> </p>
</div> </div>
<div className="p-4 rounded-xl bg-emerald-50/50 border border-emerald-100"> <div className="p-4 rounded-xl bg-emerald-50/50 border border-emerald-100">
@ -119,7 +119,7 @@ export default function TrustSealsPage() {
<div className="p-4 rounded-xl bg-amber-50/50 border border-amber-100"> <div className="p-4 rounded-xl bg-amber-50/50 border border-amber-100">
<h3 className="font-bold text-amber-900 mb-2">پشتیبانی تخصصی دامپزشکی</h3> <h3 className="font-bold text-amber-900 mb-2">پشتیبانی تخصصی دامپزشکی</h3>
<p className="text-xs text-amber-700 leading-relaxed"> <p className="text-xs text-amber-700 leading-relaxed">
امکان مشاوره و بررسی دوز مصرفی مکمل‌ها زیر نظر دامپزشکان متخصص مجموعه کنینا. امکان مشاوره و بررسی دوز مصرفی مکمل‌ها زیر نظر دامپزشکان متخصص مجموعه کانینا.
</p> </p>
</div> </div>
</div> </div>

View File

@ -3,16 +3,16 @@ import IngredientWiki from "../../components/IngredientWiki";
import type { Metadata } from 'next'; import type { Metadata } from 'next';
export const metadata: Metadata = { export const metadata: Metadata = {
title: "دانشنامه ترکیبات دارویی و علمی - کنینا ایران", title: "دانشنامه ترکیبات دارویی و علمی - کانینا ایران",
description: "اطلاعات کامل پزشکی در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی نایاب به کار رفته در محصولات تخصصی کانیتا آلمان.", description: "اطلاعات کامل پزشکی در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی نایاب به کار رفته در محصولات تخصصی کانیتا آلمان.",
alternates: { alternates: {
canonical: "/wiki", canonical: "/wiki",
}, },
openGraph: { openGraph: {
title: "دانشنامه ترکیبات دارویی و علمی - کنینا ایران", title: "دانشنامه ترکیبات دارویی و علمی - کانینا ایران",
description: "اطلاعات کامل در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کنینا ایران.", description: "اطلاعات کامل در مورد مواد موثره، ویتامین‌ها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کانینا ایران.",
url: "https://canina-iran.com/wiki", url: "https://canina-iran.com/wiki",
siteName: "کنینا ایران", siteName: "کانینا ایران",
locale: "fa_IR", locale: "fa_IR",
type: "website", type: "website",
} }

View File

@ -1,25 +1,11 @@
"use client"; "use client";
import React, { useState, useEffect, useRef, useCallback } from "react"; import React, { useState, useEffect, useRef } from "react";
import { motion, AnimatePresence } from "motion/react"; import { motion, AnimatePresence } from "motion/react";
import { import { X, Building2, ShieldCheck, Phone, Key, LogIn, ArrowRight, RefreshCw, Lock, Upload, CheckCircle2 } from "lucide-react";
X,
Building2,
ShieldCheck,
Phone,
Key,
LogIn,
ArrowRight,
RefreshCw,
Lock,
Upload,
CheckCircle2,
Eye,
EyeOff,
} from "lucide-react";
import { useUserStore } from "../lib/store/userStore"; import { useUserStore } from "../lib/store/userStore";
import { authService } from "../lib/services/authService"; import { authService } from "../lib/services/authService";
import { toast } from "sonner"; import { toast } from "sonner";
import { toPersian, toEnglishDigits } from "../lib/utils"; import { toPersian } from "../lib/utils";
interface AuthModalProps { interface AuthModalProps {
isOpen: boolean; isOpen: boolean;
@ -28,16 +14,7 @@ interface AuthModalProps {
export default function AuthModal({ isOpen, onClose }: AuthModalProps) { export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const { fetchProfile } = useUserStore(); const { fetchProfile } = useUserStore();
const [view, setView] = useState< const [view, setView] = useState<"login" | "register" | "otp-phone" | "otp" | "forgot-password" | "forgot-otp" | "reset-password" | "wholesale-request">("login");
| "login"
| "register"
| "otp-phone"
| "otp"
| "forgot-password"
| "forgot-otp"
| "reset-password"
| "wholesale-request"
>("login");
const [medicalLicense, setMedicalLicense] = useState(""); const [medicalLicense, setMedicalLicense] = useState("");
const [businessName, setBusinessName] = useState(""); const [businessName, setBusinessName] = useState("");
const [documentUploaded, setDocumentUploaded] = useState(false); const [documentUploaded, setDocumentUploaded] = useState(false);
@ -50,8 +27,6 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const [otpCode, setOtpCode] = useState(""); const [otpCode, setOtpCode] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [countdown, setCountdown] = useState(0); const [countdown, setCountdown] = useState(0);
const [showPassword, setShowPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
const otpInputRef = useRef<HTMLInputElement>(null); const otpInputRef = useRef<HTMLInputElement>(null);
useEffect(() => { useEffect(() => {
@ -77,8 +52,6 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
setOtpCode(""); setOtpCode("");
setIsLoading(false); setIsLoading(false);
setCountdown(0); setCountdown(0);
setShowPassword(false);
setShowNewPassword(false);
}); });
} }
}, [isOpen]); }, [isOpen]);
@ -91,72 +64,13 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
} }
}, [countdown]); }, [countdown]);
const triggerVerifyOtp = useCallback(
async (codeToVerify: string) => {
const cleanCode = toEnglishDigits(codeToVerify).trim();
const cleanPhone = toEnglishDigits(phoneNumber).trim();
if (cleanCode.length !== 5 || !cleanPhone) return;
setIsLoading(true);
try {
const response = await authService.verifyOtp(cleanPhone, cleanCode);
if (response.success) {
await fetchProfile();
toast.success("ورود با موفقیت انجام شد");
onClose();
}
} catch (err: unknown) {
const errObj = err as { message?: string };
toast.error(errObj.message || "کد تایید نامعتبر است");
} finally {
setIsLoading(false);
}
},
[phoneNumber, fetchProfile, onClose],
);
// WebOTP API SMS Auto-read
useEffect(() => {
if (view === "otp" && typeof window !== "undefined" && "OTPCredential" in window) {
const ac = new AbortController();
(navigator as unknown as { credentials: { get: (opts: unknown) => Promise<{ code?: string }> } }).credentials
?.get({
otp: { transport: ["sms"] },
signal: ac.signal,
})
.then((otp) => {
if (otp?.code) {
const clean = toEnglishDigits(otp.code).replace(/[^0-9]/g, "").slice(0, 5);
setOtpCode(clean);
if (clean.length === 5) {
triggerVerifyOtp(clean);
}
}
})
.catch(() => {});
return () => {
ac.abort();
};
}
}, [view, triggerVerifyOtp]);
const handleOtpChange = (val: string) => {
const clean = toEnglishDigits(val).replace(/[^0-9]/g, "").slice(0, 5);
setOtpCode(clean);
if (clean.length === 5) {
triggerVerifyOtp(clean);
}
};
const handleLogin = async (e: React.FormEvent) => { const handleLogin = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const cleanPhone = toEnglishDigits(phoneNumber).trim(); if (!phoneNumber || !password) return toast.error("شماره موبایل و رمز عبور الزامی است");
if (!cleanPhone || !password) return toast.error("شماره موبایل و رمز عبور الزامی است");
setIsLoading(true); setIsLoading(true);
try { try {
const res = await authService.login(cleanPhone, password.trim()); const res = await authService.login(phoneNumber, password);
if (res.success) { if (res.success) {
await fetchProfile(); await fetchProfile();
toast.success("با موفقیت وارد شدید"); toast.success("با موفقیت وارد شدید");
@ -172,20 +86,13 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleRegister = async (e: React.FormEvent) => { const handleRegister = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const cleanPhone = toEnglishDigits(phoneNumber).trim(); if (!firstName || !lastName || !phoneNumber || !password) {
if (!firstName || !lastName || !cleanPhone || !password) {
return toast.error("لطفاً فیلدهای الزامی را پر کنید"); return toast.error("لطفاً فیلدهای الزامی را پر کنید");
} }
setIsLoading(true); setIsLoading(true);
try { try {
const res = await authService.register({ const res = await authService.register({ firstName, lastName, mobile: phoneNumber, email, password });
firstName: firstName.trim(),
lastName: lastName.trim(),
mobile: cleanPhone,
email: email ? email.trim() : undefined,
password: password.trim(),
});
if (res.success) { if (res.success) {
await fetchProfile(); await fetchProfile();
toast.success("ثبت‌نام با موفقیت انجام شد"); toast.success("ثبت‌نام با موفقیت انجام شد");
@ -201,7 +108,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleSendOtp = async (e: React.FormEvent) => { const handleSendOtp = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const cleanPhone = toEnglishDigits(phoneNumber).trim(); const cleanPhone = phoneNumber.trim();
if (!/^09\d{9}$/.test(cleanPhone)) { if (!/^09\d{9}$/.test(cleanPhone)) {
toast.error("شماره موبایل نامعتبر است"); toast.error("شماره موبایل نامعتبر است");
return; return;
@ -228,14 +135,33 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleVerifyOtp = async (e: React.FormEvent) => { const handleVerifyOtp = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
triggerVerifyOtp(otpCode); const cleanCode = otpCode.trim();
if (cleanCode.length !== 5) {
toast.error("کد باید ۵ رقم باشد");
return;
}
setIsLoading(true);
try {
const response = await authService.verifyOtp(phoneNumber.trim(), cleanCode);
if (response.success) {
await fetchProfile();
toast.success("ورود موفقیت‌آمیز بود");
onClose();
}
} catch (err: unknown) {
const errObj = err as { message?: string };
toast.error(errObj.message || "کد تایید نامعتبر است");
} finally {
setIsLoading(false);
}
}; };
const handleResendOtp = async () => { const handleResendOtp = async () => {
if (countdown > 0) return; if (countdown > 0) return;
setIsLoading(true); setIsLoading(true);
try { try {
await authService.sendOtp(toEnglishDigits(phoneNumber).trim()); await authService.sendOtp(phoneNumber.trim());
toast.success("کد تایید جدید ارسال شد"); toast.success("کد تایید جدید ارسال شد");
setCountdown(120); setCountdown(120);
} catch (err: unknown) { } catch (err: unknown) {
@ -248,7 +174,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleForgotSendOtp = async (e: React.FormEvent) => { const handleForgotSendOtp = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const cleanPhone = toEnglishDigits(phoneNumber).trim(); const cleanPhone = phoneNumber.trim();
if (!/^09\d{9}$/.test(cleanPhone)) { if (!/^09\d{9}$/.test(cleanPhone)) {
toast.error("شماره موبایل نامعتبر است"); toast.error("شماره موبایل نامعتبر است");
return; return;
@ -274,14 +200,14 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleForgotVerifyOtp = async (e: React.FormEvent) => { const handleForgotVerifyOtp = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const cleanCode = toEnglishDigits(otpCode).trim(); if (otpCode.trim().length !== 5) {
if (cleanCode.length !== 5) {
toast.error("کد باید ۵ رقم باشد"); toast.error("کد باید ۵ رقم باشد");
return; return;
} }
setIsLoading(true); setIsLoading(true);
try { try {
await authService.verifyOtp(toEnglishDigits(phoneNumber).trim(), cleanCode); // Verify OTP - if success, allow password reset
await authService.verifyOtp(phoneNumber.trim(), otpCode.trim());
setView("reset-password"); setView("reset-password");
} catch (err: unknown) { } catch (err: unknown) {
const errObj = err as { message?: string }; const errObj = err as { message?: string };
@ -293,18 +219,18 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
const handleResetPassword = async (e: React.FormEvent) => { const handleResetPassword = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!newPassword || newPassword.length < 6) { if (newPassword.length < 6) {
return toast.error("رمز عبور جدید باید حداقل ۶ کاراکتر باشد"); toast.error("رمز جدید باید حداقل ۶ کاراکتر باشد");
return;
} }
setIsLoading(true); setIsLoading(true);
try { try {
await authService.updateProfile({ password: newPassword.trim() }); await authService.updateProfile({ password: newPassword } as unknown as Parameters<typeof authService.updateProfile>[0]);
await fetchProfile(); toast.success("رمز عبور با موفقیت تغییر یافت");
toast.success("رمز عبور جدید با موفقیت تنظیم شد"); setView("login");
onClose();
} catch (err: unknown) { } catch (err: unknown) {
const errObj = err as { message?: string }; const errObj = err as { message?: string };
toast.error(errObj.message || "خطا در تغییر رمز عبور"); toast.error(errObj.message || "خطا در تغییر رمز");
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@ -313,36 +239,52 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
return ( return (
<AnimatePresence> <AnimatePresence>
{isOpen && ( {isOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4"> <>
{/* Backdrop */}
<motion.div <motion.div
initial={{ opacity: 0 }} initial={{ opacity: 0 }}
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
exit={{ opacity: 0 }} exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[60]"
onClick={onClose} onClick={onClose}
className="absolute inset-0 bg-medical-gray-900/60 backdrop-blur-sm"
/> />
{/* Modal content */}
<motion.div <motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }} initial={{ opacity: 0, scale: 0.9, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }} animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }} exit={{ opacity: 0, scale: 0.9, y: 20 }}
className="relative w-full max-w-md bg-white rounded-[2.5rem] shadow-2xl overflow-hidden border border-medical-gray-100 z-10" className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md bg-white rounded-[2.5rem] shadow-2xl z-[70] overflow-hidden border border-medical-gray-100 font-vazir"
dir="rtl"
> >
{/* Header */} {/* Top highlight bar */}
<div className="p-6 pb-0 flex justify-between items-center"> <div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue to-indigo-500" />
<div className="flex items-center gap-2 text-canina-blue font-black text-sm">
<ShieldCheck className="w-5 h-5" /> <div className="p-8 relative">
<span>ورود امن به کانینو</span> {/* Close Button */}
</div>
<button <button
onClick={onClose} onClick={onClose}
className="w-10 h-10 rounded-full bg-medical-gray-50 flex items-center justify-center text-medical-gray-400 hover:bg-medical-gray-100 transition-colors" className="absolute top-6 left-6 p-2 rounded-full hover:bg-medical-gray-50 text-medical-gray-400 hover:text-medical-gray-600 transition-colors"
> >
<X className="w-5 h-5" /> <X className="w-6 h-6" />
</button> </button>
</div>
<div className="p-8"> {/* Title Header */}
<div className="flex flex-col items-center text-center mb-8 pt-4">
<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"
? `کد تایید ارسال شده به شماره ${toPersian(phoneNumber)} را وارد کنید`
: "برای دسترسی به پرونده سلامت و سفارشات وارد شوید"}
</p>
</div>
{/* Content Panel */}
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{view === "login" && ( {view === "login" && (
<motion.form <motion.form
@ -353,77 +295,58 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
onSubmit={handleLogin} onSubmit={handleLogin}
className="space-y-4" className="space-y-4"
> >
<div className="space-y-1"> <div className="space-y-2">
<div className="flex justify-between items-center"> <label htmlFor="login-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل</label>
<label className="text-xs font-bold text-medical-gray-500">شماره موبایل</label> <input
<button id="login-phone"
type="button" name="username"
onClick={() => setView("otp-phone")} type="tel"
className="text-xs font-bold text-canina-blue hover:underline" maxLength={11}
> autoComplete="username"
ورود با کد پیامکی (OTP) placeholder="مثال: ۰۹۱۲۳۴۵۶۷۸۹"
</button> value={phoneNumber}
</div> onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
<div className="relative"> disabled={isLoading}
<Phone className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" /> 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"
<input />
autoFocus </div>
type="tel" <div className="space-y-2">
maxLength={11} <label htmlFor="login-password" className="text-xs font-bold text-medical-gray-500">رمز عبور</label>
required <input
placeholder="۰۹۱۲۳۴۵۶۷۸۹" id="login-password"
value={phoneNumber} name="password"
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))} type="password"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 pr-11 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono tracking-wider" autoComplete="current-password"
dir="ltr" placeholder="رمز عبور خود را وارد کنید"
/> value={password}
</div> 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-canina-blue/20 outline-none text-left"
/>
</div> </div>
<div className="space-y-1"> <div className="flex items-center justify-between pt-2 flex-wrap gap-2">
<div className="flex justify-between items-center"> <button
<label className="text-xs font-bold text-medical-gray-500">رمز عبور</label> type="button"
onClick={() => setView("otp-phone")}
className="text-xs font-bold text-canina-blue hover:underline"
>
ورود با کد یکبار مصرف (OTP)
</button>
<div className="flex items-center gap-3">
<button <button
type="button" type="button"
onClick={() => setView("forgot-password")} onClick={() => { setPhoneNumber(""); setView("forgot-password"); }}
className="text-xs font-bold text-medical-gray-400 hover:text-canina-blue" className="text-xs font-bold text-medical-gray-400 hover:text-canina-blue hover:underline"
> >
فراموشی رمز عبور؟ فراموشی رمز
</button> </button>
</div>
<div className="relative">
<Lock className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400 pointer-events-none" />
<input
type={showPassword ? "text" : "password"}
autoComplete="current-password"
required
placeholder="رمز عبور..."
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 pr-11 pl-11 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono tracking-wider"
dir="ltr"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute left-3 top-1/2 -translate-y-1/2 p-1.5 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
title={showPassword ? "مخفی کردن رمز" : "نمایش رمز"}
>
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
<div className="flex items-center justify-between text-xs pt-1">
<div className="flex items-center gap-1 text-medical-gray-400">
<span>حساب کاربری ندارید؟</span>
<button <button
type="button" type="button"
onClick={() => setView("register")} onClick={() => setView("register")}
className="font-bold text-canina-blue hover:underline" className="text-xs font-bold text-canina-blue hover:underline"
> >
ثبت‌نام عادی حساب ندارید؟ ثبت‌نام
</button> </button>
</div> </div>
</div> </div>
@ -432,10 +355,10 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button <button
type="button" type="button"
onClick={() => setView("wholesale-request")} onClick={() => setView("wholesale-request")}
className="w-full py-3 bg-amber-50 text-amber-900 border border-amber-200 rounded-xl text-xs font-black flex items-center justify-center gap-2 hover:bg-amber-100 transition-colors cursor-pointer" className="w-full py-3 bg-amber-50 text-amber-900 border border-amber-200 rounded-xl text-xs font-black flex items-center justify-center gap-2 hover:bg-amber-100 transition-colors"
> >
<Building2 className="w-4 h-4 text-amber-600" /> <Building2 className="w-4 h-4 text-amber-600" />
درخواست حساب خریدار عمده (پت‌شاپ / کلینیک) درخواست ثبت‌نام حساب خریدار عمده (پت‌شاپ / کلینیک)
</button> </button>
</div> </div>
@ -457,9 +380,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
exit={{ opacity: 0, x: -20 }} exit={{ opacity: 0, x: -20 }}
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
toast.success( toast.success("درخواست احراز هویت خریدار عمده با موفقیت ارسال شد و پس از بررسی ادمین تایید خواهد شد.");
"درخواست احراز هویت خریدار عمده با موفقیت ارسال شد و پس از بررسی ادمین تایید خواهد شد.",
);
setView("login"); setView("login");
}} }}
className="space-y-3" className="space-y-3"
@ -474,7 +395,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
type="text" type="text"
required required
value={businessName} value={businessName}
onChange={(e) => setBusinessName(e.target.value)} onChange={e => setBusinessName(e.target.value)}
placeholder="مثال: کلینیک دامپزشکی رازی" placeholder="مثال: کلینیک دامپزشکی رازی"
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" 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"
/> />
@ -486,10 +407,9 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
type="text" type="text"
required required
value={medicalLicense} value={medicalLicense}
onChange={(e) => setMedicalLicense(e.target.value)} onChange={e => setMedicalLicense(e.target.value)}
placeholder="مثال: ۹۸۷۶۵۴۳۲۱" placeholder="مثال: ۹۸۷۶۵۴۳۲۱"
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 text-left font-mono" 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 text-left"
dir="ltr"
/> />
</div> </div>
@ -500,21 +420,18 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
required required
maxLength={11} maxLength={11}
value={phoneNumber} value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))} onChange={e => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
placeholder="۰۹۱۲..." placeholder="۰۹۱۲..."
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 text-left font-mono" 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 text-left"
dir="ltr"
/> />
</div> </div>
<div <div
onClick={() => { onClick={() => {
setDocumentUploaded(true); setDocumentUploaded(true);
toast.success("تصویر پروانه با موفقیت بارگذاری شد."); toast.success("تصویر پروانه با موفقیت بارگذاری شد.");
}} }}
className={`p-4 border-2 border-dashed rounded-xl text-center cursor-pointer transition-all ${ className={`p-4 border-2 border-dashed rounded-xl text-center cursor-pointer transition-all ${documentUploaded ? 'border-green-500 bg-green-50' : 'border-medical-gray-300 hover:border-canina-blue'}`}
documentUploaded ? "border-green-500 bg-green-50" : "border-medical-gray-300 hover:border-canina-blue"
}`}
> >
{documentUploaded ? ( {documentUploaded ? (
<div className="flex items-center justify-center gap-2 text-green-700 font-bold text-xs"> <div className="flex items-center justify-center gap-2 text-green-700 font-bold text-xs">
@ -533,7 +450,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button <button
type="button" type="button"
onClick={() => setView("login")} onClick={() => setView("login")}
className="text-xs font-bold text-canina-blue hover:underline cursor-pointer" className="text-xs font-bold text-canina-blue hover:underline"
> >
بازگشت به ورود بازگشت به ورود
</button> </button>
@ -563,10 +480,12 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<label htmlFor="reg-fname" className="text-xs font-bold text-medical-gray-500">نام</label> <label htmlFor="reg-fname" className="text-xs font-bold text-medical-gray-500">نام</label>
<input <input
id="reg-fname" id="reg-fname"
name="given-name"
type="text" type="text"
required autoComplete="given-name"
value={firstName} value={firstName}
onChange={(e) => setFirstName(e.target.value)} 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-canina-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>
@ -574,27 +493,29 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<label htmlFor="reg-lname" className="text-xs font-bold text-medical-gray-500">نام خانوادگی</label> <label htmlFor="reg-lname" className="text-xs font-bold text-medical-gray-500">نام خانوادگی</label>
<input <input
id="reg-lname" id="reg-lname"
name="family-name"
type="text" type="text"
required autoComplete="family-name"
value={lastName} value={lastName}
onChange={(e) => setLastName(e.target.value)} 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-canina-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>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label htmlFor="reg-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل</label> <label htmlFor="reg-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل *</label>
<input <input
id="reg-phone" id="reg-phone"
name="username"
type="tel" type="tel"
required
maxLength={11} maxLength={11}
placeholder="۰۹۱۲۳۴۵۶۷۸۹" autoComplete="username"
value={phoneNumber} value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))} onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
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 text-left font-mono tracking-wider" disabled={isLoading}
dir="ltr" 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> </div>
@ -602,45 +523,35 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<label htmlFor="reg-email" className="text-xs font-bold text-medical-gray-500">ایمیل (اختیاری)</label> <label htmlFor="reg-email" className="text-xs font-bold text-medical-gray-500">ایمیل (اختیاری)</label>
<input <input
id="reg-email" id="reg-email"
name="email"
type="email" type="email"
placeholder="name@example.com" autoComplete="email"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
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 text-left font-mono" disabled={isLoading}
dir="ltr" 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> </div>
<div className="space-y-1"> <div className="space-y-1">
<label htmlFor="reg-pass" className="text-xs font-bold text-medical-gray-500">رمز عبور</label> <label htmlFor="reg-password" className="text-xs font-bold text-medical-gray-500">رمز عبور *</label>
<div className="relative"> <input
<input id="reg-password"
id="reg-pass" name="new-password"
type={showPassword ? "text" : "password"} type="password"
autoComplete="new-password" autoComplete="new-password"
required value={password}
placeholder="حداقل ۶ کاراکتر" onChange={(e) => setPassword(e.target.value)}
value={password} disabled={isLoading}
onChange={(e) => setPassword(e.target.value)} 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"
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 pr-3 pl-10 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono" />
dir="ltr"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute left-2.5 top-1/2 -translate-y-1/2 p-1 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
>
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div> </div>
<div className="flex justify-start pt-1"> <div className="flex justify-start pt-1">
<button <button
type="button" type="button"
onClick={() => setView("login")} onClick={() => setView("login")}
className="text-xs font-bold text-canina-blue hover:underline cursor-pointer" className="text-xs font-bold text-canina-blue hover:underline"
> >
بازگشت به ورود بازگشت به ورود
</button> </button>
@ -671,7 +582,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button <button
type="button" type="button"
onClick={() => setView("login")} onClick={() => setView("login")}
className="text-[10px] font-black text-canina-blue hover:underline cursor-pointer" className="text-[10px] font-black text-canina-blue hover:underline"
> >
برگشت به صفحه ورود برگشت به صفحه ورود
</button> </button>
@ -684,10 +595,9 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
maxLength={11} maxLength={11}
placeholder="مثال: ۰۹۱۲۳۴۵۶۷۸۹" placeholder="مثال: ۰۹۱۲۳۴۵۶۷۸۹"
value={phoneNumber} value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))} onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading} 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-canina-blue/20 outline-none font-bold text-lg text-left font-mono 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"
dir="ltr"
/> />
</div> </div>
</div> </div>
@ -724,31 +634,43 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<button <button
type="button" type="button"
onClick={() => setView("otp-phone")} onClick={() => setView("otp-phone")}
className="text-[10px] font-black text-canina-blue flex items-center gap-1 hover:underline cursor-pointer" className="text-[10px] font-black text-canina-blue flex items-center gap-1 hover:underline"
> >
<ArrowRight className="w-3 h-3" /> <ArrowRight className="w-3 h-3" />
تغییر شماره تغییر شماره
</button> </button>
</div> </div>
<div className="relative"> <div className="relative">
<Key className="absolute right-4 top-1/2 -translate-y-1/2 w-5 h-5 text-medical-gray-400 pointer-events-none" /> <Key className="absolute right-4 top-1/2 -translate-y-1/2 w-5 h-5 text-medical-gray-400" />
<input <input
ref={otpInputRef} ref={otpInputRef}
type="text" type="text"
inputMode="numeric"
autoComplete="one-time-code"
maxLength={5} maxLength={5}
placeholder="کد ۵ رقمی" placeholder="کد ۵ رقمی"
value={otpCode} value={otpCode}
onChange={(e) => handleOtpChange(e.target.value)} onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
disabled={isLoading} 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-canina-blue/20 outline-none font-bold text-center text-2xl font-mono 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]"
dir="ltr"
/> />
</div> </div>
<p className="text-[11px] text-medical-gray-400 text-center font-medium pt-1"> </div>
کد پیامک‌شده به صورت خودکار شناسایی و وارد می‌شود.
</p> <div className="text-center">
{countdown > 0 ? (
<span className="text-xs font-bold text-medical-gray-400">
ارسال مجدد کد پس از {toPersian(countdown)} ثانیه
</span>
) : (
<button
type="button"
onClick={handleResendOtp}
disabled={isLoading}
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" />
ارسال مجدد کد تایید
</button>
)}
</div> </div>
<button <button
@ -760,77 +682,55 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
<RefreshCw className="w-6 h-6 animate-spin" /> <RefreshCw className="w-6 h-6 animate-spin" />
) : ( ) : (
<> <>
<ShieldCheck className="w-6 h-6" /> <LogIn className="w-6 h-6" />
تایید و ورود تایید کد و ورود
</> </>
)} )}
</button> </button>
<div className="text-center pt-2">
{countdown > 0 ? (
<span className="text-xs font-bold text-medical-gray-400">
ارسال مجدد کد تا {toPersian(countdown.toString())} ثانیه دیگر
</span>
) : (
<button
type="button"
onClick={handleResendOtp}
className="text-xs font-black text-canina-blue hover:underline cursor-pointer"
>
ارسال مجدد کد تایید
</button>
)}
</div>
</motion.form> </motion.form>
)} )}
{/* Forgot Password - Enter Phone */}
{view === "forgot-password" && ( {view === "forgot-password" && (
<motion.form <motion.form
key="forgot-view" key="forgot-password-view"
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }} exit={{ opacity: 0, x: -20 }}
onSubmit={handleForgotSendOtp} onSubmit={handleForgotSendOtp}
className="space-y-4" className="space-y-4"
> >
<div className="space-y-1"> <div className="bg-amber-50 border border-amber-200 rounded-2xl p-4 text-center">
<label className="text-xs font-bold text-medical-gray-500">شماره موبایل حساب</label> <Lock className="w-8 h-8 text-amber-500 mx-auto mb-2" />
<div className="relative"> <p className="text-sm font-bold text-amber-700">برای بازیابی رمز عبور، کد تایید به شمارهتان ارسال می‌شود</p>
<Phone className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400" />
<input
autoFocus
type="tel"
maxLength={11}
required
placeholder="۰۹۱۲۳۴۵۶۷۸۹"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 pr-11 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono tracking-wider"
dir="ltr"
/>
</div>
</div> </div>
<div className="space-y-2">
<div className="flex justify-start pt-1"> <label htmlFor="forgot-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل</label>
<button <input
type="button" id="forgot-phone"
onClick={() => setView("login")} name="username"
className="text-xs font-bold text-canina-blue hover:underline cursor-pointer" type="tel"
> maxLength={11}
بازگشت به ورود autoComplete="username"
</button> placeholder="مثال: ۰۹۱۲۳۴۵۶۷۸۹"
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-canina-blue/20 outline-none font-bold text-left tracking-widest"
/>
</div> </div>
<button <button
type="submit" type="submit"
disabled={isLoading || phoneNumber.length < 11} disabled={isLoading || phoneNumber.length < 11}
className="w-full py-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" className="w-full py-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"
> >
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>ارسال کد بازیابی</>} {isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>ارسال کد بازیابی</>}
</button> </button>
<button type="button" onClick={() => setView("login")} className="w-full text-xs font-bold text-medical-gray-400 hover:text-canina-blue">بازگشت به ورود</button>
</motion.form> </motion.form>
)} )}
{/* Forgot Password - Enter OTP */}
{view === "forgot-otp" && ( {view === "forgot-otp" && (
<motion.form <motion.form
key="forgot-otp-view" key="forgot-otp-view"
@ -838,86 +738,74 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }} exit={{ opacity: 0, x: -20 }}
onSubmit={handleForgotVerifyOtp} onSubmit={handleForgotVerifyOtp}
className="space-y-4" className="space-y-5"
> >
<div className="space-y-1"> <p className="text-sm font-bold text-medical-gray-600 text-center">کد ارسال شده به {toPersian(phoneNumber)} را وارد کنید</p>
<label className="text-xs font-bold text-medical-gray-500">کد تایید بازیابی</label> <div className="relative">
<div className="relative"> <input
<Key className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400 pointer-events-none" /> ref={otpInputRef}
<input id="forgot-otp-code"
autoFocus name="one-time-code"
type="text" type="text"
inputMode="numeric" autoComplete="one-time-code"
autoComplete="one-time-code" inputMode="numeric"
maxLength={5} maxLength={5}
required value={otpCode}
placeholder="کد ۵ رقمی" onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
value={otpCode} disabled={isLoading}
onChange={(e) => setOtpCode(toEnglishDigits(e.target.value).replace(/[^0-9]/g, "").slice(0, 5))} className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pl-4 pr-4 focus:ring-2 focus:ring-canina-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-xl py-3 pr-11 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none text-center font-mono font-bold text-xl tracking-[0.4em]" />
dir="ltr"
/>
</div>
</div> </div>
{countdown > 0 ? (
<button <p className="text-xs font-bold text-medical-gray-400 text-center">ارسال مجدد پس از {toPersian(countdown)} ثانیه</p>
type="submit" ) : (
disabled={isLoading || otpCode.length < 5} <button type="button" onClick={handleForgotSendOtp} disabled={isLoading} className="text-xs font-black text-canina-blue hover:underline flex items-center gap-1.5 justify-center mx-auto">
className="w-full py-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" <RefreshCw className="w-3.5 h-3.5" />ارسال مجدد
> </button>
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>تایید و ادامه</>} )}
<button type="submit" disabled={isLoading || otpCode.length < 5} className="w-full py-4 bg-canina-blue text-white rounded-xl font-black disabled:opacity-50 transition-all shadow-lg shadow-canina-blue/20 flex items-center justify-center gap-2">
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>تایید کد</>}
</button> </button>
</motion.form> </motion.form>
)} )}
{/* Reset Password */}
{view === "reset-password" && ( {view === "reset-password" && (
<motion.form <motion.form
key="reset-pass-view" key="reset-password-view"
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }} exit={{ opacity: 0, x: -20 }}
onSubmit={handleResetPassword} onSubmit={handleResetPassword}
className="space-y-4" className="space-y-4"
> >
<div className="space-y-1"> <div className="bg-green-50 border border-green-200 rounded-2xl p-4 text-center">
<label className="text-xs font-bold text-medical-gray-500">رمز عبور جدید</label> <p className="text-sm font-bold text-green-700">هویت تایید شد. رمز جدید خود را وارد کنید</p>
<div className="relative">
<Lock className="absolute right-4 top-1/2 -translate-y-1/2 w-4 h-4 text-medical-gray-400 pointer-events-none" />
<input
autoFocus
type={showNewPassword ? "text" : "password"}
autoComplete="new-password"
required
placeholder="حداقل ۶ کاراکتر"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 pr-11 pl-11 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono"
dir="ltr"
/>
<button
type="button"
onClick={() => setShowNewPassword(!showNewPassword)}
className="absolute left-3 top-1/2 -translate-y-1/2 p-1 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
>
{showNewPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div> </div>
<div className="space-y-2">
<button <label htmlFor="new-password" className="text-xs font-bold text-medical-gray-500">رمز جدید</label>
type="submit" <input
disabled={isLoading || newPassword.length < 6} id="new-password"
className="w-full py-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" name="new-password"
> type="password"
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>ثبت رمز عبور جدید</>} autoComplete="new-password"
placeholder="حداقل ۶ کاراکتر"
value={newPassword}
onChange={(e) => setNewPassword(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-canina-blue/20 outline-none text-left"
/>
</div>
<button type="submit" disabled={isLoading || newPassword.length < 6} className="w-full py-4 bg-canina-blue text-white rounded-xl font-black disabled:opacity-50 transition-all shadow-lg shadow-canina-blue/20 flex items-center justify-center gap-2">
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>تغییر رمز عبور</>}
</button> </button>
</motion.form> </motion.form>
)} )}
</AnimatePresence> </AnimatePresence>
</div> </div>
</motion.div> </motion.div>
</div> </>
)} )}
</AnimatePresence> </AnimatePresence>
); );

View File

@ -123,7 +123,7 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
try { try {
const api = (await import('../lib/services/api')).default; const api = (await import('../lib/services/api')).default;
await api.post('/wholesale/apply', { businessName: bName, licenseNumber: phone }); await api.post('/wholesale/apply', { businessName: bName, licenseNumber: phone });
alert('درخواست شما با موفقیت ثبت شد. کارشناسان پشتیبانی B2B کنینا به زودی جهت تایید تلفنی با شما تماس خواهند گرفت.'); alert('درخواست شما با موفقیت ثبت شد. کارشناسان پشتیبانی B2B کانینا به زودی جهت تایید تلفنی با شما تماس خواهند گرفت.');
form.reset(); form.reset();
} catch { } catch {
alert('خطا در ثبت درخواست. لطفاً دوباره تلاش کنید.'); alert('خطا در ثبت درخواست. لطفاً دوباره تلاش کنید.');

View File

@ -89,7 +89,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div> </div>
<div> <div>
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</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> </div>
<div className="flex gap-4"> <div className="flex gap-4">
@ -183,7 +183,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
مجله تخصصی <span className="text-canina-blue">سلامت پت‌ها</span> مجله تخصصی <span className="text-canina-blue">سلامت پت‌ها</span>
</h1> </h1>
<p className="text-sm sm:text-base text-medical-gray-500 font-medium mt-3 max-w-xl leading-relaxed"> <p className="text-sm sm:text-base text-medical-gray-500 font-medium mt-3 max-w-xl leading-relaxed">
آخرین یافته‌های علمی محققین کنینا آلمان در مورد تغذیه و سلامت پت‌ها. آخرین یافته‌های علمی محققین کانینا آلمان در مورد تغذیه و سلامت پت‌ها.
</p> </p>
</div> </div>
@ -226,7 +226,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
</div> </div>
<div className="text-sm"> <div className="text-sm">
<div className="font-black text-medical-gray-900">{blogs[0].author}</div> <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> </div>
<div className="flex items-center gap-2 text-canina-blue font-black"> <div className="flex items-center gap-2 text-canina-blue font-black">
@ -305,7 +305,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
C C
</div> </div>
<span className="text-xs font-black text-white/90 tracking-wider font-vazir"> <span className="text-xs font-black text-white/90 tracking-wider font-vazir">
خبرنامه اختصاصی پژوهشگاه کنینا آلمان خبرنامه اختصاصی پژوهشگاه کانینا آلمان
</span> </span>
<Sparkles className="w-3.5 h-3.5 text-canina-gold animate-pulse" /> <Sparkles className="w-3.5 h-3.5 text-canina-gold animate-pulse" />
</div> </div>
@ -316,7 +316,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
مشترک <span className="text-transparent bg-clip-text bg-gradient-to-r from-canina-gold via-white to-canina-teal">خبرنامه علمی</span> شوید مشترک <span className="text-transparent bg-clip-text bg-gradient-to-r from-canina-gold via-white to-canina-teal">خبرنامه علمی</span> شوید
</h3> </h3>
<p className="text-sm sm:text-base text-white/80 font-medium font-vazir leading-relaxed"> <p className="text-sm sm:text-base text-white/80 font-medium font-vazir leading-relaxed">
ماهانه یک ایمیل حاوی تازه‌ترین یافتـه‌های پزشکی، کاتالوگ‌های درمانی اختصاصی کنینا و کدهای تخفیف ویژه برای شما ارسال می‌شود. ماهانه یک ایمیل حاوی تازه‌ترین یافتـه‌های پزشکی، کاتالوگ‌های درمانی اختصاصی کانینا و کدهای تخفیف ویژه برای شما ارسال می‌شود.
</p> </p>
</div> </div>
@ -369,7 +369,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
<div className="flex-1"> <div className="flex-1">
<h3 className="text-3xl lg:text-4xl font-black italic mb-6">علم آلمانی در خدمت سلامت پت شما</h3> <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 className="text-white/80 mb-8 leading-relaxed max-w-xl">
تمامی مقالات این وبلاگ بر اساس کاتالوگ‌های رسمی و نتایج آزمایشگاهی کمپانی کنینا آلمان تدوین شده است. تمامی مقالات این وبلاگ بر اساس کاتالوگ‌های رسمی و نتایج آزمایشگاهی کمپانی کانینا آلمان تدوین شده است.
</p> </p>
<button <button
onClick={() => router.push('/shop')} onClick={() => router.push('/shop')}

View File

@ -152,7 +152,7 @@ export default function ContactFormClient() {
نشانی دفتر مرکزی نشانی دفتر مرکزی
</h4> </h4>
<p className="text-sm font-bold text-medical-gray-900 leading-relaxed"> <p className="text-sm font-bold text-medical-gray-900 leading-relaxed">
تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹ تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹
</p> </p>
</div> </div>
</div> </div>
@ -170,7 +170,7 @@ export default function ContactFormClient() {
<CheckCircle2 className="w-12 h-12 text-emerald-600 mx-auto" /> <CheckCircle2 className="w-12 h-12 text-emerald-600 mx-auto" />
<h4 className="text-lg font-black">پیام شما با موفقیت ثبت شد</h4> <h4 className="text-lg font-black">پیام شما با موفقیت ثبت شد</h4>
<p className="text-sm font-medium leading-relaxed"> <p className="text-sm font-medium leading-relaxed">
پیامک تایید به شماره شما ارسال شد. کارشناسان کنینا به زودی با شما تماس خواهند گرفت. پیامک تایید به شماره شما ارسال شد. کارشناسان کانینا به زودی با شما تماس خواهند گرفت.
</p> </p>
<button <button
onClick={() => setSuccess(false)} onClick={() => setSuccess(false)}

View File

@ -45,7 +45,7 @@ export const ServerErrorPage = ({ onRetry }: { onRetry: () => void }) => {
<h1 className="text-4xl font-black text-medical-gray-900 mb-4">خطای داخلی سیستم</h1> <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 className="text-medical-gray-500 mb-12 font-bold text-lg">
ارتباط با دیتابیس کنینا با مشکل مواجه شده است. در حال بررسی موضوع هستیم. ارتباط با دیتابیس کانینا با مشکل مواجه شده است. در حال بررسی موضوع هستیم.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center"> <div className="flex flex-col sm:flex-row gap-4 justify-center">

View File

@ -155,7 +155,7 @@ export default function Footer({
</div> </div>
<div> <div>
<p className="text-[11px] text-slate-400 font-extrabold uppercase mb-1">{getText('footer_address_label', "دفتر مرکزی")}</p> <p className="text-[11px] text-slate-400 font-extrabold uppercase mb-1">{getText('footer_address_label', "دفتر مرکزی")}</p>
<p className="text-sm font-bold leading-relaxed text-slate-300">{getText('CONTACT_ADDRESS', getText('footer_address', "تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹"))}</p> <p className="text-sm font-bold leading-relaxed text-slate-300">{getText('CONTACT_ADDRESS', getText('footer_address', "تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹"))}</p>
</div> </div>
</div> </div>
</div> </div>
@ -184,7 +184,7 @@ export default function Footer({
</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-bold uppercase tracking-[0.3em] font-shabnam"> <div className="pt-12 border-t border-white/5 flex flex-col md:flex-row items-center justify-between gap-6 text-[10px] font-bold uppercase tracking-[0.3em] font-shabnam">
<div className="text-slate-400 font-shabnam">{getText('footer_copyright', "© ۲۰۲۶ کنینا ایران. تمامی حقوق محفوظ است.")}</div> <div className="text-slate-400 font-shabnam">{getText('footer_copyright', "© ۲۰۲۶ کانینا ایران. تمامی حقوق محفوظ است.")}</div>
<div className="flex gap-4 sm:gap-8 font-shabnam text-slate-400 items-center"> <div className="flex gap-4 sm:gap-8 font-shabnam text-slate-400 items-center">
<Link href="/about" className="font-extrabold hover:text-white transition-colors whitespace-nowrap">{getText('footer_about', "درباره ما")}</Link> <Link href="/about" className="font-extrabold hover:text-white transition-colors whitespace-nowrap">{getText('footer_about', "درباره ما")}</Link>
<Link href="/contact" className="font-extrabold hover:text-white transition-colors whitespace-nowrap">{getText('footer_contact', "تماس با ما")}</Link> <Link href="/contact" className="font-extrabold hover:text-white transition-colors whitespace-nowrap">{getText('footer_contact', "تماس با ما")}</Link>

View File

@ -149,7 +149,7 @@ export default function Header({
{(getText('BRAND_LOGO_URL', '') || getText('site_logo', '')) ? ( {(getText('BRAND_LOGO_URL', '') || getText('site_logo', '')) ? (
<img <img
src={getText('BRAND_LOGO_URL', '') || getText('site_logo', '')} src={getText('BRAND_LOGO_URL', '') || getText('site_logo', '')}
alt={getText('brand_name_fa', "کنینا ایران")} alt={getText('brand_name_fa', "کانینا ایران")}
className="h-10 sm:h-12 w-auto max-w-[140px] sm:max-w-[180px] object-contain shrink-0" className="h-10 sm:h-12 w-auto max-w-[140px] sm:max-w-[180px] object-contain shrink-0"
/> />
) : ( ) : (
@ -410,7 +410,7 @@ export default function Header({
<div className="absolute top-full right-0 w-56 bg-white border border-medical-gray-200 shadow-xl rounded-xl p-2 z-50 space-y-1 text-xs"> <div className="absolute top-full right-0 w-56 bg-white border border-medical-gray-200 shadow-xl rounded-xl p-2 z-50 space-y-1 text-xs">
<Link href="/wiki" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold"> <Link href="/wiki" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold">
<BookOpen className="w-4 h-4 text-canina-blue" /> <BookOpen className="w-4 h-4 text-canina-blue" />
دانشنامه علمی کنینا دانشنامه علمی کانینا
</Link> </Link>
<Link href="/blog" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold"> <Link href="/blog" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold">
<FileText className="w-4 h-4 text-canina-blue" /> <FileText className="w-4 h-4 text-canina-blue" />
@ -455,14 +455,14 @@ export default function Header({
onMouseLeave={() => setActiveDropdown(null)} onMouseLeave={() => setActiveDropdown(null)}
> >
<button className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-medical-gray-700 hover:bg-medical-gray-100 hover:text-canina-blue transition-all"> <button className="flex items-center gap-1.5 px-3 py-2 rounded-xl text-medical-gray-700 hover:bg-medical-gray-100 hover:text-canina-blue transition-all">
<span>درباره کنینا و تماس</span> <span>درباره کانینا و تماس</span>
<ChevronDown className="w-3.5 h-3.5" /> <ChevronDown className="w-3.5 h-3.5" />
</button> </button>
{activeDropdown === 'company' && ( {activeDropdown === 'company' && (
<div className="absolute top-full right-0 w-60 bg-white border border-medical-gray-200 shadow-xl rounded-xl p-2 z-50 space-y-1 text-xs"> <div className="absolute top-full right-0 w-60 bg-white border border-medical-gray-200 shadow-xl rounded-xl p-2 z-50 space-y-1 text-xs">
<Link href="/about" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold"> <Link href="/about" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold">
<Award className="w-4 h-4 text-canina-blue" /> <Award className="w-4 h-4 text-canina-blue" />
درباره کمپانی کنینا آلمان درباره کمپانی کانینا آلمان
</Link> </Link>
<Link href="/trust-seals" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold text-emerald-600"> <Link href="/trust-seals" className="flex items-center gap-2 px-3 py-2 hover:bg-canina-blue/5 hover:text-canina-blue rounded-lg font-bold text-emerald-600">
<ShieldCheck className="w-4 h-4 text-emerald-600" /> <ShieldCheck className="w-4 h-4 text-emerald-600" />
@ -517,7 +517,7 @@ export default function Header({
<div className="space-y-2 text-sm font-black"> <div className="space-y-2 text-sm font-black">
<Link href="/shop" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl bg-medical-gray-50 text-medical-gray-900"> <Link href="/shop" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl bg-medical-gray-50 text-medical-gray-900">
🛒 محصولات تخصصی کنینا 🛒 محصولات تخصصی کانینا
</Link> </Link>
<Link href="/catalog" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800"> <Link href="/catalog" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800">
📑 کاتالوگ آنلاین و دوز مصرفی 📑 کاتالوگ آنلاین و دوز مصرفی

View File

@ -49,7 +49,7 @@ export default function Hero({ banners = [], onShopNavigate }: { banners?: Banne
}, []); }, []);
const defaultTitle = banners.length > 0 && banners[0].title ? banners[0].title : "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی"; const defaultTitle = banners.length > 0 && banners[0].title ? banners[0].title : "تخصص آلمانی در خدمت\nسلامت پت‌های خانگی";
const defaultSubtitle = banners.length > 0 && banners[0].subtitle ? banners[0].subtitle : 'از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کنینا نماینده رسمی این برند در ایران است.'; const defaultSubtitle = banners.length > 0 && banners[0].subtitle ? banners[0].subtitle : 'از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهره‌گیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکمل‌های دامپزشکی را تعریف می‌کند. کانینا نماینده رسمی این برند در ایران است.';
const title = (mounted && isInitialized ? getText('hero_title', '') : '') || defaultTitle; const title = (mounted && isInitialized ? getText('hero_title', '') : '') || defaultTitle;
const subtitle = (mounted && isInitialized ? getText('hero_desc', '') : '') || defaultSubtitle; const subtitle = (mounted && isInitialized ? getText('hero_desc', '') : '') || defaultSubtitle;

View File

@ -82,7 +82,7 @@ export default function IngredientWiki() {
علم در خدمت کیفیت علم در خدمت کیفیت
</div> </div>
<h2 className="text-4xl lg:text-6xl font-black text-medical-gray-900 leading-tight md:max-w-4xl"> <h2 className="text-4xl lg:text-6xl font-black text-medical-gray-900 leading-tight md:max-w-4xl">
دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کنینا دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کانینا
</h2> </h2>
<p className="mt-6 text-lg text-medical-gray-500 max-w-2xl leading-relaxed"> <p className="mt-6 text-lg text-medical-gray-500 max-w-2xl leading-relaxed">
ما از مواد اولیه‌ای استفاده می‌کنیم که در سطح دارویی فرآوری شده‌اند. در اینجا با قدرت بیولوژیک این ترکیبات آشنا شوید. ما از مواد اولیه‌ای استفاده می‌کنیم که در سطح دارویی فرآوری شده‌اند. در اینجا با قدرت بیولوژیک این ترکیبات آشنا شوید.

View File

@ -203,7 +203,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
<ShieldCheck className="w-10 h-10 text-canina-blue" /> <ShieldCheck className="w-10 h-10 text-canina-blue" />
</div> </div>
<h3 className="text-3xl font-black text-medical-gray-900 mb-2 italic"> <h3 className="text-3xl font-black text-medical-gray-900 mb-2 italic">
ورود به کنینا ورود به کانینا
</h3> </h3>
{isAdvisorContext ? ( {isAdvisorContext ? (
<p className="text-medical-gray-500 font-bold leading-relaxed px-2 text-sm"> <p className="text-medical-gray-500 font-bold leading-relaxed px-2 text-sm">

View File

@ -23,7 +23,7 @@ export default function MaintenancePage() {
</h1> </h1>
<p className="text-sm sm:text-base text-medical-gray-300 leading-relaxed"> <p className="text-sm sm:text-base text-medical-gray-300 leading-relaxed">
وب‌سایت کنینا ایران جهت ارتقای زیرساخت‌ها و ارائه خدمات بهتر به شما سرپرستان و دامپزشکان محترم به صورت موقت در دست به‌روزرسانی است. از شکیبایی شما سپاسگزاریم. وب‌سایت کانینا ایران جهت ارتقای زیرساخت‌ها و ارائه خدمات بهتر به شما سرپرستان و دامپزشکان محترم به صورت موقت در دست به‌روزرسانی است. از شکیبایی شما سپاسگزاریم.
</p> </p>
<div className="pt-4 flex flex-col sm:flex-row items-center justify-center gap-4"> <div className="pt-4 flex flex-col sm:flex-row items-center justify-center gap-4">

View File

@ -24,7 +24,7 @@ interface OrderDetailsModalProps {
export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetailsModalProps) { export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetailsModalProps) {
if (!order) return null; if (!order) return null;
const getProductName = (p: Record<string, unknown> | undefined) => String(p?.nameFa || p?.name || p?.nameEn || 'محصول کنینا'); const getProductName = (p: Record<string, unknown> | undefined) => String(p?.nameFa || p?.name || p?.nameEn || 'محصول کانینا');
const getProductImage = (p: Record<string, unknown> | undefined) => String(p?.imageUrl || p?.image || '/products/product-placeholder.png'); const getProductImage = (p: Record<string, unknown> | undefined) => String(p?.imageUrl || p?.image || '/products/product-placeholder.png');
const displayTrackingCode = String(order.trackingNumber || (typeof order.id === 'string' ? order.id.substring(0, 8) : '') || 'CN-0000'); const displayTrackingCode = String(order.trackingNumber || (typeof order.id === 'string' ? order.id.substring(0, 8) : '') || 'CN-0000');
@ -76,7 +76,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
<html dir="rtl" lang="fa"> <html dir="rtl" lang="fa">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>فاکتور رسمی کنینا - ${displayTrackingCode}</title> <title>فاکتور رسمی کانینا - ${displayTrackingCode}</title>
<style> <style>
@font-face { @font-face {
font-family: 'Vazirmatn'; font-family: 'Vazirmatn';
@ -104,7 +104,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
<div class="invoice-card"> <div class="invoice-card">
<div class="header"> <div class="header">
<div> <div>
<div class="logo-text">CANINA | کنینا</div> <div class="logo-text">CANINA | کانینا</div>
<div class="sub-logo">مکمل‌های تخصصی دامپزشکی آلمان</div> <div class="sub-logo">مکمل‌های تخصصی دامپزشکی آلمان</div>
</div> </div>
<div style="text-align: left;"> <div style="text-align: left;">
@ -167,7 +167,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
<div class="footer"> <div class="footer">
این فاکتور رسمی به صورت هوشمند و سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/> این فاکتور رسمی به صورت هوشمند و سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/>
پشتیبانی کنینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir پشتیبانی کانینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
</div> </div>
</div> </div>
@ -355,7 +355,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
className="flex-1 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" className="flex-1 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"
> >
<Download className="w-5 h-5" /> <Download className="w-5 h-5" />
دانلود و چاپ فاکتور رسمی کنینا دانلود و چاپ فاکتور رسمی کانینا
</button> </button>
</div> </div>
</motion.div> </motion.div>

View File

@ -50,7 +50,7 @@ export default function OrderTracking() {
</button> </button>
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2"> <div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2">
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کنینا</span> <span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
<ChevronLeft className="w-2.5 h-2.5" /> <ChevronLeft className="w-2.5 h-2.5" />
<span className="text-canina-blue">پیگیری سفارش</span> <span className="text-canina-blue">پیگیری سفارش</span>
</div> </div>

View File

@ -1090,9 +1090,9 @@ export default function PetProfile({ initialView }: {
<div className="flex justify-center mb-8"> <div className="flex justify-center mb-8">
<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 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> </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"> <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> </p>
</div> </div>

View File

@ -117,7 +117,7 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio
</div> </div>
<h4 className="text-lg font-black text-medical-gray-900">نسخه با موفقیت ثبت شد</h4> <h4 className="text-lg font-black text-medical-gray-900">نسخه با موفقیت ثبت شد</h4>
<p className="text-xs text-medical-gray-500 max-w-sm mx-auto leading-relaxed"> <p className="text-xs text-medical-gray-500 max-w-sm mx-auto leading-relaxed">
کارشناسان و دامپزشکان کنینا نسخه شما را بررسی کرده و ظرف حداکثر ۱۵ دقیقه جهت هماهنگی ارسال دارو با شما تماس خواهند گرفت. کارشناسان و دامپزشکان کانینا نسخه شما را بررسی کرده و ظرف حداکثر ۱۵ دقیقه جهت هماهنگی ارسال دارو با شما تماس خواهند گرفت.
</p> </p>
<button <button
onClick={handleClose} onClick={handleClose}

View File

@ -14,7 +14,7 @@ interface SafeImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>,
export default function SafeImage({ export default function SafeImage({
src, src,
alt = "تصویر مکمل کنینا", alt = "تصویر مکمل کانینا",
className, className,
imgClassName, imgClassName,
fallbackText = "در حال بروزرسانی تصویر..." fallbackText = "در حال بروزرسانی تصویر..."

View File

@ -181,9 +181,9 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<Sparkle className="w-4 h-4 text-canina-blue animate-spin" /> <Sparkle className="w-4 h-4 text-canina-blue animate-spin" />
<span suppressHydrationWarning className="text-canina-blue text-xs font-black uppercase tracking-widest font-vazir">{getText('advisor_badge', "سیستم پایش و تجویز هوشمند")}</span> <span suppressHydrationWarning className="text-canina-blue text-xs font-black uppercase tracking-widest font-vazir">{getText('advisor_badge', "سیستم پایش و تجویز هوشمند")}</span>
</motion.div> </motion.div>
<h2 suppressHydrationWarning className="text-4xl lg:text-5xl font-black text-medical-gray-900 mb-4 font-lalezar tracking-wide">{getText('advisor_title', "دستیار سلامت و الگوریتم پایش کنینا")}</h2> <h2 suppressHydrationWarning className="text-4xl lg:text-5xl font-black text-medical-gray-900 mb-4 font-lalezar tracking-wide">{getText('advisor_title', "دستیار سلامت و الگوریتم پایش کانینا")}</h2>
<p suppressHydrationWarning className="text-medical-gray-600 font-medium text-base font-shabnam max-w-2xl mx-auto leading-relaxed"> <p suppressHydrationWarning className="text-medical-gray-600 font-medium text-base font-shabnam max-w-2xl mx-auto leading-relaxed">
{getText('advisor_subtitle', "با ثبت اطلاعات همدم خود در ۴ قدم ساده، از الگوریتم علمی کنینا برای تجویز دقیق مکمل و پایش سلامت بهره‌مند شوید.")} {getText('advisor_subtitle', "با ثبت اطلاعات همدم خود در ۴ قدم ساده، از الگوریتم علمی کانینا برای تجویز دقیق مکمل و پایش سلامت بهره‌مند شوید.")}
</p> </p>
<div className="mt-4 flex justify-center"> <div className="mt-4 flex justify-center">
@ -213,7 +213,7 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
<h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">چرا ثبت شناسنامه؟</h3> <h3 className="text-base sm:text-lg font-black text-medical-gray-900 sm:mb-2 font-vazir">چرا ثبت شناسنامه؟</h3>
</div> </div>
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir"> <p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
مکمل‌های دارویی کنینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه می‌کند. مکمل‌های دارویی کانینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه می‌کند.
</p> </p>
</div> </div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir"> <div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-medical-gray-100 text-[10px] font-black text-canina-blue flex items-center gap-1 font-vazir">

View File

@ -7,7 +7,7 @@ export default function TickerBanner() {
const getText = useSettingsStore((state) => state.getText); const getText = useSettingsStore((state) => state.getText);
const announcementText = getText( const announcementText = getText(
"shipping_notice", "shipping_notice",
"ارسال رایگان برای سفارش‌های بالای ۱۵۰ هزار تومان — گارانتی اصالت کنینا آلمان — مشاوره تخصصی مکمل‌های دارویی سگ و گربه با کادر دامپزشکان مجرب" "ارسال رایگان برای سفارش‌های بالای ۱۵۰ هزار تومان — گارانتی اصالت کانینا آلمان — مشاوره تخصصی مکمل‌های دارویی سگ و گربه با کادر دامپزشکان مجرب"
); );
return ( return (

View File

@ -37,7 +37,7 @@ export default function Tooltip({ termKey, children, onWikiNavigate }: TooltipPr
> >
<div className="flex items-center gap-2 mb-2 text-canina-blue"> <div className="flex items-center gap-2 mb-2 text-canina-blue">
<Info className="w-4 h-4" /> <Info className="w-4 h-4" />
<span className="font-black text-[11px] uppercase tracking-widest text-canina-blue">دانشنامه علمی کنینا</span> <span className="font-black text-[11px] uppercase tracking-widest text-canina-blue">دانشنامه علمی کانینا</span>
</div> </div>
<h5 className="font-black text-base text-medical-gray-900 mb-2 leading-snug">{termData.term}</h5> <h5 className="font-black text-base text-medical-gray-900 mb-2 leading-snug">{termData.term}</h5>
<p className="text-medical-gray-600 text-xs leading-relaxed mb-4 font-bold"> <p className="text-medical-gray-600 text-xs leading-relaxed mb-4 font-bold">

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { useState } from "react";
import { motion } from "motion/react"; import { motion } from "motion/react";
import { User, ShoppingBag, Wallet, MapPin, LogOut, ChevronRight, Package, Calendar, UserCircle, ShoppingCart, Trash2, Edit2, Phone, Hash, CheckCircle2, ArrowUpCircle, ArrowDownCircle, Info, Clock, CheckCircle, Heart, Sparkles, MessageSquare, Send, Stethoscope, FileText, Lock, Key, Eye, EyeOff, ShieldCheck } from "lucide-react"; import { User, ShoppingBag, Wallet, MapPin, LogOut, ChevronRight, Package, Calendar, UserCircle, ShoppingCart, Trash2, Edit2, Phone, Hash, CheckCircle2, ArrowUpCircle, ArrowDownCircle, Info, Clock, CheckCircle, Heart, Sparkles, MessageSquare, Send, Stethoscope, FileText } from "lucide-react";
import { OrderRowSkeleton } from "./Skeleton"; import { OrderRowSkeleton } from "./Skeleton";
import { useUserStore, Address } from "../lib/store/userStore"; import { useUserStore, Address } from "../lib/store/userStore";
import { useCartStore } from "../lib/store/cartStore"; import { useCartStore } from "../lib/store/cartStore";
@ -107,48 +107,6 @@ export default function UserDashboard() {
} }
}; };
// Password Management State
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [showCurrentPass, setShowCurrentPass] = useState(false);
const [showNewPass, setShowNewPass] = useState(false);
const [showConfirmPass, setShowConfirmPass] = useState(false);
const [isSavingPassword, setIsSavingPassword] = useState(false);
const handleSavePassword = async (e: React.FormEvent) => {
e.preventDefault();
if (!newPassword || newPassword.length < 6) {
toast.error("رمز عبور جدید باید حداقل ۶ کاراکتر باشد");
return;
}
if (newPassword !== confirmPassword) {
toast.error("رمز عبور جدید و تکرار آن یکسان نیستند");
return;
}
if (profile.hasPassword && !currentPassword) {
toast.error("لطفاً رمز عبور فعلی خود را وارد کنید");
return;
}
setIsSavingPassword(true);
try {
await updateProfile({
password: newPassword.trim(),
currentPassword: profile.hasPassword ? currentPassword.trim() : undefined,
});
toast.success(profile.hasPassword ? "رمز عبور با موفقیت تغییر کرد" : "رمز عبور با موفقیت برای حساب شما ثبت شد");
setCurrentPassword("");
setNewPassword("");
setConfirmPassword("");
} catch (err: unknown) {
const errObj = err as { message?: string };
toast.error(errObj.message || "خطا در ثبت رمز عبور");
} finally {
setIsSavingPassword(false);
}
};
const handleLogout = () => { const handleLogout = () => {
logout(); logout();
router.push('/'); router.push('/');
@ -381,140 +339,9 @@ export default function UserDashboard() {
</button> </button>
)} )}
</div> </div>
</form> </form>
</div>
{/* Password & Security Section */} )}
<div className="mt-12 pt-8 border-t border-medical-gray-100">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-6">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-2xl bg-canina-blue/10 text-canina-blue flex items-center justify-center">
<Lock className="w-5 h-5" />
</div>
<div>
<h4 className="text-lg font-black text-medical-gray-900 italic">
{profile.hasPassword ? "تغییر رمز عبور حساب" : "تعریف رمز عبور برای حساب کاربری"}
</h4>
<p className="text-xs font-medium text-medical-gray-400">
{profile.hasPassword
? "برای افزایش امنیت می‌توانید رمز عبور ورود خود را تغییر دهید."
: "با تعیین رمز عبور می‌توانید در دفعات بعدی علاوه بر پیامک، با رمز عبور نیز وارد شوید."}
</p>
</div>
</div>
<span
className={cn(
"px-3 py-1 rounded-full text-[11px] font-bold self-start sm:self-auto",
profile.hasPassword
? "bg-green-50 text-green-700 border border-green-200"
: "bg-amber-50 text-amber-700 border border-amber-200"
)}
>
{profile.hasPassword ? "رمز عبور فعال است" : "ورود فقط با OTP"}
</span>
</div>
<form onSubmit={handleSavePassword} className="bg-medical-gray-50/50 p-6 sm:p-8 rounded-[2rem] border border-medical-gray-100 space-y-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{profile.hasPassword && (
<div className="space-y-1.5">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-2">
رمز عبور فعلی *
</label>
<div className="relative">
<input
type={showCurrentPass ? "text" : "password"}
autoComplete="current-password"
required
placeholder="رمز فعلی..."
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-xl py-3 pr-3 pl-10 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono"
dir="ltr"
/>
<button
type="button"
onClick={() => setShowCurrentPass(!showCurrentPass)}
className="absolute left-2.5 top-1/2 -translate-y-1/2 p-1 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
>
{showCurrentPass ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
)}
<div className="space-y-1.5">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-2">
{profile.hasPassword ? "رمز عبور جدید *" : "رمز عبور دلخواه *"}
</label>
<div className="relative">
<input
type={showNewPass ? "text" : "password"}
autoComplete="new-password"
required
placeholder="حداقل ۶ کاراکتر"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-xl py-3 pr-3 pl-10 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono"
dir="ltr"
/>
<button
type="button"
onClick={() => setShowNewPass(!showNewPass)}
className="absolute left-2.5 top-1/2 -translate-y-1/2 p-1 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
>
{showNewPass ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
<div className="space-y-1.5">
<label className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest block pr-2">
تکرار رمز عبور *
</label>
<div className="relative">
<input
type={showConfirmPass ? "text" : "password"}
autoComplete="new-password"
required
placeholder="تکرار رمز عبور"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full bg-white border border-medical-gray-200 rounded-xl py-3 pr-3 pl-10 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono"
dir="ltr"
/>
<button
type="button"
onClick={() => setShowConfirmPass(!showConfirmPass)}
className="absolute left-2.5 top-1/2 -translate-y-1/2 p-1 text-medical-gray-400 hover:text-medical-gray-700 transition-colors cursor-pointer"
tabIndex={-1}
>
{showConfirmPass ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
</div>
</div>
<div className="flex justify-end pt-3">
<button
type="submit"
disabled={isSavingPassword || newPassword.length < 6 || !confirmPassword}
className="px-8 py-3.5 bg-canina-blue hover:bg-indigo-700 text-white rounded-xl font-black text-xs transition-all shadow-md shadow-canina-blue/15 flex items-center gap-2 cursor-pointer disabled:opacity-50"
>
{isSavingPassword ? (
<span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
) : (
<ShieldCheck className="w-4 h-4" />
)}
{profile.hasPassword ? "بروزرسانی رمز عبور" : "ثبت رمز عبور"}
</button>
</div>
</form>
</div>
</div>
)}
{activeTab === "orders" && ( {activeTab === "orders" && (
<div> <div>

View File

@ -107,7 +107,7 @@ export default function VetGallery({ testimonials = [] }: { testimonials?: Testi
{getText('videos_title', "مشاوره ویدئویی")} <span className="text-canina-blue underline decoration-4 decoration-canina-blue/20 underline-offset-8">{getText('videos_title_highlight', "دوست دامپزشک پت شما")}</span> {getText('videos_title', "مشاوره ویدئویی")} <span className="text-canina-blue underline decoration-4 decoration-canina-blue/20 underline-offset-8">{getText('videos_title_highlight', "دوست دامپزشک پت شما")}</span>
</h2> </h2>
<p className="text-lg text-medical-gray-500 font-medium mt-6"> <p className="text-lg text-medical-gray-500 font-medium mt-6">
{getText('videos_desc', "تیم علمی و فرموله‌کنندگان کمپانی کنینا در آلمان مستقیماً با شما صحبت می‌کنند؛ آشنایی با نحوه مصرف، مزایای بالینی و دانش پزشکی پشت هر محصول.")} {getText('videos_desc', "تیم علمی و فرموله‌کنندگان کمپانی کانینا در آلمان مستقیماً با شما صحبت می‌کنند؛ آشنایی با نحوه مصرف، مزایای بالینی و دانش پزشکی پشت هر محصول.")}
</p> </p>
</div> </div>
<Link <Link

View File

@ -85,7 +85,7 @@ export default function VideosPage() {
Video Academy Video Academy
</div> </div>
<h1 className="text-4xl lg:text-6xl font-black text-white italic leading-tight"> <h1 className="text-4xl lg:text-6xl font-black text-white italic leading-tight">
آکادمی ویدئویی <span className="text-canina-blue">کنینا</span> آکادمی ویدئویی <span className="text-canina-blue">کانینا</span>
</h1> </h1>
</div> </div>
<button <button

View File

@ -8,9 +8,9 @@ describe('Footer', () => {
it('renders footer brand text and standard layout elements', () => { it('renders footer brand text and standard layout elements', () => {
render(<Footer onNavigate={vi.fn()} onShopNavigate={vi.fn()} onB2BOpen={vi.fn()} />); 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(); expect(screen.getByText('تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹')).toBeInTheDocument();
}); });
it('triggers onNavigate and onShopNavigate when quick links are clicked', () => { it('triggers onNavigate and onShopNavigate when quick links are clicked', () => {

View File

@ -121,7 +121,7 @@ export default function CatalogPageSpread({
<div className="space-y-2"> <div className="space-y-2">
<h1 className="text-2xl sm:text-3xl md:text-4xl font-black font-lalezar leading-tight text-transparent bg-clip-text bg-gradient-to-r from-amber-100 via-white to-amber-300"> <h1 className="text-2xl sm:text-3xl md:text-4xl font-black font-lalezar leading-tight text-transparent bg-clip-text bg-gradient-to-r from-amber-100 via-white to-amber-300">
کاتالوگ تخصصی و راهنمای بالینی مکمل‌های دارویی کنینا کاتالوگ تخصصی و راهنمای بالینی مکمل‌های دارویی کانینا
</h1> </h1>
<p className="text-[11px] md:text-xs text-slate-300 font-medium max-w-md mx-auto leading-relaxed"> <p className="text-[11px] md:text-xs text-slate-300 font-medium max-w-md mx-auto leading-relaxed">
مرجع رسمی مکمل‌های درمانی حیوانات خانگی با استانداردهای داروسازی آلمان (GMP) و تاییدیه‌های ارتوپدی و پوست مرجع رسمی مکمل‌های درمانی حیوانات خانگی با استانداردهای داروسازی آلمان (GMP) و تاییدیه‌های ارتوپدی و پوست
@ -242,7 +242,7 @@ export default function CatalogPageSpread({
<div className="bg-amber-50/70 border border-amber-200/60 rounded-xl p-2.5 flex items-center gap-2.5 shrink-0"> <div className="bg-amber-50/70 border border-amber-200/60 rounded-xl p-2.5 flex items-center gap-2.5 shrink-0">
<Award className="w-4 h-4 text-amber-600 shrink-0" /> <Award className="w-4 h-4 text-amber-600 shrink-0" />
<p className="text-[10px] text-amber-900 font-bold leading-relaxed"> <p className="text-[10px] text-amber-900 font-bold leading-relaxed">
تمامی فرآورده‌های کنینا آلمان مطابق با مونوگراف‌های دارویی فارماکوپه اروپا (Ph. Eur.) و تحت استاندارد GMP تولید می‌شوند. تمامی فرآورده‌های کانینا آلمان مطابق با مونوگراف‌های دارویی فارماکوپه اروپا (Ph. Eur.) و تحت استاندارد GMP تولید می‌شوند.
</p> </p>
</div> </div>
@ -298,7 +298,7 @@ export default function CatalogPageSpread({
</div> </div>
<div> <div>
<span className="text-slate-400 block">واردکننده انحصاری:</span> <span className="text-slate-400 block">واردکننده انحصاری:</span>
<span className="font-black text-white">کنینا فارما ایران</span> <span className="font-black text-white">کانینا فارما ایران</span>
</div> </div>
</div> </div>

View File

@ -464,7 +464,7 @@ export default function FlipbookCatalog({ products }: FlipbookCatalogProps) {
CP CP
</div> </div>
<h3 className="text-base font-black font-lalezar text-white"> <h3 className="text-base font-black font-lalezar text-white">
کاتالوگ تخصصی کنینا آلمان کاتالوگ تخصصی کانینا آلمان
</h3> </h3>
<p className="text-[11px] text-slate-400 leading-relaxed font-medium"> <p className="text-[11px] text-slate-400 leading-relaxed font-medium">
جهت باز کردن کاتالوگ و شروع مطالعه، روی صفحه چپ یا کلید ← کیبورد را بزنید. جهت باز کردن کاتالوگ و شروع مطالعه، روی صفحه چپ یا کلید ← کیبورد را بزنید.

View File

@ -351,7 +351,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر ماری کونیگ", name: "دکتر ماری کونیگ",
title: "متخصص تغذیه دامپزشکی", title: "متخصص تغذیه دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200", 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" image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
}, },
@ -512,7 +512,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر مونیخ", name: "دکتر مونیخ",
title: "متخصص طب طبیعی دامپزشکی", title: "متخصص طب طبیعی دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200", 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" image: "https://www.canina.de/media/1b/83/7d/1715077272/Schwarz-Kuemmel-112503-V1-Canino-250ml_600x600.webp"
}, },
@ -1066,7 +1066,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر بکر", name: "دکتر بکر",
title: "متخصص تولیدمثل دامپزشکی", title: "متخصص تولیدمثل دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200", 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" image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
}, },
@ -1100,7 +1100,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر کوهن", name: "دکتر کوهن",
title: "متخصص طب سنتی دامپزشکی", title: "متخصص طب سنتی دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200", 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" image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
}, },
@ -1224,7 +1224,7 @@ export const PRODUCTS: Product[] = [
name: "دکتر بکر", name: "دکتر بکر",
title: "متخصص تولیدمثل دامپزشکی", title: "متخصص تولیدمثل دامپزشکی",
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200", 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" image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
} }

View File

@ -9,9 +9,6 @@ export interface User {
role: string; role: string;
walletBalance: number; walletBalance: number;
charityDonationTotal: number; charityDonationTotal: number;
hasPassword?: boolean;
password?: string;
currentPassword?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
pets?: unknown[]; pets?: unknown[];

View File

@ -90,10 +90,10 @@ export class ProductService {
const priceVal = Number(data.priceValue || 0); const priceVal = Number(data.priceValue || 0);
const defaultSpecialist = local?.specialist || { const defaultSpecialist = local?.specialist || {
name: 'تیم تخصصی کنینا', name: 'تیم تخصصی کانینا',
title: 'مشاور علمی و دارویی', title: 'مشاور علمی و دارویی',
image: '/images/vets/vet1.webp', image: '/images/vets/vet1.webp',
message: 'تمامی محصولات مکمل کنینا دارای استانداردهای دارویی آلمان و تاییدیه کلینیکی هستند.' message: 'تمامی محصولات مکمل کانینا دارای استانداردهای دارویی آلمان و تاییدیه کلینیکی هستند.'
}; };
return { return {

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import { create } from "zustand"; import { create } from "zustand";
import { persist } from "zustand/middleware"; import { persist } from "zustand/middleware";
import { authService, User } from "../services/authService"; import { authService } from "../services/authService";
import api from "../services/api"; import api from "../services/api";
import { useCartStore } from "./cartStore"; import { useCartStore } from "./cartStore";
import { usePetStore } from "./usePetStore"; import { usePetStore } from "./usePetStore";
@ -37,7 +37,6 @@ interface UserProfile {
mobile: string; mobile: string;
walletBalance: number; walletBalance: number;
charityDonationTotal: number; charityDonationTotal: number;
hasPassword?: boolean;
addresses: Address[]; addresses: Address[];
transactions: Transaction[]; transactions: Transaction[];
} }
@ -50,7 +49,7 @@ interface UserStore {
setRole: (role: UserRole) => void; setRole: (role: UserRole) => void;
setLoggedIn: (isLoggedIn: boolean) => void; setLoggedIn: (isLoggedIn: boolean) => void;
setAuthModalOpen: (open: boolean) => void; setAuthModalOpen: (open: boolean) => void;
updateProfile: (profile: Partial<UserProfile & { password?: string; currentPassword?: string }>) => Promise<void>; updateProfile: (profile: Partial<UserProfile>) => Promise<void>;
addAddress: (address: Address) => Promise<void>; addAddress: (address: Address) => Promise<void>;
updateAddress: (id: string, address: Address) => Promise<void>; updateAddress: (id: string, address: Address) => Promise<void>;
deleteAddress: (id: string) => Promise<void>; deleteAddress: (id: string) => Promise<void>;
@ -73,7 +72,6 @@ export const useUserStore = create<UserStore>()(
mobile: "", mobile: "",
walletBalance: 0, walletBalance: 0,
charityDonationTotal: 0, charityDonationTotal: 0,
hasPassword: false,
addresses: [], addresses: [],
transactions: [], transactions: [],
}, },
@ -82,7 +80,7 @@ export const useUserStore = create<UserStore>()(
setAuthModalOpen: (open) => set({ isAuthModalOpen: open }), setAuthModalOpen: (open) => set({ isAuthModalOpen: open }),
updateProfile: async (updates) => { updateProfile: async (updates) => {
try { try {
const profileData = await authService.updateProfile(updates as Partial<User>); const profileData = await authService.updateProfile(updates);
set((state) => ({ set((state) => ({
profile: { profile: {
...state.profile, ...state.profile,
@ -90,7 +88,6 @@ export const useUserStore = create<UserStore>()(
lastName: profileData.lastName, lastName: profileData.lastName,
email: profileData.email, email: profileData.email,
mobile: profileData.mobile || "", mobile: profileData.mobile || "",
hasPassword: profileData.hasPassword !== undefined ? profileData.hasPassword : state.profile.hasPassword,
} }
})); }));
} catch (error) { } catch (error) {
@ -249,7 +246,6 @@ export const useUserStore = create<UserStore>()(
mobile: profileData.mobile || "", mobile: profileData.mobile || "",
walletBalance: backendWallet, walletBalance: backendWallet,
charityDonationTotal: backendCharity, charityDonationTotal: backendCharity,
hasPassword: profileData.hasPassword !== undefined ? profileData.hasPassword : state.profile.hasPassword,
addresses: Array.isArray(pd.addresses) && pd.addresses.length > 0 ? (pd.addresses as Address[]) : state.profile.addresses, addresses: Array.isArray(pd.addresses) && pd.addresses.length > 0 ? (pd.addresses as Address[]) : state.profile.addresses,
transactions: backendTransactions.length > 0 ? backendTransactions : state.profile.transactions transactions: backendTransactions.length > 0 ? backendTransactions : state.profile.transactions
} }