# 📋 تاریخچه تغییرات FrontOffice — کارا بازار سلامت

> **آخرین بروزرسانی**: اسفند ۱۴۰۴ (فوریه ۲۰۲۶)  
> **فریمورک**: Blazor Server + MudBlazor 8.14 + .NET 9

---

## 🔖 نسخه ۲.۷.۰ — اسفند ۱۴۰۴ (February 17, 2026)

### ۱. اجبار تخفیف ۱۰۰٪ و حذف اسلایدر

- **حذف** `MudSlider` و `MudNumericField` از `Checkout.razor` — کاربر دیگه درصد تخفیف انتخاب نمی‌کنه
- **حذف** کامل بخش نمایش موجودی تخفیفی
- بکند همیشه حداکثر تخفیف (`MaxDiscountPercent`) رو اعمال می‌کنه

### ۲. رفع متن Badge تخفیف

- **مشکل:** Badge روی محصولات "۱۰۰٪ تخفیفی" نشون می‌داد — گمراه‌کننده
- **رفع:** نمایش درصد واقعی محصول (مثلاً "۳۰٪ تخفیف")
- **فایل‌ها:** `Products.razor`, `Cart.razor`, `ProductDetail.razor`

### ۳. نمایش جدول مالیات (VAT) در Checkout

- جمع کل، تخفیف، مبلغ پس از تخفیف، مالیات ۹٪، مبلغ قابل پرداخت
- استفاده از `VatCalculator` برای محاسبه VAT

### ۴. نمایش وضعیت پرداخت در سفارشات

- **فیلد جدید** `payment_status` در proto `discountorder.proto` (v0.0.179)
- **صفحه Orders:** نمایش Chip رنگی بر اساس PaymentStatus (موفق/ناموفق/در انتظار)
- **صفحه OrderDetail:** Alert برای سفارشات ناموفق + دکمه بازگشت + جزئیات وضعیت
- **Helper متدها:** `GetPaymentStatusText()`, `GetPaymentStatusColor()`, `GetDeliveryStatusText()`

### ۵. فیکس مپینگ PaymentStatus و DeliveryStatus

- **مشکل:** Domain enum مقادیر متفاوتی از Proto داشت — مستقیم cast می‌شد
- **رفع:** `MapPaymentStatus()` و `MapDeliveryStatus()` در `DiscountOrderService.cs` (WebApi)
- سفارشات ناموفق حالا `DeliveryStatus=Cancelled` دارن (بجای "در حال پردازش")

### ۶. فیکس Proto به NuGet v0.0.179

- `FrontOffice.Main.csproj`: `PackageReference` به `Foursat.CMSMicroservice.Protobuf` v0.0.179

---

## 🔖 نسخه ۲.۶.۰ — بهمن ۱۴۰۴ (February 16, 2026)

### ۱. درگاه پرداخت زرین‌پال

- **یکپارچه‌سازی ZarinPal** — پرداخت مستقیم بدون PYMS واسط
- صفحه checkout فروشگاه تخفیفی: ریدایرکت به ZarinPal → callback → تأیید
- صفحه checkout فروشگاه عادی: همان جریان
- پشتیبانی از sandbox و production

### ۲. جدول PaymentTransaction

- **Entity جدید** `PaymentTransaction` — ذخیره جزئیات سطح درگاه (Authority, CardPan, CardHash, RefId)
- جدا از جدول Transaction اصلی
- Migration: `AddPaymentTransactionTable`

### ۳. فیکس نمایش وضعیت پرداخت

- **مشکل:** سفارشات تخفیفی «در انتظار پرداخت» نشان می‌دادند حتی بعد از پرداخت موفق
- **علت:** Mapster نمی‌تونست `PaymentStatus` (enum) رو به `payment_completed` (bool) مپ کنه
- **رفع:** مپینگ دستی در `DiscountOrderService`

### ۴. فیکس DeliveryStatus

- **مشکل:** فروشگاه تخفیفی بعد از پرداخت `InTransit` ست می‌کرد
- **رفع:** تغییر به `Pending` — ادمین باید وضعیت پست رو مشخص کنه

### ۵. تغییر به NuGet Package (Docker build fix)

- `ProjectReference` به CMS Protobuf → `PackageReference` (v0.0.178)
- Docker build context فقط `src/` داره → مسیر `../../../CMS` قابل دسترسی نیست

---

## 🔖 نسخه ۲.۵.۰ — بهمن ۱۴۰۴

### ۱. محافظت صفحات نیازمند احراز هویت (Auth Guard)

**فایل‌های تغییریافته:**
- `Shared/MainLayout.razor.cs`

**شرح:**  
قبلاً هیچ محافظتی در سطح مسیریابی وجود نداشت — کاربر غیرلاگین می‌توانست مستقیماً به `/profile/*`، `/commission/*`، `/cart` و... دسترسی پیدا کند.

**تغییرات:**
- متد `EnforceAuthGuardAsync()` اضافه شد — در هر تغییر مسیر و اولین بار رندر اجرا می‌شود
- متد `IsProtectedRoute(path)` مسیرهای محافظت‌شده را تشخیص می‌دهد
- کاربر غیرلاگین → ریدایرکت به `/` (صفحه اصلی)

**مسیرهای محافظت‌شده:**
| گروه | مسیرها |
|---|---|
| پروفایل | `/profile/*` |
| کمیسیون | `/commission/*` |
| شبکه | `/network/*` |
| باشگاه | `/club/*` |
| سبد خرید | `/cart`, `/checkout*`, `/orders`, `/order/*`, `/order-tracking/*` |
| پکیج‌ها | `/my-packages` |
| دروازه | `/my-orders`, `/my-cart` |
| فروشگاه تخفیفی | `/discount-store/cart`, `/discount-store/checkout`, `/discount-store/orders`, `/discount-store/order/*` |

**مسیرهای عمومی:**
`/`, `/register`, `/about`, `/faq`, `/contact`, `/blog/*`, `/packages`, `/package/*`, `/products`, `/product/*`, `/categories`, `/stores`, `/discount-store`, `/discount-store/product/*`

---

### ۲. استخراج کامپوننت PhoneVerifyForm

**فایل‌های جدید:**
- `Shared/PhoneVerifyForm.razor`
- `Shared/PhoneVerifyForm.razor.cs`

**فایل‌های تغییریافته:**
- `Shared/AuthDialog.razor`
- `Shared/AuthDialog.razor.cs`

**شرح:**  
فرم تلفن + تایید OTP + کپچا که قبلاً به‌صورت `RenderFragment` با `__builder` مستقیم در `AuthDialog` نوشته شده بود، به کامپوننت مستقل `PhoneVerifyForm` استخراج شد.

**ساختار قبل:**
```
AuthDialog.razor
  └── @code { PhoneOrVerifyContent() => __builder => { ... } }  ← RenderFragment پیچیده
```

**ساختار بعد:**
```
AuthDialog.razor
  └── <PhoneVerifyForm @ref="_phoneVerifyForm" ... />  ← کامپوننت مستقل
PhoneVerifyForm.razor       ← مارکاپ فرم
PhoneVerifyForm.razor.cs    ← پارامترها و فرم رف‌ها
```

**پارامترهای PhoneVerifyForm:**

| پارامتر | نوع | توضیح |
|---|---|---|
| `CurrentStep` | `AuthStep` | مرحله فعلی (Phone / Verify) |
| `PhoneRequest` | `CreateNewOtpTokenRequest` | مدل فرم تلفن |
| `VerifyRequest` | `VerifyOtpTokenRequest` | مدل فرم تایید |
| `CaptchaCode` | `string?` | کد کپچا نمایش‌داده‌شده |
| `CaptchaInput` / `CaptchaInputChanged` | `string?` + `EventCallback` | ورودی کپچا (two-way) |
| `OnRefreshCaptcha` | `EventCallback` | رفرش کپچا |
| `IsBusy` | `bool` | وضعیت بارگذاری |
| `ErrorMessage` / `InfoMessage` | `string?` | پیام‌های خطا/اطلاع |
| `PhoneNumber` | `string?` | شماره تایید‌شده |
| `ResendRemaining` | `int` | ثانیه تا ارسال مجدد |
| `OnChangePhone` / `OnResendOtp` | `EventCallback` | اکشن‌های تایید |

**نکته مهم — Two-way binding کپچا:**  
فیلد کپچا با `Value` + `ValueChanged` بایند شده (نه `@bind-Value`) تا مقدار تایپ‌شده از فرزند به والد برگردد:
```razor
<MudTextField Value="CaptchaInput"
              ValueChanged="@((string v) => CaptchaInputChanged.InvokeAsync(v))" ... />
```

**دسترسی به فرم‌ها از والد:**
```csharp
// AuthDialog.razor.cs
var phoneForm = _phoneVerifyForm?.GetPhoneForm();
var verifyForm = _phoneVerifyForm?.GetVerifyForm();
```

---

### ۳. بهبود لایوت مدال ورود (AuthDialog)

**فایل‌های تغییریافته:**
- `Shared/AuthDialog.razor`
- `Utilities/AuthDialogService.cs`
- `wwwroot/css/site.css`

**مشکلات قبلی:**
- دیالوگ روی موبایل `FullScreen` بود → فضای خالی بزرگ بین فرم و دکمه‌ها
- `TitleContent` و `DialogActions` جدا → گپ عمودی
- ردیف کپچا با `MudStack Row="true"` → آیتم‌ها عمودی رندر می‌شدند

**تغییرات:**
1. **حذف FullScreen**: `AuthDialogService` حالا همیشه `MaxWidth.ExtraSmall, FullWidth=true, CloseButton=true`
2. **ادغام محتوا**: آواتار + عنوان + فرم + دکمه‌ها همه داخل `DialogContent` → بدون `TitleContent` و `DialogActions`
3. **کلاس `auth-dialog-wrapper`**: CSS با `.auth-dialog-wrapper .mud-dialog-title { display: none; }` عنوان پیش‌فرض دیالوگ رو مخفی می‌کنه
4. **ردیف کپچا**: از `MudStack Row` به `div.captcha-row` با CSS flex اختصاصی
5. **حالت Inline**: بدون تغییر ساختاری — فقط از `PhoneVerifyForm` استفاده می‌کنه

**CSS جدید:**
```css
.auth-dialog-wrapper .mud-dialog-title { display: none; }
.auth-dialog-wrapper .mud-dialog-content { padding-bottom: 24px !important; }
.auth-dialog-content { max-width: 400px; margin: 0 auto; }

.captcha-row { display: flex; align-items: center; gap: 10px; }
.captcha-row > .mud-input-control { flex: 1 1 0; min-width: 0; }
.captcha-row > .mud-paper { flex: 0 0 auto; }
.captcha-row > .mud-button-root { flex: 0 0 auto; }
```

---

### ۴. صفحه لندینگ — حذف /pricing و اضافه بنر بلاگ

**فایل‌های تغییریافته:**
- `Pages/Index.razor`
- `wwwroot/css/site.css`

**تغییرات:**
1. دکمه هیرو «مشاهده پکیج‌ها» → **«آخرین اخبار»** با لینک `/blog`
2. **بنر جدیدترین مطلب** بین هیرو و «سه گام تا شروع» اضافه شد
   - تصویر بندانگشتی + عنوان + خلاصه + آیکون شیشه‌ای
   - هاور: `translateY(-2px)` + سایه بزرگ‌تر

**CSS جدید:**
```css
.landing-blog-banner { border: 1px solid var(--mud-palette-divider); transition: ... }
.landing-blog-banner:hover { box-shadow: var(--mud-elevation-4); transform: translateY(-2px); }
.landing-blog-thumb { width: 80px; height: 80px; border-radius: 12px; }
.landing-blog-title { -webkit-line-clamp: 1; font-weight: 600; }
.landing-blog-summary { -webkit-line-clamp: 1; }
```

---

### ۵. افزایش ارتفاع تکست‌باکس‌ها (Global)

**فایل تغییریافته:**
- `wwwroot/css/site.css`

**قبل:** `padding: 10px 14px`  
**بعد:** `padding: 14px 14px` + `font-size: 1rem`

```css
.mud-input-outlined .mud-input-slot {
    padding: 14px 14px !important;
    font-size: 1rem;
}
```

تمام فیلدهای Outlined در کل اپلیکیشن بزرگ‌تر شدند.

---

### ۶. اصلاح RTL فیلدهای ورودی

**فایل تغییریافته:**
- `wwwroot/css/site.css`

**مشکل:** فیلدهای `type="tel"` به‌صورت پیش‌فرض مرورگر `direction: ltr` می‌گیرن — لیبل سمت راست ولی placeholder/cursor سمت چپ.

**اصلاح:**
```css
.mud-input-slot input,
.mud-input-slot textarea {
    direction: rtl !important;
    text-align: right !important;
}
```

---

### ۷. اصلاح captcha-box CSS

**فایل تغییریافته:**
- `wwwroot/css/site.css`

**قبل:**
```css
.captcha-box {
    min-width: 120px; min-height: 56px;
    background: linear-gradient(135deg, rgba(123,97,255,.12), rgba(255,140,189,.12));
}
```

**بعد:**
```css
.captcha-box {
    min-width: 96px; min-height: 48px;
    border-radius: var(--mud-default-borderradius);
    background: rgba(99,102,241,.08);
    border: 1px solid var(--mud-palette-divider);
}
```

---

## 📁 نقشه فایل‌ها

```
Shared/
├── AuthDialog.razor              ← بازنویسی (کامپوننت PhoneVerifyForm جایگزین RenderFragment)
├── AuthDialog.razor.cs           ← بروزرسانی (استفاده از _phoneVerifyForm)
├── PhoneVerifyForm.razor         ← ✨ جدید (فرم تلفن + تایید + کپچا)
├── PhoneVerifyForm.razor.cs      ← ✨ جدید (پارامترها و فرم رف‌ها)
├── MainLayout.razor.cs           ← Auth Guard اضافه شد
Pages/
├── Index.razor                   ← /pricing → /blog + بنر بلاگ
Utilities/
├── AuthDialogService.cs          ← حذف FullScreen، ثابت‌سازی سایز
wwwroot/css/
├── site.css                      ← captcha-row, auth-dialog, RTL fix, input height
```

---

## 🔍 وضعیت بیلد

| تاریخ | خطا | هشدار | توضیح |
|---|---|---|---|
| بهمن ۱۴۰۴ | **۰** | ۱۰۵ | MUD0002 warnings (بی‌خطر — مربوط به MudBlazor analyzer) |
