From 081b9d3c102d877a29126b9dc428238fa50213af Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sun, 8 Feb 2026 00:25:12 +0330 Subject: [PATCH] refactor: update user address models and methods to use CustomerAddressModel across multiple components --- src/FrontOffice.Main/FrontOffice.Main.csproj | 3 +- src/FrontOffice.Main/Pages/Checkout.razor.cs | 10 +- .../Pages/Club/MembershipPage.razor | 18 ---- .../Pages/Profile/Addresses.razor.cs | 10 +- .../Components/AddAddressDialog.razor.cs | 4 +- .../Components/EditAddressDialog.razor.cs | 8 +- .../Pages/Profile/Index.razor.cs | 10 +- .../Pages/Profile/Wallet.razor | 98 +++++++++++++++---- .../Pages/Store/CheckoutSummary.razor.cs | 6 +- .../Pages/Store/OrderDetail.razor | 22 +++-- src/FrontOffice.Main/Pages/Store/Orders.razor | 26 ++++- src/FrontOffice.Main/Utilities/CartService.cs | 25 +++-- .../Utilities/ClubMembershipService.cs | 36 +++++-- .../Utilities/WalletService.cs | 47 +++++++-- 14 files changed, 218 insertions(+), 105 deletions(-) diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj index 57f77f3..36cf9b4 100644 --- a/src/FrontOffice.Main/FrontOffice.Main.csproj +++ b/src/FrontOffice.Main/FrontOffice.Main.csproj @@ -11,7 +11,8 @@ - + + diff --git a/src/FrontOffice.Main/Pages/Checkout.razor.cs b/src/FrontOffice.Main/Pages/Checkout.razor.cs index 1137e58..6a4813e 100644 --- a/src/FrontOffice.Main/Pages/Checkout.razor.cs +++ b/src/FrontOffice.Main/Pages/Checkout.razor.cs @@ -21,8 +21,8 @@ public partial class Checkout [Parameter] public long? PackageId { get; set; } private Pack? _selectedPackage; - private List _addresses = new(); - private GetAllUserAddressByFilterResponseModel? _selectedAddress; + private List _addresses = new(); + private CustomerAddressModel? _selectedAddress; private bool _isLoadingAddresses; private bool _isProcessingPayment; @@ -77,7 +77,7 @@ public partial class Checkout _isLoadingAddresses = true; try { - var response = await UserAddressContract.GetAllUserAddressByFilterAsync(request: new()); + var response = await UserAddressContract.GetCustomerAddressesAsync(request: new()); if (response?.Models?.Any() == true) { _addresses = response.Models.ToList(); @@ -86,13 +86,13 @@ public partial class Checkout } else { - _addresses = new List(); + _addresses = new List(); } } catch (Exception ex) { Snackbar.Add($"خطا در بارگذاری آدرس‌ها: {ex.Message}", Severity.Error); - _addresses = new List(); + _addresses = new List(); } finally { diff --git a/src/FrontOffice.Main/Pages/Club/MembershipPage.razor b/src/FrontOffice.Main/Pages/Club/MembershipPage.razor index 0f071c1..55784f1 100644 --- a/src/FrontOffice.Main/Pages/Club/MembershipPage.razor +++ b/src/FrontOffice.Main/Pages/Club/MembershipPage.razor @@ -56,19 +56,6 @@ شما هنوز عضو باشگاه مشتریان نیستید. برای استفاده از مزایای ویژه، اکنون فعال کنید! - - @if (_clubConfig != null) - { - - - - هزینه عضویت در باشگاه مشتریان - شامل @((_clubConfig.MembershipGiftValue / 10000).ToString("N0")) تومان هدیه - - @((_clubConfig.ActivationFee / 10000).ToString("N0")) تومان - - - } } @@ -103,11 +90,6 @@ - - @if (!_membership.IsActive || (_membership.DaysRemaining.HasValue && _membership.DaysRemaining.Value <= 30)) - { - - } _addresses = new(); + private List _addresses = new(); private bool _isLoadingAddresses; protected override async Task OnInitializedAsync() @@ -23,7 +23,7 @@ public partial class Addresses : ComponentBase _isLoadingAddresses = true; try { - var response = await UserAddressContract.GetAllUserAddressByFilterAsync(new()); + var response = await UserAddressContract.GetCustomerAddressesAsync(new()); _addresses = response?.Models?.ToList() ?? new(); } catch (Exception ex) @@ -45,7 +45,7 @@ public partial class Addresses : ComponentBase await LoadAddresses(); } - private async Task OpenEditAddressDialog(GetAllUserAddressByFilterResponseModel address) + private async Task OpenEditAddressDialog(CustomerAddressModel address) { var dialog = await DialogService.ShowAsync("ویرایش آدرس", new DialogParameters { @@ -60,7 +60,7 @@ public partial class Addresses : ComponentBase { try { - await UserAddressContract.SetAddressAsDefaultAsync(new() { Id = id }); + await UserAddressContract.SetCustomerDefaultAddressAsync(new() { Id = id }); Snackbar.Add("آدرس پیش‌فرض تغییر کرد.", Severity.Success); await LoadAddresses(); } @@ -77,7 +77,7 @@ public partial class Addresses : ComponentBase { try { - await UserAddressContract.DeleteUserAddressAsync(new() { Id = id }); + await UserAddressContract.DeleteCustomerAddressAsync(new() { Id = id }); Snackbar.Add("آدرس حذف شد.", Severity.Success); await LoadAddresses(); } diff --git a/src/FrontOffice.Main/Pages/Profile/Components/AddAddressDialog.razor.cs b/src/FrontOffice.Main/Pages/Profile/Components/AddAddressDialog.razor.cs index d5c6b70..b3245b9 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/AddAddressDialog.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Components/AddAddressDialog.razor.cs @@ -16,7 +16,7 @@ public partial class AddAddressDialog : ComponentBase private MudForm? _form; private bool _isSaving; - private CreateNewUserAddressRequest _request = new(); + private CreateCustomerAddressRequest _request = new(); private object? _selectedCity; private async Task> SearchCities(string value, CancellationToken ct) @@ -56,7 +56,7 @@ public partial class AddAddressDialog : ComponentBase _isSaving = true; try { - var response = await UserAddressContract.CreateNewUserAddressAsync(_request); + var response = await UserAddressContract.CreateCustomerAddressAsync(_request); Snackbar.Add("آدرس با موفقیت اضافه شد.", Severity.Success); MudDialog.Close(DialogResult.Ok(true)); } diff --git a/src/FrontOffice.Main/Pages/Profile/Components/EditAddressDialog.razor.cs b/src/FrontOffice.Main/Pages/Profile/Components/EditAddressDialog.razor.cs index aa288e9..bf959e9 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/EditAddressDialog.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Components/EditAddressDialog.razor.cs @@ -13,11 +13,11 @@ public partial class EditAddressDialog : ComponentBase [Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!; [Inject] private CityContract.CityContractClient CityContract { get; set; } = default!; - [Parameter] public GetAllUserAddressByFilterResponseModel? Model { get; set; } + [Parameter] public CustomerAddressModel? Model { get; set; } private MudForm? _form; private bool _isSaving; - private UpdateUserAddressRequest _request = new(); + private UpdateCustomerAddressRequest _request = new(); private object? _selectedCity; protected override async Task OnInitializedAsync() @@ -25,7 +25,7 @@ public partial class EditAddressDialog : ComponentBase await base.OnInitializedAsync(); if (Model != null) { - _request = Model.Adapt(); + _request = Model.Adapt(); // Load selected city if CityId exists if (Model.CityId > 0) @@ -90,7 +90,7 @@ public partial class EditAddressDialog : ComponentBase _isSaving = true; try { - await UserAddressContract.UpdateUserAddressAsync(_request); + await UserAddressContract.UpdateCustomerAddressAsync(_request); Snackbar.Add("آدرس با موفقیت ویرایش شد.", Severity.Success); MudDialog.Close(DialogResult.Ok(true)); } diff --git a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs index 0bfc264..6282e3c 100644 --- a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs @@ -46,7 +46,7 @@ public partial class Index private bool _isProcessingPayment; // Address management - private List _addresses = new(); + private List _addresses = new(); private bool _isLoadingAddresses; private CreateNewUserAddressRequest _newAddressRequest = new(); private UpdateUserAddressRequest _editAddressRequest = new(); @@ -251,20 +251,20 @@ public partial class Index _isLoadingAddresses = true; try { - var response = await UserAddressContract.GetAllUserAddressByFilterAsync(request: new()); + var response = await UserAddressContract.GetCustomerAddressesAsync(request: new()); if (response?.Models?.Any() == true) { _addresses = response.Models.ToList(); } else { - _addresses = new List(); + _addresses = new List(); } } catch (Exception ex) { Snackbar.Add($"خطا در بارگذاری آدرس‌ها: {ex.Message}", Severity.Error); - _addresses = new List(); + _addresses = new List(); } finally { @@ -284,7 +284,7 @@ public partial class Index } } - private async Task OpenEditAddressDialog(GetAllUserAddressByFilterResponseModel address) + private async Task OpenEditAddressDialog(CustomerAddressModel address) { var dialog = await DialogService.ShowAsync("ویرایش آدرس", new DialogParameters { diff --git a/src/FrontOffice.Main/Pages/Profile/Wallet.razor b/src/FrontOffice.Main/Pages/Profile/Wallet.razor index 3236f00..a42716f 100644 --- a/src/FrontOffice.Main/Pages/Profile/Wallet.razor +++ b/src/FrontOffice.Main/Pages/Profile/Wallet.razor @@ -12,20 +12,20 @@ - موجودی اعتباری + موجودی عادی @_balances.Credit - موجودی فروشگاه تخفیفی - @_balances.Discount + موجودی شبکه + @_balances.Network - موجودی پاداش تیمی - @_balances.Network + موجودی تخفیفی + @_balances.Discount @@ -71,18 +71,45 @@ - + تاریخ - مبلغ - مسیر + عادی (تغییرات / مانده) + شبکه (تغییرات / مانده) + تخفیفی (تغییرات / مانده) + شناسه ارجاع توضیحات - @context.Date - @FormatPrice(context.Amount) - @context.Channel - @context.Description + + @context.Date + + + + + @(context.CreditChange != 0 ? (context.CreditChange > 0 ? "+" : "") + FormatPrice(context.CreditChange) : "-") + + @FormatPrice(context.CreditBalance) + + + + + + @(context.NetworkChange != 0 ? (context.NetworkChange > 0 ? "+" : "") + FormatPrice(context.NetworkChange) : "-") + + @FormatPrice(context.NetworkBalance) + + + + + + @(context.DiscountChange != 0 ? (context.DiscountChange > 0 ? "+" : "") + FormatPrice(context.DiscountChange) : "-") + + @FormatPrice(context.DiscountBalance) + + + @context.Channel + @context.Description @@ -91,13 +118,50 @@ @foreach (var tx in _txs) { - - + + - @tx.Date - @FormatPrice(tx.Amount) + @tx.Date + شناسه: @tx.Channel - @tx.Channel + + + + + + + + عادی + + @(tx.CreditChange != 0 ? (tx.CreditChange > 0 ? "+" : "") + FormatPrice(tx.CreditChange) : "-") + + @FormatPrice(tx.CreditBalance) + + + + + + + شبکه + + @(tx.NetworkChange != 0 ? (tx.NetworkChange > 0 ? "+" : "") + FormatPrice(tx.NetworkChange) : "-") + + @FormatPrice(tx.NetworkBalance) + + + + + + + تخفیفی + + @(tx.DiscountChange != 0 ? (tx.DiscountChange > 0 ? "+" : "") + FormatPrice(tx.DiscountChange) : "-") + + @FormatPrice(tx.DiscountBalance) + + + + @tx.Description diff --git a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs index 7d8af27..ad5c5c3 100644 --- a/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs +++ b/src/FrontOffice.Main/Pages/Store/CheckoutSummary.razor.cs @@ -16,8 +16,8 @@ public partial class CheckoutSummary : ComponentBase [Inject] private UserOrderContract.UserOrderContractClient UserOrderContract { get; set; } = default!; // Snackbar and Navigation are injected via _Imports.razor - private List _addresses = new(); - private GetAllUserAddressByFilterResponseModel? _selectedAddress; + private List _addresses = new(); + private CustomerAddressModel? _selectedAddress; private bool _loadingAddresses; private long walletBalance; @@ -56,7 +56,7 @@ public partial class CheckoutSummary : ComponentBase _loadingAddresses = true; try { - var response = await UserAddressContract.GetAllUserAddressByFilterAsync(new()); + var response = await UserAddressContract.GetCustomerAddressesAsync(new()); if (response?.Models?.Any() == true) { _addresses = response.Models.ToList(); diff --git a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor index cdff00e..98e25cf 100644 --- a/src/FrontOffice.Main/Pages/Store/OrderDetail.razor +++ b/src/FrontOffice.Main/Pages/Store/OrderDetail.razor @@ -24,9 +24,15 @@ else سفارش #@_order.Id - تاریخ: @_order.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + @if (_order.PaymentDate != null) + { + تاریخ پرداخت: @_order.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + } + else + { + تاریخ ثبت: @DateTime.Now.MiladiToJalaliWithTime() + } وضعیت: @GetStatusText(_order.PaymentStatus) - روش پرداخت: @GetPaymentMethodText(_order.PaymentMethod) آدرس: @_order.UserAddressText @@ -42,12 +48,12 @@ else - @context.ProductThumbnailPath + @context.ProductTitle - @FormatPrice(context.UnitPrice.Value) + @FormatPrice(context.UnitPrice ?? 0) @context.Count - @FormatPrice(context.UnitPrice.Value*context.Count.Value) + @FormatPrice((context.UnitPrice ?? 0) * (context.Count ?? 0)) @@ -64,10 +70,10 @@ else @it.ProductTitle - @FormatPrice(it.UnitPrice.Value) واحد + @FormatPrice(it.UnitPrice ?? 0) واحد تعداد: @it.Count - جمع: @FormatPrice(it.UnitPrice.Value*it.Count.Value) + جمع: @FormatPrice((it.UnitPrice ?? 0) * (it.Count ?? 0)) } @@ -77,7 +83,7 @@ else @* نمایش جزئیات مالی *@ @{ - var subtotal = _order.FactorDetails.Sum(s => s.UnitPrice.Value * s.Count.Value); + var subtotal = _order.FactorDetails.Sum(s => (s.UnitPrice ?? 0) * (s.Count ?? 0)); } diff --git a/src/FrontOffice.Main/Pages/Store/Orders.razor b/src/FrontOffice.Main/Pages/Store/Orders.razor index 1355e6d..a40cd5a 100644 --- a/src/FrontOffice.Main/Pages/Store/Orders.razor +++ b/src/FrontOffice.Main/Pages/Store/Orders.razor @@ -28,9 +28,18 @@ @context.Id - @context.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + + @if (context.PaymentDate != null) + { + @context.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + } + else + { + در انتظار پرداخت + } + @GetStatusText(context.PaymentStatus) - @FormatPrice(context.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value)) + @FormatPrice(context.FactorDetails.Sum(s=>(s.UnitPrice ?? 0) * (s.Count ?? 0))) جزئیات @@ -46,11 +55,20 @@ سفارش #@o.Id - @o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + + @if (o.PaymentDate != null) + { + @o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() + } + else + { + در انتظار پرداخت + } + وضعیت: @GetStatusText(o.PaymentStatus) - @FormatPrice(o.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value)) + @FormatPrice(o.FactorDetails.Sum(s=>(s.UnitPrice ?? 0) * (s.Count ?? 0))) جزئیات diff --git a/src/FrontOffice.Main/Utilities/CartService.cs b/src/FrontOffice.Main/Utilities/CartService.cs index bbd8fcf..ad5c586 100644 --- a/src/FrontOffice.Main/Utilities/CartService.cs +++ b/src/FrontOffice.Main/Utilities/CartService.cs @@ -71,7 +71,7 @@ public class CartService { if (existing is null) { - await _client.AddNewUserCartAsync(new AddNewUserCartRequest + await _client.AddNewUserCartForCustomerAsync(new AddNewUserCartForCustomerRequest { ProductId = product.Id, Count = newQuantity @@ -80,10 +80,9 @@ public class CartService } else { - await _client.UpdateUserCartAsync(new UpdateUserCartRequest + await _client.UpdateUserCartForCustomerAsync(new UpdateUserCartForCustomerRequest { - UserCartId = existing.cartId, - + CartItemId = existing.cartId, Count = newQuantity }); } @@ -112,9 +111,9 @@ public class CartService try { - await _client.UpdateUserCartAsync(new UpdateUserCartRequest + await _client.UpdateUserCartForCustomerAsync(new UpdateUserCartForCustomerRequest { - UserCartId = existing.cartId, + CartItemId = existing.cartId, Count = quantity }); } @@ -134,11 +133,10 @@ public class CartService try { - // Interpret Count=0 as remove from cart - await _client.UpdateUserCartAsync(new UpdateUserCartRequest + // Use dedicated remove endpoint + await _client.RemoveUserCartForCustomerAsync(new RemoveUserCartForCustomerRequest { - UserCartId = cartId, - Count = 0 + CartItemId = cartId }); } catch @@ -158,12 +156,11 @@ public class CartService try { - foreach (var id in productIds) + foreach (var item in productIds) { - await _client.UpdateUserCartAsync(new UpdateUserCartRequest + await _client.RemoveUserCartForCustomerAsync(new RemoveUserCartForCustomerRequest { - UserCartId = id, - Count = 0 + CartItemId = item }); } } diff --git a/src/FrontOffice.Main/Utilities/ClubMembershipService.cs b/src/FrontOffice.Main/Utilities/ClubMembershipService.cs index 92ad728..9252a81 100644 --- a/src/FrontOffice.Main/Utilities/ClubMembershipService.cs +++ b/src/FrontOffice.Main/Utilities/ClubMembershipService.cs @@ -5,15 +5,19 @@ namespace FrontOffice.Main.Utilities; /// /// Service for Club Membership operations -/// Connected to FrontOffice.BFF gRPC ClubMembershipCQ +/// Connected to CMS gRPC ClubMembershipCQ /// public class ClubMembershipService { private readonly ClubMembershipContract.ClubMembershipContractClient _client; + private readonly UserAuthInfo _authInfo; - public ClubMembershipService(ClubMembershipContract.ClubMembershipContractClient client) + public ClubMembershipService( + ClubMembershipContract.ClubMembershipContractClient client, + UserAuthInfo authInfo) { _client = client; + _authInfo = authInfo; } /// @@ -24,8 +28,8 @@ public class ClubMembershipService { try { - var userId = await GetCurrentUserIdAsync(); - var response = await _client.GetClubMembershipAsync(new GetClubMembershipRequest { UserId = userId }); + // UserId = 0 میفرستیم تا CMS از JWT بخونه + var response = await _client.GetClubMembershipAsync(new GetClubMembershipRequest { UserId = 0 }); return new ClubMembershipDto { UserId = response.UserId, @@ -34,8 +38,11 @@ public class ClubMembershipService DaysRemaining = response.DaysRemaining > 0 ? response.DaysRemaining : null }; } - catch + catch (Exception ex) { + // Log the error for debugging + Console.WriteLine($"GetMyMembershipAsync error: {ex.Message}"); + // Return empty membership if backend is unavailable return new ClubMembershipDto { @@ -59,6 +66,19 @@ public class ClubMembershipService try { var userId = await GetCurrentUserIdAsync(); + + // Check if user is authenticated + if (userId <= 0) + { + return new ClubActivationResponseDto + { + Success = false, + Message = "کاربر احراز هویت نشده است. لطفاً ابتدا وارد شوید.", + ActivationDate = null, + AmountPaid = 0 + }; + } + var request = new ActivateClubMembershipRequest { UserId = userId, @@ -93,10 +113,8 @@ public class ClubMembershipService } } - private async Task GetCurrentUserIdAsync() + private Task GetCurrentUserIdAsync() { - // Get current user ID from auth service or JWT token - // This is a placeholder - should be implemented based on your auth system - return 1; // TODO: Implement proper user ID retrieval + return Task.FromResult(_authInfo.UserId); } } diff --git a/src/FrontOffice.Main/Utilities/WalletService.cs b/src/FrontOffice.Main/Utilities/WalletService.cs index 32b14a9..f1a0c30 100644 --- a/src/FrontOffice.Main/Utilities/WalletService.cs +++ b/src/FrontOffice.Main/Utilities/WalletService.cs @@ -6,7 +6,17 @@ using Google.Protobuf.WellKnownTypes; namespace FrontOffice.Main.Utilities; public record WalletBalances(long CreditBalance, long DiscountBalance, long NetworkBalance); -public record WalletTransaction(string Date, long Amount, string Channel, string Description); +public record WalletTransaction( + string Date, + long CreditChange, + long CreditBalance, + long NetworkChange, + long NetworkBalance, + long DiscountChange, + long DiscountBalance, + string Channel, + string Description +); public record WalletWithdrawal(long Id, long WeekDefinitionId, string WeekDisplayName, long Amount, int Status, int? Method, string? Iban, string Created); public enum WithdrawalMethodClient { @@ -52,12 +62,19 @@ public class WalletService request.IsIncrease = isIncrease.Value; } var response = await _client.GetCustomerWalletChangeLogAsync(request); + return response.Models - .Select(t => new WalletTransaction( - ResolveTransactionDate(t), - t.ChangeValue != 0 ? t.ChangeValue : t.CurrentBalance, - t.RefrenceId?.ToString() ?? "-", - ResolveDescription(t))) + .Select(log => new WalletTransaction( + ResolveTransactionDate(log), + log.ChangeValue, + log.CurrentBalance, + log.ChangeNerworkValue, + log.CurrentNetworkBalance, + log.ChangeDiscountValue, + log.CurrentDiscountBalance, + log.RefrenceId?.ToString() ?? "-", + ResolveDescription(log) + )) .OrderByDescending(t => t.Date) .ToList(); } @@ -74,7 +91,8 @@ public class WalletService { try { - return model.CreatedAt.ToDateTime().MiladiToJalaliWithTime(); + var utcDate = model.CreatedAt.ToDateTime(); + return utcDate.ToLocalTime().MiladiToJalaliWithTime(); } catch { @@ -87,9 +105,18 @@ public class WalletService private static string ResolveDescription(CustomerWalletChangeLogModel model) { - if (model.ChangeValue > 0) return "شارژ کیف پول"; - if (model.ChangeValue < 0) return "برداشت/خرید"; - return "تراکنش کیف پول"; + var parts = new List(); + + if (model.ChangeValue != 0) + parts.Add(model.ChangeValue > 0 ? "شارژ عادی" : "برداشت عادی"); + + if (model.ChangeNerworkValue != 0) + parts.Add(model.ChangeNerworkValue > 0 ? "دریافت شبکه" : "برداشت شبکه"); + + if (model.ChangeDiscountValue != 0) + parts.Add(model.ChangeDiscountValue > 0 ? "شارژ تخفیفی" : "خرید تخفیفی"); + + return parts.Count > 0 ? string.Join(" | ", parts) : "تراکنش کیف پول"; } public async Task RequestWithdrawalAsync(long payoutId, WithdrawalMethodClient method, string? iban)