Compare commits
No commits in common. "8d1b786a24be715b2e51c1d6bb3ef998b064a427" and "897b4d61ec7016dc7b0ce14c007d5cda35c7cad4" have entirely different histories.
8d1b786a24
...
897b4d61ec
@ -1,6 +1,6 @@
|
||||
# نقشه جامع اتصال به بکبند (Comprehensive Backend Integration Map) 🏗️
|
||||
|
||||
این سند حاوی معماری دقیق، فهرست کامل نقاط اتصال (API Endpoints)، کامنتهای مکاننما در کد (TODO Markers)، و تعاریف رسمی تمامی تایپهای ورودی (Inputs) و خروجی (Outputs) پلتفرم درمانی و فروشگاهی کنینا ایران است.
|
||||
این سند حاوی معماری دقیق، فهرست کامل نقاط اتصال (API Endpoints)، کامنتهای مکاننما در کد (TODO Markers)، و تعاریف رسمی تمامی تایپهای ورودی (Inputs) و خروجی (Outputs) پلتفرم درمانی و فروشگاهی کانینا ایران است.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
-- ۴. جدول کاتالوگ محصولات کنینا (products)
|
||||
-- ۴. جدول کاتالوگ محصولات کانینا (products)
|
||||
CREATE TABLE products (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
art_no VARCHAR(20) UNIQUE NOT NULL,
|
||||
@ -250,7 +250,7 @@ CREATE INDEX idx_reminder_completions_ref ON reminder_completions(reminder_id, c
|
||||
"reminders": [
|
||||
{
|
||||
"id": "REM-001",
|
||||
"productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کنینا فیزیکی جهت کسر انبار پت
|
||||
"productId": "6472f8d38bfcb8234eccb611", // مکمل آرتروفیت کانینا فیزیکی جهت کسر انبار پت
|
||||
"title": "مصرف قرص مفصلساز Canhydrox",
|
||||
"time": "08:30",
|
||||
"frequency": "روزانه",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# پلتفرم کنینا ایران (Canina Iran Platform) 🐾
|
||||
# پلتفرم کانینا ایران (Canina Iran Platform) 🐾
|
||||
### لندینگ، فروشگاه تخصصی و پرونده سلامت الکترونیک پت (نمایندگی رسمی دارویی Canina Pharma)
|
||||
|
||||
پلتفرم **کنینا ایران** یک برنامه جامع تحت وب (SPA/PWA) مجهز به بردهای تعاملی و ابزارهای بهداشتی-دامپزشکی است که با هدف ارتقای سلامت حیوانات خانگی و دسترسی آسانتر به مکملهای دارویی گرید فوقارگانیک و دارویی کمپانی والای **Canina pharma GmbH آلمان** توسعه یافته است.
|
||||
پلتفرم **کانینا ایران** یک برنامه جامع تحت وب (SPA/PWA) مجهز به بردهای تعاملی و ابزارهای بهداشتی-دامپزشکی است که با هدف ارتقای سلامت حیوانات خانگی و دسترسی آسانتر به مکملهای دارویی گرید فوقارگانیک و دارویی کمپانی والای **Canina pharma GmbH آلمان** توسعه یافته است.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ async function main() {
|
||||
'<p>کلسیم یکی از مهمترین مواد معدنی برای رشد ساختار استخوانی است. تولهسگها در ماههای اول زندگی به کلسیم بیشتری نیاز دارند تا اسکلتبندی محکمی داشته باشند.</p>',
|
||||
'',
|
||||
'<h2>نسبت Ca:P (کلسیم به فسفر)</h2>',
|
||||
'<p>نسبت ایدهآل کلسیم به فسفر در رژیم تولهسگها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت میتواند منجر به ناهنجاریهای استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کنینا</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>',
|
||||
'<p>نسبت ایدهآل کلسیم به فسفر در رژیم تولهسگها <strong>۱.۲:۱ تا ۱.۵:۱</strong> است. عدم تعادل در این نسبت میتواند منجر به ناهنجاریهای استخوانی مانند پاهای پرانتزی و دیسپلازی هیپ شود. <strong>پودر پوسته تخم مرغ کانینا</strong> با ۳۶٪ کلسیم خالص و فسفر ۰.۱٪ بهترین گزینه برای تنظیم این نسبت است.</p>',
|
||||
'',
|
||||
'<h2>نقش ویتامین D3 در جذب کلسیم</h2>',
|
||||
'<p>ویتامین D3 (کولهکلسیفرول) جذب کلسیم از روده را تا ۳۰٪ افزایش میدهد. <strong>مصرف همزمان ویتامین D2 (ارگوکلسیفرول) با D3 مجاز نیست</strong> زیرا این دو با یکدیگر رقابت کرده و جذب مؤثر را کاهش میدهند.</p>',
|
||||
@ -49,12 +49,12 @@ async function main() {
|
||||
'<li><strong>B1 (تیامین):</strong> متابولیسم کربوهیدراتها و عملکرد سیستم عصبی</li>',
|
||||
'<li><strong>B2 (ریبوفلاوین):</strong> تولید انرژی و سلامت پوست</li>',
|
||||
'<li><strong>B6 (پیریدوکسین):</strong> سنتز پروتئین و تولید گلبول قرمز</li>',
|
||||
'<li><strong>B7 (بیوتین / ویتامین H):</strong> کراتینسازی مو و پنجه - <strong>Biotin-Tabs کنینا</strong> با ۱ میلیون میکروگرم بیوتین در کیلوگرم، قویترین دوز موجود در بازار است</li>',
|
||||
'<li><strong>B7 (بیوتین / ویتامین H):</strong> کراتینسازی مو و پنجه - <strong>Biotin-Tabs کانینا</strong> با ۱ میلیون میکروگرم بیوتین در کیلوگرم، قویترین دوز موجود در بازار است</li>',
|
||||
'<li><strong>B12 (کوبالامین):</strong> خونسازی و عملکرد عصبی</li>',
|
||||
'</ul>',
|
||||
'',
|
||||
'<h2>نقش بیوتین در سلامت پوشش</h2>',
|
||||
'<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانههای کلاسیک کمبود بیوتین هستند. قرص بیوتین کنینا با تأثیر از هفته چهارم، پوشش براق و پنجههای محکم را تضمین میکند.</p>',
|
||||
'<p>بیوتین کوآنزیم کربوکسیلازهای مسئول سنتز اسیدهای چرب و گلوکونئوژنز است. <strong>ریزش مو و شکنندگی پنجه</strong> از نشانههای کلاسیک کمبود بیوتین هستند. قرص بیوتین کانینا با تأثیر از هفته چهارم، پوشش براق و پنجههای محکم را تضمین میکند.</p>',
|
||||
'',
|
||||
'<h2>محصولات تقویتکننده پوست و مو</h2>',
|
||||
'<ul>',
|
||||
|
||||
@ -39,7 +39,7 @@ export async function main() {
|
||||
vetName: 'دکتر علیرضا رضایی',
|
||||
clinicName: 'کلینیک دامپزشکی پایتخت',
|
||||
imageUrl: '/assets/images/regenerated_image_1779109861747.png',
|
||||
quote: 'مکملهای مفصلی کنینا از نظر سرعت جذب و اثربخشی در سگهای نژاد بزرگ بینظیر هستند. ما نتایج فوقالعادهای روی دیسپلازی هیپ مشاهده کردیم.',
|
||||
quote: 'مکملهای مفصلی کانینا از نظر سرعت جذب و اثربخشی در سگهای نژاد بزرگ بینظیر هستند. ما نتایج فوقالعادهای روی دیسپلازی هیپ مشاهده کردیم.',
|
||||
rating: 5,
|
||||
order: 1,
|
||||
isActive: true,
|
||||
@ -48,7 +48,7 @@ export async function main() {
|
||||
vetName: 'دکتر سارا شمس',
|
||||
clinicName: 'بیمارستان دامپزشکی تهران',
|
||||
imageUrl: '/assets/images/regenerated_image_1779109861747.png',
|
||||
quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربهها، قرصهای مخمر و بیوتین کنینا را تجویز میکنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.',
|
||||
quote: 'من همیشه برای ریزش مو و مشکلات پوستی گربهها، قرصهای مخمر و بیوتین کانینا را تجویز میکنم. نتایج معمولاً در کمتر از ۳ هفته قابل مشاهده است.',
|
||||
rating: 5,
|
||||
order: 2,
|
||||
isActive: true,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
[
|
||||
{
|
||||
"name": "Canina Ballaststoff Mix (فیبر میکس کنینا)",
|
||||
"name": "Canina Ballaststoff Mix (فیبر میکس کانینا)",
|
||||
"category_slug": "immune",
|
||||
"description": "فیبر میکس کنینا حاوی منابع فیبر گیاهی از سیب، یونجه، نخود فرنگی و هویج است که به طور روزانه رژیم غذایی خام پت را تقویت میکند. فیبرها برای فلور پایدار روده مهم هستند؛ به عنوان پریبیوتیک، آنها به عنوان غذا برای باکتریهای روده بزرگ عمل میکنند. اجزای گیاهی، همیسلولز، سلولز، لیگنین و مواد معدنی طبیعی مانند منیزیم و پتاسیم را فراهم میکنند. فیبر میکس کنینا را میتوان به هر نوع غذایی اضافه کرد. حتی رژیمهای غذایی خام و غذاهای خانگی اغلب فاقد فیبری هستند که حرکت طبیعی روده را تحریک کرده و مدفوع را حجیمتر میکند. این فیبرها میتوانند تأثیر مثبتی بر حرکات دودی روده، مدفوع و تخلیه غدد مقعدی داشته باشند. مانان الیگوساکارید و بتا گلوکان از دیواره سلولی مخمر سیستم ایمنی روده را تقویت میکنند. بتا گلوکانها به عنوان منبع انرژی برای باکتریهای روده بزرگ عمل میکنند و توسط آنها به اسیدهای چرب زنجیره کوتاه تبدیل میشوند که به نوبه خود به عنوان ماده مغذی برای سلولهای دیواره روده عمل میکنند.",
|
||||
"description": "فیبر میکس کانینا حاوی منابع فیبر گیاهی از سیب، یونجه، نخود فرنگی و هویج است که به طور روزانه رژیم غذایی خام پت را تقویت میکند. فیبرها برای فلور پایدار روده مهم هستند؛ به عنوان پریبیوتیک، آنها به عنوان غذا برای باکتریهای روده بزرگ عمل میکنند. اجزای گیاهی، همیسلولز، سلولز، لیگنین و مواد معدنی طبیعی مانند منیزیم و پتاسیم را فراهم میکنند. فیبر میکس کانینا را میتوان به هر نوع غذایی اضافه کرد. حتی رژیمهای غذایی خام و غذاهای خانگی اغلب فاقد فیبری هستند که حرکت طبیعی روده را تحریک کرده و مدفوع را حجیمتر میکند. این فیبرها میتوانند تأثیر مثبتی بر حرکات دودی روده، مدفوع و تخلیه غدد مقعدی داشته باشند. مانان الیگوساکارید و بتا گلوکان از دیواره سلولی مخمر سیستم ایمنی روده را تقویت میکنند. بتا گلوکانها به عنوان منبع انرژی برای باکتریهای روده بزرگ عمل میکنند و توسط آنها به اسیدهای چرب زنجیره کوتاه تبدیل میشوند که به نوبه خود به عنوان ماده مغذی برای سلولهای دیواره روده عمل میکنند.",
|
||||
"short_description": "فیبر گیاهی پریبیوتیک برای تنظیم فلور روده و بهبود گوارش سگ و گربه.",
|
||||
"ingredients": "تفاله سیب، پودر یونجه سبز، فیبر نخود فرنگی، تفاله هویج، کیک بذر کتان، کمپلکس الیگوساکارید و بتا-گلوکان، مخمر آبجو، کنگر فرنگی، خاک دیاتومه، روغن کلزا، کربنات کلسیم.",
|
||||
"usage_and_dosage": "گرم به ازای هر کیلوگرم وزن بدن، حداکثر 15 گرم در روز.",
|
||||
@ -34,9 +34,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Eierschalenpulver (پودر پوسته تخم مرغ کنینا)",
|
||||
"name": "Canina Eierschalenpulver (پودر پوسته تخم مرغ کانینا)",
|
||||
"category_slug": "energy",
|
||||
"description": "پودر پوسته تخم مرغ کنینا نه تنها کلسیم معدنی مهم مورد نیاز برای متابولیسم استخوان، سلامت دندانها و فعالیت عضلات را تأمین میکند، بلکه سایر مواد معدنی طبیعی مانند منیزیم، پتاسیم، سدیم، آهن، مس و روی را نیز تأمین میکند. از آنجایی که پودر پوسته تخم مرغ کنینا ریز آسیاب شده است، به خوبی تحمل میشود و بنابراین جذب کلسیم بسیار بالا است. پودر پوسته تخم مرغ کنینا یک جایگزین با کیفیت بالا برای پودر استخوان گوشت برای سگهایی است که به پروتئینهای گوشتی مانند گوشت گاو، مرغ یا خوک حساسیت دارند. پودر پوسته تخم مرغ کنینا به دلیل فسفر کم و کلسیم بالا، به ویژه برای تکمیل وعدههای غذایی گوشتی خام غنی از فسفر و کم کلسیم یا آمادهسازیهای گوشتی پخته شده مناسب است.",
|
||||
"description": "پودر پوسته تخم مرغ کانینا نه تنها کلسیم معدنی مهم مورد نیاز برای متابولیسم استخوان، سلامت دندانها و فعالیت عضلات را تأمین میکند، بلکه سایر مواد معدنی طبیعی مانند منیزیم، پتاسیم، سدیم، آهن، مس و روی را نیز تأمین میکند. از آنجایی که پودر پوسته تخم مرغ کانینا ریز آسیاب شده است، به خوبی تحمل میشود و بنابراین جذب کلسیم بسیار بالا است. پودر پوسته تخم مرغ کانینا یک جایگزین با کیفیت بالا برای پودر استخوان گوشت برای سگهایی است که به پروتئینهای گوشتی مانند گوشت گاو، مرغ یا خوک حساسیت دارند. پودر پوسته تخم مرغ کانینا به دلیل فسفر کم و کلسیم بالا، به ویژه برای تکمیل وعدههای غذایی گوشتی خام غنی از فسفر و کم کلسیم یا آمادهسازیهای گوشتی پخته شده مناسب است.",
|
||||
"short_description": "تامینکننده کلسیم ارگانیک و طبیعی مناسب رژیم خام گوشتی.",
|
||||
"ingredients": "100% پوسته تخم مرغ آسیاب شده. خاکستر خام 96%، کلسیم 36%، فسفر 0.1%.",
|
||||
"usage_and_dosage": "0.2 گرم به ازای هر کیلوگرم وزن بدن در روز.",
|
||||
@ -51,9 +51,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina FLEXAN (فلکسان کنینا)",
|
||||
"name": "Canina FLEXAN (فلکسان کانینا)",
|
||||
"category_slug": "joints",
|
||||
"description": "فلکسان کنینا به طور طبیعی از سیستم اسکلتی عضلانی سگ شما پشتیبانی میکند. مفاصل متحرک، استخوانهای پایدار، تحرک و تناسب اندام - پپتیدهای کلاژن زیستفعال، بلوکهای سازنده اولیه بدن هستند. کلاژن پروتئین ساختاری اصلی بافت همبند است. نشان داده شده است که تأمین هدفمند هیدرولیز کلاژن، سلولهای غضروف را فعال میکند و بنابراین به طور بهینه از بازسازی غضروف مفاصل پشتیبانی کرده و روند تخریب آن را کند میکند. همچنین سلولهای تشکیلدهنده استخوان را تحریک کرده و بافت استخوان را از نظر پایداري، انعطافپذیري، ماده و چگالی بهبود میبخشد. کلاژن زیستفعال موجود در مواد اولیه طبیعی با منشأ حیوانی تولید میشود. پپتیدهای کلاژن با فراهمی زیستی عالی مشخص میشوند و تقریباً بدون از دست رفتن توسط بدن جذب میشوند. پودر گوشت صدف لب سبز از صدف لب سبز نیوزیلند بلوکهای ساختمانی ارزشمندی (گلیکوزآمینوگلیکانها) را برای غضروف مفصل فراهم میکند و تمام بافت همبند را تقویت میکند. پپتیدهای کلاژن زیستفعال و پودر گوشت صدف لب سبز به صورت همافزایی با هم کار میکنند و تأثیر را بر کل سیستم اسکلتی عضلانی بهینه میکنند.",
|
||||
"description": "فلکسان کانینا به طور طبیعی از سیستم اسکلتی عضلانی سگ شما پشتیبانی میکند. مفاصل متحرک، استخوانهای پایدار، تحرک و تناسب اندام - پپتیدهای کلاژن زیستفعال، بلوکهای سازنده اولیه بدن هستند. کلاژن پروتئین ساختاری اصلی بافت همبند است. نشان داده شده است که تأمین هدفمند هیدرولیز کلاژن، سلولهای غضروف را فعال میکند و بنابراین به طور بهینه از بازسازی غضروف مفاصل پشتیبانی کرده و روند تخریب آن را کند میکند. همچنین سلولهای تشکیلدهنده استخوان را تحریک کرده و بافت استخوان را از نظر پایداري، انعطافپذیري، ماده و چگالی بهبود میبخشد. کلاژن زیستفعال موجود در مواد اولیه طبیعی با منشأ حیوانی تولید میشود. پپتیدهای کلاژن با فراهمی زیستی عالی مشخص میشوند و تقریباً بدون از دست رفتن توسط بدن جذب میشوند. پودر گوشت صدف لب سبز از صدف لب سبز نیوزیلند بلوکهای ساختمانی ارزشمندی (گلیکوزآمینوگلیکانها) را برای غضروف مفصل فراهم میکند و تمام بافت همبند را تقویت میکند. پپتیدهای کلاژن زیستفعال و پودر گوشت صدف لب سبز به صورت همافزایی با هم کار میکنند و تأثیر را بر کل سیستم اسکلتی عضلانی بهینه میکنند.",
|
||||
"short_description": "پپتیدهای کلاژن زیستفعال برای بازسازی غضروف و بهبود تحرک سگ.",
|
||||
"ingredients": "90% کلاژن هیدرولیز شده، 10% پودر گوشت صدف لب سبز.",
|
||||
"usage_and_dosage": "2 گرم به ازای هر 10 کیلوگرم وزن بدن، حداکثر 15 گرم در روز.",
|
||||
@ -68,7 +68,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina HERZ VITAL (هرز ویتال کنینا)",
|
||||
"name": "Canina HERZ VITAL (هرز ویتال کانینا)",
|
||||
"category_slug": "general",
|
||||
"description": "سگها و گربههای مسن اغلب از نارسایی قلبی رنج میبرند. ال-کارنیتین میتواند بر تأمین انرژی قلب و عضلات اسکلتی تأثیر مثبت بگذارد. این ماده میتواند نشاط، انگیزه و رفاه سگ/گربه شما را افزایش دهد. ال-کارنیتین میتواند عملکرد فیزیولوژیکی قلب را تقویت کند.",
|
||||
"short_description": "تقویتکننده طبیعی کارکرد ماهیچه قلب برای سگ و گربه مسن.",
|
||||
@ -85,9 +85,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina IMMUN-BOOSTER (ایمون بوستر کنینا)",
|
||||
"name": "Canina IMMUN-BOOSTER (ایمون بوستر کانینا)",
|
||||
"category_slug": "immune",
|
||||
"description": "بازیابی و نقاهت تغذیهای > چگالی انرژی بالا، غلظت بالای مواد مغذی ضروری و مواد تشکیلدهنده با قابلیت هضم بالا. تقویتکننده سیستم ایمنی کنینا انرژی قابل هضم و در دسترس، ویتامینهای با غلظت بالا و ایمونوگلوبولینهای آغوز را برای سگها و گربهها فراهم میکند. این اولین شیری است که مادر در طول و بعد از تولد تولید میکند. این شیر سرشار از لاکتوفرین و لیزوزیم است. تقویتکننده سیستم ایمنی کنینا از سیستم دفاعی بدن پشتیبانی میکند و مرحله بهبودی حیوانات را، به ویژه در حین و بعد از فعالیتهای بدنی مانند زایمان (حیوان مادر و همچنین توله سگها و بچه گربهها)، تمرین، ورزش و آزمایش، بهینه میکند. میکروب تشکیلدهنده اسید لاکتیک، انتروکوک فاسیوم، در تقویتکننده سیستم ایمنی کنینا، کلونیزاسیون سریع با لاکتوباسیلهای مهم را تضمین میکند. این باکتریها برای فلور روده سالم و متعادل و در نتیجه برای سیستم ایمنی پایدار روده ضروری هستند. اتصال میکروبهای منفی به مخاط روده خنثی میشود. این محصول یک خمیر خوشمزه است که سگها و گربهها از آن لذت میبرند. این محصول از توله سگها/بچه گربهها تا گربههای مسن مناسب است. برای حمایت از سلامت و عملکرد، این محصول میتواند جیره غذایی روزانه را افزایش دهد. این خمیر همچنین میتواند در مراحل خاصی از زندگی که غذای روزانه به طور مطلوب نیازهای بالای حیوان را برآورده نمیکند، تجویز شود.",
|
||||
"description": "بازیابی و نقاهت تغذیهای > چگالی انرژی بالا، غلظت بالای مواد مغذی ضروری و مواد تشکیلدهنده با قابلیت هضم بالا. تقویتکننده سیستم ایمنی کانینا انرژی قابل هضم و در دسترس، ویتامینهای با غلظت بالا و ایمونوگلوبولینهای آغوز را برای سگها و گربهها فراهم میکند. این اولین شیری است که مادر در طول و بعد از تولد تولید میکند. این شیر سرشار از لاکتوفرین و لیزوزیم است. تقویتکننده سیستم ایمنی کانینا از سیستم دفاعی بدن پشتیبانی میکند و مرحله بهبودی حیوانات را، به ویژه در حین و بعد از فعالیتهای بدنی مانند زایمان (حیوان مادر و همچنین توله سگها و بچه گربهها)، تمرین، ورزش و آزمایش، بهینه میکند. میکروب تشکیلدهنده اسید لاکتیک، انتروکوک فاسیوم، در تقویتکننده سیستم ایمنی کانینا، کلونیزاسیون سریع با لاکتوباسیلهای مهم را تضمین میکند. این باکتریها برای فلور روده سالم و متعادل و در نتیجه برای سیستم ایمنی پایدار روده ضروری هستند. اتصال میکروبهای منفی به مخاط روده خنثی میشود. این محصول یک خمیر خوشمزه است که سگها و گربهها از آن لذت میبرند. این محصول از توله سگها/بچه گربهها تا گربههای مسن مناسب است. برای حمایت از سلامت و عملکرد، این محصول میتواند جیره غذایی روزانه را افزایش دهد. این خمیر همچنین میتواند در مراحل خاصی از زندگی که غذای روزانه به طور مطلوب نیازهای بالای حیوان را برآورده نمیکند، تجویز شود.",
|
||||
"short_description": "خمیر انرژیبخش و ایمنساز حاوی آغوز و پروبیوتیک فعال.",
|
||||
"ingredients": "روغن ها و چربی های گیاهی، پودر آغوز 20%، شکر انگور.",
|
||||
"usage_and_dosage": "توله سگ ها: 0.25 میلی لیتر. سگ های متوسط: 0.5 تا 1 میلی لیتر. گربه ها: 0.25 میلی لیتر.",
|
||||
@ -102,7 +102,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Katzenmilch (شیر گربه کنینا)",
|
||||
"name": "Canina Katzenmilch (شیر گربه کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "غذای کامل جایگزین شیر مادر با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت. غذا با تمام ویتامینها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای بچهگربهها از ۱ روزگی، برای تغذیه بچهگربههای بیمادر، اگر تولید شیر مادر کافی نیست، برای تولههای بزرگ، برای آمادهسازی و در طول شیردهی، به عنوان مکمل برای گربههای مولد، به عنوان مکمل برای گربههای مسن و بیمار. فرمول این شیر بر اساس شیر طبیعی گربه مادر تهیه شده است.",
|
||||
"short_description": "شیر خشک غنی از تورین جایگزین کامل شیر مادر برای بچهگربهها.",
|
||||
@ -119,9 +119,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Lachsol (روغن ماهی سالمون کنینا)",
|
||||
"name": "Canina Lachsol (روغن ماهی سالمون کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "روغن ماهی سالمون کنینا از روغن ماهی سالمون ۱۰۰٪ خالص با کیفیت غذایی ساخته شده و سرشار از اسیدهای چرب چند غیراشباع (اسیدهای چرب امگا، EPA و DPA) است. از آنجایی که این اسیدهای چرب نمیتوانند توسط خود سگها و گربهها تولید شوند، باید از منابع خارجی در غذای آنها تأمین شوند. آنها برای متابولیسم روان ضروری و حیاتی هستند. روغن ماهی سالمون کنینا از بازسازی پوست و رشد مو پشتیبانی میکند و کل فرآیندهای متابولیکی بدن را هماهنگ میکند. صرف نظر از نوع خوراک، روغن ماهی سالمون کنینا غذای حیوان شما را به عنوان یک ماده خوراکی با کیفیت بالا بهینه میکند.",
|
||||
"description": "روغن ماهی سالمون کانینا از روغن ماهی سالمون ۱۰۰٪ خالص با کیفیت غذایی ساخته شده و سرشار از اسیدهای چرب چند غیراشباع (اسیدهای چرب امگا، EPA و DPA) است. از آنجایی که این اسیدهای چرب نمیتوانند توسط خود سگها و گربهها تولید شوند، باید از منابع خارجی در غذای آنها تأمین شوند. آنها برای متابولیسم روان ضروری و حیاتی هستند. روغن ماهی سالمون کانینا از بازسازی پوست و رشد مو پشتیبانی میکند و کل فرآیندهای متابولیکی بدن را هماهنگ میکند. صرف نظر از نوع خوراک، روغن ماهی سالمون کانینا غذای حیوان شما را به عنوان یک ماده خوراکی با کیفیت بالا بهینه میکند.",
|
||||
"short_description": "روغن سالمون ۱۰۰٪ خالص برای براقیت پوست و مو و تنظیم متابولیسم.",
|
||||
"ingredients": "100% روغن طبیعی ماهی سالمون.",
|
||||
"usage_and_dosage": "2 میلی لیتر به ازای هر 10 کیلوگرم وزن بدن روزانه.",
|
||||
@ -136,7 +136,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Marine-Olmischung PREMIUM (روغن دریایی پریمیوم کنینا)",
|
||||
"name": "Canina Marine-Olmischung PREMIUM (روغن دریایی پریمیوم کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "روغن دریایی پریمیوم، ترکیبی هماهنگ و ویژه از روغنهای خوراکی با کیفیت بالا است که در اثرات مثبت خود بر کل ارگانیسم، یکدیگر را به طور بهینه تکمیل میکنند. روغن دریایی امگا ۳ طبیعی (کنترل شده با آفتکش) سرشار از اسیدهای چرب اشباع نشده EPA و DHA است که برای سگها و گربهها ضروری هستند. این اسیدهای چرب باید با غذا تأمین شوند، زیرا حیوانات نمیتوانند خودشان آنها را تولید کنند. ویتامینهایی مانند آ و د ۳ که به طور طبیعی در این محصول وجود دارند، متابولیسم استخوان و پوست را پشتیبانی میکنند. این محصول سرشار از آنتیاکسیدانهای طبیعی است. روغن گردو، روغن دانه گل رز و روغن آرگان سرشار از ویتامین E هستند که از سلولها محافظت و بازسازی میکند و رادیکالهای آزاد و مضر را جذب میکند. ویتامین آ حاصل از روغن دانه گل رز تأثیر مثبتی بر پوست و غشاهای مخاطی دارد و به ویژه برای بینایی و رشد مهم است. روغن آرگان از دانههای درخت آرگان به دست میآید. روغن آرگان علاوه بر طیف متعادلی از اسیدهای چرب، حاوی مواد گیاهی ثانویه مانند فیتواسترولها و اسکوالن است که تأثیر مثبتی بر متابولیسم سگها و گربهها دارند. صرف نظر از نوع خوراک، ترکیب روغن دریایی پریمیوم تمام وعدههای غذایی حیوان را بهبود میبخشد. این محصول از کمبود مواد مغذی در وعدههای غذایی خام (ویتامین آ، ایی، د ۳ و اسیدهای چرب امگا ۳) جلوگیری میکند.",
|
||||
"short_description": "روغن دریایی امگا ۳ غنی از روغن آرگان و گل رز برای پوست و رشد.",
|
||||
@ -153,7 +153,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Moortranke (عصاره پیت کنینا - مایع)",
|
||||
"name": "Canina Moortranke (عصاره پیت کانینا - مایع)",
|
||||
"category_slug": "immune",
|
||||
"description": "مواد هومیک موجود در عصاره پیت، از غشاهای مخاطی دستگاه گوارش محافظت کرده و از سیستم ایمنی روده، چه در حیوانات جوان و چه در حیوانات بالغ، پشتیبانی میکنند. عصاره پیت برای حیوانات خانگی یک ماده خوراکی طبیعی بدون افزودنی و بدون مواد نگهدارنده است. موارد استفاده: برای تحریک دستگاه گوارش، تغییر غلظت مدفوع، نفخ یا پس از درمانهای آنتیبیوتیکی، برای تحریک اشتها، برای تقویت رشد و تقویت سیستم ایمنی، برای تقویت باروری در حیوانات نر و ماده، برای تحریک خونسازی و برای اتصال و حذف مواد مضر.",
|
||||
"short_description": "عصاره طبیعی پیت غنی از اسید هومیک برای تنظیم فلور گوارشی.",
|
||||
@ -303,9 +303,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Rinderblut Pulver (پودر خون گاو کنینا)",
|
||||
"name": "Canina Rinderblut Pulver (پودر خون گاو کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "پودر خون گاو کنینا منبع ارزشمندی از رنگدانه قرمز خون (هموگلوبین) است که حاوی آهن به عنوان اتم مرکزی است. آهن اکسیژن را به خون منتقل میکند. سایر مواد معدنی که به طور طبیعی در پودر خون گاو وجود دارند عبارتند از کلسیم، فسفر، سدیم، پتاسیم، منیزیم، مس، منگنز و روی. علاوه بر این، خون گاو حاوی پروتئینهایی است که به نوبه خود از اسیدهای آمینه تشکیل شدهاند که برای رشد ماده ژنتیکی در هر سلول بدن مورد نیاز هستند. افزودن پودر خون گاو کنینا به ویژه برای سگها و گربههایی که با گوشت تازه (B.A.R.F.) تغذیه میشوند توصیه میشود زیرا گوشت خام دیگر حاوی خون نیست. به دلیل محتوای پروتئین طبیعی بالا، پودر خون گاو کنینا باعث رشد عضلات میشود. پودر خون گاو کنینا از ایجاد شکل بدنی هماهنگ در طول مرحله رشد پشتیبانی میکند. سگها و گربههایی که در حال گذراندن دوره نقاهت هستند یا تحت فشار خاصی قرار دارند از مصرف پودر خون گاو کنینا سود میبرند: این پودر از قدرت، استقامت و رفاه پشتیبانی میکند و عملکرد را بهبود میبخشد.",
|
||||
"description": "پودر خون گاو کانینا منبع ارزشمندی از رنگدانه قرمز خون (هموگلوبین) است که حاوی آهن به عنوان اتم مرکزی است. آهن اکسیژن را به خون منتقل میکند. سایر مواد معدنی که به طور طبیعی در پودر خون گاو وجود دارند عبارتند از کلسیم، فسفر، سدیم، پتاسیم، منیزیم، مس، منگنز و روی. علاوه بر این، خون گاو حاوی پروتئینهایی است که به نوبه خود از اسیدهای آمینه تشکیل شدهاند که برای رشد ماده ژنتیکی در هر سلول بدن مورد نیاز هستند. افزودن پودر خون گاو کانینا به ویژه برای سگها و گربههایی که با گوشت تازه (B.A.R.F.) تغذیه میشوند توصیه میشود زیرا گوشت خام دیگر حاوی خون نیست. به دلیل محتوای پروتئین طبیعی بالا، پودر خون گاو کانینا باعث رشد عضلات میشود. پودر خون گاو کانینا از ایجاد شکل بدنی هماهنگ در طول مرحله رشد پشتیبانی میکند. سگها و گربههایی که در حال گذراندن دوره نقاهت هستند یا تحت فشار خاصی قرار دارند از مصرف پودر خون گاو کانینا سود میبرند: این پودر از قدرت، استقامت و رفاه پشتیبانی میکند و عملکرد را بهبود میبخشد.",
|
||||
"short_description": "منبع آهن طبیعی هموگلوبین و اسیدهای آمینه برای سگ و گربه بارف.",
|
||||
"ingredients": "100% پودر خون گاو خشک شده.",
|
||||
"usage_and_dosage": "0.3 گرم به ازای هر کیلوگرم وزن بدن روزانه، حداکثر 12 گرم.",
|
||||
@ -327,9 +327,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Rinderfett Pulver (پودر چربی گوشت گاو کنینا)",
|
||||
"name": "Canina Rinderfett Pulver (پودر چربی گوشت گاو کانینا)",
|
||||
"category_slug": "energy",
|
||||
"description": "پودر چربی گوشت گاو کنینا یک منبع انرژی طبیعی از چربی گوشت گاو آبپز و آبگوشت حاصل از آن، بدون افزودن شکر است. سگها و گربهها میتوانند انرژی چربی را از این چربی حیوانی، منحصراً چربی گاو، تبدیل کرده و برای بدن خود استفاده کنند. حیوانات جوان در حال رشد که با وجود خوردن غذای کافی، لاغر هستند و وزن کم میکنند، بدنشان را برای نمایش آماده میکنند. حیوانات باردار و شیرده از کالری چربی سود میبرند، همچنین در مورد تغذیه توله سگهایشان. برای سگهایی که از نظر جسمی بسیار فعال هستند، پودر چربی گوشت گاو کنینا باید به عنوان یک منبع انرژی طبیعی برای قدرت و استقامت در وعدههای غذایی روزانه آنها گنجانده شود. پودر چربی گوشت گاو کنینا میتواند به حیوانات حساس به طعم و بدخوران کمک کند تا اشتهای خود را افزایش دهند زیرا چربی در انتقال طعم عالی است. علاوه بر این، پودر چربی گوشت گاو کنینا یک منبع عالی چربی حیوانی برای بهینهسازی وعدههای غذایی خام است.",
|
||||
"description": "پودر چربی گوشت گاو کانینا یک منبع انرژی طبیعی از چربی گوشت گاو آبپز و آبگوشت حاصل از آن، بدون افزودن شکر است. سگها و گربهها میتوانند انرژی چربی را از این چربی حیوانی، منحصراً چربی گاو، تبدیل کرده و برای بدن خود استفاده کنند. حیوانات جوان در حال رشد که با وجود خوردن غذای کافی، لاغر هستند و وزن کم میکنند، بدنشان را برای نمایش آماده میکنند. حیوانات باردار و شیرده از کالری چربی سود میبرند، همچنین در مورد تغذیه توله سگهایشان. برای سگهایی که از نظر جسمی بسیار فعال هستند، پودر چربی گوشت گاو کانینا باید به عنوان یک منبع انرژی طبیعی برای قدرت و استقامت در وعدههای غذایی روزانه آنها گنجانده شود. پودر چربی گوشت گاو کانینا میتواند به حیوانات حساس به طعم و بدخوران کمک کند تا اشتهای خود را افزایش دهند زیرا چربی در انتقال طعم عالی است. علاوه بر این، پودر چربی گوشت گاو کانینا یک منبع عالی چربی حیوانی برای بهینهسازی وعدههای غذایی خام است.",
|
||||
"short_description": "پودر چربی طبیعی گاو جهت افزایش سریع وزن و اشتهاآور پتهای بدخوراک.",
|
||||
"ingredients": "72% چربی گوشت گاو خشک شده، 28% عصاره گوشت گاو.",
|
||||
"usage_and_dosage": "نصف قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن، حداکثر 3 قاشق چایخوری روزانه.",
|
||||
@ -344,9 +344,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Schwarz Kummel Samen (سیاه دانه مصری کنینا)",
|
||||
"name": "Canina Schwarz Kummel Samen (سیاه دانه مصری کانینا)",
|
||||
"category_slug": "immune",
|
||||
"description": "دانههای زیره سیاه کنینا غنی از اسیدهای چرب غیراشباع چندگانه مانند اسید لینولئیک هستند و همچنین حاوی روغنهای ضروری و مواد تلخ مانند نیژلین میباشند. آنها میتوانند تأثیر تنظیمکنندهای بر متابولیسم و هضم داشته باشند. آنها میتوانند تأثیر مثبتی بر سلامت و عملکرد سگ شما داشته باشند و سیستم دفاعی بدن را تقویت کنند. به دلیل عطر تند و آجیلی، پذیرش دانههای زیره سیاه کنینا عموماً بسیار خوب است. برای سگهای باردار و شیرده استفاده نشود.",
|
||||
"description": "دانههای زیره سیاه کانینا غنی از اسیدهای چرب غیراشباع چندگانه مانند اسید لینولئیک هستند و همچنین حاوی روغنهای ضروری و مواد تلخ مانند نیژلین میباشند. آنها میتوانند تأثیر تنظیمکنندهای بر متابولیسم و هضم داشته باشند. آنها میتوانند تأثیر مثبتی بر سلامت و عملکرد سگ شما داشته باشند و سیستم دفاعی بدن را تقویت کنند. به دلیل عطر تند و آجیلی، پذیرش دانههای زیره سیاه کانینا عموماً بسیار خوب است. برای سگهای باردار و شیرده استفاده نشود.",
|
||||
"short_description": "دانههای سیاه دانه مصری جهت تقویت سیستم ایمنی و دفع انگلهای گوارشی.",
|
||||
"ingredients": "100% دانه های سیاه دانه مصری.",
|
||||
"usage_and_dosage": "1 قاشق چایخوری به ازای هر 10 کیلوگرم وزن بدن روزانه، حداکثر 4 قاشق چایخوری.",
|
||||
@ -361,7 +361,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Seelgen Tabletten (قرص جلبک دریایی کنینا)",
|
||||
"name": "Canina Seelgen Tabletten (قرص جلبک دریایی کانینا)",
|
||||
"category_slug": "special-care",
|
||||
"description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست میآید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانههای پوشش، بینی و پنجهها را پشتیبانی میکند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه میکند؛ سلولز و مانیتول هضم را پشتیبانی میکنند. محتوای بالای ویتامینها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش میدهد.",
|
||||
"short_description": "قرص جلبک دریایی ارگانیک جهت تیرهسازی پیگمنت بینی، پنجه و براقیت مو.",
|
||||
@ -385,7 +385,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Bio-Seelgenmehl (پودر جلبک دریایی ارگانیک کنینا)",
|
||||
"name": "Canina Bio-Seelgenmehl (پودر جلبک دریایی ارگانیک کانینا)",
|
||||
"category_slug": "special-care",
|
||||
"description": "این محصول از جلبک دریایی تازه (از کشت ارگانیک کنترل شده) به دست میآید. با توجه به محتوای بالای مواد معدنی، اسیدهای آمینه و عناصر کمیاب موجود در این محصول، این محصول طبیعی با کیفیت بالا، تغذیه نامتعادل را جبران کرده و از طریق محتوای ید، روی و کاروتنوئید خود، متابولیسم پوست و رنگدانههای پوشش، بینی و پنجهها را پشتیبانی میکند. اسید آمینه لیزین موجود در این محصول ضریب تبدیل غذایی را بهینه میکند؛ سلولز و مانیتول هضم را پشتیبانی میکنند. محتوای بالای ویتامینها (به عنوان مثال ویتامین سی) سیستم ایمنی را تقویت کرده و تناسب اندام، انگیزه و رفاه را افزایش میدهد.",
|
||||
"short_description": "پودر خالص جلبک دریایی ارگانیک برای تقویت پیگمنتهای تیره و غده تیروئید.",
|
||||
@ -402,7 +402,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina TAURIN Fur Katzen (پودر تورین مخصوص گربهها کنینا)",
|
||||
"name": "Canina TAURIN Fur Katzen (پودر تورین مخصوص گربهها کانینا)",
|
||||
"category_slug": "special-care",
|
||||
"description": "تورین یک اسید آمینه مبتنی بر گوگرد است که در تمام سلولهای بدن حیوانات یافت میشود. گربهها نمیتوانند خود تورین تولید کنند. تورین برای آنها ضروری (حیاتی) است و بنابراین باید با غذا تأمین شود. تورین دارای اثر سوخت و ساز است، سیستم ایمنی را تقویت میکند، از بینایی و عملکرد قلب پشتیبانی میکند و پوست و پوشش را بهبود میبخشد. مواد معدنی و آنزیمهای ارزشمندی را فراهم میکند، مخمر آبجو موجود در این محصول، ویتامینهای گروه بی که تأثیر مثبتی بر سوخت و ساز بدن دارند و سیستم ایمنی را تقویت میکنند.",
|
||||
"short_description": "پودر تورین ۱۰۰٪ خالص و مخمر آبجو برای سلامت قلب و بینایی گربهها.",
|
||||
@ -419,7 +419,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Velox Gelenkenergie (ولوکس ژلنکانرژی کنینا)",
|
||||
"name": "Canina Velox Gelenkenergie (ولوکس ژلنکانرژی کانینا)",
|
||||
"category_slug": "joints",
|
||||
"description": "قدرت متمرکز صدف لب سبز نیوزیلندی برای سیستم اسکلتی عضلانی و عملکرد دوست چهارپای شما! این محصول برای تأمین با کیفیت بالای گلیکوزآمینوگلیکانها به سیستم اسکلتی عضلانی استفاده میشود که در صدف لب سبز نیوزیلندی موجود است. گگها، مانند سولفات کندرویتین، سولفات هپاران و اسید هیالورونیک، ساختارهای بافت همبند مانند تاندونها، رباطها، غضروف مفاصل و دیسکهای بین مهرهای را تثبیت و بازسازی میکنند. عملکرد دوست چهارپای شما بهبود مییابد و در نتیجه سلامت آنها را ارتقا میدهد. اسیدهای چرب امگا طبیعی به طور کلی سهم ارزشمندی در متابولیسم کلی و به طور خاص در متابولیسم مفاصل دارند. ظرفیت بافری غضروف مفصلی در عملکرد فیزیولوژیکی آن پشتیبانی میشود.",
|
||||
"short_description": "پودر ۱۰۰٪ خالص صدف لبسبز نیوزیلندی برای بازسازی مفاصل و تاندونها.",
|
||||
@ -436,9 +436,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Welpenbrei (سرلاک توله سگ - ولپنبرای کنینا)",
|
||||
"name": "Canina Welpenbrei (سرلاک توله سگ - ولپنبرای کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "فرنی توله سگ کنینا پرورش سالم توله سگهای شما را ارتقا میدهد. طیف گستردهای از پروتئینها، ترکیب مناسب مواد مغذی و فیبر و محتوای بالای مواد معدنی، عناصر کمیاب و ویتامینها، این خوراک را به یک محصول برتر تبدیل میکند. از آنجایی که فقط شیر توله سگ کنینا باید در طول ۳ هفته اول به توله سگها داده شود، فرنی توله سگ کنینا را میتوان از این مرحله شروع کرد. توله سگها هنوز باید شیر توله سگ دریافت کنند و این مقدار فقط باید از ۶ هفتگی کاهش یابد. رشد بهینه دندانها و سیستم اسکلتی تضمین شود. تجویز همزمان ویتامین دی ۲ مجاز نیست.",
|
||||
"description": "فرنی توله سگ کانینا پرورش سالم توله سگهای شما را ارتقا میدهد. طیف گستردهای از پروتئینها، ترکیب مناسب مواد مغذی و فیبر و محتوای بالای مواد معدنی، عناصر کمیاب و ویتامینها، این خوراک را به یک محصول برتر تبدیل میکند. از آنجایی که فقط شیر توله سگ کانینا باید در طول ۳ هفته اول به توله سگها داده شود، فرنی توله سگ کانینا را میتوان از این مرحله شروع کرد. توله سگها هنوز باید شیر توله سگ دریافت کنند و این مقدار فقط باید از ۶ هفتگی کاهش یابد. رشد بهینه دندانها و سیستم اسکلتی تضمین شود. تجویز همزمان ویتامین دی ۲ مجاز نیست.",
|
||||
"short_description": "غذای کمکی توله سگ از ۳ هفتگی سرشار از کلسیم برای رشد اسکلتی.",
|
||||
"ingredients": "غلات، گوشت و فرآورده های فرعی حیوانی، فرآورده های فرعی گیاهی، شیر و محصولات لبنی، مخمر.",
|
||||
"usage_and_dosage": "1 قسمت فرنی با 3 قسمت آب گرم مخلوط شود. از سن 3 تا 6 هفتگی.",
|
||||
@ -453,7 +453,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Welpenmilch (شیر خشک توله سگ کنینا)",
|
||||
"name": "Canina Welpenmilch (شیر خشک توله سگ کانینا)",
|
||||
"category_slug": "nutrition",
|
||||
"description": "شیر مخصوص توله سگ با اجزای سازنده بیولوژیکی ارزشمند: انرژی و قدرت تغذیه با تمام ویتامینها و مواد معدنی لازم برای رشد سالم. جایگزین شیر مادر برای توله سگها از ۱ روزگی، برای تغذیه توله سگهای بی مادر - اگر تولید شیر مادر کافی نیست - برای تولههای بزرگ - برای آمادهسازی و در طول شیردهی - به عنوان مکمل برای سگهای کار و پرورش - به عنوان مکمل برای سگهای مسن و بیمار. طرز تهیه: بر اساس شیر طبیعی سگ مادر، نوشیدنیهای شیر را با ۴ قسمت وزنی آب (۸۰٪) و ۱ قسمت وزنی شیر توله سگ (۲۰٪) آماده کنید.",
|
||||
"short_description": "شیر خشک غنی از پروتئین جایگزین کامل شیر مادر مخصوص توله سگها.",
|
||||
@ -494,9 +494,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Canina Mikrosilber Zahngel (ژل دندان میکروسیلور کنینا)",
|
||||
"name": "Canina Mikrosilber Zahngel (ژل دندان میکروسیلور کانینا)",
|
||||
"category_slug": "special-care",
|
||||
"description": "ژل دندانی میکروسیلور کنینا با عصاره دانه گریپ فروت مشکلات اصلی بهداشت دهان و دندان در سگها و گربهها، مانند پلاک، جرم و التهاب لثه را برطرف میکند. اثر تمیزکنندگی دندان بر اساس فرمولاسیونی از میکروسیلور و عصاره دانه گریپ فروت است که به خوبی تحمل میشود. در صورت استفاده منظم، تأثیر واقعی بر تشکیل جرم جدید دارد. مصرف آن بی خطر است. بیوفلاونوئیدهای موجود در عصاره دانه گریپ فروت دارای اثر آنتیاکسیدانی هستند. آنها به محافظت از دندانها در برابر حملات باکتریهای پلاک کمک میکنند. ویتامین سی موجود در این محصول از سلامت لثهها پشتیبانی میکند و اسیدهای آمینه و چرب عصاره دانه گریپ فروت، حل شدن پلاک دندان را تقویت میکنند.",
|
||||
"description": "ژل دندانی میکروسیلور کانینا با عصاره دانه گریپ فروت مشکلات اصلی بهداشت دهان و دندان در سگها و گربهها، مانند پلاک، جرم و التهاب لثه را برطرف میکند. اثر تمیزکنندگی دندان بر اساس فرمولاسیونی از میکروسیلور و عصاره دانه گریپ فروت است که به خوبی تحمل میشود. در صورت استفاده منظم، تأثیر واقعی بر تشکیل جرم جدید دارد. مصرف آن بی خطر است. بیوفلاونوئیدهای موجود در عصاره دانه گریپ فروت دارای اثر آنتیاکسیدانی هستند. آنها به محافظت از دندانها در برابر حملات باکتریهای پلاک کمک میکنند. ویتامین سی موجود در این محصول از سلامت لثهها پشتیبانی میکند و اسیدهای آمینه و چرب عصاره دانه گریپ فروت، حل شدن پلاک دندان را تقویت میکنند.",
|
||||
"short_description": "ژل دندان تخصصی برای از بین بردن پلاک، تارتار و بوی بد دهان.",
|
||||
"ingredients": "آب، پلی گلیسریل-4-کاپرات، کربومر، نقره میکروسیلور، عصاره دانه گریپ فروت، ویتامین C.",
|
||||
"usage_and_dosage": "روزانه یک بار ترجیحا عصرها روی لثه و قسمت بیرونی دندان ها مالیده شود.",
|
||||
@ -513,7 +513,7 @@
|
||||
{
|
||||
"name": "Canina Nova Gard Green Augenpflege (قطره تمیزکننده چشم نوواگارد گرین)",
|
||||
"category_slug": "special-care",
|
||||
"description": "مراقبت صحیح از چشمها و گوشها برای سلامت و رفاه سگها و گربهها بسیار مهم است. آبریزش یا گرفتگی چشم، مانند خارش گوشها، به ویژه در گربهها به طور کلی و در سگهایی با گوشهای افتاده، یک مشکل روزمره است. پیشگیری با یک محصول مراقبتی طبیعی، ملایم و مؤثر که به طور مؤثر از درمان دامپزشکی نیز پشتیبانی میکند. مراقبت از چشم کنینا (برای سگها و گربهها) چشمهای گرفته/گریان حیوانات (به علاوه ناحیه چشم) را تمیز و مراقبت میکند. با چکاندن قطره در چشم، چشمهای تحریک شده تسکین مییابند. این محصول را میتوان برای مراقبت روزانه از چشم استفاده کرد و از چسبندگی و سوزش مجدد جلوگیری میکند. استفاده نوآورانه از نقره کلوئیدی از التهاب جلوگیری میکند.",
|
||||
"description": "مراقبت صحیح از چشمها و گوشها برای سلامت و رفاه سگها و گربهها بسیار مهم است. آبریزش یا گرفتگی چشم، مانند خارش گوشها، به ویژه در گربهها به طور کلی و در سگهایی با گوشهای افتاده، یک مشکل روزمره است. پیشگیری با یک محصول مراقبتی طبیعی، ملایم و مؤثر که به طور مؤثر از درمان دامپزشکی نیز پشتیبانی میکند. مراقبت از چشم کانینا (برای سگها و گربهها) چشمهای گرفته/گریان حیوانات (به علاوه ناحیه چشم) را تمیز و مراقبت میکند. با چکاندن قطره در چشم، چشمهای تحریک شده تسکین مییابند. این محصول را میتوان برای مراقبت روزانه از چشم استفاده کرد و از چسبندگی و سوزش مجدد جلوگیری میکند. استفاده نوآورانه از نقره کلوئیدی از التهاب جلوگیری میکند.",
|
||||
"short_description": "قطره استریل حاوی نقره کلوئیدی جهت رفع التهاب و ترشحات چشم پت.",
|
||||
"ingredients": "آب، هیالورونات سدیم، نقره کلوئیدی، رتینول پالمیتات.",
|
||||
"usage_and_dosage": "چند قطره روزانه روی کیسه ملتحمه چشم ریخته شود. اطراف چشم تمیز شود.",
|
||||
|
||||
@ -455,16 +455,16 @@ export async function main() {
|
||||
|
||||
// 3. Seed some Blogs
|
||||
const blog1Content = [
|
||||
'<p><strong>تغذیه صحیح سگهای بالغ</strong> یکی از مهمترین عوامل در حفظ سلامت و افزایش طول عمر آنهاست. برند کنینا (Canina) با بیش از ۴۰ سال سابقه در تولید مکملهای دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>',
|
||||
'<p><strong>تغذیه صحیح سگهای بالغ</strong> یکی از مهمترین عوامل در حفظ سلامت و افزایش طول عمر آنهاست. برند کانینا (Canina) با بیش از ۴۰ سال سابقه در تولید مکملهای دامپزشکی در آلمان، استاندارد طلایی تغذیه تکمیلی را تعریف کرده است.</p>',
|
||||
'',
|
||||
'<h2>اصول تغذیه سگ بالغ</h2>',
|
||||
'<p>سگهای بالغ به رژیم غذایی متعادل حاوی پروتئین، چربی، کربوهیدرات، ویتامینها و مواد معدنی نیاز دارند. نسبت Ca:P (کلسیم به فسفر) باید در محدوده ۱.۲:۱ تا ۱.۵:۱ باشد. هرگونه عدم تعادل در این نسبت میتواند منجر به مشکلات کلیوی و استخوانی شود.</p>',
|
||||
'',
|
||||
'<h2>نقش مکملها در رژیم غذایی</h2>',
|
||||
'<p>حتی با بهترین رژیم غذایی، ممکن است برخی مواد مغذی به اندازه کافی تأمین نشوند. محصولات کنینا مانند <strong>Petvital Vitamin-Tabs</strong> (کمپلکس کامل A تا K3) و <strong>Biotin-Tabs</strong> (۱ میلیون میکروگرم بیوتین) نیازهای تغذیهای را پوشش میدهند.</p>',
|
||||
'<p>حتی با بهترین رژیم غذایی، ممکن است برخی مواد مغذی به اندازه کافی تأمین نشوند. محصولات کانینا مانند <strong>Petvital Vitamin-Tabs</strong> (کمپلکس کامل A تا K3) و <strong>Biotin-Tabs</strong> (۱ میلیون میکروگرم بیوتین) نیازهای تغذیهای را پوشش میدهند.</p>',
|
||||
'',
|
||||
'<h2>اسیدهای چرب ضروری</h2>',
|
||||
'<p>روغن سالمون کنینا (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج میشود و تمام ویتامینهای حساس به حرارت را حفظ میکند. EPA پیشماده رزولوینهای ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل میدهد.</p>',
|
||||
'<p>روغن سالمون کانینا (Lachs-Öl) با ۱۴٪ امگا ۳ (EPA/DHA) به روش Cold Press استخراج میشود و تمام ویتامینهای حساس به حرارت را حفظ میکند. EPA پیشماده رزولوینهای ضدالتهابی و DHA ۳۰٪ وزن خشک مغز را تشکیل میدهد.</p>',
|
||||
'',
|
||||
'<h2>مراقبت از مفاصل</h2>',
|
||||
'<p>با افزایش سن سگ، غضروف مفصلی تحلیل میرود. گلیکوزآمینوگلیکانهای صدف لب سبز (GAG) با جذب مولکولهای آب در ماتریکس غضروفی، خاصیت بافری مفاصل را بازیابی میکنند. <strong>CANHYDROX GAG</strong> و <strong>FLEXAN</strong> حاوی این ترکیبات حیاتی هستند.</p>',
|
||||
@ -479,12 +479,12 @@ export async function main() {
|
||||
].join('\n');
|
||||
|
||||
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>',
|
||||
'<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>',
|
||||
'<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>',
|
||||
'',
|
||||
'<h2>تعهد به سلامت حیوانات</h2>',
|
||||
'<p>کنینا به عنوان نماینده رسمی کنینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بستهبندی اصلی آلمان و بارکد اختصاصی هستند.</p>',
|
||||
'<p>کانینا به عنوان نماینده رسمی کانینا در ایران، متعهد به ارائه محصولات اصل با ضمانت اصالت و پروانه دامپزشکی است. تمام محصولات دارای بستهبندی اصلی آلمان و بارکد اختصاصی هستند.</p>',
|
||||
].join('\n');
|
||||
|
||||
const blogs = [
|
||||
@ -511,7 +511,7 @@ export async function main() {
|
||||
isPublished: true,
|
||||
},
|
||||
{
|
||||
title: 'چرا مکملهای کنینا؟',
|
||||
title: 'چرا مکملهای کانینا؟',
|
||||
slug: 'why-canino-supplements',
|
||||
content: blog2Content,
|
||||
authorId: adminId,
|
||||
|
||||
@ -24,7 +24,7 @@ const UI_TEXTS: Record<string, string> = {
|
||||
"nav_pet_switcher_title": "تغییر پت یا مدیریت حساب",
|
||||
"nav_register_pet": "ثبت همدم (Pet) جدید",
|
||||
"nav_wallet_orders": "کیف پول و سفارشات",
|
||||
"nav_logout": "خروج از حساب کنینا",
|
||||
"nav_logout": "خروج از حساب کانینا",
|
||||
"nav_login": "ورود / ثبتنام",
|
||||
"nav_cart": "سبد خرید",
|
||||
|
||||
@ -44,7 +44,7 @@ const UI_TEXTS: Record<string, string> = {
|
||||
|
||||
// === Smart Advisor ===
|
||||
"advisor_badge": "تکنولوژی پایش هوشمند",
|
||||
"advisor_title": "دستیار سلامت کنینا",
|
||||
"advisor_title": "دستیار سلامت کانینا",
|
||||
"advisor_subtitle": "فقط چند قدم تا صدور شناسنامه هوشمند و دریافت پیشنهادات تخصصی",
|
||||
"advisor_step1_title": "گام اول: هویت بصری",
|
||||
"advisor_step1_desc": "همدم شما رو با چه اسمی صدا میزنید؟",
|
||||
@ -69,7 +69,7 @@ const UI_TEXTS: Record<string, string> = {
|
||||
"featured_badge": "بیشترین انتخاب توسط دامپزشکان",
|
||||
"featured_title_line1": "محصولات برگزیده و راهکارهای",
|
||||
"featured_title_line2": "درمان تخصصی",
|
||||
"featured_desc": "محصولات دارویی کنینا با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شدهاند.",
|
||||
"featured_desc": "محصولات دارویی کانینا با استفاده از دانش پیشرفته بیوتکنولوژی و مواد اولیه ارگانیک نایاب فرآوری شدهاند.",
|
||||
"featured_view_all": "مشاهده تمامی محصولات",
|
||||
"product_view_details": "مشاهده جزییات",
|
||||
"featured_no_products_title": "هیچ محصولی یافت نشد",
|
||||
@ -79,7 +79,7 @@ const UI_TEXTS: Record<string, string> = {
|
||||
"videos_badge": "Vet Insights",
|
||||
"videos_title": "مشاوره ویدئویی",
|
||||
"videos_title_highlight": "دوست دامپزشک پت شما",
|
||||
"videos_desc": "متخصصین آلمانی کنینا مستقیماً با شما صحبت میکنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.",
|
||||
"videos_desc": "متخصصین آلمانی کانینا مستقیماً با شما صحبت میکنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.",
|
||||
"videos_view_all": "مشاهده همه ویدئوها",
|
||||
|
||||
// === Navigation Cards (Home Page) ===
|
||||
@ -87,7 +87,7 @@ const UI_TEXTS: Record<string, string> = {
|
||||
"nav_card_shop_desc": "دسترسی به تمامی محصولات بر اساس علائم بالینی و نیازهای پت شما.",
|
||||
"nav_card_shop_cta": "کاتالوگ کامل محصولات",
|
||||
"nav_card_wiki_title": "دانشنامه علمی",
|
||||
"nav_card_wiki_desc": "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کنینا.",
|
||||
"nav_card_wiki_desc": "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینا.",
|
||||
"nav_card_wiki_cta": "مطالعه مقالات تخصصی",
|
||||
|
||||
// === About Section ===
|
||||
@ -102,12 +102,12 @@ const UI_TEXTS: Record<string, string> = {
|
||||
|
||||
// === CTA Section ===
|
||||
"cta_title": "میخواهید بدانید کدام محصول برای پت شما مناسبتر است؟",
|
||||
"cta_desc": "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست.",
|
||||
"cta_desc": "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست.",
|
||||
"cta_btn_primary": "دریافت رژیم مکمل رایگان",
|
||||
"cta_btn_secondary": "پروانه دامپزشکی و اصالت کالا",
|
||||
|
||||
// === Footer ===
|
||||
"footer_brand_title": "کنینا ایران",
|
||||
"footer_brand_title": "کانینا ایران",
|
||||
"footer_brand_subtitle": "نماینده رسمی در ایران",
|
||||
"footer_brand_desc": "تدارک هوشمندانه سلامت برای همراهان وفادار شما. واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان با سابقه ۴۰ سال نوآوری.",
|
||||
"footer_links_title": "دسترسی سریع",
|
||||
@ -122,11 +122,11 @@ const UI_TEXTS: Record<string, string> = {
|
||||
"footer_email_label": "مکاتبات رسمی",
|
||||
"footer_email": "info@canino-iran.com",
|
||||
"footer_address_label": "دفتر مرکزی",
|
||||
"footer_address": "تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹",
|
||||
"footer_address": "تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹",
|
||||
"footer_auth_title": "اصالت کالا تضمین میشود",
|
||||
"footer_auth_desc": "تمامی محصولات دارای لیبل اصالت وزارت بهداشت و QR Code اختصاصی هستند.",
|
||||
"footer_auth_badge": "اصالت آلمانی کنینا",
|
||||
"footer_copyright": "© ۲۰۲۶ کنینا ایران. تمامی حقوق محفوظ است.",
|
||||
"footer_auth_badge": "اصالت آلمانی کانینا",
|
||||
"footer_copyright": "© ۲۰۲۶ کانینا ایران. تمامی حقوق محفوظ است.",
|
||||
"footer_about": "درباره ما",
|
||||
"footer_contact": "تماس با ما",
|
||||
"footer_privacy": "حریم خصوصی",
|
||||
|
||||
@ -53,7 +53,7 @@ async function main() {
|
||||
const uiTexts = {
|
||||
hero_badge: "از ۱۹۸۴ در خدمت سلامت حیوانات",
|
||||
hero_title: "تخصص آلمانی در خدمت\nسلامت پتهای خانگی",
|
||||
hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهرهگیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکملهای دامپزشکی را تعریف میکند. کنینا نماینده رسمی این برند در ایران است.",
|
||||
hero_desc: "از سال ۱۹۸۴، شرکت Canina pharma GmbH در برگیش گلادباخ آلمان، با بهرهگیری از مواد اولیه طبیعی و فرآیندهای پیشرفته، استاندارد طلایی مکملهای دامپزشکی را تعریف میکند. کانینا نماینده رسمی این برند در ایران است.",
|
||||
hero_btn_advisor: "دستیار سلامت پت",
|
||||
hero_btn_products: "مشاهده محصولات",
|
||||
hero_stat_founded: "۱۹۸۴ سال تأسیس",
|
||||
@ -63,12 +63,12 @@ async function main() {
|
||||
hero_image_title: "مکملهای تایید شده دامپزشکی با گواهی IFS",
|
||||
hero_quality_standard: "استاندارد کیفی آلمان (IFS & HACCP)",
|
||||
cta_title: "میخواهید بدانید کدام محصول برای پت شما مناسبتر است؟",
|
||||
cta_subtitle: "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.",
|
||||
cta_subtitle: "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست. با بیش از ۴۰ محصول تخصصی، راهکار مناسب هر نیاز بالینی را خواهید یافت.",
|
||||
cta_btn_free: "دریافت رژیم مکمل رایگان",
|
||||
cta_btn_products: "ورود به محصولات تخصصی",
|
||||
about_teaser_badge: "داستان ما از آلمان",
|
||||
about_teaser_title: "Canina pharma GmbH – میراثی از ۱۹۸۴",
|
||||
about_teaser_desc: "شرکت Canina pharma GmbH در سال ۱۹۸۴ توسط پتر و کریستین کرشنمایر در شهر برگیش گلادباخ آلمان تأسیس شد. این شرکت با شعار «مادر طبیعت بهترین نسخه را میداند» از مواد اولیه طبیعی و تجدیدپذیر برای تولید مکملهای با گرید دارویی استفاده میکند. امروزه محصولات کنینا در بیش از ۴۰ کشور جهان توزیع میشود و نماینده رسمی آن در ایران با نام کنینا به ارائه محصولات اصل با پروانه دامپزشکی میپردازد.",
|
||||
about_teaser_desc: "شرکت Canina pharma GmbH در سال ۱۹۸۴ توسط پتر و کریستین کرشنمایر در شهر برگیش گلادباخ آلمان تأسیس شد. این شرکت با شعار «مادر طبیعت بهترین نسخه را میداند» از مواد اولیه طبیعی و تجدیدپذیر برای تولید مکملهای با گرید دارویی استفاده میکند. امروزه محصولات کانینا در بیش از ۴۰ کشور جهان توزیع میشود و نماینده رسمی آن در ایران با نام کانینا به ارائه محصولات اصل با پروانه دامپزشکی میپردازد.",
|
||||
about_teaser_feat1_title: "مواد اولیه نایاب",
|
||||
about_teaser_feat1_desc: "استفاده از پودر صدف لبسبز اصل نیوزیلند (Perna canaliculus)، پیت طبیعی آلمان، آغوز و روغنهای گیاهی ارگانیک با گرید دارویی.",
|
||||
about_teaser_feat2_title: "فاقد مواد نگهدارنده",
|
||||
|
||||
@ -339,7 +339,7 @@ export class SmsService {
|
||||
{
|
||||
id: config.otpBodyId,
|
||||
title: 'کد تایید ورود و ثبتنام (OTP)',
|
||||
body: 'کد ورود به کنینا: {0}',
|
||||
body: 'کد ورود به کانینا: {0}',
|
||||
assigned: 'otp',
|
||||
},
|
||||
{
|
||||
|
||||
@ -100,7 +100,7 @@ export class ContactService {
|
||||
{
|
||||
key: 'address_info',
|
||||
title: 'نشانی دفتر مرکزی',
|
||||
value: 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹',
|
||||
value: 'تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹',
|
||||
icon: 'map-pin',
|
||||
order: 3,
|
||||
},
|
||||
|
||||
@ -65,7 +65,7 @@ export class PaymentService {
|
||||
callbackUrl,
|
||||
orderId: order.id,
|
||||
mobile: order.user?.mobile || undefined,
|
||||
description: `پرداخت سفارش ${order.trackingNumber || ''} - پتشاپ کنینا`,
|
||||
description: `پرداخت سفارش ${order.trackingNumber || ''} - پتشاپ کانینا`,
|
||||
};
|
||||
|
||||
// Create a pending PaymentTransaction in database
|
||||
@ -159,7 +159,7 @@ export class PaymentService {
|
||||
amountRials,
|
||||
callbackUrl,
|
||||
mobile: user.mobile || undefined,
|
||||
description: `شارژ کیف پول - پت شاپ کنینا`,
|
||||
description: `شارژ کیف پول - پت شاپ کانینا`,
|
||||
};
|
||||
|
||||
const transaction = await this.prisma.paymentTransaction.create({
|
||||
|
||||
@ -136,7 +136,7 @@ export class ZibalService implements IPaymentGateway {
|
||||
merchant,
|
||||
amount: params.amountRials,
|
||||
callbackUrl: params.callbackUrl,
|
||||
description: params.description || 'پرداخت سفارش در پت شاپ کنینا',
|
||||
description: params.description || 'پرداخت سفارش در پت شاپ کانینا',
|
||||
orderId: params.orderId,
|
||||
mobile: params.mobile,
|
||||
nationalCode: params.nationalCode,
|
||||
|
||||
@ -36,7 +36,7 @@ export class PrescriptionsService {
|
||||
mobile: cleanPhone,
|
||||
role: 'Customer',
|
||||
firstName: data.petName ? `سرپرست ${data.petName}` : 'کاربر',
|
||||
lastName: 'کنینا',
|
||||
lastName: 'کانینا',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString, IsEmail, MinLength } from 'class-validator';
|
||||
import { IsOptional, IsString, IsEmail } from 'class-validator';
|
||||
|
||||
export class UpdateProfileDto {
|
||||
@ApiPropertyOptional({ description: 'نام کاربر' })
|
||||
@ -21,15 +21,4 @@ export class UpdateProfileDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
mobile?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'رمز عبور جدید' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(6, { message: 'رمز عبور باید حداقل ۶ کاراکتر باشد' })
|
||||
password?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'رمز عبور فعلی (در صورت وجود)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
currentPassword?: string;
|
||||
}
|
||||
|
||||
@ -1,13 +1,6 @@
|
||||
import {
|
||||
Injectable,
|
||||
BadRequestException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
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 {
|
||||
title: string;
|
||||
@ -56,13 +49,7 @@ export class UsersService {
|
||||
},
|
||||
});
|
||||
|
||||
if (dbUser) {
|
||||
const { password, ...safeUser } = dbUser;
|
||||
return {
|
||||
...safeUser,
|
||||
hasPassword: !!password,
|
||||
};
|
||||
}
|
||||
if (dbUser) return dbUser;
|
||||
|
||||
return {
|
||||
id: '12345678-1234-1234-1234-123456789012',
|
||||
@ -77,13 +64,12 @@ export class UsersService {
|
||||
orders: [],
|
||||
addresses: [],
|
||||
walletTransactions: [],
|
||||
hasPassword: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
}
|
||||
|
||||
const user = await this.prisma.user.findUnique({
|
||||
return this.prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
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) {
|
||||
const user = await this.prisma.user.findUnique({ where: { id } });
|
||||
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({
|
||||
async update(id: string, data: Prisma.UserUpdateInput) {
|
||||
return this.prisma.user.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
data,
|
||||
include: {
|
||||
pets: true,
|
||||
orders: {
|
||||
@ -189,12 +117,6 @@ export class UsersService {
|
||||
walletTransactions: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { password, ...safeUser } = updatedUser;
|
||||
return {
|
||||
...safeUser,
|
||||
hasPassword: !!password,
|
||||
};
|
||||
}
|
||||
|
||||
async addAddress(userId: string, data: UserAddressInput) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# معرفی پروژه کنینا ایران (Canina Iran)
|
||||
# معرفی پروژه کانینا ایران (Canina Iran)
|
||||
|
||||
## این پروژه چیست؟
|
||||
سامانه «کنینا ایران» پلتفرم تخصصی معرفی، فروش و مدیریت مکملهای درمانی حیوانات خانگی با گرید دارویی است. این سامانه به عنوان درگاه آنلاین نماینده انحصاری کنینا آلمان در ایران فعالیت میکند. هدف اصلی پروژه، ارائه یک تجربه کاربری (UX) بسیار غنی، سریع و در کلاس جهانی برای خریداران، کلینیکهای دامپزشکی (مشتریان B2B) و همچنین فراهمکردن ابزارهای هوشمند (مانند مشاوره هوشمند و دانشنامه ترکیبات دارویی) است.
|
||||
سامانه «کانینا ایران» پلتفرم تخصصی معرفی، فروش و مدیریت مکملهای درمانی حیوانات خانگی با گرید دارویی است. این سامانه به عنوان درگاه آنلاین نماینده انحصاری کانینا آلمان در ایران فعالیت میکند. هدف اصلی پروژه، ارائه یک تجربه کاربری (UX) بسیار غنی، سریع و در کلاس جهانی برای خریداران، کلینیکهای دامپزشکی (مشتریان B2B) و همچنین فراهمکردن ابزارهای هوشمند (مانند مشاوره هوشمند و دانشنامه ترکیبات دارویی) است.
|
||||
|
||||
## قابلیتهای کلیدی سامانه
|
||||
سامانه به گونهای طراحی شده تا تمام نیازهای یک کسبوکار مدرن e-commerce را در کنار قابلیتهای تخصصی حوزه سلامت حیوانات برآورده کند:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# راهنمای کاربری سیستم (User Guide)
|
||||
|
||||
سیستم کنینا از نظر نوع مخاطب به دو دسته کلی B2C (مشتریان عادی) و B2B (کلینیکها و فروشگاهها) تقسیم میشود. علاوه بر این، نقش «ادمین» برای مدیریت سیستم وجود دارد.
|
||||
سیستم کانینا از نظر نوع مخاطب به دو دسته کلی B2C (مشتریان عادی) و B2B (کلینیکها و فروشگاهها) تقسیم میشود. علاوه بر این، نقش «ادمین» برای مدیریت سیستم وجود دارد.
|
||||
|
||||
## ۱. مشتریان عادی (B2C Users)
|
||||
مشتری عادی کسی است که وارد سایت میشود تا برای حیوان خانگی خود مکمل خریداری کند یا اطلاعات کسب کند.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# مستندات توسعهدهندگان (Developer Documentation)
|
||||
|
||||
به مستندات رسمی سامانه «کنینا ایران» خوش آمدید. این مستندات به منظور راهنمایی توسعهدهندگان، مهندسین دواپس و تیم فنی شرکت نوشته شده است و نباید در دسترس کاربران عمومی قرار گیرد.
|
||||
به مستندات رسمی سامانه «کانینا ایران» خوش آمدید. این مستندات به منظور راهنمایی توسعهدهندگان، مهندسین دواپس و تیم فنی شرکت نوشته شده است و نباید در دسترس کاربران عمومی قرار گیرد.
|
||||
|
||||
در این دایرکتوری تمامی ساختارها، معماریها، قوانین کدنویسی و مراحل انتشار (Deployment) به دقت تدوین شدهاند تا سرعت 온بوردینگ (Onboarding) توسعهدهندگان جدید افزایش یافته و نگهداری کدهای قدیمی با کمترین ریسک انجام شود.
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ This document defines the strict integration contract between the NestJS backend
|
||||
"authorName": "دکتر علیرضا محمدی",
|
||||
"roleTitle": "دامپزشک و متخصص جراحی",
|
||||
"avatarUrl": "https://example.com/avatar.jpg",
|
||||
"content": "فرمولاسیون کنهیدروکس کنینا در بهبودی پاهای O شکل سگهای نژاد بزرگ معجزه میکند.",
|
||||
"content": "فرمولاسیون کنهیدروکس کانینا در بهبودی پاهای O شکل سگهای نژاد بزرگ معجزه میکند.",
|
||||
"rating": 5,
|
||||
"isFeatured": true,
|
||||
"isActive": true,
|
||||
@ -233,9 +233,9 @@ This document defines the strict integration contract between the NestJS backend
|
||||
- **Response (200 OK)**:
|
||||
```json
|
||||
{
|
||||
"defaultMetaTitle": "کنینا ایران | مکملهای دارویی آلمانی حیوانات خانگی",
|
||||
"defaultMetaDescription": "نمایندگی رسمی محصولات کنینا فارما آلمان",
|
||||
"keywords": "مکمل سگ, مکمل گربه, کنهیدروکس, کنینا",
|
||||
"defaultMetaTitle": "کانینا ایران | مکملهای دارویی آلمانی حیوانات خانگی",
|
||||
"defaultMetaDescription": "نمایندگی رسمی محصولات کانینا فارما آلمان",
|
||||
"keywords": "مکمل سگ, مکمل گربه, کنهیدروکس, کانینا",
|
||||
"canonicalBaseUrl": "https://caninairan.com",
|
||||
"ogImageUrl": "https://caninairan.com/og-default.jpg"
|
||||
}
|
||||
|
||||
@ -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'
|
||||
}`}>
|
||||
<div className="h-16 flex items-center justify-center border-b border-gray-200 shrink-0">
|
||||
<h1 className="text-xl font-black text-purple-600">کنینا | ادمینپنل</h1>
|
||||
<h1 className="text-xl font-black text-purple-600">کانینا | ادمینپنل</h1>
|
||||
</div>
|
||||
|
||||
<nav className="flex-1 overflow-y-auto py-4 px-3 space-y-6">
|
||||
|
||||
@ -67,7 +67,7 @@ export default function Dashboard() {
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900">داشبورد</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">خلاصهای از وضعیت فروشگاه کنینا</p>
|
||||
<p className="text-gray-500 font-medium mt-1">خلاصهای از وضعیت فروشگاه کانینا</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
|
||||
@ -162,7 +162,7 @@ export default function IngredientsManager() {
|
||||
<FlaskConical className="w-6 h-6 text-purple-600" />
|
||||
مدیریت ترکیبات و دانشنامه علمی (Scientific Wiki)
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت مواد موثره، ترکیبات دارویی و خواص درمانی محصولات کنینا</p>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت مواد موثره، ترکیبات دارویی و خواص درمانی محصولات کانینا</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => openModal()}
|
||||
|
||||
@ -94,7 +94,7 @@ export default function Login() {
|
||||
ورود به پنل مدیریت
|
||||
</h2>
|
||||
<p className="mt-2 text-center text-sm text-gray-600 font-bold">
|
||||
کنینا | لابراتوار تخصصی مکملهای درمانی حیوانات
|
||||
کانینا | لابراتوار تخصصی مکملهای درمانی حیوانات
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@ -478,7 +478,7 @@ export default function MediaManager() {
|
||||
type="text"
|
||||
value={seoFormData.altText}
|
||||
onChange={(e) => setSeoFormData({ ...seoFormData, altText: e.target.value })}
|
||||
placeholder="مثال: عکس مکمل کانیدروکس گپ کنینا"
|
||||
placeholder="مثال: عکس مکمل کانیدروکس گپ کانینا"
|
||||
className="w-full px-3 py-2 border rounded-xl text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -186,7 +186,7 @@ export default function Orders() {
|
||||
const paymentMethodText = orderToPrint.paymentMethod === 'wallet' ? 'پرداخت از کیف پول الکترونیک' : 'پرداخت آنلاین از درگاه شتاب';
|
||||
|
||||
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 pPrice = Number(item.product?.priceValue || item.priceValue || 0);
|
||||
const rowTotal = pPrice * (item.quantity || 1);
|
||||
@ -210,7 +210,7 @@ export default function Orders() {
|
||||
<html dir="rtl" lang="fa">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>فاکتور رسمی کنینا - ${trackingCode}</title>
|
||||
<title>فاکتور رسمی کانینا - ${trackingCode}</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Vazirmatn';
|
||||
@ -238,7 +238,7 @@ export default function Orders() {
|
||||
<div class="invoice-card">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="logo-text">CANINA | کنینا</div>
|
||||
<div class="logo-text">CANINA | کانینا</div>
|
||||
<div class="sub-logo">پنل مدیریت سفارشات آلمان</div>
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
@ -303,7 +303,7 @@ export default function Orders() {
|
||||
|
||||
<div class="footer">
|
||||
این فاکتور رسمی به صورت سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/>
|
||||
پشتیبانی کنینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
|
||||
پشتیبانی کانینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -581,7 +581,7 @@ export default function Orders() {
|
||||
</h4>
|
||||
<div className="space-y-3">
|
||||
{(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 pPrice = Number(item.product?.priceValue || item.priceValue || 0);
|
||||
const qty = item.quantity || 1;
|
||||
|
||||
@ -241,8 +241,8 @@ export default function Products() {
|
||||
buyPrice: formData.buyPrice ? Number(formData.buyPrice) : 0,
|
||||
wholesalePrice: formData.wholesalePrice ? Number(formData.wholesalePrice) : null,
|
||||
slug: derivedSlug,
|
||||
metaTitle: formData.metaTitle.trim() || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کنینا`,
|
||||
metaDescription: formData.metaDescription.trim() || formData.shortDescription || 'خرید آنلاین مکمل اصل کنینا آلمان با بالاترین کیفیت بالینی...',
|
||||
metaTitle: formData.metaTitle.trim() || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کانینا`,
|
||||
metaDescription: formData.metaDescription.trim() || formData.shortDescription || 'خرید آنلاین مکمل اصل کانینا آلمان با بالاترین کیفیت بالینی...',
|
||||
canonicalUrl: formData.canonicalUrl.trim() || `/shop/${derivedSlug}`
|
||||
};
|
||||
|
||||
@ -918,8 +918,8 @@ export default function Products() {
|
||||
<div className={activeTab === 'seo' ? 'block' : 'hidden'}>
|
||||
{(() => {
|
||||
const derivedSlug = formData.slug || slugify(formData.nameEn);
|
||||
const derivedMetaTitle = formData.metaTitle || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کنینا`;
|
||||
const derivedMetaDescription = formData.metaDescription || (formData.shortDescription || 'خرید آنلاین مکمل اصل کنینا آلمان با بالاترین کیفیت بالینی و ضمانت اصالت فیزیکی...');
|
||||
const derivedMetaTitle = formData.metaTitle || `${formData.nameFa || 'نام محصول'} | خرید و قیمت مکمل کانینا`;
|
||||
const derivedMetaDescription = formData.metaDescription || (formData.shortDescription || 'خرید آنلاین مکمل اصل کانینا آلمان با بالاترین کیفیت بالینی و ضمانت اصالت فیزیکی...');
|
||||
const derivedCanonicalUrl = formData.canonicalUrl || `/shop/${derivedSlug}`;
|
||||
|
||||
return (
|
||||
|
||||
@ -101,7 +101,7 @@ export default function Reports() {
|
||||
onClick={() => {
|
||||
if (!reportData) return;
|
||||
const rows = [
|
||||
['گزارش کلی سیستم کنینا ایران'],
|
||||
['گزارش کلی سیستم کانینا ایران'],
|
||||
['درآمد کل (تومان)', overview?.totalRevenue || 0],
|
||||
['تعداد سفارشات', overview?.totalOrders || 0],
|
||||
['تعداد کاربران', overview?.totalUsers || 0],
|
||||
|
||||
@ -8,9 +8,9 @@ import type { SeoSettings } from '../types/admin';
|
||||
|
||||
export default function SeoSettingsPage() {
|
||||
const [seo, setSeo] = useState<SeoSettings>({
|
||||
defaultMetaTitle: 'کنینا ایران | مکملهای دارویی آلمانی حیوانات خانگی',
|
||||
defaultMetaDescription: 'نمایندگی رسمی محصولات کنینا فارما آلمان در ایران',
|
||||
keywords: 'مکمل سگ, مکمل گربه, کنهیدروکس, کنینا',
|
||||
defaultMetaTitle: 'کانینا ایران | مکملهای دارویی آلمانی حیوانات خانگی',
|
||||
defaultMetaDescription: 'نمایندگی رسمی محصولات کانینا فارما آلمان در ایران',
|
||||
keywords: 'مکمل سگ, مکمل گربه, کنهیدروکس, کانینا',
|
||||
canonicalBaseUrl: 'https://caninairan.com',
|
||||
ogImageUrl: 'https://caninairan.com/og-default.jpg',
|
||||
});
|
||||
|
||||
@ -29,7 +29,7 @@ export default function Settings() {
|
||||
SOCIAL_WHATSAPP: '09120000000',
|
||||
SOCIAL_INSTAGRAM: 'https://instagram.com/canina_iran',
|
||||
SOCIAL_TELEGRAM: 'https://t.me/canina_iran',
|
||||
CONTACT_ADDRESS: 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹',
|
||||
CONTACT_ADDRESS: 'تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹',
|
||||
BRAND_LOGO_URL: '/logo.png',
|
||||
ENAMAD_CODE: '',
|
||||
THEME_PRIMARY_COLOR: '#7c3aed',
|
||||
@ -66,7 +66,7 @@ export default function Settings() {
|
||||
SOCIAL_WHATSAPP: response.data.data.SOCIAL_WHATSAPP || '09120000000',
|
||||
SOCIAL_INSTAGRAM: response.data.data.SOCIAL_INSTAGRAM || 'https://instagram.com/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',
|
||||
ENAMAD_CODE: response.data.data.ENAMAD_CODE || '',
|
||||
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" />
|
||||
تنظیمات فروشگاه
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کنینا</p>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت پارامترهای اصلی و سیستمی کانینا</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<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>
|
||||
<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>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
|
||||
@ -1344,7 +1344,7 @@ export default function SmsSettingsPage() {
|
||||
required
|
||||
value={newPatternTitle}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@ -1372,7 +1372,7 @@ export default function SmsSettingsPage() {
|
||||
required
|
||||
value={newPatternBody}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -182,7 +182,7 @@ export default function UITexts() {
|
||||
مدیریت محتوا و بنرهای صفحات (Page Builder)
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500 font-bold mt-1">
|
||||
ویرایش زنده متون، تصاویر بنر، لینک دکمهها و عناوین تمام صفحات سایت کنینا
|
||||
ویرایش زنده متون، تصاویر بنر، لینک دکمهها و عناوین تمام صفحات سایت کانینا
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -173,7 +173,7 @@ export default function Videos() {
|
||||
مدیریت ویدئوها و آکادمی آموزشی
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500 font-bold mt-1">
|
||||
آپلود مستقیم ویدئو/کاور یا درج کد آیفرم آپارات/یوتیوب برای مشاوره ویدئویی دامپزشکان کنینا
|
||||
آپلود مستقیم ویدئو/کاور یا درج کد آیفرم آپارات/یوتیوب برای مشاوره ویدئویی دامپزشکان کانینا
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@ -134,7 +134,7 @@ export default function Wiki() {
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
<BookOpen className="w-6 h-6 text-purple-600" />
|
||||
دانشنامه کنینا (Wiki)
|
||||
دانشنامه کانینا (Wiki)
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت اصطلاحات علمی، مواد تشکیلدهنده و خواص درمانی</p>
|
||||
</div>
|
||||
|
||||
@ -5,7 +5,7 @@ This version has breaking changes — APIs, conventions, and file structure may
|
||||
<!-- END:nextjs-agent-rules -->
|
||||
|
||||
# Brand Name
|
||||
نام برند رسمی «**کنینا**» / «**Canina**» است (نه «کانینو» / «Canino»). در سرتاسر پروژه باید از Canina / کنینا استفاده شود.
|
||||
نام برند رسمی «**کانینا**» / «**Canina**» است (نه «کانینو» / «Canino»). در سرتاسر پروژه باید از Canina / کانینا استفاده شود.
|
||||
- CSS class names: `canina-blue`, `canina-gold`, `canina-teal`, `canina-dark`
|
||||
- Store/cookie names: `canina-user`, `canina-cart`, `canina-pets`
|
||||
- URL `https://canino-iran.com` (domain name, بدون تغییر میماند)
|
||||
|
||||
@ -92,7 +92,7 @@ export default function HomeClient({ initialData }: HomeClientProps) {
|
||||
{getText('nav_card_wiki_title', "دانشنامه علمی")}
|
||||
</h3>
|
||||
<p className="text-medical-gray-600 mb-8 leading-relaxed font-shabnam">
|
||||
{getText('nav_card_wiki_desc', "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کنینا.")}
|
||||
{getText('nav_card_wiki_desc', "آشنایی با ترکیبات نایاب و استانداردهای دارویی محصولات آلمانی کانینا.")}
|
||||
</p>
|
||||
<div className="flex items-center gap-2 text-emerald-700 font-black tracking-widest uppercase text-xs font-vazir">
|
||||
{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" />
|
||||
<Image
|
||||
src="/assets/images/regenerated_image_1779109861747.png"
|
||||
alt="آزمایشگاه تخصصی تولید مکملهای دارویی کنینا آلمان"
|
||||
alt="آزمایشگاه تخصصی تولید مکملهای دارویی کانینا آلمان"
|
||||
className="rounded-[3rem] shadow-2xl relative z-10 grayscale-[10%] w-full"
|
||||
width={640}
|
||||
height={425}
|
||||
@ -172,7 +172,7 @@ export default function HomeClient({ initialData }: HomeClientProps) {
|
||||
{getText('cta_title', "میخواهید بدانید کدام محصول برای پت شما مناسبتر است؟")}
|
||||
</h2>
|
||||
<p className="text-white/80 text-lg mb-10 leading-relaxed font-shabnam">
|
||||
{getText('cta_desc', "تیم متخصص دامپزشکی کنینا ایران آماده پاسخگویی به سوالات شماست.")}
|
||||
{getText('cta_desc', "تیم متخصص دامپزشکی کانینا ایران آماده پاسخگویی به سوالات شماست.")}
|
||||
</p>
|
||||
<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">
|
||||
|
||||
@ -3,15 +3,15 @@ import { ShieldCheck, History, Award, CheckCircle } from "lucide-react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "درباره ما - میراث ۴۰ ساله کانیتا آلمان در ایران",
|
||||
description: "داستان کنینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکملهای فوقتخصصی دامپزشکی با گرید دارویی اختصاصی.",
|
||||
description: "داستان کانینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکملهای فوقتخصصی دامپزشکی با گرید دارویی اختصاصی.",
|
||||
alternates: {
|
||||
canonical: "/about",
|
||||
},
|
||||
openGraph: {
|
||||
title: "درباره ما - کنینا ایران",
|
||||
description: "داستان کنینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکملهای فوقتخصصی دامپزشکی.",
|
||||
title: "درباره ما - کانینا ایران",
|
||||
description: "داستان کانینا ایران و میراث ۴۰ ساله شرکت Canina pharma GmbH آلمان در تولید مکملهای فوقتخصصی دامپزشکی.",
|
||||
url: "https://canina-iran.com/about",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
@ -29,7 +29,7 @@ export default function AboutPage() {
|
||||
داستان ما از ۱۹۸۴
|
||||
</span>
|
||||
<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>
|
||||
<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 */}
|
||||
<div className="space-y-8 text-medical-gray-700 leading-relaxed">
|
||||
<p>
|
||||
امروز محصولات کنینا در بیش از ۴۰ کشور جهان توزیع میشود. کنینا ایران به عنوان نماینده رسمی این برند، با هدف ارتقای کیفیت زندگی حیوانات خانگی و دسترسی آسان جامعه دامپزشکی و دارندگان حیوانات به این مکملهای ارزشمند، فعالیت خود را آغاز نموده است. تمامی محصولات با بستهبندی اصلی آلمان و دارای برچسب اصالت سازمان دامپزشکی ارائه میشوند.
|
||||
امروز محصولات کانینا در بیش از ۴۰ کشور جهان توزیع میشود. کانینا ایران به عنوان نماینده رسمی این برند، با هدف ارتقای کیفیت زندگی حیوانات خانگی و دسترسی آسان جامعه دامپزشکی و دارندگان حیوانات به این مکملهای ارزشمند، فعالیت خود را آغاز نموده است. تمامی محصولات با بستهبندی اصلی آلمان و دارای برچسب اصالت سازمان دامپزشکی ارائه میشوند.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ async function getBlog(slug: string) {
|
||||
excerpt: b.metaDescription || b.content.substring(0, 150).replace(/<[^>]+>/g, '') + '...',
|
||||
image: b.imageUrl,
|
||||
date: new Date(b.createdAt).toLocaleDateString('fa-IR'),
|
||||
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کنینا',
|
||||
author: b.author ? `${b.author.firstName} ${b.author.lastName}` : 'نویسنده کانینا',
|
||||
content: b.content
|
||||
};
|
||||
} catch (error) {
|
||||
@ -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> {
|
||||
const { slug } = await params;
|
||||
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();
|
||||
|
||||
return {
|
||||
@ -48,7 +48,7 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
description,
|
||||
images: [blog.image],
|
||||
url: `/blog/${slug}`,
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
type: "article",
|
||||
}
|
||||
};
|
||||
@ -112,7 +112,7 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</div>
|
||||
<div className="font-bold text-medical-gray-400">نویسنده کنینا</div>
|
||||
<div className="font-bold text-medical-gray-400">نویسنده کانینا</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
|
||||
@ -2,16 +2,16 @@ import BlogPage from "../../components/BlogPage";
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "مجله سلامت حیوانات خانگی و مقالات علمی - کنینا ایران",
|
||||
title: "مجله سلامت حیوانات خانگی و مقالات علمی - کانینا ایران",
|
||||
description: "آخرین مقالات، آموزشهای دامپزشکی و اخبار علمی روز دنیا در زمینه نگهداری، تغذیه تخصصی و سلامت سگ و گربه.",
|
||||
alternates: {
|
||||
canonical: "/blog",
|
||||
},
|
||||
openGraph: {
|
||||
title: "مجله سلامت حیوانات خانگی - کنینا ایران",
|
||||
title: "مجله سلامت حیوانات خانگی - کانینا ایران",
|
||||
description: "آخرین مقالات، آموزشها و اخبار علمی در زمینه نگهداری، تغذیه و سلامت سگ و گربه.",
|
||||
url: "https://canina-iran.com/blog",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
|
||||
@ -3,15 +3,15 @@ import CatalogClient from "./CatalogClient";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "کاتالوگ محصولات Canina - راهنمای مکملهای درمانی سگ و گربه",
|
||||
description: "کاتالوگ جامع محصولات آلمانی کنینا شامل راهنمای ترکیبات، گرید دارویی، دوز مصرفی و موارد درمان بالینی مفصل، پوست و مو و رشد پتها.",
|
||||
description: "کاتالوگ جامع محصولات آلمانی کانینا شامل راهنمای ترکیبات، گرید دارویی، دوز مصرفی و موارد درمان بالینی مفصل، پوست و مو و رشد پتها.",
|
||||
alternates: {
|
||||
canonical: "/catalog",
|
||||
},
|
||||
openGraph: {
|
||||
title: "کاتالوگ رسمی مکملهای درمانی Canina Pharma Germany",
|
||||
description: "دانلود و مشاهده آنلاین کاتالوگ مکملهای دارویی حیوانات خانگی کنینا آلمان",
|
||||
description: "دانلود و مشاهده آنلاین کاتالوگ مکملهای دارویی حیوانات خانگی کانینا آلمان",
|
||||
url: "https://canina-iran.com/catalog",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
|
||||
@ -2,16 +2,16 @@ import type { Metadata } from "next";
|
||||
import ContactFormClient from "@/components/ContactFormClient";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "تماس با ما - نمایندگی رسمی مکملهای کنینا آلمان در ایران",
|
||||
title: "تماس با ما - نمایندگی رسمی مکملهای کانینا آلمان در ایران",
|
||||
description: "راههای ارتباطی، تلفن تماس ویژه، آدرس دفتر مرکزی و فرم تماس مستقیم با نمایندگی انحصاری کانیتا آلمان در ایران.",
|
||||
alternates: {
|
||||
canonical: "/contact",
|
||||
},
|
||||
openGraph: {
|
||||
title: "تماس با ما - کنینا ایران",
|
||||
description: "راههای ارتباطی با نمایندگی رسمی مکملهای دامپزشکی کنینا در ایران.",
|
||||
title: "تماس با ما - کانینا ایران",
|
||||
description: "راههای ارتباطی با نمایندگی رسمی مکملهای دامپزشکی کانینا در ایران.",
|
||||
url: "https://canina-iran.com/contact",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
@ -28,7 +28,7 @@ export default function ContactPage() {
|
||||
پاسخگوی شما هستیم
|
||||
</span>
|
||||
<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>
|
||||
<p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed">
|
||||
جهت مشاوره تخصصی، خرید عمده و پیگیری سفارشات با ما در ارتباط باشید.
|
||||
|
||||
@ -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 titleDefault = seoSettings?.defaultMetaTitle || 'کنینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی';
|
||||
const descriptionDefault = seoSettings?.defaultMetaDescription || 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کنینا ایران واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان.';
|
||||
const titleDefault = seoSettings?.defaultMetaTitle || 'کانینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی';
|
||||
const descriptionDefault = seoSettings?.defaultMetaDescription || 'تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینا ایران واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان.';
|
||||
|
||||
let keywordsList: string[] = ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کنینا', 'داروی حیوانات', 'Canina Iran'];
|
||||
let keywordsList: string[] = ['مکمل حیوانات خانگی', 'مکمل سگ', 'مکمل گربه', 'کانینا', 'داروی حیوانات', 'Canina Iran'];
|
||||
if (seoSettings?.keywords) {
|
||||
if (Array.isArray(seoSettings.keywords)) {
|
||||
keywordsList = seoSettings.keywords;
|
||||
@ -39,7 +39,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
metadataBase: new URL(siteUrl),
|
||||
title: {
|
||||
template: '%s | کنینا ایران',
|
||||
template: '%s | کانینا ایران',
|
||||
default: titleDefault,
|
||||
},
|
||||
description: descriptionDefault,
|
||||
@ -59,7 +59,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
title: titleDefault,
|
||||
description: descriptionDefault,
|
||||
url: siteUrl,
|
||||
siteName: 'کنینا ایران',
|
||||
siteName: 'کانینا ایران',
|
||||
locale: 'fa_IR',
|
||||
type: 'website',
|
||||
images: [
|
||||
@ -99,7 +99,7 @@ export default function RootLayout({
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Organization',
|
||||
name: 'کنینا ایران',
|
||||
name: 'کانینا ایران',
|
||||
url: 'https://canina-iran.com',
|
||||
logo: 'https://canina.de/media/fb/d5/47/1683116813/Logo.png',
|
||||
contactPoint: {
|
||||
|
||||
@ -2,16 +2,16 @@ import type { Metadata } from "next";
|
||||
import HomeClient from "./HomeClient";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "کنینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما. کنینا ایران واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان با پروانه رسمی دامپزشکی.",
|
||||
title: "کانینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما. کانینا ایران واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان با پروانه رسمی دامپزشکی.",
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
},
|
||||
openGraph: {
|
||||
title: "کنینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
title: "کانینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
description: "واردکننده انحصاری مکملهای درمانی با گرید دارویی اختصاصی از آلمان",
|
||||
url: "https://canina-iran.com",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
images: [
|
||||
@ -19,13 +19,13 @@ export const metadata: Metadata = {
|
||||
url: "/assets/images/regenerated_image_1779109861747.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "کنینا ایران - مکملهای درمانی حیوانات خانگی",
|
||||
alt: "کانینا ایران - مکملهای درمانی حیوانات خانگی",
|
||||
}
|
||||
]
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "کنینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
title: "کانینا ایران - مکملهای درمانی حیوانات خانگی با گرید دارویی اختصاصی",
|
||||
description: "تدارک هوشمندانه سلامت برای همراهان وفادار شما.",
|
||||
images: ["/assets/images/regenerated_image_1779109861747.png"],
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ function VerifyContent() {
|
||||
|
||||
{orderDetails?.trackingNumber && (
|
||||
<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">
|
||||
{orderDetails.trackingNumber}
|
||||
</span>
|
||||
|
||||
@ -2,16 +2,16 @@ import type { Metadata } from "next";
|
||||
import { Shield } from "lucide-react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "حریم خصوصی کاربران - کنینا ایران",
|
||||
description: "سیاستهای حفاظت از اطلاعات شخصی کاربران، امنیت دادههای پزشکی و پروندههای درمانی پت در وبسایت کنینا ایران.",
|
||||
title: "حریم خصوصی کاربران - کانینا ایران",
|
||||
description: "سیاستهای حفاظت از اطلاعات شخصی کاربران، امنیت دادههای پزشکی و پروندههای درمانی پت در وبسایت کانینا ایران.",
|
||||
alternates: {
|
||||
canonical: "/privacy",
|
||||
},
|
||||
openGraph: {
|
||||
title: "حریم خصوصی کاربران - کنینا ایران",
|
||||
description: "سیاستهای حفاظت از اطلاعات شخصی کاربران در وبسایت کنینا ایران.",
|
||||
title: "حریم خصوصی کاربران - کانینا ایران",
|
||||
description: "سیاستهای حفاظت از اطلاعات شخصی کاربران در وبسایت کانینا ایران.",
|
||||
url: "https://canina-iran.com/privacy",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
@ -31,7 +31,7 @@ export default function PrivacyPage() {
|
||||
حریم خصوصی کاربران
|
||||
</h1>
|
||||
<p className="text-lg text-medical-gray-500 max-w-2xl mx-auto leading-relaxed">
|
||||
تعهد ما به امنیت دادهها و اطلاعات شخصی ثبت شده در وبسایت کنینا ایران.
|
||||
تعهد ما به امنیت دادهها و اطلاعات شخصی ثبت شده در وبسایت کانینا ایران.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -54,7 +54,7 @@ export default function PrivacyPage() {
|
||||
<section className="space-y-4">
|
||||
<h3 className="text-xl font-black text-medical-gray-900">۳. امنیت دادهها</h3>
|
||||
<p>
|
||||
تمامی اطلاعات حساس کاربران با استفاده از پروتکلهای امنیتی استاندارد و بستر امن HTTPS رمزگذاری شده و بر روی سرورهای ابری محافظت شده ذخیره میگردند. تیم فنی کنینا متعهد به پایش مداوم و بهروزرسانی سیستمهای امنیتی جهت جلوگیری از دسترسیهای غیرمجاز است.
|
||||
تمامی اطلاعات حساس کاربران با استفاده از پروتکلهای امنیتی استاندارد و بستر امن HTTPS رمزگذاری شده و بر روی سرورهای ابری محافظت شده ذخیره میگردند. تیم فنی کانینا متعهد به پایش مداوم و بهروزرسانی سیستمهای امنیتی جهت جلوگیری از دسترسیهای غیرمجاز است.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'جستجوی محصولات',
|
||||
description: 'جستجوی مکملهای درمانی حیوانات خانگی، داروها و مقالات سلامت در کنینا ایران.',
|
||||
description: 'جستجوی مکملهای درمانی حیوانات خانگی، داروها و مقالات سلامت در کانینا ایران.',
|
||||
};
|
||||
|
||||
export default async function SearchPage({ searchParams }: { searchParams: Promise<{ q?: string }> }) {
|
||||
|
||||
@ -11,13 +11,13 @@ export async function generateMetadata(
|
||||
|
||||
if (!product) {
|
||||
return {
|
||||
title: 'خرید مکمل درمانی پت | کنینا ایران',
|
||||
title: 'خرید مکمل درمانی پت | کانینا ایران',
|
||||
};
|
||||
}
|
||||
|
||||
const nameFa = product.nameFa || product.name;
|
||||
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 rawKeywords = (product as unknown as Record<string, unknown>).keywords;
|
||||
const keywords = typeof rawKeywords === 'string' ? rawKeywords.split(',') : product.main_ingredients;
|
||||
@ -31,7 +31,7 @@ export async function generateMetadata(
|
||||
description,
|
||||
images: [product.image],
|
||||
url: `/shop/${resolvedParams.slug}`,
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
type: "website",
|
||||
},
|
||||
alternates: {
|
||||
@ -74,7 +74,7 @@ export default async function ShopProductPage({ params }: { params: Promise<{ sl
|
||||
itemCondition: 'https://schema.org/NewCondition',
|
||||
seller: {
|
||||
'@type': 'Organization',
|
||||
name: 'کنینا ایران'
|
||||
name: 'کانینا ایران'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -2,16 +2,16 @@ import type { Metadata } from "next";
|
||||
import ArchivePage from "../../components/ArchivePage";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "فروشگاه تخصصی مکملهای دارویی - کنینا ایران",
|
||||
title: "فروشگاه تخصصی مکملهای دارویی - کانینا ایران",
|
||||
description: "خرید آنلاین انواع مکملهای درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامینها و مراقبتهای ویژه سگ و گربه با تضمین اصالت و گواهی سلامت دامپزشکی.",
|
||||
alternates: {
|
||||
canonical: "/shop",
|
||||
},
|
||||
openGraph: {
|
||||
title: "فروشگاه تخصصی مکملهای دارویی - کنینا ایران",
|
||||
title: "فروشگاه تخصصی مکملهای دارویی - کانینا ایران",
|
||||
description: "خرید آنلاین انواع مکملهای درمانی، مفاصل و استخوان، گوارش و ایمنی، ویتامینها و مراقبتهای ویژه سگ و گربه.",
|
||||
url: "https://canina-iran.com/shop",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
|
||||
@ -4,8 +4,8 @@ import EnamadBadge from '@/components/EnamadBadge';
|
||||
import { ShieldCheck, Award, FileCheck, CheckCircle2, Building2 } from 'lucide-react';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'نمادهای اعتماد و مجوزهای رسمی | کنینا ایران',
|
||||
description: 'مشاهده نماد اعتماد الکترونیکی (اینماد)، مجوزهای سازمان دامپزشکی کشور و گواهینامههای اصالت کالاهای کنینا ایران.',
|
||||
title: 'نمادهای اعتماد و مجوزهای رسمی | کانینا ایران',
|
||||
description: 'مشاهده نماد اعتماد الکترونیکی (اینماد)، مجوزهای سازمان دامپزشکی کشور و گواهینامههای اصالت کالاهای کانینا ایران.',
|
||||
};
|
||||
|
||||
export default function TrustSealsPage() {
|
||||
@ -19,7 +19,7 @@ export default function TrustSealsPage() {
|
||||
color: 'from-teal-500 to-emerald-600',
|
||||
},
|
||||
{
|
||||
title: 'پروانه بهداشتی واردات محصولات کنینا',
|
||||
title: 'پروانه بهداشتی واردات محصولات کانینا',
|
||||
authority: 'سازمان دامپزشکی کل کشور',
|
||||
code: 'IVC-8840192',
|
||||
status: 'تایید شده رسمی',
|
||||
@ -56,7 +56,7 @@ export default function TrustSealsPage() {
|
||||
تضمین اصالت و اطمینان خرید
|
||||
</div>
|
||||
<h1 className="text-3xl md:text-5xl font-extrabold tracking-tight mb-4 leading-tight">
|
||||
نمادهای اعتماد و مجوزهای قانونی کنینا
|
||||
نمادهای اعتماد و مجوزهای قانونی کانینا
|
||||
</h1>
|
||||
<p className="text-teal-100 text-base md:text-lg leading-relaxed">
|
||||
تمام کلیه مکملها، ویتامینها و داروها به صورت مستقیم از کمپانی 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">
|
||||
<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" />
|
||||
تعهدات کنینا ایران به مشتریان
|
||||
تعهدات کانینا ایران به مشتریان
|
||||
</h2>
|
||||
<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">
|
||||
<h3 className="font-bold text-teal-900 mb-2">۱۰۰٪ گارانتی اصالت کالا</h3>
|
||||
<p className="text-xs text-teal-700 leading-relaxed">
|
||||
تمامی مکملها دارای هولوگرام اصلی کمپانی کنینا آلمان و تاریخ انقضای معتبر و بروز میباشند.
|
||||
تمامی مکملها دارای هولوگرام اصلی کمپانی کانینا آلمان و تاریخ انقضای معتبر و بروز میباشند.
|
||||
</p>
|
||||
</div>
|
||||
<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">
|
||||
<h3 className="font-bold text-amber-900 mb-2">پشتیبانی تخصصی دامپزشکی</h3>
|
||||
<p className="text-xs text-amber-700 leading-relaxed">
|
||||
امکان مشاوره و بررسی دوز مصرفی مکملها زیر نظر دامپزشکان متخصص مجموعه کنینا.
|
||||
امکان مشاوره و بررسی دوز مصرفی مکملها زیر نظر دامپزشکان متخصص مجموعه کانینا.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,16 +3,16 @@ import IngredientWiki from "../../components/IngredientWiki";
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "دانشنامه ترکیبات دارویی و علمی - کنینا ایران",
|
||||
title: "دانشنامه ترکیبات دارویی و علمی - کانینا ایران",
|
||||
description: "اطلاعات کامل پزشکی در مورد مواد موثره، ویتامینها و ترکیبات گیاهی نایاب به کار رفته در محصولات تخصصی کانیتا آلمان.",
|
||||
alternates: {
|
||||
canonical: "/wiki",
|
||||
},
|
||||
openGraph: {
|
||||
title: "دانشنامه ترکیبات دارویی و علمی - کنینا ایران",
|
||||
description: "اطلاعات کامل در مورد مواد موثره، ویتامینها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کنینا ایران.",
|
||||
title: "دانشنامه ترکیبات دارویی و علمی - کانینا ایران",
|
||||
description: "اطلاعات کامل در مورد مواد موثره، ویتامینها و ترکیبات گیاهی به کار رفته در محصولات تخصصی کانینا ایران.",
|
||||
url: "https://canina-iran.com/wiki",
|
||||
siteName: "کنینا ایران",
|
||||
siteName: "کانینا ایران",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
}
|
||||
|
||||
@ -1,25 +1,11 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { motion, AnimatePresence } from "motion/react";
|
||||
import {
|
||||
X,
|
||||
Building2,
|
||||
ShieldCheck,
|
||||
Phone,
|
||||
Key,
|
||||
LogIn,
|
||||
ArrowRight,
|
||||
RefreshCw,
|
||||
Lock,
|
||||
Upload,
|
||||
CheckCircle2,
|
||||
Eye,
|
||||
EyeOff,
|
||||
} from "lucide-react";
|
||||
import { X, Building2, ShieldCheck, Phone, Key, LogIn, ArrowRight, RefreshCw, Lock, Upload, CheckCircle2 } from "lucide-react";
|
||||
import { useUserStore } from "../lib/store/userStore";
|
||||
import { authService } from "../lib/services/authService";
|
||||
import { toast } from "sonner";
|
||||
import { toPersian, toEnglishDigits } from "../lib/utils";
|
||||
import { toPersian } from "../lib/utils";
|
||||
|
||||
interface AuthModalProps {
|
||||
isOpen: boolean;
|
||||
@ -28,16 +14,7 @@ interface AuthModalProps {
|
||||
|
||||
export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
const { fetchProfile } = useUserStore();
|
||||
const [view, setView] = useState<
|
||||
| "login"
|
||||
| "register"
|
||||
| "otp-phone"
|
||||
| "otp"
|
||||
| "forgot-password"
|
||||
| "forgot-otp"
|
||||
| "reset-password"
|
||||
| "wholesale-request"
|
||||
>("login");
|
||||
const [view, setView] = useState<"login" | "register" | "otp-phone" | "otp" | "forgot-password" | "forgot-otp" | "reset-password" | "wholesale-request">("login");
|
||||
const [medicalLicense, setMedicalLicense] = useState("");
|
||||
const [businessName, setBusinessName] = useState("");
|
||||
const [documentUploaded, setDocumentUploaded] = useState(false);
|
||||
@ -50,8 +27,6 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
const [otpCode, setOtpCode] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [countdown, setCountdown] = useState(0);
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const otpInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@ -77,8 +52,6 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
setOtpCode("");
|
||||
setIsLoading(false);
|
||||
setCountdown(0);
|
||||
setShowPassword(false);
|
||||
setShowNewPassword(false);
|
||||
});
|
||||
}
|
||||
}, [isOpen]);
|
||||
@ -91,72 +64,13 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
}
|
||||
}, [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) => {
|
||||
e.preventDefault();
|
||||
const cleanPhone = toEnglishDigits(phoneNumber).trim();
|
||||
if (!cleanPhone || !password) return toast.error("شماره موبایل و رمز عبور الزامی است");
|
||||
if (!phoneNumber || !password) return toast.error("شماره موبایل و رمز عبور الزامی است");
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await authService.login(cleanPhone, password.trim());
|
||||
const res = await authService.login(phoneNumber, password);
|
||||
if (res.success) {
|
||||
await fetchProfile();
|
||||
toast.success("با موفقیت وارد شدید");
|
||||
@ -172,20 +86,13 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleRegister = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const cleanPhone = toEnglishDigits(phoneNumber).trim();
|
||||
if (!firstName || !lastName || !cleanPhone || !password) {
|
||||
if (!firstName || !lastName || !phoneNumber || !password) {
|
||||
return toast.error("لطفاً فیلدهای الزامی را پر کنید");
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await authService.register({
|
||||
firstName: firstName.trim(),
|
||||
lastName: lastName.trim(),
|
||||
mobile: cleanPhone,
|
||||
email: email ? email.trim() : undefined,
|
||||
password: password.trim(),
|
||||
});
|
||||
const res = await authService.register({ firstName, lastName, mobile: phoneNumber, email, password });
|
||||
if (res.success) {
|
||||
await fetchProfile();
|
||||
toast.success("ثبتنام با موفقیت انجام شد");
|
||||
@ -201,7 +108,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleSendOtp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const cleanPhone = toEnglishDigits(phoneNumber).trim();
|
||||
const cleanPhone = phoneNumber.trim();
|
||||
if (!/^09\d{9}$/.test(cleanPhone)) {
|
||||
toast.error("شماره موبایل نامعتبر است");
|
||||
return;
|
||||
@ -228,14 +135,33 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleVerifyOtp = async (e: React.FormEvent) => {
|
||||
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 () => {
|
||||
if (countdown > 0) return;
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await authService.sendOtp(toEnglishDigits(phoneNumber).trim());
|
||||
await authService.sendOtp(phoneNumber.trim());
|
||||
toast.success("کد تایید جدید ارسال شد");
|
||||
setCountdown(120);
|
||||
} catch (err: unknown) {
|
||||
@ -248,7 +174,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleForgotSendOtp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const cleanPhone = toEnglishDigits(phoneNumber).trim();
|
||||
const cleanPhone = phoneNumber.trim();
|
||||
if (!/^09\d{9}$/.test(cleanPhone)) {
|
||||
toast.error("شماره موبایل نامعتبر است");
|
||||
return;
|
||||
@ -274,14 +200,14 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleForgotVerifyOtp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const cleanCode = toEnglishDigits(otpCode).trim();
|
||||
if (cleanCode.length !== 5) {
|
||||
if (otpCode.trim().length !== 5) {
|
||||
toast.error("کد باید ۵ رقم باشد");
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
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");
|
||||
} catch (err: unknown) {
|
||||
const errObj = err as { message?: string };
|
||||
@ -293,18 +219,18 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
|
||||
const handleResetPassword = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!newPassword || newPassword.length < 6) {
|
||||
return toast.error("رمز عبور جدید باید حداقل ۶ کاراکتر باشد");
|
||||
if (newPassword.length < 6) {
|
||||
toast.error("رمز جدید باید حداقل ۶ کاراکتر باشد");
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await authService.updateProfile({ password: newPassword.trim() });
|
||||
await fetchProfile();
|
||||
toast.success("رمز عبور جدید با موفقیت تنظیم شد");
|
||||
onClose();
|
||||
await authService.updateProfile({ password: newPassword } as unknown as Parameters<typeof authService.updateProfile>[0]);
|
||||
toast.success("رمز عبور با موفقیت تغییر یافت");
|
||||
setView("login");
|
||||
} catch (err: unknown) {
|
||||
const errObj = err as { message?: string };
|
||||
toast.error(errObj.message || "خطا در تغییر رمز عبور");
|
||||
toast.error(errObj.message || "خطا در تغییر رمز");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@ -313,36 +239,52 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[60]"
|
||||
onClick={onClose}
|
||||
className="absolute inset-0 bg-medical-gray-900/60 backdrop-blur-sm"
|
||||
/>
|
||||
|
||||
{/* Modal content */}
|
||||
<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 }}
|
||||
exit={{ opacity: 0, scale: 0.95, 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"
|
||||
exit={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
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 */}
|
||||
<div className="p-6 pb-0 flex justify-between items-center">
|
||||
<div className="flex items-center gap-2 text-canina-blue font-black text-sm">
|
||||
<ShieldCheck className="w-5 h-5" />
|
||||
<span>ورود امن به کانینو</span>
|
||||
</div>
|
||||
{/* Top highlight bar */}
|
||||
<div className="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-canina-blue to-indigo-500" />
|
||||
|
||||
<div className="p-8 relative">
|
||||
{/* Close Button */}
|
||||
<button
|
||||
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>
|
||||
</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">
|
||||
{view === "login" && (
|
||||
<motion.form
|
||||
@ -353,77 +295,58 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
onSubmit={handleLogin}
|
||||
className="space-y-4"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between items-center">
|
||||
<label className="text-xs font-bold text-medical-gray-500">شماره موبایل</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setView("otp-phone")}
|
||||
className="text-xs font-bold text-canina-blue hover:underline"
|
||||
>
|
||||
ورود با کد پیامکی (OTP)
|
||||
</button>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<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 className="space-y-2">
|
||||
<label htmlFor="login-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل</label>
|
||||
<input
|
||||
id="login-phone"
|
||||
name="username"
|
||||
type="tel"
|
||||
maxLength={11}
|
||||
autoComplete="username"
|
||||
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 className="space-y-2">
|
||||
<label htmlFor="login-password" className="text-xs font-bold text-medical-gray-500">رمز عبور</label>
|
||||
<input
|
||||
id="login-password"
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
placeholder="رمز عبور خود را وارد کنید"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-3 px-4 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between items-center">
|
||||
<label className="text-xs font-bold text-medical-gray-500">رمز عبور</label>
|
||||
<div className="flex items-center justify-between pt-2 flex-wrap gap-2">
|
||||
<button
|
||||
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
|
||||
type="button"
|
||||
onClick={() => setView("forgot-password")}
|
||||
className="text-xs font-bold text-medical-gray-400 hover:text-canina-blue"
|
||||
onClick={() => { setPhoneNumber(""); setView("forgot-password"); }}
|
||||
className="text-xs font-bold text-medical-gray-400 hover:text-canina-blue hover:underline"
|
||||
>
|
||||
فراموشی رمز عبور؟
|
||||
فراموشی رمز
|
||||
</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
|
||||
type="button"
|
||||
onClick={() => setView("register")}
|
||||
className="font-bold text-canina-blue hover:underline"
|
||||
className="text-xs font-bold text-canina-blue hover:underline"
|
||||
>
|
||||
ثبتنام عادی
|
||||
حساب ندارید؟ ثبتنام
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -432,10 +355,10 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
<button
|
||||
type="button"
|
||||
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" />
|
||||
درخواست حساب خریدار عمده (پتشاپ / کلینیک)
|
||||
درخواست ثبتنام حساب خریدار عمده (پتشاپ / کلینیک)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -457,9 +380,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
toast.success(
|
||||
"درخواست احراز هویت خریدار عمده با موفقیت ارسال شد و پس از بررسی ادمین تایید خواهد شد.",
|
||||
);
|
||||
toast.success("درخواست احراز هویت خریدار عمده با موفقیت ارسال شد و پس از بررسی ادمین تایید خواهد شد.");
|
||||
setView("login");
|
||||
}}
|
||||
className="space-y-3"
|
||||
@ -474,7 +395,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
type="text"
|
||||
required
|
||||
value={businessName}
|
||||
onChange={(e) => setBusinessName(e.target.value)}
|
||||
onChange={e => setBusinessName(e.target.value)}
|
||||
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"
|
||||
/>
|
||||
@ -486,10 +407,9 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
type="text"
|
||||
required
|
||||
value={medicalLicense}
|
||||
onChange={(e) => setMedicalLicense(e.target.value)}
|
||||
onChange={e => setMedicalLicense(e.target.value)}
|
||||
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"
|
||||
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-sm text-left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -500,10 +420,9 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
required
|
||||
maxLength={11}
|
||||
value={phoneNumber}
|
||||
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))}
|
||||
onChange={e => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
|
||||
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"
|
||||
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-sm text-left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -512,9 +431,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
setDocumentUploaded(true);
|
||||
toast.success("تصویر پروانه با موفقیت بارگذاری شد.");
|
||||
}}
|
||||
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"
|
||||
}`}
|
||||
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 ? (
|
||||
<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
|
||||
type="button"
|
||||
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>
|
||||
@ -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>
|
||||
<input
|
||||
id="reg-fname"
|
||||
name="given-name"
|
||||
type="text"
|
||||
required
|
||||
autoComplete="given-name"
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(e.target.value)}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm"
|
||||
/>
|
||||
</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>
|
||||
<input
|
||||
id="reg-lname"
|
||||
name="family-name"
|
||||
type="text"
|
||||
required
|
||||
autoComplete="family-name"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(e.target.value)}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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
|
||||
id="reg-phone"
|
||||
name="username"
|
||||
type="tel"
|
||||
required
|
||||
maxLength={11}
|
||||
placeholder="۰۹۱۲۳۴۵۶۷۸۹"
|
||||
autoComplete="username"
|
||||
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-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-sm text-left font-mono tracking-wider"
|
||||
dir="ltr"
|
||||
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left tracking-widest text-sm"
|
||||
/>
|
||||
</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>
|
||||
<input
|
||||
id="reg-email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="name@example.com"
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
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"
|
||||
dir="ltr"
|
||||
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-left text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<label htmlFor="reg-pass" className="text-xs font-bold text-medical-gray-500">رمز عبور</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
id="reg-pass"
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="new-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-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>
|
||||
<label htmlFor="reg-password" className="text-xs font-bold text-medical-gray-500">رمز عبور *</label>
|
||||
<input
|
||||
id="reg-password"
|
||||
name="new-password"
|
||||
type="password"
|
||||
autoComplete="new-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 focus:ring-2 focus:ring-canina-blue/20 outline-none text-left text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-start pt-1">
|
||||
<button
|
||||
type="button"
|
||||
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>
|
||||
@ -671,7 +582,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
<button
|
||||
type="button"
|
||||
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>
|
||||
@ -684,10 +595,9 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
maxLength={11}
|
||||
placeholder="مثال: ۰۹۱۲۳۴۵۶۷۸۹"
|
||||
value={phoneNumber}
|
||||
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ""))}
|
||||
onChange={(e) => setPhoneNumber(e.target.value.replace(/[^0-9]/g, ''))}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-lg text-left font-mono tracking-widest"
|
||||
dir="ltr"
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-lg text-left tracking-widest"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -724,31 +634,43 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
<button
|
||||
type="button"
|
||||
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" />
|
||||
تغییر شماره
|
||||
</button>
|
||||
</div>
|
||||
<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
|
||||
ref={otpInputRef}
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
autoComplete="one-time-code"
|
||||
maxLength={5}
|
||||
placeholder="کد ۵ رقمی"
|
||||
value={otpCode}
|
||||
onChange={(e) => handleOtpChange(e.target.value)}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-bold text-center text-2xl font-mono tracking-[0.5em]"
|
||||
dir="ltr"
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pr-12 pl-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-2xl text-center tracking-[0.5em]"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[11px] text-medical-gray-400 text-center font-medium pt-1">
|
||||
کد پیامکشده به صورت خودکار شناسایی و وارد میشود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<button
|
||||
@ -760,77 +682,55 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<ShieldCheck className="w-6 h-6" />
|
||||
تایید و ورود
|
||||
<LogIn className="w-6 h-6" />
|
||||
تایید کد و ورود
|
||||
</>
|
||||
)}
|
||||
</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>
|
||||
)}
|
||||
|
||||
{/* Forgot Password - Enter Phone */}
|
||||
{view === "forgot-password" && (
|
||||
<motion.form
|
||||
key="forgot-view"
|
||||
key="forgot-password-view"
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
onSubmit={handleForgotSendOtp}
|
||||
className="space-y-4"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-medical-gray-500">شماره موبایل حساب</label>
|
||||
<div className="relative">
|
||||
<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 className="bg-amber-50 border border-amber-200 rounded-2xl p-4 text-center">
|
||||
<Lock className="w-8 h-8 text-amber-500 mx-auto mb-2" />
|
||||
<p className="text-sm font-bold text-amber-700">برای بازیابی رمز عبور، کد تایید به شمارهتان ارسال میشود</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-start pt-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setView("login")}
|
||||
className="text-xs font-bold text-canina-blue hover:underline cursor-pointer"
|
||||
>
|
||||
بازگشت به ورود
|
||||
</button>
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="forgot-phone" className="text-xs font-bold text-medical-gray-500">شماره موبایل</label>
|
||||
<input
|
||||
id="forgot-phone"
|
||||
name="username"
|
||||
type="tel"
|
||||
maxLength={11}
|
||||
autoComplete="username"
|
||||
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>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
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" /> : <>ارسال کد بازیابی</>}
|
||||
</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>
|
||||
)}
|
||||
|
||||
{/* Forgot Password - Enter OTP */}
|
||||
{view === "forgot-otp" && (
|
||||
<motion.form
|
||||
key="forgot-otp-view"
|
||||
@ -838,86 +738,74 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) {
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
onSubmit={handleForgotVerifyOtp}
|
||||
className="space-y-4"
|
||||
className="space-y-5"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-medical-gray-500">کد تایید بازیابی</label>
|
||||
<div className="relative">
|
||||
<Key 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="text"
|
||||
inputMode="numeric"
|
||||
autoComplete="one-time-code"
|
||||
maxLength={5}
|
||||
required
|
||||
placeholder="کد ۵ رقمی"
|
||||
value={otpCode}
|
||||
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-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>
|
||||
<p className="text-sm font-bold text-medical-gray-600 text-center">کد ارسال شده به {toPersian(phoneNumber)} را وارد کنید</p>
|
||||
<div className="relative">
|
||||
<input
|
||||
ref={otpInputRef}
|
||||
id="forgot-otp-code"
|
||||
name="one-time-code"
|
||||
type="text"
|
||||
autoComplete="one-time-code"
|
||||
inputMode="numeric"
|
||||
maxLength={5}
|
||||
value={otpCode}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/[^0-9]/g, ''))}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-medical-gray-50 border border-medical-gray-200 rounded-2xl py-4 pl-4 pr-4 focus:ring-2 focus:ring-canina-blue/20 outline-none font-black text-2xl text-center tracking-[0.5em]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading || otpCode.length < 5}
|
||||
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"
|
||||
>
|
||||
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>تایید و ادامه</>}
|
||||
{countdown > 0 ? (
|
||||
<p className="text-xs font-bold text-medical-gray-400 text-center">ارسال مجدد پس از {toPersian(countdown)} ثانیه</p>
|
||||
) : (
|
||||
<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">
|
||||
<RefreshCw className="w-3.5 h-3.5" />ارسال مجدد
|
||||
</button>
|
||||
)}
|
||||
<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>
|
||||
</motion.form>
|
||||
)}
|
||||
|
||||
{/* Reset Password */}
|
||||
{view === "reset-password" && (
|
||||
<motion.form
|
||||
key="reset-pass-view"
|
||||
key="reset-password-view"
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
onSubmit={handleResetPassword}
|
||||
className="space-y-4"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-medical-gray-500">رمز عبور جدید</label>
|
||||
<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 className="bg-green-50 border border-green-200 rounded-2xl p-4 text-center">
|
||||
<p className="text-sm font-bold text-green-700">هویت تایید شد. رمز جدید خود را وارد کنید</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading || newPassword.length < 6}
|
||||
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"
|
||||
>
|
||||
{isLoading ? <RefreshCw className="w-5 h-5 animate-spin" /> : <>ثبت رمز عبور جدید</>}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="new-password" className="text-xs font-bold text-medical-gray-500">رمز جدید</label>
|
||||
<input
|
||||
id="new-password"
|
||||
name="new-password"
|
||||
type="password"
|
||||
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>
|
||||
</motion.form>
|
||||
)}
|
||||
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
||||
@ -123,7 +123,7 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) {
|
||||
try {
|
||||
const api = (await import('../lib/services/api')).default;
|
||||
await api.post('/wholesale/apply', { businessName: bName, licenseNumber: phone });
|
||||
alert('درخواست شما با موفقیت ثبت شد. کارشناسان پشتیبانی B2B کنینا به زودی جهت تایید تلفنی با شما تماس خواهند گرفت.');
|
||||
alert('درخواست شما با موفقیت ثبت شد. کارشناسان پشتیبانی B2B کانینا به زودی جهت تایید تلفنی با شما تماس خواهند گرفت.');
|
||||
form.reset();
|
||||
} catch {
|
||||
alert('خطا در ثبت درخواست. لطفاً دوباره تلاش کنید.');
|
||||
|
||||
@ -89,7 +89,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-black text-medical-gray-900 text-lg">{selectedPost.author}</div>
|
||||
<div className="font-bold text-medical-gray-400">تیم تحقیق و توسعه کنینا آلمان</div>
|
||||
<div className="font-bold text-medical-gray-400">تیم تحقیق و توسعه کانینا آلمان</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
@ -183,7 +183,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
مجله تخصصی <span className="text-canina-blue">سلامت پتها</span>
|
||||
</h1>
|
||||
<p className="text-sm sm:text-base text-medical-gray-500 font-medium mt-3 max-w-xl leading-relaxed">
|
||||
آخرین یافتههای علمی محققین کنینا آلمان در مورد تغذیه و سلامت پتها.
|
||||
آخرین یافتههای علمی محققین کانینا آلمان در مورد تغذیه و سلامت پتها.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -226,7 +226,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<div className="font-black text-medical-gray-900">{blogs[0].author}</div>
|
||||
<div className="font-bold text-medical-gray-400">نویسنده کنینا</div>
|
||||
<div className="font-bold text-medical-gray-400">نویسنده کانینا</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-canina-blue font-black">
|
||||
@ -305,7 +305,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
C
|
||||
</div>
|
||||
<span className="text-xs font-black text-white/90 tracking-wider font-vazir">
|
||||
خبرنامه اختصاصی پژوهشگاه کنینا آلمان
|
||||
خبرنامه اختصاصی پژوهشگاه کانینا آلمان
|
||||
</span>
|
||||
<Sparkles className="w-3.5 h-3.5 text-canina-gold animate-pulse" />
|
||||
</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> شوید
|
||||
</h3>
|
||||
<p className="text-sm sm:text-base text-white/80 font-medium font-vazir leading-relaxed">
|
||||
ماهانه یک ایمیل حاوی تازهترین یافتـههای پزشکی، کاتالوگهای درمانی اختصاصی کنینا و کدهای تخفیف ویژه برای شما ارسال میشود.
|
||||
ماهانه یک ایمیل حاوی تازهترین یافتـههای پزشکی، کاتالوگهای درمانی اختصاصی کانینا و کدهای تخفیف ویژه برای شما ارسال میشود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -369,7 +369,7 @@ export default function BlogPage({ blogs = [] }: { blogs: BlogPost[] }) {
|
||||
<div className="flex-1">
|
||||
<h3 className="text-3xl lg:text-4xl font-black italic mb-6">علم آلمانی در خدمت سلامت پت شما</h3>
|
||||
<p className="text-white/80 mb-8 leading-relaxed max-w-xl">
|
||||
تمامی مقالات این وبلاگ بر اساس کاتالوگهای رسمی و نتایج آزمایشگاهی کمپانی کنینا آلمان تدوین شده است.
|
||||
تمامی مقالات این وبلاگ بر اساس کاتالوگهای رسمی و نتایج آزمایشگاهی کمپانی کانینا آلمان تدوین شده است.
|
||||
</p>
|
||||
<button
|
||||
onClick={() => router.push('/shop')}
|
||||
|
||||
@ -152,7 +152,7 @@ export default function ContactFormClient() {
|
||||
نشانی دفتر مرکزی
|
||||
</h4>
|
||||
<p className="text-sm font-bold text-medical-gray-900 leading-relaxed">
|
||||
تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹
|
||||
تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -170,7 +170,7 @@ export default function ContactFormClient() {
|
||||
<CheckCircle2 className="w-12 h-12 text-emerald-600 mx-auto" />
|
||||
<h4 className="text-lg font-black">پیام شما با موفقیت ثبت شد</h4>
|
||||
<p className="text-sm font-medium leading-relaxed">
|
||||
پیامک تایید به شماره شما ارسال شد. کارشناسان کنینا به زودی با شما تماس خواهند گرفت.
|
||||
پیامک تایید به شماره شما ارسال شد. کارشناسان کانینا به زودی با شما تماس خواهند گرفت.
|
||||
</p>
|
||||
<button
|
||||
onClick={() => setSuccess(false)}
|
||||
|
||||
@ -45,7 +45,7 @@ export const ServerErrorPage = ({ onRetry }: { onRetry: () => void }) => {
|
||||
|
||||
<h1 className="text-4xl font-black text-medical-gray-900 mb-4">خطای داخلی سیستم</h1>
|
||||
<p className="text-medical-gray-500 mb-12 font-bold text-lg">
|
||||
ارتباط با دیتابیس کنینا با مشکل مواجه شده است. در حال بررسی موضوع هستیم.
|
||||
ارتباط با دیتابیس کانینا با مشکل مواجه شده است. در حال بررسی موضوع هستیم.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
|
||||
@ -155,7 +155,7 @@ export default function Footer({
|
||||
</div>
|
||||
<div>
|
||||
<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>
|
||||
@ -184,7 +184,7 @@ export default function Footer({
|
||||
</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="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">
|
||||
<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>
|
||||
|
||||
@ -149,7 +149,7 @@ export default function Header({
|
||||
{(getText('BRAND_LOGO_URL', '') || getText('site_logo', '')) ? (
|
||||
<img
|
||||
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"
|
||||
/>
|
||||
) : (
|
||||
@ -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">
|
||||
<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" />
|
||||
دانشنامه علمی کنینا
|
||||
دانشنامه علمی کانینا
|
||||
</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">
|
||||
<FileText className="w-4 h-4 text-canina-blue" />
|
||||
@ -455,14 +455,14 @@ export default function Header({
|
||||
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">
|
||||
<span>درباره کنینا و تماس</span>
|
||||
<span>درباره کانینا و تماس</span>
|
||||
<ChevronDown className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
{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">
|
||||
<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" />
|
||||
درباره کمپانی کنینا آلمان
|
||||
درباره کمپانی کانینا آلمان
|
||||
</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">
|
||||
<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">
|
||||
<Link href="/shop" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl bg-medical-gray-50 text-medical-gray-900">
|
||||
🛒 محصولات تخصصی کنینا
|
||||
🛒 محصولات تخصصی کانینا
|
||||
</Link>
|
||||
<Link href="/catalog" onClick={() => setIsMobileMenuOpen(false)} className="block p-3 rounded-xl hover:bg-medical-gray-50 text-medical-gray-800">
|
||||
📑 کاتالوگ آنلاین و دوز مصرفی
|
||||
|
||||
@ -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 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 subtitle = (mounted && isInitialized ? getText('hero_desc', '') : '') || defaultSubtitle;
|
||||
|
||||
@ -82,7 +82,7 @@ export default function IngredientWiki() {
|
||||
علم در خدمت کیفیت
|
||||
</div>
|
||||
<h2 className="text-4xl lg:text-6xl font-black text-medical-gray-900 leading-tight md:max-w-4xl">
|
||||
دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کنینا
|
||||
دانشنامه مواد <span className="text-canina-blue italic">نایاب و ارگانیک</span> کانینا
|
||||
</h2>
|
||||
<p className="mt-6 text-lg text-medical-gray-500 max-w-2xl leading-relaxed">
|
||||
ما از مواد اولیهای استفاده میکنیم که در سطح دارویی فرآوری شدهاند. در اینجا با قدرت بیولوژیک این ترکیبات آشنا شوید.
|
||||
|
||||
@ -203,7 +203,7 @@ export default function LoginModal({ isOpen, onClose, onLogin, petName, isAdviso
|
||||
<ShieldCheck className="w-10 h-10 text-canina-blue" />
|
||||
</div>
|
||||
<h3 className="text-3xl font-black text-medical-gray-900 mb-2 italic">
|
||||
ورود به کنینا
|
||||
ورود به کانینا
|
||||
</h3>
|
||||
{isAdvisorContext ? (
|
||||
<p className="text-medical-gray-500 font-bold leading-relaxed px-2 text-sm">
|
||||
|
||||
@ -23,7 +23,7 @@ export default function MaintenancePage() {
|
||||
</h1>
|
||||
|
||||
<p className="text-sm sm:text-base text-medical-gray-300 leading-relaxed">
|
||||
وبسایت کنینا ایران جهت ارتقای زیرساختها و ارائه خدمات بهتر به شما سرپرستان و دامپزشکان محترم به صورت موقت در دست بهروزرسانی است. از شکیبایی شما سپاسگزاریم.
|
||||
وبسایت کانینا ایران جهت ارتقای زیرساختها و ارائه خدمات بهتر به شما سرپرستان و دامپزشکان محترم به صورت موقت در دست بهروزرسانی است. از شکیبایی شما سپاسگزاریم.
|
||||
</p>
|
||||
|
||||
<div className="pt-4 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
|
||||
@ -24,7 +24,7 @@ interface OrderDetailsModalProps {
|
||||
export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetailsModalProps) {
|
||||
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 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">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>فاکتور رسمی کنینا - ${displayTrackingCode}</title>
|
||||
<title>فاکتور رسمی کانینا - ${displayTrackingCode}</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Vazirmatn';
|
||||
@ -104,7 +104,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
|
||||
<div class="invoice-card">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="logo-text">CANINA | کنینا</div>
|
||||
<div class="logo-text">CANINA | کانینا</div>
|
||||
<div class="sub-logo">مکملهای تخصصی دامپزشکی آلمان</div>
|
||||
</div>
|
||||
<div style="text-align: left;">
|
||||
@ -167,7 +167,7 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
|
||||
|
||||
<div class="footer">
|
||||
این فاکتور رسمی به صورت هوشمند و سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/>
|
||||
پشتیبانی کنینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
|
||||
پشتیبانی کانینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
|
||||
</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"
|
||||
>
|
||||
<Download className="w-5 h-5" />
|
||||
دانلود و چاپ فاکتور رسمی کنینا
|
||||
دانلود و چاپ فاکتور رسمی کانینا
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@ -50,7 +50,7 @@ export default function OrderTracking() {
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-2 text-[10px] font-black text-medical-gray-400 uppercase tracking-widest overflow-x-auto whitespace-nowrap pb-2">
|
||||
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کنینا</span>
|
||||
<span className="cursor-pointer hover:text-canina-blue" onClick={() => router.push('/')}>کانینا</span>
|
||||
<ChevronLeft className="w-2.5 h-2.5" />
|
||||
<span className="text-canina-blue">پیگیری سفارش</span>
|
||||
</div>
|
||||
|
||||
@ -1090,9 +1090,9 @@ export default function PetProfile({ initialView }: {
|
||||
<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>
|
||||
<h4 className="text-2xl font-black text-medical-gray-900 mb-4 italic">ضمانت اصالت و سلامت کنینا آلمان</h4>
|
||||
<h4 className="text-2xl font-black text-medical-gray-900 mb-4 italic">ضمانت اصالت و سلامت کانینا آلمان</h4>
|
||||
<p className="text-sm text-medical-gray-500 font-medium leading-relaxed max-w-2xl mx-auto italic">
|
||||
این گزارش توسط سیستم هوش مصنوعی کنینا و با انطباق کامل بر پروتکلهای درمانی Canina Pharma GmbH آلمان تولید شده است. تمامی مکملهای پیشنهادی دارای استاندارد دارویی (Pharmaceutical Grade) میباشند.
|
||||
این گزارش توسط سیستم هوش مصنوعی کانینا و با انطباق کامل بر پروتکلهای درمانی Canina Pharma GmbH آلمان تولید شده است. تمامی مکملهای پیشنهادی دارای استاندارد دارویی (Pharmaceutical Grade) میباشند.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio
|
||||
</div>
|
||||
<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>
|
||||
<button
|
||||
onClick={handleClose}
|
||||
|
||||
@ -14,7 +14,7 @@ interface SafeImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>,
|
||||
|
||||
export default function SafeImage({
|
||||
src,
|
||||
alt = "تصویر مکمل کنینا",
|
||||
alt = "تصویر مکمل کانینا",
|
||||
className,
|
||||
imgClassName,
|
||||
fallbackText = "در حال بروزرسانی تصویر..."
|
||||
|
||||
@ -181,9 +181,9 @@ export default function SmartAdvisor({ onComplete, rules = [] }: SmartAdvisorPro
|
||||
<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>
|
||||
</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">
|
||||
{getText('advisor_subtitle', "با ثبت اطلاعات همدم خود در ۴ قدم ساده، از الگوریتم علمی کنینا برای تجویز دقیق مکمل و پایش سلامت بهرهمند شوید.")}
|
||||
{getText('advisor_subtitle', "با ثبت اطلاعات همدم خود در ۴ قدم ساده، از الگوریتم علمی کانینا برای تجویز دقیق مکمل و پایش سلامت بهرهمند شوید.")}
|
||||
</p>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
<p className="text-xs text-medical-gray-500 font-medium leading-relaxed font-vazir">
|
||||
مکملهای دارویی کنینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه میکند.
|
||||
مکملهای دارویی کانینا غلیظ و تخصصی هستند؛ الگوریتم هوشمند ما بر اساس سن، وزن و جثه پت شما، دوز دقیق مصرفی روزانه را محاسبه میکند.
|
||||
</p>
|
||||
</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">
|
||||
|
||||
@ -7,7 +7,7 @@ export default function TickerBanner() {
|
||||
const getText = useSettingsStore((state) => state.getText);
|
||||
const announcementText = getText(
|
||||
"shipping_notice",
|
||||
"ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان — گارانتی اصالت کنینا آلمان — مشاوره تخصصی مکملهای دارویی سگ و گربه با کادر دامپزشکان مجرب"
|
||||
"ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان — گارانتی اصالت کانینا آلمان — مشاوره تخصصی مکملهای دارویی سگ و گربه با کادر دامپزشکان مجرب"
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@ -37,7 +37,7 @@ export default function Tooltip({ termKey, children, onWikiNavigate }: TooltipPr
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-2 text-canina-blue">
|
||||
<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>
|
||||
<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">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import React, { useState } from "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 { useUserStore, Address } from "../lib/store/userStore";
|
||||
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 = () => {
|
||||
logout();
|
||||
router.push('/');
|
||||
@ -381,140 +339,9 @@ export default function UserDashboard() {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* 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>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === "orders" && (
|
||||
<div>
|
||||
|
||||
@ -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>
|
||||
</h2>
|
||||
<p className="text-lg text-medical-gray-500 font-medium mt-6">
|
||||
{getText('videos_desc', "تیم علمی و فرمولهکنندگان کمپانی کنینا در آلمان مستقیماً با شما صحبت میکنند؛ آشنایی با نحوه مصرف، مزایای بالینی و دانش پزشکی پشت هر محصول.")}
|
||||
{getText('videos_desc', "تیم علمی و فرمولهکنندگان کمپانی کانینا در آلمان مستقیماً با شما صحبت میکنند؛ آشنایی با نحوه مصرف، مزایای بالینی و دانش پزشکی پشت هر محصول.")}
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
|
||||
@ -85,7 +85,7 @@ export default function VideosPage() {
|
||||
Video Academy
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
<button
|
||||
|
||||
@ -8,9 +8,9 @@ describe('Footer', () => {
|
||||
it('renders footer brand text and standard layout elements', () => {
|
||||
render(<Footer onNavigate={vi.fn()} onShopNavigate={vi.fn()} onB2BOpen={vi.fn()} />);
|
||||
|
||||
expect(screen.getByText('کنینا ایران')).toBeInTheDocument();
|
||||
expect(screen.getByText('کانینا ایران')).toBeInTheDocument();
|
||||
expect(screen.getByText('نماینده رسمی در ایران')).toBeInTheDocument();
|
||||
expect(screen.getByText('تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹')).toBeInTheDocument();
|
||||
expect(screen.getByText('تهران، جردن، خیابان سعیدی، ساختمان کانینا، طبقه ۵، واحد ۱۹')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('triggers onNavigate and onShopNavigate when quick links are clicked', () => {
|
||||
|
||||
@ -121,7 +121,7 @@ export default function CatalogPageSpread({
|
||||
|
||||
<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>
|
||||
<p className="text-[11px] md:text-xs text-slate-300 font-medium max-w-md mx-auto leading-relaxed">
|
||||
مرجع رسمی مکملهای درمانی حیوانات خانگی با استانداردهای داروسازی آلمان (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">
|
||||
<Award className="w-4 h-4 text-amber-600 shrink-0" />
|
||||
<p className="text-[10px] text-amber-900 font-bold leading-relaxed">
|
||||
تمامی فرآوردههای کنینا آلمان مطابق با مونوگرافهای دارویی فارماکوپه اروپا (Ph. Eur.) و تحت استاندارد GMP تولید میشوند.
|
||||
تمامی فرآوردههای کانینا آلمان مطابق با مونوگرافهای دارویی فارماکوپه اروپا (Ph. Eur.) و تحت استاندارد GMP تولید میشوند.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -298,7 +298,7 @@ export default function CatalogPageSpread({
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-slate-400 block">واردکننده انحصاری:</span>
|
||||
<span className="font-black text-white">کنینا فارما ایران</span>
|
||||
<span className="font-black text-white">کانینا فارما ایران</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -464,7 +464,7 @@ export default function FlipbookCatalog({ products }: FlipbookCatalogProps) {
|
||||
CP
|
||||
</div>
|
||||
<h3 className="text-base font-black font-lalezar text-white">
|
||||
کاتالوگ تخصصی کنینا آلمان
|
||||
کاتالوگ تخصصی کانینا آلمان
|
||||
</h3>
|
||||
<p className="text-[11px] text-slate-400 leading-relaxed font-medium">
|
||||
جهت باز کردن کاتالوگ و شروع مطالعه، روی صفحه چپ یا کلید ← کیبورد را بزنید.
|
||||
|
||||
@ -351,7 +351,7 @@ export const PRODUCTS: Product[] = [
|
||||
name: "دکتر ماری کونیگ",
|
||||
title: "متخصص تغذیه دامپزشکی",
|
||||
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
|
||||
message: "روغن سالمون کنینا به روش پرس سرد تهیه شده تا تمامی ویتامینهای حساس به حرارت حفظ شوند."
|
||||
message: "روغن سالمون کانینا به روش پرس سرد تهیه شده تا تمامی ویتامینهای حساس به حرارت حفظ شوند."
|
||||
},
|
||||
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
|
||||
},
|
||||
@ -512,7 +512,7 @@ export const PRODUCTS: Product[] = [
|
||||
name: "دکتر مونیخ",
|
||||
title: "متخصص طب طبیعی دامپزشکی",
|
||||
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
|
||||
message: "روغن سیاه دانه مصری کنینا حاوی مقادیر بالایی اسیدهای چرب چند غیراشباع است."
|
||||
message: "روغن سیاه دانه مصری کانینا حاوی مقادیر بالایی اسیدهای چرب چند غیراشباع است."
|
||||
},
|
||||
image: "https://www.canina.de/media/1b/83/7d/1715077272/Schwarz-Kuemmel-112503-V1-Canino-250ml_600x600.webp"
|
||||
},
|
||||
@ -1066,7 +1066,7 @@ export const PRODUCTS: Product[] = [
|
||||
name: "دکتر بکر",
|
||||
title: "متخصص تولیدمثل دامپزشکی",
|
||||
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
|
||||
message: "شیر تولهسگ کنینا نزدیکترین ترکیب به شیر طبیعی سگ ماده را دارد."
|
||||
message: "شیر تولهسگ کانینا نزدیکترین ترکیب به شیر طبیعی سگ ماده را دارد."
|
||||
},
|
||||
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
|
||||
},
|
||||
@ -1100,7 +1100,7 @@ export const PRODUCTS: Product[] = [
|
||||
name: "دکتر کوهن",
|
||||
title: "متخصص طب سنتی دامپزشکی",
|
||||
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
|
||||
message: "فرنی تولهسگ کنینا انتقال نرم از شیر به غذای جامد را تضمین میکند."
|
||||
message: "فرنی تولهسگ کانینا انتقال نرم از شیر به غذای جامد را تضمین میکند."
|
||||
},
|
||||
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
|
||||
},
|
||||
@ -1224,7 +1224,7 @@ export const PRODUCTS: Product[] = [
|
||||
name: "دکتر بکر",
|
||||
title: "متخصص تولیدمثل دامپزشکی",
|
||||
image: "https://images.unsplash.com/photo-1559839734-2b71f1536783?auto=format&fit=crop&q=80&w=200",
|
||||
message: "شیر گربه کنینا با تورین بالا برای سلامت قلب و بینایی بچهگربهها حیاتی است."
|
||||
message: "شیر گربه کانینا با تورین بالا برای سلامت قلب و بینایی بچهگربهها حیاتی است."
|
||||
},
|
||||
image: "https://www.canina.de/media/6b/48/81/731000_Canino_Lachsoel_Lachs_Oel_1280x1280.png"
|
||||
}
|
||||
|
||||
@ -9,9 +9,6 @@ export interface User {
|
||||
role: string;
|
||||
walletBalance: number;
|
||||
charityDonationTotal: number;
|
||||
hasPassword?: boolean;
|
||||
password?: string;
|
||||
currentPassword?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
pets?: unknown[];
|
||||
|
||||
@ -90,10 +90,10 @@ export class ProductService {
|
||||
const priceVal = Number(data.priceValue || 0);
|
||||
|
||||
const defaultSpecialist = local?.specialist || {
|
||||
name: 'تیم تخصصی کنینا',
|
||||
name: 'تیم تخصصی کانینا',
|
||||
title: 'مشاور علمی و دارویی',
|
||||
image: '/images/vets/vet1.webp',
|
||||
message: 'تمامی محصولات مکمل کنینا دارای استانداردهای دارویی آلمان و تاییدیه کلینیکی هستند.'
|
||||
message: 'تمامی محصولات مکمل کانینا دارای استانداردهای دارویی آلمان و تاییدیه کلینیکی هستند.'
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { authService, User } from "../services/authService";
|
||||
import { authService } from "../services/authService";
|
||||
import api from "../services/api";
|
||||
import { useCartStore } from "./cartStore";
|
||||
import { usePetStore } from "./usePetStore";
|
||||
@ -37,7 +37,6 @@ interface UserProfile {
|
||||
mobile: string;
|
||||
walletBalance: number;
|
||||
charityDonationTotal: number;
|
||||
hasPassword?: boolean;
|
||||
addresses: Address[];
|
||||
transactions: Transaction[];
|
||||
}
|
||||
@ -50,7 +49,7 @@ interface UserStore {
|
||||
setRole: (role: UserRole) => void;
|
||||
setLoggedIn: (isLoggedIn: 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>;
|
||||
updateAddress: (id: string, address: Address) => Promise<void>;
|
||||
deleteAddress: (id: string) => Promise<void>;
|
||||
@ -73,7 +72,6 @@ export const useUserStore = create<UserStore>()(
|
||||
mobile: "",
|
||||
walletBalance: 0,
|
||||
charityDonationTotal: 0,
|
||||
hasPassword: false,
|
||||
addresses: [],
|
||||
transactions: [],
|
||||
},
|
||||
@ -82,7 +80,7 @@ export const useUserStore = create<UserStore>()(
|
||||
setAuthModalOpen: (open) => set({ isAuthModalOpen: open }),
|
||||
updateProfile: async (updates) => {
|
||||
try {
|
||||
const profileData = await authService.updateProfile(updates as Partial<User>);
|
||||
const profileData = await authService.updateProfile(updates);
|
||||
set((state) => ({
|
||||
profile: {
|
||||
...state.profile,
|
||||
@ -90,7 +88,6 @@ export const useUserStore = create<UserStore>()(
|
||||
lastName: profileData.lastName,
|
||||
email: profileData.email,
|
||||
mobile: profileData.mobile || "",
|
||||
hasPassword: profileData.hasPassword !== undefined ? profileData.hasPassword : state.profile.hasPassword,
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
@ -249,7 +246,6 @@ export const useUserStore = create<UserStore>()(
|
||||
mobile: profileData.mobile || "",
|
||||
walletBalance: backendWallet,
|
||||
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,
|
||||
transactions: backendTransactions.length > 0 ? backendTransactions : state.profile.transactions
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user