From c764614d261406c8427dba730c70d1a8d7350ca5 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 17:35:05 +0330 Subject: [PATCH 1/6] feat(order-tracking): enhance tracking steps logic and delivery status handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refactored the BuildTrackingSteps method to improve the logic for displaying order tracking steps based on various delivery statuses. - Added handling for new delivery statuses: "آماده تحویل در دفتر" and "مرجوع شده". - Updated the payment status step to consolidate descriptions based on payment completion. - Enhanced the overall user experience by providing clearer tracking information for different order states. These changes improve the clarity and functionality of the order tracking feature, ensuring users receive accurate updates on their order status. --- .../Pages/Store/OrderTracking.razor.cs | 121 ++++++++++++------ .../Utilities/DiscountOrderService.cs | 6 +- 2 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs b/src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs index c15808c..585eae4 100644 --- a/src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs @@ -46,12 +46,19 @@ public partial class OrderTracking : ComponentBase private void BuildTrackingSteps() { if (_order is null) return; - - // Build tracking steps based on PaymentStatus + var isPaid = _order.PaymentStatus == Messages.PaymentStatus.Success; - - _trackingSteps = new List - { + // Domain/public_messages: None=0, Pending=1, InTransit=2, Delivered=3, Returned=4, Cancelled=5, ReadyForOfficePickup=6 + var delivery = (int)_order.DeliveryStatus; + var isCancelled = delivery == 5; + var isReturned = delivery == 4; + var isOfficePickup = delivery == 6; + var isInTransit = delivery == 2; + var isDelivered = delivery == 3; + var isPendingDelivery = delivery is 0 or 1; + + _trackingSteps = + [ new() { Title = "ثبت سفارش", @@ -61,45 +68,77 @@ public partial class OrderTracking : ComponentBase }, new() { - Title = "در انتظار پرداخت", - Description = "منتظر تایید پرداخت هستیم", + Title = "پرداخت", + Description = isPaid ? "پرداخت شما تایید شد" : "منتظر تایید پرداخت هستیم", IsCompleted = isPaid, - IsCurrent = !isPaid, + IsCurrent = !isPaid && !isCancelled, Date = isPaid ? FormatDate(_order.PaymentDate) : "" - }, - new() - { - Title = "تایید پرداخت", - Description = "پرداخت شما تایید شد", - IsCompleted = isPaid, - IsCurrent = false, - Date = isPaid ? FormatDate(_order.PaymentDate) : "" - }, - new() - { - Title = "در حال پردازش", - Description = "سفارش شما در حال آماده‌سازی است", - IsCompleted = false, - IsCurrent = isPaid, - Date = "" - }, - new() - { - Title = "ارسال شده", - Description = "سفارش شما به پست تحویل داده شد", - IsCompleted = false, - IsCurrent = false, - Date = "" - }, - new() - { - Title = "تحویل داده شده", - Description = "سفارش به دست شما رسید", - IsCompleted = false, - IsCurrent = false, - Date = "" } - }; + ]; + + if (isCancelled) + { + _trackingSteps.Add(new() + { + Title = "لغو شده", + Description = "ارسال این سفارش لغو شده است", + IsCompleted = true, + IsCurrent = true, + Date = "" + }); + return; + } + + if (isReturned) + { + _trackingSteps.Add(new() + { + Title = "مرجوع شده", + Description = "سفارش مرجوع شده است", + IsCompleted = true, + IsCurrent = true, + Date = "" + }); + return; + } + + if (isOfficePickup) + { + _trackingSteps.Add(new() + { + Title = "آماده تحویل در دفتر", + Description = "سفارش برای تحویل حضوری در دفتر آماده است", + IsCompleted = true, + IsCurrent = true, + Date = "" + }); + return; + } + + _trackingSteps.Add(new() + { + Title = "در حال آماده‌سازی", + Description = "سفارش شما در حال آماده‌سازی است", + IsCompleted = isInTransit || isDelivered, + IsCurrent = isPaid && isPendingDelivery, + Date = "" + }); + _trackingSteps.Add(new() + { + Title = "ارسال شده", + Description = "سفارش شما به پست تحویل داده شد", + IsCompleted = isDelivered, + IsCurrent = isInTransit, + Date = "" + }); + _trackingSteps.Add(new() + { + Title = "تحویل داده شده", + Description = "سفارش به دست شما رسید", + IsCompleted = isDelivered, + IsCurrent = false, + Date = "" + }); } private static string FormatDate(Google.Protobuf.WellKnownTypes.Timestamp? timestamp) diff --git a/src/FrontOffice.Main/Utilities/DiscountOrderService.cs b/src/FrontOffice.Main/Utilities/DiscountOrderService.cs index 53c0d75..fe275d9 100644 --- a/src/FrontOffice.Main/Utilities/DiscountOrderService.cs +++ b/src/FrontOffice.Main/Utilities/DiscountOrderService.cs @@ -219,6 +219,8 @@ public class DiscountOrderService 2 => "ارسال شده", 3 => "تحویل داده شده", 4 => "لغو شده", + 5 => "آماده تحویل در دفتر", + 6 => "مرجوع شده", _ => "نامشخص" }; @@ -228,7 +230,9 @@ public class DiscountOrderService 1 => Color.Info, 2 => Color.Primary, 3 => Color.Success, - 4 => Color.Error, + 4 => Color.Dark, + 5 => Color.Primary, + 6 => Color.Error, _ => Color.Default }; From c7e6d01c11b86d742ead5b0d0f3bae8d0b0c2cbc Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 18:28:38 +0330 Subject: [PATCH 2/6] feat(orders): enhance order display and interaction for improved user experience - Refactored the Orders page to improve the layout and presentation of order information, including a new responsive design for mobile and desktop views. - Added a button to navigate to the store when no orders are present, enhancing user engagement. - Updated the order details display to include payment and delivery status with color-coded chips for better visual feedback. - Introduced helper methods for formatting prices and dates, improving code readability and maintainability. These changes significantly enhance the usability and clarity of the order management interface, providing users with a more intuitive experience. --- src/FrontOffice.Main/Pages/Store/Orders.razor | 166 ++++++++++-------- .../Pages/Store/Orders.razor.cs | 94 +++++++--- 2 files changed, 167 insertions(+), 93 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Store/Orders.razor b/src/FrontOffice.Main/Pages/Store/Orders.razor index 811451b..0aa3ab3 100644 --- a/src/FrontOffice.Main/Pages/Store/Orders.razor +++ b/src/FrontOffice.Main/Pages/Store/Orders.razor @@ -1,80 +1,102 @@ @attribute [Route(RouteConstants.Store.Orders)] -@* Injection is handled in code-behind *@ سفارشات من - - @if (_loading) - { - - } - else if (_orders.Count == 0) - { - هنوز سفارشی ثبت نکرده‌اید. - } - else - { - - - - شناسه - تاریخ - وضعیت - مبلغ - - - - @context.Id - - @if (context.PaymentDate != null) - { - @context.PaymentDate.ToDateTime().MiladiToJalaliWithTime() - } - else - { - در انتظار پرداخت - } - - @GetStatusText(context.PaymentStatus) - @FormatPrice(context.FactorDetails.Sum(s=>(s.UnitPrice ?? 0) * (s.Count ?? 0))) - - جزئیات - - - - + + - - - @foreach (var o in _orders) - { - - - - سفارش #@o.Id - - @if (o.PaymentDate != null) - { - @o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() - } - else - { - در انتظار پرداخت - } - + @if (_loading) + { + + } + else if (_orders.Count == 0) + { + هنوز سفارشی ثبت نشده است. + + مشاهده فروشگاه + + } + else + { + + + + + + شماره سفارش + تعداد اقلام + مبلغ کل + وضعیت پرداخت + وضعیت ارسال + تاریخ + + + + @context.Id + @GetItemsCount(context) + @FormatPrice(GetTotalAmount(context)) + + + @GetPaymentStatusText(context.PaymentStatus) + + + + + @GetDeliveryStatusText((int)context.DeliveryStatus) + + + @FormatDate(context) + + + جزئیات + + + + + + + + + + + @foreach (var order in _orders) + { + + + + سفارش #@order.Id + + @GetPaymentStatusText(order.PaymentStatus) + + + + @FormatDate(order) + + @GetDeliveryStatusText((int)order.DeliveryStatus) + + + + + @GetItemsCount(order) قلم + @FormatPrice(GetTotalAmount(order)) تومان + - - وضعیت: @GetStatusText(o.PaymentStatus) - @FormatPrice(o.FactorDetails.Sum(s=>(s.UnitPrice ?? 0) * (s.Count ?? 0))) - - - جزئیات - - - - } - - - } + + } + + + } + diff --git a/src/FrontOffice.Main/Pages/Store/Orders.razor.cs b/src/FrontOffice.Main/Pages/Store/Orders.razor.cs index 0ce3138..da4304d 100644 --- a/src/FrontOffice.Main/Pages/Store/Orders.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/Orders.razor.cs @@ -1,5 +1,5 @@ -using System; using CMSMicroservice.Protobuf.Protos.UserOrder; +using DateTimeConverterCL; using FrontOffice.Main.Utilities; using Microsoft.AspNetCore.Components; using Messages = CMSMicroservice.Protobuf.Protos; @@ -10,7 +10,6 @@ namespace FrontOffice.Main.Pages.Store; public partial class Orders : ComponentBase { [Inject] private OrderService OrderService { get; set; } = default!; - [Inject] private VATService VAT { get; set; } = default!; private List _orders = new(); private bool _loading; @@ -33,28 +32,81 @@ public partial class Orders : ComponentBase } } - protected override async Task OnAfterRenderAsync(bool firstRender) + private void ViewOrder(long orderId) { - if (firstRender) + Navigation.NavigateTo($"{RouteConstants.Store.OrderDetail}{orderId}"); + } + + private static string FormatPrice(long price) => $"{price:N0}"; + + private static string FormatDate(GetUserOrderResponse order) + { + try { - // بارگذاری نرخ VAT - await VAT.LoadAsync(); + var timestamp = order.PaymentDate; + if (timestamp is null) + return "در انتظار پرداخت"; + + return timestamp.ToDateTime().ToLocalTime().MiladiToJalaliWithTime(); } - await base.OnAfterRenderAsync(firstRender); - } - - private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price); - - - private string GetStatusText(Messages.PaymentStatus contextPaymentStatus) - { - return contextPaymentStatus switch + catch { - Messages.PaymentStatus.Pending => "در انتظار پرداخت", - Messages.PaymentStatus.Success => "پرداخت شده", - Messages.PaymentStatus.Reject => "پرداخت ناموفق", - _ => "نامشخص", - }; + return "—"; + } } -} + private static int GetItemsCount(GetUserOrderResponse order) => + order.FactorDetails.Sum(f => f.Count ?? 0); + + private static long GetTotalAmount(GetUserOrderResponse order) + { + if (order.VatInfo is not null && order.VatInfo.TotalAmount > 0) + return order.VatInfo.TotalAmount; + + if (order.Amount > 0) + return order.Amount; + + return order.FactorDetails.Sum(f => (f.UnitPrice ?? 0) * (f.Count ?? 0)); + } + + private static string GetPaymentStatusText(Messages.PaymentStatus status) => status switch + { + Messages.PaymentStatus.Pending => "در انتظار پرداخت", + Messages.PaymentStatus.Success => "پرداخت شده", + Messages.PaymentStatus.Reject => "پرداخت ناموفق", + _ => "نامشخص" + }; + + private static Color GetPaymentStatusColor(Messages.PaymentStatus status) => status switch + { + Messages.PaymentStatus.Pending => Color.Warning, + Messages.PaymentStatus.Success => Color.Success, + Messages.PaymentStatus.Reject => Color.Error, + _ => Color.Default + }; + + // Domain/public_messages: None=0, Pending=1, InTransit=2, Delivered=3, Returned=4, Cancelled=5, ReadyForOfficePickup=6 + private static string GetDeliveryStatusText(int status) => status switch + { + 0 => "بدون ارسال", + 1 => "در انتظار ارسال", + 2 => "ارسال شده", + 3 => "تحویل داده شده", + 4 => "مرجوع شده", + 5 => "لغو شده", + 6 => "آماده تحویل در دفتر", + _ => "نامشخص" + }; + + private static Color GetDeliveryStatusColor(int status) => status switch + { + 0 => Color.Default, + 1 => Color.Warning, + 2 => Color.Primary, + 3 => Color.Success, + 4 => Color.Error, + 5 => Color.Dark, + 6 => Color.Primary, + _ => Color.Default + }; +} From acad1a719f2b3592b0342f86adad5e8879eff25f Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 18:39:49 +0330 Subject: [PATCH 3/6] feat(index): add conditional rendering for testimonials section - Implemented a check to display the testimonials section only when there are testimonials available, enhancing the user experience by preventing empty sections. - Updated the logic for loading testimonials from settings to handle cases where the testimonials list may be null, ensuring robustness in data handling. These changes improve the layout and presentation of the Index page, providing users with relevant content based on available testimonials. --- src/FrontOffice.Main/Pages/Index.razor | 3 +++ src/FrontOffice.Main/Pages/Index.razor.cs | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Index.razor b/src/FrontOffice.Main/Pages/Index.razor index 15d3329..ed08e12 100644 --- a/src/FrontOffice.Main/Pages/Index.razor +++ b/src/FrontOffice.Main/Pages/Index.razor @@ -429,6 +429,8 @@ else @* ═══════════════════════════════════════════════ 6. TESTIMONIALS ═══════════════════════════════════════════════ *@ +@if (_testimonials.Count > 0) +{
@@ -465,6 +467,7 @@ else
+} @* ═══════════════════════════════════════════════ 7. FAQ diff --git a/src/FrontOffice.Main/Pages/Index.razor.cs b/src/FrontOffice.Main/Pages/Index.razor.cs index f688624..a66bc26 100644 --- a/src/FrontOffice.Main/Pages/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Index.razor.cs @@ -193,9 +193,10 @@ public partial class Index : IDisposable } // ── Testimonials ── - if (_settings?.Testimonials?.Any() == true) + // اگر تنظیمات از CMS لود شده، لیست خالی یعنی ادمین عمداً حذف کرده — بدون fallback hardcode + if (_settings is not null) { - _testimonials = _settings.Testimonials + _testimonials = (_settings.Testimonials ?? []) .Select((t, i) => new TestimonialItem(t.Quote ?? "", t.Name ?? "", t.Role ?? "", i * 150)) .ToList(); } From 6123e4796888827e7ef65b0678882ad8e9ff8f53 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sat, 8 Aug 2026 22:22:03 +0330 Subject: [PATCH 4/6] feat(wallet): enhance ChargeCreditWallet and Wallet components with magic wallet functionality - Added logic to handle redirection and alerts for users with a magic wallet status in the ChargeCreditWallet component. - Updated the Wallet component to conditionally render buttons and alerts based on the user's magic wallet status. - Implemented a method to check the magic wallet status and provide user feedback regarding wallet charging options. These changes improve user experience by clearly guiding users on the appropriate wallet charging methods based on their current wallet status. --- docs/CHANGELOG.md | 1 + .../Pages/Profile/ChargeCreditWallet.razor | 18 ++++++++- .../Pages/Profile/ChargeCreditWallet.razor.cs | 39 ++++++++++++++++++- .../Pages/Profile/Wallet.razor | 38 +++++++++++++----- .../Pages/Profile/Wallet.razor.cs | 11 ++++++ 5 files changed, 95 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 18c6348..88d2fa8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,4 @@ # Docs moved to totalDoc See [totalDoc/INDEX.md](../../totalDoc/INDEX.md) for all documentation. + \ No newline at end of file diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor index d55b8bc..eaab334 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor @@ -35,7 +35,23 @@ } - @if (_authLoaded && !_isClubMemberActive) + @if (_authLoaded && _redirectingToMagic) + { + + + + + کیف پول شما در حالت جادویی است. در حال انتقال به صفحه شارژ کیف پول جادویی... + + + رفتن به شارژ کیف جادویی + + + + } + else if (_authLoaded && !_isClubMemberActive) { diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs index 816aada..bac834d 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs @@ -16,6 +16,7 @@ public partial class ChargeCreditWallet : ComponentBase private bool _isClubMemberActive; private bool _hasPurchasedPackage; private bool _authLoaded; + private bool _redirectingToMagic; private readonly long[] _presetAmounts = { 500_000, 1_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000 }; @@ -53,11 +54,15 @@ public partial class ChargeCreditWallet : ComponentBase { _authLoaded = true; } + + // اگر کیف پول جادویی فعال است، فرم شارژ ۱:۱ نشان داده نشود + if (_isClubMemberActive && await TryRedirectIfMagicWalletAsync()) + return; } protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl) && _isClubMemberActive) + if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl) && _isClubMemberActive && !_redirectingToMagic) { await CreditChargeNavigation.SaveReturnUrlAsync(JSRuntime, _pendingReturnUrl); } @@ -75,6 +80,9 @@ public partial class ChargeCreditWallet : ComponentBase return; } + if (await TryRedirectIfMagicWalletAsync()) + return; + if (_chargeAmount <= 0 || _isProcessing) return; _isProcessing = true; @@ -113,6 +121,35 @@ public partial class ChargeCreditWallet : ComponentBase } } + /// + /// اگر WalletMode جادویی باشد، پیام می‌دهد و به صفحه شارژ کیف جادویی هدایت می‌کند. + /// + private async Task TryRedirectIfMagicWalletAsync() + { + try + { + var status = await WalletService.GetMagicWalletStatusAsync(); + if (status.WalletMode != 1) + return false; + + var multiplier = status.MagicMultiplier > 0 ? status.MagicMultiplier : 2.5; + var multiplierText = multiplier.ToString("0.#"); + + _redirectingToMagic = true; + Snackbar.Add( + $"کیف پول شما در حالت جادویی است. شارژ از این صفحه موجودی را چندبرابر نمی‌کند. برای دریافت ضریب جادویی (×{multiplierText}) به صفحه شارژ کیف پول جادویی هدایت می‌شوید.", + Severity.Info); + + Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); + return true; + } + catch + { + // در صورت خطا در خواندن وضعیت، مانع شارژ عادی نشو + return false; + } + } + private async Task ContinueShoppingAsync() { var returnUrl = await CreditChargeNavigation.GetReturnUrlAsync(JSRuntime); diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor b/src/FrontOffice.Main/Pages/Profile/Wallet.razor index d52d737..e13abee 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor @@ -38,18 +38,36 @@ درخواست‌های برداشت - + @if (_isClubMemberActive) { - - شارژ کیف‌پول اصلی - + @if (_isMagicWallet) + { + + شارژ کیف‌پول جادویی + + + کیف پول شما در حالت جادویی است؛ شارژ از مسیر جادویی با ضریب چندبرابر اعمال می‌شود. + + } + else + { + + شارژ کیف‌پول اصلی + + } } else { diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs b/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs index 04f9c96..f20a00c 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs @@ -14,6 +14,7 @@ public partial class Wallet : ComponentBase private string _filterType = "all"; private bool _isClubMemberActive; private bool _hasPurchasedPackage; + private bool _isMagicWallet; protected override async Task OnInitializedAsync() { @@ -29,6 +30,16 @@ public partial class Wallet : ComponentBase _hasPurchasedPackage = false; } + try + { + var magicStatus = await WalletService.GetMagicWalletStatusAsync(); + _isMagicWallet = magicStatus.WalletMode == 1; + } + catch + { + _isMagicWallet = false; + } + var b = await WalletService.GetBalancesAsync(); _balances = (FormatPrice(b.CreditBalance), FormatPrice(b.DiscountBalance), FormatPrice(b.NetworkBalance)); _txs = await WalletService.GetTransactionsAsync(); From 8e98c50bdf8f190d4deafdfbfd0cb136c214b6c0 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sat, 8 Aug 2026 23:59:36 +0330 Subject: [PATCH 5/6] feat(wallet): enhance ChargeCreditWallet and Wallet components with magic ceiling consent logic - Added new logic to handle user consent for charging without a magic multiplier when the magic wallet ceiling is full. - Updated the ChargeCreditWallet component to display alerts and prompts based on the user's magic wallet status and consent. - Enhanced the Wallet component to conditionally render buttons and alerts related to the magic wallet ceiling status. - Improved user feedback in the InsufficientCreditDialog to guide users on charging options based on their wallet status. These changes enhance the user experience by providing clear instructions and options for charging wallets under specific conditions. --- .../Pages/Profile/ChargeCreditWallet.razor | 20 ++++- .../Pages/Profile/ChargeCreditWallet.razor.cs | 85 ++++++++++++++++--- .../Pages/Profile/MagicWallet.razor | 19 ++++- .../Pages/Profile/Wallet.razor | 24 +++++- .../Pages/Profile/Wallet.razor.cs | 3 + .../Pages/Store/CheckoutSummary.razor.cs | 18 +++- .../Shared/InsufficientCreditDialog.razor | 53 ++++++++++-- 7 files changed, 194 insertions(+), 28 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor index eaab334..34a492a 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor @@ -83,7 +83,18 @@ } - else if (_authLoaded) + else if (_authLoaded && _needsMagicCeilingConsent && !_allowNormalDespiteMagic && !_redirectingToMagic) + { + + + + + سقف شارژ جادویی پر است. برای شارژ بدون ضریب باید تأیید کنید... + + + + } + else if (ShowChargeForm) { @@ -91,6 +102,13 @@ شارژ موجودی اصلی + @if (_allowNormalDespiteMagic) + { + + این شارژ بدون ضریب جادویی است (۱:۱). سقف واریز جادویی شما در این دور پر شده است. + + } + مبلغ وارد شده (به تومان) از طریق درگاه پرداخت به موجودی اصلی شما اضافه می‌شود. از موجودی اصلی برای خرید از فروشگاه عادی و پرداخت سفارش استفاده می‌شود. diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs index bac834d..8b7ffff 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs @@ -17,6 +17,9 @@ public partial class ChargeCreditWallet : ComponentBase private bool _hasPurchasedPackage; private bool _authLoaded; private bool _redirectingToMagic; + private bool _allowNormalDespiteMagic; + private bool _needsMagicCeilingConsent; + private bool _magicConsentPrompted; private readonly long[] _presetAmounts = { 500_000, 1_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000 }; @@ -29,6 +32,12 @@ public partial class ChargeCreditWallet : ComponentBase [SupplyParameterFromQuery(Name = "returnUrl")] public string? ReturnUrlQueryParam { get; set; } + private bool ShowChargeForm => + _authLoaded + && _isClubMemberActive + && !_redirectingToMagic + && (!_needsMagicCeilingConsent || _allowNormalDespiteMagic); + protected override async Task OnInitializedAsync() { _paymentResult = PaymentQueryParam; @@ -55,16 +64,20 @@ public partial class ChargeCreditWallet : ComponentBase _authLoaded = true; } - // اگر کیف پول جادویی فعال است، فرم شارژ ۱:۱ نشان داده نشود - if (_isClubMemberActive && await TryRedirectIfMagicWalletAsync()) - return; + if (_isClubMemberActive) + await EvaluateMagicWalletGateAsync(promptConsent: false); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl) && _isClubMemberActive && !_redirectingToMagic) - { await CreditChargeNavigation.SaveReturnUrlAsync(JSRuntime, _pendingReturnUrl); + + if (firstRender && _needsMagicCeilingConsent && !_allowNormalDespiteMagic && !_magicConsentPrompted) + { + _magicConsentPrompted = true; + await PromptMagicCeilingConsentAsync(); + StateHasChanged(); } await base.OnAfterRenderAsync(firstRender); @@ -80,7 +93,10 @@ public partial class ChargeCreditWallet : ComponentBase return; } - if (await TryRedirectIfMagicWalletAsync()) + if (await EvaluateMagicWalletGateAsync(promptConsent: true)) + return; + + if (!_allowNormalDespiteMagic && _needsMagicCeilingConsent) return; if (_chargeAmount <= 0 || _isProcessing) return; @@ -122,25 +138,47 @@ public partial class ChargeCreditWallet : ComponentBase } /// - /// اگر WalletMode جادویی باشد، پیام می‌دهد و به صفحه شارژ کیف جادویی هدایت می‌کند. + /// Magic با ظرفیت باقی‌مانده → ریدایرکت به MagicWallet. + /// Magic با سقف پر → نیاز به رضایت برای شارژ ۱:۱. + /// true یعنی مسیر شارژ فعلی باید متوقف شود. /// - private async Task TryRedirectIfMagicWalletAsync() + private async Task EvaluateMagicWalletGateAsync(bool promptConsent) { + if (_allowNormalDespiteMagic) + return false; + try { var status = await WalletService.GetMagicWalletStatusAsync(); if (status.WalletMode != 1) + { + _needsMagicCeilingConsent = false; return false; + } - var multiplier = status.MagicMultiplier > 0 ? status.MagicMultiplier : 2.5; - var multiplierText = multiplier.ToString("0.#"); + if (status.MagicRemainingDeposit > 0) + { + var multiplier = status.MagicMultiplier > 0 ? status.MagicMultiplier : 2.5; + var multiplierText = multiplier.ToString("0.#"); - _redirectingToMagic = true; - Snackbar.Add( - $"کیف پول شما در حالت جادویی است. شارژ از این صفحه موجودی را چندبرابر نمی‌کند. برای دریافت ضریب جادویی (×{multiplierText}) به صفحه شارژ کیف پول جادویی هدایت می‌شوید.", - Severity.Info); + _redirectingToMagic = true; + _needsMagicCeilingConsent = false; + Snackbar.Add( + $"کیف پول شما در حالت جادویی است. شارژ از این صفحه موجودی را چندبرابر نمی‌کند. برای دریافت ضریب جادویی (×{multiplierText}) به صفحه شارژ کیف پول جادویی هدایت می‌شوید.", + Severity.Info); + + Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); + return true; + } + + _needsMagicCeilingConsent = true; + + if (promptConsent) + { + await PromptMagicCeilingConsentAsync(); + return !_allowNormalDespiteMagic; + } - Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); return true; } catch @@ -150,6 +188,25 @@ public partial class ChargeCreditWallet : ComponentBase } } + private async Task PromptMagicCeilingConsentAsync() + { + var confirmed = await DialogService.ShowMessageBox( + "شارژ بدون ضریب جادویی", + "سقف شارژ کیف پول جادویی شما در این دور پر شده است. شارژ از این صفحه بدون ضریب (۱:۱) به موجودی اضافه می‌شود و ضریب جادویی اعمال نمی‌شود. آیا مایلید ادامه دهید؟", + yesText: "ادامه شارژ بدون ضریب", + cancelText: "انصراف"); + + if (confirmed == true) + { + _allowNormalDespiteMagic = true; + _redirectingToMagic = false; + return; + } + + _redirectingToMagic = true; + Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); + } + private async Task ContinueShoppingAsync() { var returnUrl = await CreditChargeNavigation.GetReturnUrlAsync(JSRuntime); diff --git a/src/FrontOffice.Main/Pages/Profile/MagicWallet.razor b/src/FrontOffice.Main/Pages/Profile/MagicWallet.razor index 19d4e2d..89e973b 100644 --- a/src/FrontOffice.Main/Pages/Profile/MagicWallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/MagicWallet.razor @@ -166,8 +166,23 @@ else { - سقف شارژ جادویی در این دور پر شده است. - با خرج کردن موجودی و خرید مجدد پکیج، سقف ریست می‌شود. + + + سقف شارژ جادویی در این دور پر شده است. + با خرج کردن موجودی و خرید مجدد پکیج، سقف ریست می‌شود. + + + اگر برای تکمیل خرید به موجودی بیشتری نیاز دارید، می‌توانید به‌صورت استثنایی کیف اصلی را بدون ضریب (۱:۱) شارژ کنید. + + + شارژ عادی بدون ضریب + + } diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor b/src/FrontOffice.Main/Pages/Profile/Wallet.razor index e13abee..5da6575 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor @@ -52,9 +52,27 @@ Class="rounded-lg"> شارژ کیف‌پول جادویی - - کیف پول شما در حالت جادویی است؛ شارژ از مسیر جادویی با ضریب چندبرابر اعمال می‌شود. - + @if (_magicCeilingFull) + { + + سقف شارژ جادویی این دور پر است. در صورت نیاز می‌توانید به‌صورت استثنایی بدون ضریب شارژ کنید. + + + شارژ عادی بدون ضریب + + } + else + { + + کیف پول شما در حالت جادویی است؛ شارژ از مسیر جادویی با ضریب چندبرابر اعمال می‌شود. + + } } else { diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs b/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs index f20a00c..491e09d 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor.cs @@ -15,6 +15,7 @@ public partial class Wallet : ComponentBase private bool _isClubMemberActive; private bool _hasPurchasedPackage; private bool _isMagicWallet; + private bool _magicCeilingFull; protected override async Task OnInitializedAsync() { @@ -34,10 +35,12 @@ public partial class Wallet : ComponentBase { var magicStatus = await WalletService.GetMagicWalletStatusAsync(); _isMagicWallet = magicStatus.WalletMode == 1; + _magicCeilingFull = _isMagicWallet && magicStatus.MagicRemainingDeposit <= 0; } catch { _isMagicWallet = false; + _magicCeilingFull = false; } var b = await WalletService.GetBalancesAsync(); diff --git a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs index d199997..8437093 100644 --- a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs @@ -127,6 +127,8 @@ public partial class CheckoutSummary : ComponentBase var shortfall = totalRequired - walletBalance; var allowCharge = false; var hasPurchasedPackage = false; + var isMagicWallet = false; + var magicCeilingFull = false; try { var userInfo = await AuthService.GetUserAuthInfo(); @@ -138,13 +140,27 @@ public partial class CheckoutSummary : ComponentBase allowCharge = false; } + try + { + var magicStatus = await WalletService.GetMagicWalletStatusAsync(); + isMagicWallet = magicStatus.WalletMode == 1; + magicCeilingFull = isMagicWallet && magicStatus.MagicRemainingDeposit <= 0; + } + catch + { + isMagicWallet = false; + magicCeilingFull = false; + } + var parameters = new DialogParameters { { x => x.CurrentBalance, walletBalance }, { x => x.RequiredAmount, totalRequired }, { x => x.ShortfallAmount, shortfall }, { x => x.AllowChargeCredit, allowCharge }, - { x => x.HasPurchasedPackage, hasPurchasedPackage } + { x => x.HasPurchasedPackage, hasPurchasedPackage }, + { x => x.IsMagicWallet, isMagicWallet }, + { x => x.MagicCeilingFull, magicCeilingFull } }; var dialog = await DialogService.ShowAsync( diff --git a/src/FrontOffice.Main/Shared/InsufficientCreditDialog.razor b/src/FrontOffice.Main/Shared/InsufficientCreditDialog.razor index b55951d..b0fb437 100644 --- a/src/FrontOffice.Main/Shared/InsufficientCreditDialog.razor +++ b/src/FrontOffice.Main/Shared/InsufficientCreditDialog.razor @@ -11,9 +11,24 @@ @if (AllowChargeCredit) { - - برای تکمیل این سفارش، موجودی اصلی شما کافی نیست. می‌توانید کیف پول را شارژ کنید و سپس سفارش را ثبت کنید. - + @if (IsMagicWallet && !MagicCeilingFull) + { + + برای تکمیل این سفارش موجودی شما کافی نیست. کیف پول شما در حالت جادویی است؛ برای دریافت ضریب، از مسیر شارژ جادویی اقدام کنید. + + } + else if (IsMagicWallet && MagicCeilingFull) + { + + سقف شارژ جادویی شما در این دور پر است. می‌توانید به‌صورت استثنایی کیف اصلی را بدون ضریب (۱:۱) شارژ کنید. + + } + else + { + + برای تکمیل این سفارش، موجودی اصلی شما کافی نیست. می‌توانید کیف پول را شارژ کنید و سپس سفارش را ثبت کنید. + + } } else { @@ -46,10 +61,10 @@ @if (AllowChargeCredit) { - شارژ حساب اصلی + @ChargeButtonLabel } else if (!HasPurchasedPackage) @@ -93,9 +108,33 @@ [Parameter] public bool HasPurchasedPackage { get; set; } + [Parameter] + public bool IsMagicWallet { get; set; } + + /// سقف واریز جادویی این دور پر شده است. + [Parameter] + public bool MagicCeilingFull { get; set; } + + private string ChargeButtonLabel => + IsMagicWallet && !MagicCeilingFull + ? "شارژ کیف جادویی" + : IsMagicWallet && MagicCeilingFull + ? "شارژ عادی بدون ضریب (سقف جادویی پر است)" + : "شارژ حساب اصلی"; + private void Cancel() => MudDialog.Cancel(); - private void GoToCharge() => MudDialog.Close(DialogResult.Ok(ShortfallAmount)); + private void GoToCharge() + { + if (IsMagicWallet && !MagicCeilingFull) + { + MudDialog.Cancel(); + Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); + return; + } + + MudDialog.Close(DialogResult.Ok(ShortfallAmount)); + } private void GoToPackages() { From 13091849cf2ba97bdcb9f6f8b326d8529dc42cb0 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sun, 9 Aug 2026 00:11:49 +0330 Subject: [PATCH 6/6] feat(wallet): update ChargeCreditWallet component for improved magic ceiling consent handling - Enhanced the user interface to provide clearer instructions and options for charging without a magic multiplier when the magic wallet ceiling is full. - Removed the previous consent prompting logic and replaced it with direct buttons for user actions. - Updated methods to streamline the consent process and improve navigation based on user choices. These changes enhance user experience by simplifying the consent flow and providing immediate options for wallet charging. --- .../Pages/Profile/ChargeCreditWallet.razor | 25 ++++++-- .../Pages/Profile/ChargeCreditWallet.razor.cs | 58 ++++++------------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor index 34a492a..e5da011 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor @@ -86,11 +86,28 @@ else if (_authLoaded && _needsMagicCeilingConsent && !_allowNormalDespiteMagic && !_redirectingToMagic) { - - - - سقف شارژ جادویی پر است. برای شارژ بدون ضریب باید تأیید کنید... + + + سقف شارژ کیف پول جادویی در این دور پر شده است. + + شارژ از این صفحه بدون ضریب (۱:۱) به موجودی اضافه می‌شود و ضریب جادویی اعمال نمی‌شود. + برای ادامه، تأیید کنید. + + + + ادامه شارژ بدون ضریب + + + بازگشت به کیف جادویی + + } diff --git a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs index 8b7ffff..fe0fc00 100644 --- a/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/ChargeCreditWallet.razor.cs @@ -19,7 +19,6 @@ public partial class ChargeCreditWallet : ComponentBase private bool _redirectingToMagic; private bool _allowNormalDespiteMagic; private bool _needsMagicCeilingConsent; - private bool _magicConsentPrompted; private readonly long[] _presetAmounts = { 500_000, 1_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000 }; @@ -65,7 +64,7 @@ public partial class ChargeCreditWallet : ComponentBase } if (_isClubMemberActive) - await EvaluateMagicWalletGateAsync(promptConsent: false); + await EvaluateMagicWalletGateAsync(); } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -73,16 +72,21 @@ public partial class ChargeCreditWallet : ComponentBase if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl) && _isClubMemberActive && !_redirectingToMagic) await CreditChargeNavigation.SaveReturnUrlAsync(JSRuntime, _pendingReturnUrl); - if (firstRender && _needsMagicCeilingConsent && !_allowNormalDespiteMagic && !_magicConsentPrompted) - { - _magicConsentPrompted = true; - await PromptMagicCeilingConsentAsync(); - StateHasChanged(); - } - await base.OnAfterRenderAsync(firstRender); } + private void AcceptMagicCeilingConsent() + { + _allowNormalDespiteMagic = true; + _redirectingToMagic = false; + } + + private void DeclineMagicCeilingConsent() + { + _redirectingToMagic = true; + Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); + } + private async Task StartCreditCharge() { if (!_isClubMemberActive) @@ -93,10 +97,10 @@ public partial class ChargeCreditWallet : ComponentBase return; } - if (await EvaluateMagicWalletGateAsync(promptConsent: true)) + if (await EvaluateMagicWalletGateAsync()) return; - if (!_allowNormalDespiteMagic && _needsMagicCeilingConsent) + if (_needsMagicCeilingConsent && !_allowNormalDespiteMagic) return; if (_chargeAmount <= 0 || _isProcessing) return; @@ -139,10 +143,10 @@ public partial class ChargeCreditWallet : ComponentBase /// /// Magic با ظرفیت باقی‌مانده → ریدایرکت به MagicWallet. - /// Magic با سقف پر → نیاز به رضایت برای شارژ ۱:۱. + /// Magic با سقف پر → نمایش تأیید روی صفحه برای شارژ ۱:۱. /// true یعنی مسیر شارژ فعلی باید متوقف شود. /// - private async Task EvaluateMagicWalletGateAsync(bool promptConsent) + private async Task EvaluateMagicWalletGateAsync() { if (_allowNormalDespiteMagic) return false; @@ -172,14 +176,7 @@ public partial class ChargeCreditWallet : ComponentBase } _needsMagicCeilingConsent = true; - - if (promptConsent) - { - await PromptMagicCeilingConsentAsync(); - return !_allowNormalDespiteMagic; - } - - return true; + return !_allowNormalDespiteMagic; } catch { @@ -188,25 +185,6 @@ public partial class ChargeCreditWallet : ComponentBase } } - private async Task PromptMagicCeilingConsentAsync() - { - var confirmed = await DialogService.ShowMessageBox( - "شارژ بدون ضریب جادویی", - "سقف شارژ کیف پول جادویی شما در این دور پر شده است. شارژ از این صفحه بدون ضریب (۱:۱) به موجودی اضافه می‌شود و ضریب جادویی اعمال نمی‌شود. آیا مایلید ادامه دهید؟", - yesText: "ادامه شارژ بدون ضریب", - cancelText: "انصراف"); - - if (confirmed == true) - { - _allowNormalDespiteMagic = true; - _redirectingToMagic = false; - return; - } - - _redirectingToMagic = true; - Navigation.NavigateTo(RouteConstants.Profile.MagicWallet); - } - private async Task ContinueShoppingAsync() { var returnUrl = await CreditChargeNavigation.GetReturnUrlAsync(JSRuntime);