From 585109ab868dc49a3b838bc3a3d5489bf5b2919b Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 17 Feb 2026 02:56:01 +0330 Subject: [PATCH 1/8] chore: clean up commented-out GwUrl in appsettings --- src/FrontOffice.Main/appsettings.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FrontOffice.Main/appsettings.json b/src/FrontOffice.Main/appsettings.json index de0550d..6f287e6 100644 --- a/src/FrontOffice.Main/appsettings.json +++ b/src/FrontOffice.Main/appsettings.json @@ -1,5 +1,4 @@ { -// "GwUrl": "https://localhost:34781", "GwUrl": "https://localhost:32846", "DownloadUrl": "", "EncryptionSettings": { From f070a0b294e84caa0ac2dd29e7e8c39ecc01e324 Mon Sep 17 00:00:00 2001 From: Masoud <64721166+masoodafar-web@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:22:19 +0330 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20update=20references=20from=20"=D9=81?= =?UTF-8?q?=D8=B1=D9=88=D8=B4=DA=AF=D8=A7=D9=87=20=D8=AA=D8=AE=D9=81=DB=8C?= =?UTF-8?q?=D9=81=DB=8C"=20to=20"=D9=81=D8=B1=D9=88=D8=B4=DA=AF=D8=A7?= =?UTF-8?q?=D9=87=20=D8=A7=D8=B9=D8=AA=D8=A8=D8=A7=D8=B1=DB=8C"=20across?= =?UTF-8?q?=20multiple=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/CHANGELOG.md | 6 +++--- docs/UI-UNIFICATION-PLAN.md | 2 +- src/FrontOffice.Main/Pages/Club/MembershipPage.razor | 4 ++-- src/FrontOffice.Main/Pages/DiscountStore/Cart.razor | 2 +- src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor | 2 +- src/FrontOffice.Main/Pages/DiscountStore/Orders.razor | 4 ++-- .../Pages/DiscountStore/ProductDetail.razor | 2 +- src/FrontOffice.Main/Pages/DiscountStore/Products.razor | 4 ++-- src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor | 2 +- src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor | 2 +- src/FrontOffice.Main/Pages/Package/MyPackages.razor | 2 +- src/FrontOffice.Main/Shared/MainLayout.razor | 4 ++-- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 282ffe3..f575004 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -48,7 +48,7 @@ ### ۱. درگاه پرداخت زرین‌پال - **یکپارچه‌سازی ZarinPal** — پرداخت مستقیم بدون PYMS واسط -- صفحه checkout فروشگاه تخفیفی: ریدایرکت به ZarinPal → callback → تأیید +- صفحه checkout فروشگاه اعتباری: ریدایرکت به ZarinPal → callback → تأیید - صفحه checkout فروشگاه عادی: همان جریان - پشتیبانی از sandbox و production @@ -66,7 +66,7 @@ ### ۴. فیکس DeliveryStatus -- **مشکل:** فروشگاه تخفیفی بعد از پرداخت `InTransit` ست می‌کرد +- **مشکل:** فروشگاه اعتباری بعد از پرداخت `InTransit` ست می‌کرد - **رفع:** تغییر به `Pending` — ادمین باید وضعیت پست رو مشخص کنه ### ۵. تغییر به NuGet Package (Docker build fix) @@ -101,7 +101,7 @@ | سبد خرید | `/cart`, `/checkout*`, `/orders`, `/order/*`, `/order-tracking/*` | | پکیج‌ها | `/my-packages` | | دروازه | `/my-orders`, `/my-cart` | -| فروشگاه تخفیفی | `/discount-store/cart`, `/discount-store/checkout`, `/discount-store/orders`, `/discount-store/order/*` | +| فروشگاه اعتباری | `/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/*` diff --git a/docs/UI-UNIFICATION-PLAN.md b/docs/UI-UNIFICATION-PLAN.md index daa7d19..40c3105 100644 --- a/docs/UI-UNIFICATION-PLAN.md +++ b/docs/UI-UNIFICATION-PLAN.md @@ -215,7 +215,7 @@ Primary = "#0380C0" // آبی ساده /* ── Semantic Colors ── */ --ds-color-store: #10b981; /* فروشگاه عادی */ - --ds-color-discount: #ef4444; /* فروشگاه تخفیفی */ + --ds-color-discount: #ef4444; /* فروشگاه اعتباری */ --ds-color-success: #10b981; --ds-color-warning: #f59e0b; --ds-color-error: #ef4444; diff --git a/src/FrontOffice.Main/Pages/Club/MembershipPage.razor b/src/FrontOffice.Main/Pages/Club/MembershipPage.razor index a788171..f551432 100644 --- a/src/FrontOffice.Main/Pages/Club/MembershipPage.razor +++ b/src/FrontOffice.Main/Pages/Club/MembershipPage.razor @@ -64,8 +64,8 @@ - شارژ کیف پول فروشگاه تخفیفی - شارژ ۵۶ میلیون تومان کیف پول فروشگاه تخفیفی + شارژ کیف پول فروشگاه اعتباری + شارژ ۵۶ میلیون تومان کیف پول فروشگاه اعتباری diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor index 5b2ad42..0db1b16 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor @@ -11,7 +11,7 @@ سبد خرید تخفیفی شما خالی است. - بازگشت به فروشگاه تخفیفی + بازگشت به فروشگاه اعتباری } else diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor index 7de3d94..2624315 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor @@ -1,7 +1,7 @@ @using CMSMicroservice.Protobuf.Protos.UserAddress @attribute [Route(RouteConstants.DiscountStore.Checkout)] -تسویه حساب فروشگاه تخفیفی +تسویه حساب فروشگاه اعتباری diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor b/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor index 7b0b99d..57e488a 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor @@ -1,6 +1,6 @@ @attribute [Route(RouteConstants.DiscountStore.Orders)] -سفارش‌های فروشگاه تخفیفی +سفارش‌های فروشگاه اعتباری @@ -15,7 +15,7 @@ هنوز سفارشی ثبت نشده است. - مشاهده فروشگاه تخفیفی + مشاهده فروشگاه اعتباری } else diff --git a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor index 2e37808..c33a86d 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor @@ -11,7 +11,7 @@ { } else diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor index edb5959..a7c9c9f 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor @@ -1,13 +1,13 @@ @attribute [Route(RouteConstants.DiscountStore.Products)] -فروشگاه تخفیفی +فروشگاه اعتباری - فروشگاه تخفیفی + فروشگاه اعتباری خرید با استفاده از موجودی کیف پول تخفیفی diff --git a/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor b/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor index 58c531b..d32efbd 100644 --- a/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor +++ b/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor @@ -30,7 +30,7 @@ - سفارشات فروشگاه تخفیفی + سفارشات فروشگاه اعتباری سفارشات خرید تخفیفی diff --git a/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor b/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor index 30becda..b0f41d5 100644 --- a/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor +++ b/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor @@ -38,7 +38,7 @@ - فروشگاه تخفیفی + فروشگاه اعتباری خرید با استفاده از موجودی کیف تخفیفی + درگاه پرداخت diff --git a/src/FrontOffice.Main/Pages/Package/MyPackages.razor b/src/FrontOffice.Main/Pages/Package/MyPackages.razor index 95a2685..7c137ed 100644 --- a/src/FrontOffice.Main/Pages/Package/MyPackages.razor +++ b/src/FrontOffice.Main/Pages/Package/MyPackages.razor @@ -171,7 +171,7 @@ - فروشگاه تخفیفی + فروشگاه اعتباری خرید با تخفیف ویژه diff --git a/src/FrontOffice.Main/Shared/MainLayout.razor b/src/FrontOffice.Main/Shared/MainLayout.razor index 343fa08..76445d7 100644 --- a/src/FrontOffice.Main/Shared/MainLayout.razor +++ b/src/FrontOffice.Main/Shared/MainLayout.razor @@ -42,7 +42,7 @@ else if (IsInDiscountStore) { فروشگاه تخفیفی + Class="d-none d-md-flex" Icon="@Icons.Material.Filled.Loyalty">فروشگاه اعتباری } @@ -159,7 +159,7 @@ } else if (IsInDiscountStore) { - فروشگاه تخفیفی + فروشگاه اعتباری محصولات تخفیفی Date: Tue, 17 Feb 2026 15:28:52 +0330 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20update=20references=20from=20"=D8=AA?= =?UTF-8?q?=D8=AE=D9=81=DB=8C=D9=81=DB=8C"=20to=20"=D8=A7=D8=B9=D8=AA?= =?UTF-8?q?=D8=A8=D8=A7=D8=B1=DB=8C"=20across=20multiple=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/CHANGELOG.md | 6 +++--- docs/UI-UNIFICATION-PLAN.md | 2 +- src/FrontOffice.Main/Pages/DiscountStore/Cart.razor | 6 +++--- .../Pages/DiscountStore/Checkout.razor | 4 ++-- .../Pages/DiscountStore/OrderDetail.razor | 4 ++-- src/FrontOffice.Main/Pages/DiscountStore/Orders.razor | 6 +++--- .../Pages/DiscountStore/ProductDetail.razor | 6 +++--- .../Pages/DiscountStore/Products.razor | 2 +- src/FrontOffice.Main/Pages/Gateway/CartChooser.razor | 2 +- src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor | 2 +- src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor | 2 +- src/FrontOffice.Main/Pages/Profile/Wallet.razor | 10 +++++----- src/FrontOffice.Main/Shared/MainLayout.razor | 4 ++-- src/FrontOffice.Main/Utilities/WalletService.cs | 2 +- 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f575004..9a93d3c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,12 +10,12 @@ ### ۱. اجبار تخفیف ۱۰۰٪ و حذف اسلایدر - **حذف** `MudSlider` و `MudNumericField` از `Checkout.razor` — کاربر دیگه درصد تخفیف انتخاب نمی‌کنه -- **حذف** کامل بخش نمایش موجودی تخفیفی +- **حذف** کامل بخش نمایش موجودی اعتباری - بکند همیشه حداکثر تخفیف (`MaxDiscountPercent`) رو اعمال می‌کنه ### ۲. رفع متن Badge تخفیف -- **مشکل:** Badge روی محصولات "۱۰۰٪ تخفیفی" نشون می‌داد — گمراه‌کننده +- **مشکل:** Badge روی محصولات "۱۰۰٪ اعتباری" نشون می‌داد — گمراه‌کننده - **رفع:** نمایش درصد واقعی محصول (مثلاً "۳۰٪ تخفیف") - **فایل‌ها:** `Products.razor`, `Cart.razor`, `ProductDetail.razor` @@ -60,7 +60,7 @@ ### ۳. فیکس نمایش وضعیت پرداخت -- **مشکل:** سفارشات تخفیفی «در انتظار پرداخت» نشان می‌دادند حتی بعد از پرداخت موفق +- **مشکل:** سفارشات اعتباری «در انتظار پرداخت» نشان می‌دادند حتی بعد از پرداخت موفق - **علت:** Mapster نمی‌تونست `PaymentStatus` (enum) رو به `payment_completed` (bool) مپ کنه - **رفع:** مپینگ دستی در `DiscountOrderService` diff --git a/docs/UI-UNIFICATION-PLAN.md b/docs/UI-UNIFICATION-PLAN.md index 40c3105..e43f290 100644 --- a/docs/UI-UNIFICATION-PLAN.md +++ b/docs/UI-UNIFICATION-PLAN.md @@ -100,7 +100,7 @@ py-16 سکشنی → Index, About, Contact, FAQ | رنگ | استفاده | باید باشد | |---|---|---| | `#10b981` | Gateway (سبز فروشگاه) | `var(--ds-color-store)` | -| `#ef4444` | Gateway (قرمز تخفیفی) | `var(--ds-color-discount)` | +| `#ef4444` | Gateway (قرمز اعتباری) | `var(--ds-color-discount)` | | `#6366f1`, `#818cf8`, `#a78bfa` | Hero/Banner gradients | `var(--ds-gradient-primary)` | | `rgba(99,102,241,.12)` | Dashboard backgrounds | `var(--ds-primary-soft)` | | `rgba(16,185,129,.06)` | Discount product highlights | `var(--ds-success-soft)` | diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor index 0db1b16..57a6683 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor @@ -1,14 +1,14 @@ @attribute [Route(RouteConstants.DiscountStore.Cart)] -سبد خرید تخفیفی +سبد خرید اعتباری - + @if (DiscountCart.Items.Count == 0) { - سبد خرید تخفیفی شما خالی است. + سبد خرید اعتباری شما خالی است. بازگشت به فروشگاه اعتباری diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor index 2624315..079977b 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor @@ -4,7 +4,7 @@ تسویه حساب فروشگاه اعتباری - + @@ -108,7 +108,7 @@ - تخفیف از کیف تخفیفی: + تخفیف از کیف اعتباری: @FormatPrice(DiscountCart.TotalDiscount)- تومان diff --git a/src/FrontOffice.Main/Pages/DiscountStore/OrderDetail.razor b/src/FrontOffice.Main/Pages/DiscountStore/OrderDetail.razor index 0ce13da..db96ab8 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/OrderDetail.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/OrderDetail.razor @@ -1,6 +1,6 @@ @attribute [Route("/discount-store/order/{Id:long}")] -جزئیات سفارش تخفیفی +جزئیات سفارش اعتباری @if (!string.IsNullOrEmpty(_paymentMessage)) { @@ -158,7 +158,7 @@ else @if (_order.DiscountBalanceUsed > 0) { - از کیف تخفیفی: + از کیف اعتباری: @FormatPrice(_order.DiscountBalanceUsed)- } diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor b/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor index 57e488a..3bdc6ee 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Orders.razor @@ -4,7 +4,7 @@ - + @if (_loading) { @@ -28,7 +28,7 @@ شماره سفارش تعداد اقلام مبلغ کل - از کیف تخفیفی + از کیف اعتباری درگاه وضعیت پرداخت وضعیت ارسال @@ -108,7 +108,7 @@ @if (order.DiscountBalanceUsed > 0) { - از کیف تخفیفی: @FormatPrice(order.DiscountBalanceUsed) تومان + از کیف اعتباری: @FormatPrice(order.DiscountBalanceUsed) تومان } diff --git a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor index c33a86d..4d02723 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor @@ -1,6 +1,6 @@ @attribute [Route("/discount-store/product/{Id:long}")] -@(_product?.Title ?? "محصول تخفیفی") +@(_product?.Title ?? "محصول اعتباری") @if (_loading) @@ -17,7 +17,7 @@ else { - + @@ -74,7 +74,7 @@ @if (_product.MaxDiscountPercent > 0) { - تخفیف از کیف تخفیفی: + تخفیف از کیف اعتباری: @_product.MaxDiscountPercent% (@($"{_product.Price * _product.MaxDiscountPercent / 100:N0}") تومان) diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor index a7c9c9f..9c3c643 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor @@ -9,7 +9,7 @@ فروشگاه اعتباری - خرید با استفاده از موجودی کیف پول تخفیفی + خرید با استفاده از موجودی کیف پول اعتباری diff --git a/src/FrontOffice.Main/Pages/Gateway/CartChooser.razor b/src/FrontOffice.Main/Pages/Gateway/CartChooser.razor index c1e57d1..56e5593 100644 --- a/src/FrontOffice.Main/Pages/Gateway/CartChooser.razor +++ b/src/FrontOffice.Main/Pages/Gateway/CartChooser.razor @@ -38,7 +38,7 @@ - سبد خرید تخفیفی + سبد خرید اعتباری @if (_discountCartCount > 0) { diff --git a/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor b/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor index d32efbd..b116f68 100644 --- a/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor +++ b/src/FrontOffice.Main/Pages/Gateway/OrdersChooser.razor @@ -31,7 +31,7 @@ سفارشات فروشگاه اعتباری - سفارشات خرید تخفیفی + سفارشات خرید اعتباری diff --git a/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor b/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor index b0f41d5..50c7098 100644 --- a/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor +++ b/src/FrontOffice.Main/Pages/Gateway/StoreChooser.razor @@ -40,7 +40,7 @@ فروشگاه اعتباری - خرید با استفاده از موجودی کیف تخفیفی + درگاه پرداخت + خرید با استفاده از موجودی کیف اعتباری + درگاه پرداخت @if (_discountCartCount > 0) { diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor b/src/FrontOffice.Main/Pages/Profile/Wallet.razor index 98a94c1..5c79048 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor @@ -21,7 +21,7 @@ - موجودی تخفیفی + موجودی اعتباری @_balances.Discount @@ -73,7 +73,7 @@ تاریخ عادی (تغییرات / مانده) شبکه (تغییرات / مانده) - تخفیفی (تغییرات / مانده) + اعتباری (تغییرات / مانده) شناسه ارجاع توضیحات @@ -97,7 +97,7 @@ @FormatPrice(context.NetworkBalance) - + @(context.DiscountChange != 0 ? (context.DiscountChange > 0 ? "+" : "") + FormatPrice(context.DiscountChange) : "-") @@ -147,10 +147,10 @@ - + - تخفیفی + اعتباری @(tx.DiscountChange != 0 ? (tx.DiscountChange > 0 ? "+" : "") + FormatPrice(tx.DiscountChange) : "-") diff --git a/src/FrontOffice.Main/Shared/MainLayout.razor b/src/FrontOffice.Main/Shared/MainLayout.razor index 76445d7..8766d9d 100644 --- a/src/FrontOffice.Main/Shared/MainLayout.razor +++ b/src/FrontOffice.Main/Shared/MainLayout.razor @@ -57,7 +57,7 @@ else if (IsInDiscountStore && _isAuthenticated) { @* ── Discount store nav ── *@ - محصولات تخفیفی + محصولات اعتباری سبد خرید سفارشات من } @@ -161,7 +161,7 @@ { فروشگاه اعتباری محصولات تخفیفی + OnClick="() => _drawerOpen=false">محصولات اعتباری سبد خرید 0 ? "دریافت شبکه" : "برداشت شبکه"); if (model.ChangeDiscountValue != 0) - parts.Add(model.ChangeDiscountValue > 0 ? "شارژ تخفیفی" : "خرید تخفیفی"); + parts.Add(model.ChangeDiscountValue > 0 ? "شارژ اعتباری" : "خرید اعتباری"); return parts.Count > 0 ? string.Join(" | ", parts) : "تراکنش کیف پول"; } From bba9c1d1d8166f63b0790cfe8e36b08b683af7c3 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 17 Feb 2026 22:35:20 +0330 Subject: [PATCH 4/8] feat: Add Licenses page + SitePageSettingsService - SitePageSettingsService: new gRPC client for simplified page settings - Licenses.razor: new page showing license certificates from CMS - RouteConstants: added Licenses route - Footer + MainLayout: added Licenses navigation link - Proto NuGet updated to 0.0.180 --- src/FrontOffice.Main/ConfigureServices.cs | 4 + src/FrontOffice.Main/FrontOffice.Main.csproj | 2 +- src/FrontOffice.Main/Pages/Licenses.razor | 99 ++++++++++++++ src/FrontOffice.Main/Pages/Licenses.razor.cs | 31 +++++ src/FrontOffice.Main/Shared/Footer.razor | 1 + src/FrontOffice.Main/Shared/MainLayout.razor | 4 + .../Utilities/RouteConstants.cs | 5 + .../Utilities/SitePageSettingsService.cs | 125 ++++++++++++++++++ 8 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 src/FrontOffice.Main/Pages/Licenses.razor create mode 100644 src/FrontOffice.Main/Pages/Licenses.razor.cs create mode 100644 src/FrontOffice.Main/Utilities/SitePageSettingsService.cs diff --git a/src/FrontOffice.Main/ConfigureServices.cs b/src/FrontOffice.Main/ConfigureServices.cs index 0f1c61a..702733a 100644 --- a/src/FrontOffice.Main/ConfigureServices.cs +++ b/src/FrontOffice.Main/ConfigureServices.cs @@ -22,6 +22,7 @@ using CMSMicroservice.Protobuf.Protos.NetworkMembership; using CMSMicroservice.Protobuf.Protos.Commission; using CMSMicroservice.Protobuf.Protos.AppVersion; using CMSMicroservice.Protobuf.Protos.SitePage; +using CMSMicroservice.Protobuf.Protos.SitePageSettings; using CMSMicroservice.Protobuf.Protos.BlogPost; using CMSMicroservice.Protobuf.Protos.BlogCategory; using CMSMicroservice.Protobuf.Protos.DiscountProduct; @@ -83,6 +84,8 @@ public static class ConfigureServices services.AddScoped(); services.AddScoped(); services.AddScoped(); + // Site Page Settings Service (simplified page management) + services.AddScoped(); // Device detection: very light, dependency-free services.AddTransient(); // PDF generation (Chromium only) @@ -133,6 +136,7 @@ public static class ConfigureServices services.AddScoped(CreateAuthenticatedClient); services.AddScoped(CreateAuthenticatedClient); services.AddScoped(CreateAuthenticatedClient); + services.AddScoped(CreateAuthenticatedClient); services.AddScoped(CreateAuthenticatedClient); services.AddScoped(CreateAuthenticatedClient); // Image Resolver Service diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj index 7339178..a4662dc 100644 --- a/src/FrontOffice.Main/FrontOffice.Main.csproj +++ b/src/FrontOffice.Main/FrontOffice.Main.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/FrontOffice.Main/Pages/Licenses.razor b/src/FrontOffice.Main/Pages/Licenses.razor new file mode 100644 index 0000000..bef2351 --- /dev/null +++ b/src/FrontOffice.Main/Pages/Licenses.razor @@ -0,0 +1,99 @@ +@attribute [Route(RouteConstants.Licenses.Index)] +@inject SitePageSettingsService PageSettingsService + +مجوزها و گواهینامه‌ها | کارا بازار سلامت + +@if (_loading) +{ + + + +} +else +{ + +
+ + + مجوزها و گواهینامه‌ها + + @(_pageData?.HeroTitle ?? "مجوزها و گواهینامه‌های رسمی") + + + @(_pageData?.HeroSubtitle ?? "ما با دریافت مجوزهای رسمی و تأییدیه‌های معتبر، اطمینان شما را در استفاده از خدمات خود جلب کرده‌ایم.") + + + +
+ + + + +
+ + مجوزهای ما + @if (_licenseImages.Any()) + { + + @foreach (var license in _licenseImages) + { + + + + + @if (!string.IsNullOrWhiteSpace(license.Title)) + { + @license.Title + } + @if (!string.IsNullOrWhiteSpace(license.Description)) + { + @license.Description + } + + @if (!string.IsNullOrWhiteSpace(license.LinkUrl)) + { + + + مشاهده جزئیات + + + } + + + } + + } + else + { + + اطلاعات مجوزها به‌زودی بارگذاری خواهد شد. + + } + +
+ + +
+ + + + نیاز به اطلاعات بیشتر دارید؟ + + برای دریافت اطلاعات بیشتر درباره مجوزها و گواهینامه‌های ما، با ما تماس بگیرید. + + + تماس با ما + + + +
+ +
+} diff --git a/src/FrontOffice.Main/Pages/Licenses.razor.cs b/src/FrontOffice.Main/Pages/Licenses.razor.cs new file mode 100644 index 0000000..89f8fa0 --- /dev/null +++ b/src/FrontOffice.Main/Pages/Licenses.razor.cs @@ -0,0 +1,31 @@ +using FrontOffice.Main.Utilities; + +namespace FrontOffice.Main.Pages; + +public partial class Licenses +{ + private bool _loading = true; + private PageSettingsDto? _pageData; + private List _licenseImages = new(); + + protected override async Task OnInitializedAsync() + { + try + { + _pageData = await PageSettingsService.GetPageAsync("licenses"); + + if (_pageData != null) + { + _licenseImages = _pageData.GetImages("licenses"); + } + } + catch + { + // Fallback: page remains null → hardcoded content will render + } + finally + { + _loading = false; + } + } +} diff --git a/src/FrontOffice.Main/Shared/Footer.razor b/src/FrontOffice.Main/Shared/Footer.razor index 4b88d89..71f1637 100644 --- a/src/FrontOffice.Main/Shared/Footer.razor +++ b/src/FrontOffice.Main/Shared/Footer.razor @@ -55,6 +55,7 @@ سوالات متداول ارتباط با ما درباره ما + مجوزها
diff --git a/src/FrontOffice.Main/Shared/MainLayout.razor b/src/FrontOffice.Main/Shared/MainLayout.razor index 8766d9d..0f0f72d 100644 --- a/src/FrontOffice.Main/Shared/MainLayout.razor +++ b/src/FrontOffice.Main/Shared/MainLayout.razor @@ -73,6 +73,7 @@ بلاگ ارتباط با ما درباره ما + مجوزها
@@ -191,6 +192,9 @@ ارتباط با ما + + مجوزها + @if (_isAuthenticated) diff --git a/src/FrontOffice.Main/Utilities/RouteConstants.cs b/src/FrontOffice.Main/Utilities/RouteConstants.cs index f83d29c..7fd1f65 100644 --- a/src/FrontOffice.Main/Utilities/RouteConstants.cs +++ b/src/FrontOffice.Main/Utilities/RouteConstants.cs @@ -67,6 +67,11 @@ public static class RouteConstants public const string Index = "/contact"; } + public static class Licenses + { + public const string Index = "/licenses"; + } + public static class Blog { public const string Index = "/blog"; diff --git a/src/FrontOffice.Main/Utilities/SitePageSettingsService.cs b/src/FrontOffice.Main/Utilities/SitePageSettingsService.cs new file mode 100644 index 0000000..86b5b29 --- /dev/null +++ b/src/FrontOffice.Main/Utilities/SitePageSettingsService.cs @@ -0,0 +1,125 @@ +using System.Text.Json; +using CMSMicroservice.Protobuf.Protos.SitePageSettings; + +namespace FrontOffice.Main.Utilities; + +/// +/// سرویس ساده‌شده مدیریت صفحات سایت +/// ۴ صفحه ثابت: landing, about, contact, licenses +/// +public class SitePageSettingsService +{ + private readonly SitePageSettingsContract.SitePageSettingsContractClient _client; + + public SitePageSettingsService(SitePageSettingsContract.SitePageSettingsContractClient client) + { + _client = client; + } + + /// + /// دریافت تنظیمات صفحه با کلید + /// + public async Task GetPageAsync(string pageKey) + { + try + { + var response = await _client.GetPageSettingsAsync( + new GetPageSettingsRequest { PageKey = pageKey }); + + if (response == null || response.Id <= 0) return null; + + return MapToDto(response); + } + catch (Exception ex) + { +#if DEBUG + Console.WriteLine($"SitePageSettingsService.GetPageAsync error: {ex.Message}"); +#endif + return null; + } + } + + private static PageSettingsDto MapToDto(PageSettingsResponse response) => new() + { + Id = response.Id, + PageKey = response.PageKey, + Title = response.Title, + MetaDescription = response.MetaDescription, + HeroTitle = response.HeroTitle, + HeroSubtitle = response.HeroSubtitle, + HeroImagePath = response.HeroImagePath, + IsActive = response.IsActive, + SettingsJson = response.SettingsJson, + Images = response.Images.Select(i => new PageSettingsImageDto + { + Id = i.Id, + ImageGroup = i.ImageGroup, + Title = i.Title, + Subtitle = i.Subtitle, + Description = i.Description, + ImagePath = i.ImagePath, + ThumbnailPath = i.ThumbnailPath, + LinkUrl = i.LinkUrl, + IconName = i.IconName, + SortOrder = i.SortOrder, + IsActive = i.IsActive + }).OrderBy(i => i.SortOrder).ToList() + }; +} + +// ── DTOs ── + +public class PageSettingsDto +{ + public long Id { get; set; } + public string PageKey { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public string? MetaDescription { get; set; } + public string? HeroTitle { get; set; } + public string? HeroSubtitle { get; set; } + public string? HeroImagePath { get; set; } + public bool IsActive { get; set; } + public string? SettingsJson { get; set; } + public List Images { get; set; } = new(); + + /// + /// دریافت تصاویر یک گروه خاص + /// + public List GetImages(string group) => + Images.Where(i => i.ImageGroup == group && i.IsActive) + .OrderBy(i => i.SortOrder).ToList(); + + /// + /// دریافت تنظیمات JSON به عنوان یک نوع مشخص + /// + public T? GetSettings() where T : class + { + if (string.IsNullOrWhiteSpace(SettingsJson)) return null; + try + { + return JsonSerializer.Deserialize(SettingsJson, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }); + } + catch + { + return null; + } + } +} + +public class PageSettingsImageDto +{ + public long Id { get; set; } + public string ImageGroup { get; set; } = string.Empty; + public string? Title { get; set; } + public string? Subtitle { get; set; } + public string? Description { get; set; } + public string ImagePath { get; set; } = string.Empty; + public string? ThumbnailPath { get; set; } + public string? LinkUrl { get; set; } + public string? IconName { get; set; } + public int SortOrder { get; set; } + public bool IsActive { get; set; } +} From 997ab80fa4b08fd68e306b1484149c3e4d14a0db Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 17 Feb 2026 23:02:58 +0330 Subject: [PATCH 5/8] refactor: migrate About & Contact pages to SitePageSettings system - About.razor: use SitePageSettingsService + GetSettings() - About.razor.cs: read values/team from ImageGroups instead of SitePage sections - Contact.razor: use SitePageSettingsService + GetSettings() - Contact.razor.cs: read address/phone/email/social from SettingsJson --- src/FrontOffice.Main/Pages/About.razor | 54 ++++++----------- src/FrontOffice.Main/Pages/About.razor.cs | 30 ++++++---- src/FrontOffice.Main/Pages/Contact.razor | 20 +++---- src/FrontOffice.Main/Pages/Contact.razor.cs | 65 +++++---------------- 4 files changed, 62 insertions(+), 107 deletions(-) diff --git a/src/FrontOffice.Main/Pages/About.razor b/src/FrontOffice.Main/Pages/About.razor index 57485ba..784f052 100644 --- a/src/FrontOffice.Main/Pages/About.razor +++ b/src/FrontOffice.Main/Pages/About.razor @@ -1,6 +1,6 @@ @attribute [Route(RouteConstants.About.Index)] @inject NavigationManager Navigation -@inject SitePageService SitePageService +@inject SitePageSettingsService PageSettingsService درباره ما | کارا بازار سلامت @@ -66,40 +66,22 @@ else - @(_visionSection?.Title ?? "چشم‌انداز") + @(_settings?.VisionTitle ?? "چشم‌انداز") + + + @(_settings?.VisionText ?? "تبدیل شدن به پیشروترین پلتفرم مدیریت تیم‌های فروش در منطقه، با ارائه راهکارهای هوشمند و کاربرپسند برای کسب‌وکارهای کوچک و بزرگ.") - @if (!string.IsNullOrWhiteSpace(_visionSection?.HtmlContent)) - { - - @((MarkupString)_visionSection.HtmlContent) - - } - else - { - - تبدیل شدن به پیشروترین پلتفرم مدیریت تیم‌های فروش در منطقه، با ارائه راهکارهای هوشمند و کاربرپسند برای کسب‌وکارهای کوچک و بزرگ. - - } - @(_missionSection?.Title ?? "مأموریت") + @(_settings?.MissionTitle ?? "مأموریت") + + + @(_settings?.MissionText ?? "توانمندسازی کسب‌وکارها از طریق فناوری‌های نوین، ساده‌سازی فرآیندهای پیچیده و ایجاد فرصت‌های جدید برای رشد و توسعه پایدار.") - @if (!string.IsNullOrWhiteSpace(_missionSection?.HtmlContent)) - { - - @((MarkupString)_missionSection.HtmlContent) - - } - else - { - - توانمندسازی کسب‌وکارها از طریق فناوری‌های نوین، ساده‌سازی فرآیندهای پیچیده و ایجاد کارا بازار سلامت‌های جدید برای رشد و توسعه پایدار. - - } @@ -111,21 +93,21 @@ else ارزش‌های ما - @if (_valueSections.Any()) + @if (_valueImages.Any()) { - @foreach (var value in _valueSections) + @foreach (var value in _valueImages) { @if (!string.IsNullOrWhiteSpace(value.IconName)) { - + } @value.Title - @if (!string.IsNullOrWhiteSpace(value.HtmlContent)) + @if (!string.IsNullOrWhiteSpace(value.Description)) { - @((MarkupString)value.HtmlContent) + @value.Description } @@ -199,9 +181,9 @@ else تیم ما - @if (_teamSections.Any()) + @if (_teamImages.Any()) { - @foreach (var member in _teamSections) + @foreach (var member in _teamImages) { @@ -222,10 +204,10 @@ else { @member.Subtitle } - @if (!string.IsNullOrWhiteSpace(member.HtmlContent)) + @if (!string.IsNullOrWhiteSpace(member.Description)) { - @((MarkupString)member.HtmlContent) + @member.Description } diff --git a/src/FrontOffice.Main/Pages/About.razor.cs b/src/FrontOffice.Main/Pages/About.razor.cs index af24e4b..f076c56 100644 --- a/src/FrontOffice.Main/Pages/About.razor.cs +++ b/src/FrontOffice.Main/Pages/About.razor.cs @@ -5,24 +5,22 @@ namespace FrontOffice.Main.Pages; public partial class About { private bool _loading = true; - private SitePageDto? _page; - private SitePageSectionDto? _visionSection; - private SitePageSectionDto? _missionSection; - private List _valueSections = new(); - private List _teamSections = new(); + private PageSettingsDto? _page; + private AboutSettings? _settings; + private List _valueImages = new(); + private List _teamImages = new(); protected override async Task OnInitializedAsync() { try { - _page = await SitePageService.GetByKeyAsync("about"); + _page = await PageSettingsService.GetPageAsync("about"); if (_page != null) { - _visionSection = _page.GetSection("vision"); - _missionSection = _page.GetSection("mission"); - _valueSections = _page.GetSections("value-").ToList(); - _teamSections = _page.GetSections("team-").ToList(); + _settings = _page.GetSettings(); + _valueImages = _page.GetImages("values"); + _teamImages = _page.GetImages("team"); } } catch @@ -34,4 +32,16 @@ public partial class About _loading = false; } } + + private class AboutSettings + { + public string? VisionTitle { get; set; } + public string? VisionText { get; set; } + public string? VisionIcon { get; set; } + public string? MissionTitle { get; set; } + public string? MissionText { get; set; } + public string? MissionIcon { get; set; } + public string? ValuesTitle { get; set; } + public string? TeamTitle { get; set; } + } } \ No newline at end of file diff --git a/src/FrontOffice.Main/Pages/Contact.razor b/src/FrontOffice.Main/Pages/Contact.razor index ed61fa4..af2968a 100644 --- a/src/FrontOffice.Main/Pages/Contact.razor +++ b/src/FrontOffice.Main/Pages/Contact.razor @@ -1,5 +1,5 @@ @attribute [Route(RouteConstants.Contact.Index)] -@inject SitePageService SitePageService +@inject SitePageSettingsService PageSettingsService ارتباط با ما | کارا بازار سلامت @@ -133,7 +133,7 @@
آدرس - @(_contactAddress ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶") + @(_settings?.Address ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶")
@@ -142,7 +142,7 @@
تلفن - @(_contactPhone ?? "026-34233563") + @(_settings?.Phone ?? "026-34233563")
@@ -150,7 +150,7 @@
ایمیل - @(_contactEmail ?? "info@kbs1.co") + @(_settings?.Email ?? "info@kbs1.co")
@@ -159,7 +159,7 @@
ساعات کاری - @((MarkupString)(_contactHours ?? "شنبه تا پنج‌شنبه
۹ صبح تا ۶ عصر")) + @((MarkupString)(_settings?.WorkingHours ?? "شنبه تا پنج‌شنبه
۹ صبح تا ۶ عصر"))
@@ -174,7 +174,7 @@ تلگرام @@ -183,7 +183,7 @@ اینستاگرام @@ -192,7 +192,7 @@ لینکدین @@ -201,7 +201,7 @@ واتس‌اپ @@ -226,7 +226,7 @@ نقشه موقعیت مکانی - @(_contactAddress ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶") + @(_settings?.Address ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶")
diff --git a/src/FrontOffice.Main/Pages/Contact.razor.cs b/src/FrontOffice.Main/Pages/Contact.razor.cs index d44c34c..2e7f2d4 100644 --- a/src/FrontOffice.Main/Pages/Contact.razor.cs +++ b/src/FrontOffice.Main/Pages/Contact.razor.cs @@ -12,52 +12,19 @@ public partial class Contact private bool _isSubmitting; private readonly ContactFormValidator _contactFormValidator = new(); - // Dynamic CMS data - private SitePageDto? _page; - private string? _contactAddress; - private string? _contactPhone; - private string? _contactEmail; - private string? _contactHours; - private string? _socialTelegram; - private string? _socialInstagram; - private string? _socialLinkedin; - private string? _socialWhatsapp; + // Dynamic CMS data (new simplified system) + private PageSettingsDto? _page; + private ContactSettings? _settings; protected override async Task OnInitializedAsync() { try { - _page = await SitePageService.GetByKeyAsync("contact"); + _page = await PageSettingsService.GetPageAsync("contact"); if (_page != null) { - // Load contact info from CMS section - var contactInfoSection = _page.GetSection("contact-info"); - if (contactInfoSection != null) - { - var contactData = contactInfoSection.GetExtraData(); - if (contactData != null) - { - _contactAddress = contactData.Address; - _contactPhone = contactData.Phone; - _contactEmail = contactData.Email; - _contactHours = contactData.Hours; - } - } - - // Load social media links from CMS section - var socialSection = _page.GetSection("social-media"); - if (socialSection != null) - { - var socialData = socialSection.GetExtraData(); - if (socialData != null) - { - _socialTelegram = socialData.Telegram; - _socialInstagram = socialData.Instagram; - _socialLinkedin = socialData.Linkedin; - _socialWhatsapp = socialData.Whatsapp; - } - } + _settings = _page.GetSettings(); } } catch @@ -111,12 +78,12 @@ public partial class Contact private void CallSupport() { - Snackbar.Add($"شماره تماس: {_contactPhone ?? "026-34233563"}", Severity.Info); + Snackbar.Add($"شماره تماس: {_settings?.Phone ?? "026-34233563"}", Severity.Info); } private void SendEmail() { - Snackbar.Add($"ایمیل: {_contactEmail ?? "info@kbs1.co"}", Severity.Info); + Snackbar.Add($"ایمیل: {_settings?.Email ?? "info@kbs1.co"}", Severity.Info); } public class ContactForm @@ -142,20 +109,16 @@ public partial class Contact } } - // DTO classes for ExtraData JSON deserialization - private class ContactInfoData + // DTO class for SettingsJson deserialization + private class ContactSettings { public string? Address { get; set; } public string? Phone { get; set; } public string? Email { get; set; } - public string? Hours { get; set; } - } - - private class SocialMediaData - { - public string? Telegram { get; set; } - public string? Instagram { get; set; } - public string? Linkedin { get; set; } - public string? Whatsapp { get; set; } + public string? WorkingHours { get; set; } + public string? TelegramUrl { get; set; } + public string? InstagramUrl { get; set; } + public string? LinkedinUrl { get; set; } + public string? WhatsappUrl { get; set; } } } \ No newline at end of file From be78bc683aeb14bb3998e0e6938f1e231e60b267 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 17 Feb 2026 23:17:09 +0330 Subject: [PATCH 6/8] refactor: migrate Landing page to SitePageSettings system - Index.razor.cs: load landing SettingsJson via SitePageSettingsService - PopulateFromSettings(): parse trustBadges, steps, features, stats, testimonials, faqs from DB - ResolveIcon(): dynamically resolve MudBlazor icons from icon name strings - Index.razor: make hero text, section titles, CTA dynamic with fallback defaults - All hardcoded data preserved as fallbacks when DB is unavailable --- src/FrontOffice.Main/Pages/Index.razor | 22 +- src/FrontOffice.Main/Pages/Index.razor.cs | 265 +++++++++++++++++----- 2 files changed, 219 insertions(+), 68 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Index.razor b/src/FrontOffice.Main/Pages/Index.razor index 2be5568..4ba4291 100644 --- a/src/FrontOffice.Main/Pages/Index.razor +++ b/src/FrontOffice.Main/Pages/Index.razor @@ -15,11 +15,11 @@ - رشد تیم، فروش واقعی، پاداش شفاف + @(_pageData?.HeroTitle ?? "رشد تیم، فروش واقعی، پاداش شفاف") - با دعوت از دوستان، از خریدهای واقعی محصولات سلامت پاداش بگیرید. ثبت‌نام سریع، داشبورد لحظه‌ای. + @(_pageData?.HeroSubtitle ?? "با دعوت از دوستان، از خریدهای واقعی محصولات سلامت پاداش بگیرید. ثبت‌نام سریع، داشبورد لحظه‌ای.") @@ -27,13 +27,13 @@ Class="rounded-pill hero-cta-primary" Size="Size.Large" OnClick="NavigateToRegistrationWizard"> - شروع رایگان + @(_settings?.HeroButtonPrimaryText ?? "شروع رایگان") - آخرین اخبار + @(_settings?.HeroButtonSecondaryText ?? "آخرین اخبار") @@ -99,7 +99,7 @@
- سه گام تا شروع + @(_settings?.StepsTitle ?? "سه گام تا شروع") بدون پیچیدگی، سریع و آسان @@ -128,7 +128,7 @@
- چرا کارا بازار سلامت؟ + @(_settings?.FeaturesTitle ?? "چرا کارا بازار سلامت؟") ابزارهایی ساده و قدرتمند برای رشد کسب‌وکار شما @@ -259,7 +259,7 @@
- اعتماد مشتریان + @(_settings?.TestimonialsTitle ?? "اعتماد مشتریان") بخشی از تجربه استفاده از «کارا بازار سلامت» @@ -299,7 +299,7 @@
- سوالات متداول + @(_settings?.FaqTitle ?? "سوالات متداول") پاسخ به سوالات رایج شما @@ -326,16 +326,16 @@
- آماده شروع هستید؟ + @(_settings?.CtaTitle ?? "آماده شروع هستید؟") - همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید. + @(_settings?.CtaDescription ?? "همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید.") - شروع رایگان + @(_settings?.CtaButtonText ?? "شروع رایگان")
diff --git a/src/FrontOffice.Main/Pages/Index.razor.cs b/src/FrontOffice.Main/Pages/Index.razor.cs index 595ff44..96875f8 100644 --- a/src/FrontOffice.Main/Pages/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Index.razor.cs @@ -9,21 +9,48 @@ public partial class Index : IDisposable { [Inject] private BlogPostService BlogPostService { get; set; } = default!; [Inject] private AuthService AuthService { get; set; } = default!; + [Inject] private SitePageSettingsService PageSettingsService { get; set; } = default!; + + // ── CMS page data ── + private PageSettingsDto? _pageData; + private LandingSettings? _settings; // ── Latest blog posts (loaded from CMS) ── private List _latestPosts = new(); + // ── Data lists (populated from DB or fallback) ── + private List<(string Icon, string Text)> _trustBadges = new(); + private List<(string Title, string Desc)> _steps = new(); + private List<(string Icon, string Title, string Desc, int Delay)> _features = new(); + private List _stats = new(); + private List _testimonials = new(); + private List _faqs = new(); + protected override async Task OnInitializedAsync() { MainService.OnChangeHandler += OnStateChanged; + // Load landing page settings from CMS + try + { + _pageData = await PageSettingsService.GetPageAsync("landing"); + if (_pageData != null) + { + _settings = _pageData.GetSettings(); + } + } + catch + { + // Fallback: settings remain null → defaults below + } + + PopulateFromSettings(); + // Load latest published blog posts - // اول پین‌شده‌ها، اگر کافی نبود آخرین پست‌ها اضافه شود try { _latestPosts = await BlogPostService.GetFeaturedPostsAsync(2); - - // اگر فقط ۱ پین‌شده داریم، ۱ پست آخر هم اضافه کن + if (_latestPosts.Count < 2) { var result = await BlogPostService.GetPublishedPostsAsync(page: 1, pageSize: 2); @@ -44,6 +71,155 @@ public partial class Index : IDisposable } } + private void PopulateFromSettings() + { + // ── Trust badges ── + if (_settings?.TrustBadges?.Any() == true) + { + _trustBadges = _settings.TrustBadges + .Select(b => (ResolveIcon(b.IconName), b.Text ?? "")) + .ToList(); + } + else + { + _trustBadges = new() + { + (Icons.Material.Outlined.Timer, "ثبت‌نام زیر ۲ دقیقه"), + (Icons.Material.Outlined.SupportAgent, "پشتیبانی ۷×۲۴"), + (Icons.Material.Outlined.Lock, "پرداخت ایمن"), + (Icons.Material.Outlined.Verified, "تضمین کیفیت"), + }; + } + + // ── Steps ── + if (_settings?.Steps?.Any() == true) + { + _steps = _settings.Steps + .Select(s => (s.Title ?? "", s.Description ?? "")) + .ToList(); + } + else + { + _steps = new() + { + ("ثبت‌نام و احراز هویت", "یک حساب بسازید، شماره موبایل را تأیید و اطلاعات هویتی را تکمیل کنید."), + ("دعوت دوستان", "لینک دعوت اختصاصی خود را با دوستان و آشنایان به اشتراک بگذارید."), + ("دریافت پاداش", "از خریدهای واقعی اعضای تیمتان پاداش شفاف و لحظه‌ای دریافت کنید."), + }; + } + + // ── Features ── + if (_settings?.Features?.Any() == true) + { + _features = _settings.Features + .Select((f, i) => (ResolveIcon(f.IconName), f.Title ?? "", f.Description ?? "", i * 100)) + .ToList(); + } + else + { + _features = new() + { + (Icons.Material.Outlined.VerifiedUser, "ثبت‌نام سریع و ساده", "در چند گام کوتاه حساب بسازید و شروع کنید.", 0), + (Icons.Material.Outlined.StarBorder, "پاداش‌های شفاف", "قوانین روشن، دسترسی آسان به سوابق و گزارش‌ها.", 100), + (Icons.Material.Outlined.Devices, "طراحی واکنش‌گرا", "تجربه‌ای روان در موبایل و دسکتاپ.", 200), + (Icons.Material.Outlined.Groups, "تیم‌سازی هوشمند", "ساختار درختی شبکه و مدیریت تیم‌های فروش.", 300), + (Icons.Material.Outlined.Insights, "گزارش‌های لحظه‌ای", "داشبورد پویا برای مشاهده عملکرد و کمیسیون.", 400), + (Icons.Material.Outlined.Lock, "امنیت بالا", "رمزنگاری اطلاعات و احراز هویت چندمرحله‌ای.", 500), + }; + } + + // ── Stats ── + if (_settings?.Stats?.Any() == true) + { + _stats = _settings.Stats + .Select((s, i) => new StatItem( + $"stat-{i}", + $"{s.Value}{s.Suffix}", + s.Value, + s.Suffix ?? "", + ResolveColor(s.Color), + s.Label ?? "")) + .ToList(); + } + else + { + _stats = new() + { + new("stat-growth", "+۵۰٪", 50, "%+", Color.Success, "رشد میانگین تیم"), + new("stat-uptime", "۹۹.۹٪", 99.9, "%", Color.Primary, "آپ‌تایم سرویس"), + new("stat-deploy", "۳ روز", 3, " روز", Color.Warning, "میانگین زمان استقرار"), + new("stat-coverage", "+۲۰ کشور", 20, "+", Color.Secondary, "پوشش ارسال کد"), + }; + } + + // ── Testimonials ── + if (_settings?.Testimonials?.Any() == true) + { + _testimonials = _settings.Testimonials + .Select((t, i) => new TestimonialItem(t.Quote ?? "", t.Name ?? "", t.Role ?? "", i * 150)) + .ToList(); + } + else + { + _testimonials = new() + { + new("با کارا بازار سلامت، محاسبه کارمزدها و پایش تیم‌ها بدون اکسل و دردسر انجام می‌شود.", "شرکت سینا نت", "مدیر عملیات", 0), + new("شجره‌نامه بصری و گزارش‌های دقیق باعث شد رشد تیم را لحظه‌ای ببینیم.", "هولدینگ آریانا", "مدیر فروش", 150), + new("سادگی ثبت‌نام و شفافیت پاداش‌ها مهم‌ترین مزیت این پلتفرم است.", "گروه بهداشتی نوین", "مدیر توسعه", 300), + }; + } + + // ── FAQs ── + if (_settings?.Faqs?.Any() == true) + { + _faqs = _settings.Faqs + .Select(f => new QA(f.Question ?? "", f.Answer ?? "")) + .ToList(); + } + else + { + _faqs = new() + { + new("دامنه اختصاصی دارم؛ قابل اتصال است؟", "بله، پشت دامنه و گواهی SSL خودتان مستقر می‌شود."), + new("با دیتابیس خودم کار می‌کند؟", "کاملاً. SQL Server، PostgreSQL و MySQL پشتیبانی می‌شود."), + new("چه درگاه‌هایی پشتیبانی می‌شود؟", "Stripe و PayPal یا درگاه اختصاصی از طریق وب‌هوک‌ها."), + new("می‌توانم داده‌ها را خروجی بگیرم؟", "هر زمان از داشبورد ادمین خروجی CSV/Excel بگیرید."), + }; + } + } + + /// + /// Resolve icon name from SettingsJson to MudBlazor icon string. + /// Falls back to a generic icon. + /// + private static string ResolveIcon(string? iconName) + { + if (string.IsNullOrWhiteSpace(iconName)) return Icons.Material.Outlined.Info; + + // Try to get from MudBlazor Icons via reflection + var field = typeof(Icons.Material.Outlined).GetField(iconName, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (field != null) return (string)(field.GetValue(null) ?? Icons.Material.Outlined.Info); + + // Also try Filled + field = typeof(Icons.Material.Filled).GetField(iconName, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (field != null) return (string)(field.GetValue(null) ?? Icons.Material.Outlined.Info); + + return Icons.Material.Outlined.Info; + } + + private static Color ResolveColor(string? colorName) => colorName?.ToLowerInvariant() switch + { + "primary" => Color.Primary, + "secondary" => Color.Secondary, + "success" => Color.Success, + "warning" => Color.Warning, + "error" => Color.Error, + "info" => Color.Info, + _ => Color.Default + }; + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) @@ -88,65 +264,40 @@ public partial class Index : IDisposable await InvokeAsync(StateHasChanged); } - // ── Trust badges ── - private readonly List<(string Icon, string Text)> _trustBadges = new() - { - (Icons.Material.Outlined.Timer, "ثبت‌نام زیر ۲ دقیقه"), - (Icons.Material.Outlined.SupportAgent, "پشتیبانی ۷×۲۴"), - (Icons.Material.Outlined.Lock, "پرداخت ایمن"), - (Icons.Material.Outlined.Verified, "تضمین کیفیت"), - }; - - // ── How it works steps ── - private readonly List<(string Title, string Desc)> _steps = new() - { - ("ثبت‌نام و احراز هویت", "یک حساب بسازید، شماره موبایل را تأیید و اطلاعات هویتی را تکمیل کنید."), - ("دعوت دوستان", "لینک دعوت اختصاصی خود را با دوستان و آشنایان به اشتراک بگذارید."), - ("دریافت پاداش", "از خریدهای واقعی اعضای تیمتان پاداش شفاف و لحظه‌ای دریافت کنید."), - }; - - // ── Feature cards data (6 cards) ── - private readonly List<(string Icon, string Title, string Desc, int Delay)> _features = new() - { - (Icons.Material.Outlined.VerifiedUser, "ثبت‌نام سریع و ساده", "در چند گام کوتاه حساب بسازید و شروع کنید.", 0), - (Icons.Material.Outlined.StarBorder, "پاداش‌های شفاف", "قوانین روشن، دسترسی آسان به سوابق و گزارش‌ها.", 100), - (Icons.Material.Outlined.Devices, "طراحی واکنش‌گرا", "تجربه‌ای روان در موبایل و دسکتاپ.", 200), - (Icons.Material.Outlined.Groups, "تیم‌سازی هوشمند", "ساختار درختی شبکه و مدیریت تیم‌های فروش.", 300), - (Icons.Material.Outlined.Insights, "گزارش‌های لحظه‌ای", "داشبورد پویا برای مشاهده عملکرد و کمیسیون.", 400), - (Icons.Material.Outlined.Lock, "امنیت بالا", "رمزنگاری اطلاعات و احراز هویت چندمرحله‌ای.", 500), - }; - - // ── Stats data (animated counters) ── - private readonly List _stats = new() - { - new("stat-growth", "+۵۰٪", 50, "%+", Color.Success, "رشد میانگین تیم"), - new("stat-uptime", "۹۹.۹٪", 99.9, "%", Color.Primary, "آپ‌تایم سرویس"), - new("stat-deploy", "۳ روز", 3, " روز", Color.Warning, "میانگین زمان استقرار"), - new("stat-coverage", "+۲۰ کشور", 20, "+", Color.Secondary, "پوشش ارسال کد"), - }; - - // ── Testimonials ── - private readonly List _testimonials = new() - { - new("با کارا بازار سلامت، محاسبه کارمزدها و پایش تیم‌ها بدون اکسل و دردسر انجام می‌شود.", "شرکت سینا نت", "مدیر عملیات", 0), - new("شجره‌نامه بصری و گزارش‌های دقیق باعث شد رشد تیم را لحظه‌ای ببینیم.", "هولدینگ آریانا", "مدیر فروش", 150), - new("سادگی ثبت‌نام و شفافیت پاداش‌ها مهم‌ترین مزیت این پلتفرم است.", "گروه بهداشتی نوین", "مدیر توسعه", 300), - }; - - // ── FAQ data ── - private readonly List _faqs = new() - { - new("دامنه اختصاصی دارم؛ قابل اتصال است؟", "بله، پشت دامنه و گواهی SSL خودتان مستقر می‌شود."), - new("با دیتابیس خودم کار می‌کند؟", "کاملاً. SQL Server، PostgreSQL و MySQL پشتیبانی می‌شود."), - new("چه درگاه‌هایی پشتیبانی می‌شود؟", "Stripe و PayPal یا درگاه اختصاصی از طریق وب‌هوک‌ها."), - new("می‌توانم داده‌ها را خروجی بگیرم؟", "هر زمان از داشبورد ادمین خروجی CSV/Excel بگیرید."), - }; - // ── Records ── private record QA(string Q, string A); private record StatItem(string ElementId, string Display, double Target, string Suffix, Color Color, string Label); private record TestimonialItem(string Quote, string Name, string Role, int Delay); + // ── SettingsJson DTO ── + private class LandingSettings + { + public string? HeroButtonPrimaryText { get; set; } + public string? HeroButtonSecondaryText { get; set; } + public List? TrustBadges { get; set; } + public string? StepsTitle { get; set; } + public List? Steps { get; set; } + public string? FeaturesTitle { get; set; } + public List? Features { get; set; } + public string? StatsTitle { get; set; } + public List? Stats { get; set; } + public string? TestimonialsTitle { get; set; } + public List? Testimonials { get; set; } + public string? FaqTitle { get; set; } + public List? Faqs { get; set; } + public string? CtaTitle { get; set; } + public string? CtaDescription { get; set; } + public string? CtaButtonText { get; set; } + public bool? FeaturedBlogEnabled { get; set; } + } + + private class TrustBadgeItem { public string? IconName { get; set; } public string? Text { get; set; } } + private class StepItem { public string? Title { get; set; } public string? Description { get; set; } } + private class FeatureItem { public string? IconName { get; set; } public string? Title { get; set; } public string? Description { get; set; } } + private class StatSettingItem { public string? Label { get; set; } public double Value { get; set; } public string? Suffix { get; set; } public string? Color { get; set; } } + private class TestimonialSettingItem { public string? Quote { get; set; } public string? Name { get; set; } public string? Role { get; set; } } + private class FaqItem { public string? Question { get; set; } public string? Answer { get; set; } } + public void Dispose() { MainService.OnChangeHandler -= OnStateChanged; From bf0eb089bb9e835bbd32573d1c6fc6235fa16bdc Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 17 Feb 2026 23:57:41 +0330 Subject: [PATCH 7/8] fix: re-init scroll animations after data loads from DB - initScrollAnimations ran only on firstRender when data wasn't loaded yet - Items with fade-in-up class stayed invisible (opacity:0) after data render - Now tracks _dataLoaded/_animationsInitialized flags to re-init JS after data loads - Also fixes stat counter animations not running (stats were empty on firstRender) --- src/FrontOffice.Main/Pages/Index.razor.cs | 10 +++++++++- src/FrontOffice.Main/Shared/MainLayout.razor | 6 +++--- .../appsettings.Development.json | 18 ------------------ 3 files changed, 12 insertions(+), 22 deletions(-) delete mode 100644 src/FrontOffice.Main/appsettings.Development.json diff --git a/src/FrontOffice.Main/Pages/Index.razor.cs b/src/FrontOffice.Main/Pages/Index.razor.cs index 96875f8..88fb346 100644 --- a/src/FrontOffice.Main/Pages/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Index.razor.cs @@ -26,6 +26,10 @@ public partial class Index : IDisposable private List _testimonials = new(); private List _faqs = new(); + // Track whether animations need re-initialization after data load + private bool _dataLoaded; + private bool _animationsInitialized; + protected override async Task OnInitializedAsync() { MainService.OnChangeHandler += OnStateChanged; @@ -45,6 +49,7 @@ public partial class Index : IDisposable } PopulateFromSettings(); + _dataLoaded = true; // Load latest published blog posts try @@ -222,8 +227,11 @@ public partial class Index : IDisposable protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender) + // Init/re-init scroll animations after data is loaded and rendered + if ((firstRender || (_dataLoaded && !_animationsInitialized)) && _steps.Any()) { + _animationsInitialized = true; + // Init scroll-triggered fade-in animations await JS.InvokeVoidAsync("initScrollAnimations"); diff --git a/src/FrontOffice.Main/Shared/MainLayout.razor b/src/FrontOffice.Main/Shared/MainLayout.razor index 0f0f72d..0a9f4b2 100644 --- a/src/FrontOffice.Main/Shared/MainLayout.razor +++ b/src/FrontOffice.Main/Shared/MainLayout.razor @@ -19,7 +19,7 @@
- + + - خانه + @(_isAuthenticated ? "داشبورد" : "خانه") @if (_isAuthenticated) { diff --git a/src/FrontOffice.Main/appsettings.Development.json b/src/FrontOffice.Main/appsettings.Development.json deleted file mode 100644 index 36c36cb..0000000 --- a/src/FrontOffice.Main/appsettings.Development.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "GwUrl": "https://cms.kbs2.ir", - "DownloadUrl": "", - "EncryptionSettings": { - "Key": "kmcQ3XTmH4mrdh8VHziuscyf8LLYjG//Kyni81nH/0E=", - "IV": "1wyF3Tt142MOkCpIyCxh/g==" - }, - "SignalR": { - "HubPath": "/hubs/token-notification" - }, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -} From 22203fd8f4a9563892b4c5506ae41e67612f54c2 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Wed, 18 Feb 2026 01:00:42 +0330 Subject: [PATCH 8/8] feat: make all product images 1:1 square ratio across both stores - Store/Products.razor: aspect-ratio:1/1 instead of height:60% - DiscountStore/Products.razor: same square ratio - Store/ProductDetail.razor: aspect-ratio:1/1 instead of max-height:400px - DiscountStore/ProductDetail.razor: ObjectFit.Cover + aspect-ratio:1/1 - Store/Cart.razor: rounded-lg instead of rounded-circle (desktop+mobile) - Store/CheckoutSummary.razor: rounded-lg + ObjectFit.Cover - Store/OrderDetail.razor: rounded-lg + ObjectFit.Cover (desktop+mobile) - DiscountStore/Cart.razor: rounded-lg + ObjectFit.Cover (desktop+mobile) - DiscountStore/Checkout.razor: rounded-lg + ObjectFit.Cover --- src/FrontOffice.Main/Pages/DiscountStore/Cart.razor | 4 ++-- src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor | 2 +- src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor | 4 ++-- src/FrontOffice.Main/Pages/DiscountStore/Products.razor | 4 ++-- src/FrontOffice.Main/Pages/Store/Cart.razor | 4 ++-- src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor | 2 +- src/FrontOffice.Main/Pages/Store/OrderDetail.razor | 4 ++-- src/FrontOffice.Main/Pages/Store/ProductDetail.razor | 2 +- src/FrontOffice.Main/Pages/Store/Products.razor | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor index 57a6683..23d468b 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Cart.razor @@ -33,7 +33,7 @@ + ImgWidth="64" ImgHeight="64" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @context.Title @@ -82,7 +82,7 @@ + ImgWidth="50" ImgHeight="50" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @item.Title diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor index 079977b..949e630 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Checkout.razor @@ -80,7 +80,7 @@ + ImgWidth="40" ImgHeight="40" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @item.Title @FormatPrice(item.FinalPrice) diff --git a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor index 4d02723..0b582e4 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/ProductDetail.razor @@ -24,8 +24,8 @@ + ObjectFit="ObjectFit.Cover" + Style="width:100%; aspect-ratio:1/1; border-radius:12px;" /> @if (_product.Images.Count > 1) { diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor index 9c3c643..3527a69 100644 --- a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor +++ b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor @@ -77,9 +77,9 @@ + Style="cursor:pointer;"> -
+
@if (p.RemainingCount <= 0) {
diff --git a/src/FrontOffice.Main/Pages/Store/Cart.razor b/src/FrontOffice.Main/Pages/Store/Cart.razor index 60f8a38..16234fd 100644 --- a/src/FrontOffice.Main/Pages/Store/Cart.razor +++ b/src/FrontOffice.Main/Pages/Store/Cart.razor @@ -31,7 +31,7 @@ + ImgWidth="64" ImgHeight="64" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @context.Title @if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description)) @@ -87,7 +87,7 @@ + ImgWidth="50" ImgHeight="50" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @item.Title @if (item.Discount > 0) diff --git a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor index 95d7974..b894fb3 100644 --- a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor +++ b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor @@ -86,7 +86,7 @@ + ImgWidth="48" ImgHeight="48" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @item.Title @FormatPrice(item.LineTotal) diff --git a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor index 823f6a5..d94751d 100644 --- a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor +++ b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor @@ -47,7 +47,7 @@ else + ImgWidth="60" ImgHeight="60" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @context.ProductTitle @@ -66,7 +66,7 @@ else + ImgWidth="60" ImgHeight="60" Class="rounded-lg" ObjectFit="ObjectFit.Cover" /> @it.ProductTitle diff --git a/src/FrontOffice.Main/Pages/Store/ProductDetail.razor b/src/FrontOffice.Main/Pages/Store/ProductDetail.razor index 3426a9a..2b6a0a0 100644 --- a/src/FrontOffice.Main/Pages/Store/ProductDetail.razor +++ b/src/FrontOffice.Main/Pages/Store/ProductDetail.razor @@ -33,7 +33,7 @@ else { + Style="width:100%; aspect-ratio:1/1; border-radius:12px;" /> } else { diff --git a/src/FrontOffice.Main/Pages/Store/Products.razor b/src/FrontOffice.Main/Pages/Store/Products.razor index b3cdb04..370abbc 100644 --- a/src/FrontOffice.Main/Pages/Store/Products.razor +++ b/src/FrontOffice.Main/Pages/Store/Products.razor @@ -120,11 +120,11 @@ + Style="cursor:pointer;"> -
+
@if (p.RemainingCount <= 0) {