diff --git a/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor b/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor index 96da6a3..abea33f 100644 --- a/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor +++ b/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor @@ -11,35 +11,73 @@ - ثبت درخواست برداشت جدید - - - - برداشت نقدی (نیاز به شبا) - الماس/غیرنقدی - - - - حداقل مبلغ برداشت: @FormatPrice(_minWithdrawalAmount) - - - @(_isSubmittingWithdrawal ? "در حال ثبت..." : "ثبت درخواست برداشت") - - + ثبت درخواست برداشت جدید + + @if (!_availablePayouts.Any()) + { + + در حال حاضر واریزی برای برداشت وجود ندارد. + + } + else + { + + + @foreach (var payout in _availablePayouts) + { + + + @payout.WeekDisplayName + + @payout.AmountFormatted + + + + } + + + @if (_selectedPayout != null) + { + + مبلغ قابل برداشت: @_selectedPayout.AmountFormatted + + } + + + + برداشت نقدی (نیاز به شبا) + + + الماس/غیرنقدی + + + + + + + حداقل مبلغ برداشت: @FormatPrice(_minWithdrawalAmount) + + + + @(_isSubmittingWithdrawal ? "در حال ثبت..." : "ثبت درخواست برداشت") + + + } diff --git a/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor.cs b/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor.cs index 3473f3e..abd9568 100644 --- a/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/WithdrawalRequests.razor.cs @@ -6,12 +6,15 @@ namespace FrontOffice.Main.Pages.Profile; public partial class WithdrawalRequests : ComponentBase { + [Inject] private CommissionService CommissionService { get; set; } = default!; + private long _minWithdrawalAmount = 1_000_000; private List _withdrawals = new(); + private List _availablePayouts = new(); private string _statusFilter = "all"; private bool _isLoading = true; private bool _isSubmittingWithdrawal; - private long _withdrawPayoutId; + private CommissionPayoutDto? _selectedPayout; private WithdrawalMethodClient _withdrawMethod = WithdrawalMethodClient.Cash; private string? _withdrawIban; @@ -26,6 +29,7 @@ public partial class WithdrawalRequests : ComponentBase try { _withdrawals = await WalletService.GetWithdrawalsAsync(); + _availablePayouts = await CommissionService.GetWithdrawablePayoutsAsync(); var settings = await WalletService.GetWithdrawalSettingsAsync(); if (settings.MinWithdrawalAmount > 0) _minWithdrawalAmount = settings.MinWithdrawalAmount; @@ -40,9 +44,9 @@ public partial class WithdrawalRequests : ComponentBase private async Task SubmitWithdrawal() { - if (_withdrawPayoutId <= 0) + if (_selectedPayout == null) { - Snackbar.Add("شناسه واریز (PayoutId) الزامی است.", Severity.Warning); + Snackbar.Add("لطفاً یک واریز را انتخاب کنید.", Severity.Warning); return; } if (_withdrawMethod == WithdrawalMethodClient.Cash && string.IsNullOrWhiteSpace(_withdrawIban)) @@ -54,14 +58,14 @@ public partial class WithdrawalRequests : ComponentBase try { _isSubmittingWithdrawal = true; - await WalletService.RequestWithdrawalAsync(_withdrawPayoutId, _withdrawMethod, _withdrawIban); + await WalletService.RequestWithdrawalAsync(_selectedPayout.Id, _withdrawMethod, _withdrawIban); Snackbar.Add("درخواست برداشت ثبت شد.", Severity.Success); // بروزرسانی لیست await LoadData(); // ریست فرم - _withdrawPayoutId = 0; + _selectedPayout = null; _withdrawIban = null; } catch (Exception ex) diff --git a/src/FrontOffice.Main/Pages/Store/Products.razor b/src/FrontOffice.Main/Pages/Store/Products.razor index 4207ed2..88d5cca 100644 --- a/src/FrontOffice.Main/Pages/Store/Products.razor +++ b/src/FrontOffice.Main/Pages/Store/Products.razor @@ -3,37 +3,91 @@ محصولات - - + + - + @* ردیف اول: جستجو و دکمه‌ها *@ + + Variant="Variant.Outlined" + Margin="Margin.Dense"/> - - + + دسته‌بندی‌ها - - سبد خرید (@Cart.Count) + سبد خرید + @if (Cart.Count > 0) + { + + } + + @* ردیف دوم: فیلترها و مرتب‌سازی *@ + + + + + + +
+ + گران‌ترین +
+
+ +
+ + ارزان‌ترین +
+
+ +
+ + جدیدترین +
+
+ +
+ + الفبایی +
+
+
+
+ + @if (_activeCategoryId.HasValue) + { + + @(_activeCategoryTitle ?? $"دسته‌بندی #{_activeCategoryId}") + + } + else + { + + + @(_products.Count) محصول + + } +
- @if (_activeCategoryId.HasValue) - { - - - @(_activeCategoryTitle ?? $"دسته‌بندی #{_activeCategoryId}") - - - }
@if (_loading) diff --git a/src/FrontOffice.Main/Pages/Store/Products.razor.cs b/src/FrontOffice.Main/Pages/Store/Products.razor.cs index 7156e3f..5c8163d 100644 --- a/src/FrontOffice.Main/Pages/Store/Products.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/Products.razor.cs @@ -7,6 +7,14 @@ using FrontOffice.Main.Utilities; namespace FrontOffice.Main.Pages.Store; +public enum ProductSortOption +{ + PriceDesc, // گران‌ترین (پیش‌فرض) + PriceAsc, // ارزان‌ترین + Newest, // جدیدترین + Title // الفبایی +} + public partial class Products : ComponentBase, IDisposable { [Inject] private ProductService ProductService { get; set; } = default!; @@ -19,6 +27,8 @@ public partial class Products : ComponentBase, IDisposable private List _products = new(); private long? _activeCategoryId; private string? _activeCategoryTitle; + + private ProductSortOption _sortOption = ProductSortOption.PriceDesc; // پیش‌فرض: گران‌ترین protected override async Task OnInitializedAsync() { @@ -43,13 +53,31 @@ public partial class Products : ComponentBase, IDisposable { _loading = true; UpdateCategoryFilterFromUri(); - _products = await ProductService.GetProductsAsync(_query, _activeCategoryId); + var sortBy = GetSortByValue(); + _products = await ProductService.GetProductsAsync(_query, _activeCategoryId, sortBy); _activeCategoryTitle = _activeCategoryId is { } categoryId ? (await CategoryService.GetByIdAsync(categoryId))?.Title : null; _loading = false; } + private string GetSortByValue() + { + return _sortOption switch + { + ProductSortOption.PriceDesc => "price desc", + ProductSortOption.PriceAsc => "price asc", + ProductSortOption.Newest => "id desc", + ProductSortOption.Title => "title asc", + _ => "price desc" + }; + } + + private async Task OnSortChanged() + { + await Load(); + } + private async Task OnQueryChanged(KeyboardEventArgs _) { await Load(); diff --git a/src/FrontOffice.Main/Pages/_Host.cshtml b/src/FrontOffice.Main/Pages/_Host.cshtml index 6925fc6..e22f5de 100644 --- a/src/FrontOffice.Main/Pages/_Host.cshtml +++ b/src/FrontOffice.Main/Pages/_Host.cshtml @@ -4,7 +4,7 @@ @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers - + diff --git a/src/FrontOffice.Main/Shared/ReleaseNotesDialog.razor b/src/FrontOffice.Main/Shared/ReleaseNotesDialog.razor index 7446e0b..508c10a 100644 --- a/src/FrontOffice.Main/Shared/ReleaseNotesDialog.razor +++ b/src/FrontOffice.Main/Shared/ReleaseNotesDialog.razor @@ -21,7 +21,7 @@ @* اطلاعات نسخه با انیمیشن *@ + Style=""> diff --git a/src/FrontOffice.Main/Utilities/CommissionService.cs b/src/FrontOffice.Main/Utilities/CommissionService.cs index b45c498..bee9bfe 100644 --- a/src/FrontOffice.Main/Utilities/CommissionService.cs +++ b/src/FrontOffice.Main/Utilities/CommissionService.cs @@ -191,6 +191,46 @@ public class CommissionService #region Helper Methods + /// + /// Get payouts that are eligible for withdrawal (all statuses except Withdrawn=3) + /// + public async Task> GetWithdrawablePayoutsAsync() + { + try + { + // Get all payouts that are not yet withdrawn + // We'll get all and filter out Withdrawn (status=3) on client side + var request = new GetMyCommissionPayoutsRequest + { + PageNumber = 1, + PageSize = 100 + // No status filter - get all + }; + + var response = await _client.GetMyCommissionPayoutsAsync(request); + + // Filter: exclude already withdrawn (status text contains "برداشت" or status=3) + return response.Payouts + .Where(p => !p.Status.Contains("برداشت") && p.Status != "Withdrawn") + .Select(p => new CommissionPayoutDto + { + Id = p.Id, + WeekDefinitionId = p.WeekDefinitionId, + WeekDisplayName = p.WeekDisplayName, + BalancesEarned = p.BalancesEarned, + TotalAmount = p.TotalAmount, + AmountFormatted = p.AmountFormatted, + Status = p.Status, + StatusBadgeColor = p.StatusBadgeColor, + DatePersian = p.DatePersian + }).ToList(); + } + catch + { + return new List(); + } + } + private static WeeklyBalanceDto CreateEmptyWeeklyBalance() { return new WeeklyBalanceDto diff --git a/src/FrontOffice.Main/Utilities/ProductService.cs b/src/FrontOffice.Main/Utilities/ProductService.cs index 28451b3..f8a0c1b 100644 --- a/src/FrontOffice.Main/Utilities/ProductService.cs +++ b/src/FrontOffice.Main/Utilities/ProductService.cs @@ -58,7 +58,7 @@ public class ProductService _client = client; } - public async Task> GetProductsAsync(string? query = null, long? categoryId = null) + public async Task> GetProductsAsync(string? query = null, long? categoryId = null, string? sortBy = null) { try { @@ -75,7 +75,12 @@ public class ProductService if (categoryId is { } value) { - request.Filter.CategoryId = value ; + request.Filter.CategoryId = value; + } + + if (!string.IsNullOrEmpty(sortBy)) + { + request.SortBy = sortBy; } var resp = await _client.GetAllProductsByFilterAsync(request); diff --git a/src/FrontOffice.Main/wwwroot/css/site.css b/src/FrontOffice.Main/wwwroot/css/site.css index b983cb2..9735a1a 100644 --- a/src/FrontOffice.Main/wwwroot/css/site.css +++ b/src/FrontOffice.Main/wwwroot/css/site.css @@ -49,6 +49,8 @@ html, body { font-weight: 400; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + direction: rtl; + text-align: right; } /* Apply Vazir to common Mud components */ diff --git a/src/FrontOffice.Main/wwwroot/js/print-utils.js b/src/FrontOffice.Main/wwwroot/js/print-utils.js index 98f58f1..b3e1818 100644 --- a/src/FrontOffice.Main/wwwroot/js/print-utils.js +++ b/src/FrontOffice.Main/wwwroot/js/print-utils.js @@ -27,7 +27,7 @@ var doc = iframe.contentDocument || iframe.contentWindow.document; doc.open(); - doc.write(""+ + doc.write(""+ ""+ title +""+ ""+ ""+