From fe79089770e07f1cddb23ba4cb28fe99eff22c3f Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 14 Aug 2026 03:19:10 +0330 Subject: [PATCH 1/2] feat(user-page): enhance user main page with additional address and postal code fields in export - Added new columns for default address and postal code in the user export functionality. - Updated the export logic to handle the new fields and changed the file format from CSV to Excel (.xls) for better compatibility. - Bumped Foursat.CMSMicroservice.Protobuf version to 0.0.209 to align with recent changes. - Made minor adjustments to the .gitignore for clarity. --- .gitignore | 2 +- src/BackOffice/BackOffice.csproj | 2 +- src/BackOffice/Pages/User/UserMainPage.razor | 19 ++++- .../Pages/User/UserMainPage.razor.cs | 75 +++++++++++-------- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 0260adb..3508f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ *.userosscache *.sln.docstates -# User-specific files (MonoDevelop/Xamarin Studio) +# User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files diff --git a/src/BackOffice/BackOffice.csproj b/src/BackOffice/BackOffice.csproj index 605345f..29ae5c3 100644 --- a/src/BackOffice/BackOffice.csproj +++ b/src/BackOffice/BackOffice.csproj @@ -143,7 +143,7 @@ - + diff --git a/src/BackOffice/Pages/User/UserMainPage.razor b/src/BackOffice/Pages/User/UserMainPage.razor index 6d2418e..872b9e0 100644 --- a/src/BackOffice/Pages/User/UserMainPage.razor +++ b/src/BackOffice/Pages/User/UserMainPage.razor @@ -28,6 +28,8 @@ + + @@ -46,8 +48,21 @@ - - + + + + @(string.IsNullOrWhiteSpace(context.Item.DefaultAddress) ? "-" : context.Item.DefaultAddress) + + + + + + + @(string.IsNullOrWhiteSpace(context.Item.DefaultPostalCode) ? "-" : context.Item.DefaultPostalCode) + + + diff --git a/src/BackOffice/Pages/User/UserMainPage.razor.cs b/src/BackOffice/Pages/User/UserMainPage.razor.cs index 50d8436..bb612b2 100644 --- a/src/BackOffice/Pages/User/UserMainPage.razor.cs +++ b/src/BackOffice/Pages/User/UserMainPage.razor.cs @@ -1,11 +1,10 @@ using CMSMicroservice.Protobuf.Protos.User; using BackOffice.Common.BaseComponents; +using BackOffice.Common.Utilities; using BackOffice.Pages.User.Components; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using MudBlazor; -using System.Text; -using DateTimeConverterCL; using DataModel = CMSMicroservice.Protobuf.Protos.User.GetAllUserByFilterResponseModel; namespace BackOffice.Pages.User; @@ -84,51 +83,63 @@ public partial class UserMainPage { try { - var exportRequest = new GetAllUserByFilterRequest + var filter = _request.Filter?.Clone() ?? new(); + var all = new List(); + const int pageSize = 200; + var page = 1; + + while (page <= 500) { - Filter = _request.Filter?.Clone() ?? new(), - PaginationState = new() { PageNumber = 1, PageSize = 1000 } - }; + var result = await UserContract.GetAllUserByFilterAsync(new GetAllUserByFilterRequest + { + Filter = filter, + PaginationState = new() { PageNumber = page, PageSize = pageSize } + }); - var result = await UserContract.GetAllUserByFilterAsync(exportRequest); + var batch = result?.Models?.ToList() ?? new(); + if (batch.Count == 0) + break; - if (result?.Models == null || !result.Models.Any()) + all.AddRange(batch); + + var hasNext = result?.MetaData?.HasNext == true; + if (!hasNext || batch.Count < pageSize) + break; + + page++; + } + + if (all.Count == 0) { Snackbar.Add("داده‌ای برای خروجی وجود ندارد.", Severity.Info); return; } - var sb = new StringBuilder(); - sb.AppendLine("شناسه,موبایل,نام,نام خانوادگی,کدملی"); - - foreach (var u in result.Models) + var headers = new[] { - sb.AppendLine(string.Join(",", - u.Id, - EscapeCsv(u.Mobile), - EscapeCsv(u.FirstName), - EscapeCsv(u.LastName), - EscapeCsv(u.NationalCode))); - } + "شناسه", "موبایل", "نام", "نام خانوادگی", "کدملی", + "آدرس پیش‌فرض", "کدپستی پیش‌فرض" + }; - var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray(); - var base64 = Convert.ToBase64String(bytes); - var filename = $"users-{DateTime.Now:yyyyMMddHHmmss}.csv"; + var rows = all.Select(u => new object?[] + { + u.Id, + u.Mobile, + u.FirstName, + u.LastName, + u.NationalCode, + u.DefaultAddress, + u.DefaultPostalCode + }); - await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64); - Snackbar.Add("خروجی Excel (CSV) آماده شد.", Severity.Success); + var filename = $"users-{DateTime.Now:yyyyMMddHHmmss}.xls"; + await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, + CsvExportHelper.ToExcelXmlBase64("کاربران", headers, rows)); + Snackbar.Add($"خروجی Excel آماده شد ({all.Count} کاربر).", Severity.Success); } catch (Exception ex) { Snackbar.Add($"خطا در خروجی Excel: {ex.Message}", Severity.Error); } } - - private static string EscapeCsv(string value) - { - if (string.IsNullOrEmpty(value)) return ""; - if (value.Contains(',') || value.Contains('"') || value.Contains('\n')) - return $"\"{value.Replace("\"", "\"\"")}\""; - return value; - } } From 4338d0ed1afc2b49eeb11ed88ffefc95096d474a Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 27 Aug 2026 21:28:53 +0330 Subject: [PATCH 2/2] refactor(club-members): remove activation dialog and related functionality - Deleted the ActivateClubDialog component and its associated logic from ClubMembers.razor and ClubMembers.razor.cs. - Removed the button for activating new club members from the ClubMembers page. - Streamlined the codebase by eliminating unused methods and components related to member activation. --- src/BackOffice/Pages/Club/ClubMembers.razor | 6 - .../Pages/Club/ClubMembers.razor.cs | 17 -- .../Club/Components/ActivateClubDialog.razor | 156 ------------------ 3 files changed, 179 deletions(-) delete mode 100644 src/BackOffice/Pages/Club/Components/ActivateClubDialog.razor diff --git a/src/BackOffice/Pages/Club/ClubMembers.razor b/src/BackOffice/Pages/Club/ClubMembers.razor index da3e8f6..df466a1 100644 --- a/src/BackOffice/Pages/Club/ClubMembers.razor +++ b/src/BackOffice/Pages/Club/ClubMembers.razor @@ -33,12 +33,6 @@ StartIcon="@Icons.Material.Filled.Refresh"> بارگذاری - - فعال‌سازی عضو جدید - ("فعال‌سازی عضویت باشگاه", new DialogOptions - { - CloseButton = true, - MaxWidth = MaxWidth.Small, - FullWidth = true - }); - - var result = await dialog.Result; - if (!result.Canceled) - { - Snackbar.Add("عضویت با موفقیت فعال شد", Severity.Success); - await ApplyFilter(); - } - } - private async Task ViewDetails(ClubMembershipModel member) { var parameters = new DialogParameters diff --git a/src/BackOffice/Pages/Club/Components/ActivateClubDialog.razor b/src/BackOffice/Pages/Club/Components/ActivateClubDialog.razor deleted file mode 100644 index cc9d66e..0000000 --- a/src/BackOffice/Pages/Club/Components/ActivateClubDialog.razor +++ /dev/null @@ -1,156 +0,0 @@ -@using CMSMicroservice.Protobuf.Protos.ClubMembership -@using CMSMicroservice.Protobuf.Protos.Package -@using BackOffice.Pages.AutoComplete - - - - - - - - @if (_isLoadingPackages) - { - - } - else - { - - @foreach (var pkg in _packages) - { - - @pkg.Title — @($"{pkg.Price:N0}") ریال - - } - - } - - - - با تایید، عضویت باشگاه برای کاربر فعال می‌شود. -
- عضویت باشگاه بدون محدودیت زمانی است. -
-
-
-
-
- - لغو - - @if (_isSubmitting) - { - - در حال پردازش... - } - else - { - تایید و فعال‌سازی - } - - -
- -@code { - [CascadingParameter] IMudDialogInstance MudDialog { get; set; } - [Inject] public ClubMembershipContract.ClubMembershipContractClient ClubContract { get; set; } - [Inject] public PackageContract.PackageContractClient PackageClient { get; set; } - - private MudForm _form; - private bool _formValid; - private bool _isSubmitting; - private bool _isLoadingPackages = true; - private List _packages = new(); - private ActivateModel _model = new(); - - protected override async Task OnInitializedAsync() - { - await LoadPackages(); - } - - private async Task LoadPackages() - { - _isLoadingPackages = true; - try - { - var request = new GetAllPackageByFilterRequest - { - PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState - { - PageNumber = 1, - PageSize = 50 - } - }; - var result = await PackageClient.GetAllPackageByFilterAsync(request); - if (result?.Models != null) - { - _packages = result.Models.ToList(); - } - } - catch (Exception ex) - { - Snackbar.Add($"خطا در بارگذاری پکیج‌ها: {ex.Message}", Severity.Error); - } - finally - { - _isLoadingPackages = false; - } - } - - private void Cancel() => MudDialog.Cancel(); - - private async Task Submit() - { - await _form.Validate(); - if (!_formValid) return; - - if (!_model.UserId.HasValue || _model.UserId.Value <= 0) - { - Snackbar.Add("لطفاً کاربر را انتخاب کنید.", Severity.Warning); - return; - } - - if (_model.PackageId <= 0) - { - Snackbar.Add("لطفاً پکیج را انتخاب کنید.", Severity.Warning); - return; - } - - _isSubmitting = true; - try - { - var request = new ActivateClubMembershipRequest - { - UserId = _model.UserId.Value, - PackageId = _model.PackageId, - ForceActivation = true - }; - - var response = await ClubContract.ActivateClubMembershipAsync(request); - - Snackbar.Add("عضویت با موفقیت فعال شد.", Severity.Success); - MudDialog.Close(DialogResult.Ok(true)); - } - catch (Exception ex) - { - Snackbar.Add($"خطا: {ex.Message}", Severity.Error); - } - finally - { - _isSubmitting = false; - } - } - - private class ActivateModel - { - public long? UserId { get; set; } - public long PackageId { get; set; } - } -}