using FluentValidation; using FrontOffice.Main.Pages.Profile.Components; using FrontOffice.Main.Utilities; using Mapster; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using MudBlazor; using System.ComponentModel.DataAnnotations; using CMSMicroservice.Protobuf.Protos.Package; using CMSMicroservice.Protobuf.Protos.User; using CMSMicroservice.Protobuf.Protos.UserAddress; using CMSMicroservice.Protobuf.Validator.User; using CMSMicroservice.Protobuf.Validator.UserAddress; using Severity = MudBlazor.Severity; namespace FrontOffice.Main.Pages.Profile; public partial class Index { [Inject] private UserContract.UserContractClient UserContract { get; set; } = default!; [Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!; [Inject] private PackageContract.PackageContractClient PackageContract { get; set; } = default!; [Inject] private AuthService AuthService { get; set; } = default!; [Inject] private BlogPostService BlogPostService { get; set; } = default!; private GetUserForCustomerResponse _userProfile = new(); private BlogPostCardDto? _latestPost; private UpdateCustomerProfileRequest _updateUserRequest = new(); private MudForm? _personalForm; private bool _isPersonalSaving; private bool _isSettingsSaving; private string _copyMessage = string.Empty; private DateTime? _date; // Referral Link Control private bool _hasPurchasedPackage; private bool _isClubMemberActive; private bool CanShowReferralLink => _hasPurchasedPackage && _isClubMemberActive; // Purchase flow private bool _isProcessingPayment; private int _purchaseCycleCount; // تعداد دورهای خرید — اگر > 0 فقط IPG مجاز // Dashboard Tiles private readonly List _dashTiles = new() { new(RouteConstants.Profile.Personal, Icons.Material.Filled.Person, "اطلاعات شخصی", "نمایش و ویرایش", "background:rgba(99,102,241,.12); color:#6366f1;"), new(RouteConstants.Profile.Addresses, Icons.Material.Filled.LocationOn, "آدرس‌ها", "مدیریت آدرس‌ها", "background:rgba(99,102,241,.12); color:#6366f1;"), new(RouteConstants.Profile.Tree, Icons.Material.Filled.AccountTree, "شجره‌نامه", "ساختار تیم", "background:rgba(99,102,241,.12); color:#6366f1;"), new(RouteConstants.Gateway.StoreChooser, Icons.Material.Filled.Store, "فروشگاه‌ها", "ورود به فروشگاه", "background:rgba(16,185,129,.12); color:#10b981;"), new(RouteConstants.Profile.Wallet, Icons.Material.Filled.AccountBalanceWallet, "کیف پول", "مدیریت و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"), new(RouteConstants.Profile.MagicWallet, Icons.Material.Filled.AutoAwesome, "کیف‌پول جادویی", "شارژ چند‌برابری", "background:rgba(168,85,247,.12); color:#a855f7;"), new(RouteConstants.Profile.WithdrawalRequests, Icons.Material.Filled.RequestPage, "درخواست برداشت", "ثبت و پیگیری", "background:rgba(245,158,11,.12); color:#f59e0b;"), new(RouteConstants.Club.Membership, Icons.Material.Filled.CardMembership, "باشگاه مشتریان", "عضویت و مزایا", "background:rgba(168,85,247,.12); color:#a855f7;"), new(RouteConstants.Network.Statistics, Icons.Material.Filled.Groups, "آمار باشگاه", "جزئیات باشگاه", "background:rgba(59,130,246,.12); color:#3b82f6;"), new(RouteConstants.Commission.Dashboard, Icons.Material.Filled.Payments, "پاداش", "درآمد و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"), }; private record DashTile(string Href, string Icon, string Title, string Subtitle, string AvatarStyle); // Address management private List _addresses = new(); private bool _isLoadingAddresses; private CreateNewUserAddressRequest _newAddressRequest = new(); private UpdateUserAddressRequest _editAddressRequest = new(); private MudForm? _addressForm; private readonly CreateNewUserAddressRequestValidator _addressValidator = new(); protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (firstRender) { // Refresh token to get latest user claims await AuthService.RefreshTokenAsync(); await LoadUserAuthInfo(); await LoadUserProfile(); await LoadAddresses(); await LoadWallet(); await LoadLatestPost(); // نمایش Modal قرارداد باشگاه اگر پکیج خریده ولی باشگاه فعال نشده await CheckAndShowClubContractModal(); } } private async Task LoadUserAuthInfo() { try { var userInfo = await AuthService.GetUserAuthInfo(); _hasPurchasedPackage = userInfo.HasPurchasedPackage; _isClubMemberActive = userInfo.IsClubMemberActive; } catch { _hasPurchasedPackage = false; _isClubMemberActive = false; } StateHasChanged(); } /// /// بررسی و نمایش Modal قرارداد باشگاه مشتریان /// اگر کاربر پکیج خریده ولی هنوز قرارداد باشگاه را امضا نکرده /// private async Task CheckAndShowClubContractModal() { // اگر پکیج خریده ولی باشگاه فعال نیست = باید قرارداد امضا کند if (_hasPurchasedPackage && !_isClubMemberActive) { var options = new DialogOptions { BackdropClick = false, // غیرقابل بسته شدن با کلیک بیرون CloseOnEscapeKey = false, // غیرقابل بسته شدن با Escape CloseButton = false, // بدون دکمه بستن MaxWidth = MaxWidth.Medium, FullWidth = true }; var dialog = await DialogService.ShowAsync( "قرارداد باشگاه مشتریان", options); var result = await dialog.Result; // اگر موفق بود، صفحه را refresh کنیم if (!result.Canceled) { await LoadUserAuthInfo(); StateHasChanged(); } } } private string _walletCredit = "-"; private string _walletDiscount = "-"; private string _walletNetwork = "-"; private async Task LoadWallet() { var b = await WalletService.GetBalancesAsync(); _walletCredit = FormatPrice(b.CreditBalance); var discount = FormatPrice(b.DiscountBalance); _walletNetwork = FormatPrice(b.NetworkBalance); _walletDiscount = discount; // بارگذاری تعداد دورهای خرید برای کنترل روش‌های پرداخت var magicStatus = await WalletService.GetMagicWalletStatusAsync(); _purchaseCycleCount = magicStatus.PurchaseCycleCount; StateHasChanged(); } private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price); private async Task LoadLatestPost() { try { var posts = await BlogPostService.GetFeaturedPostsAsync(1); if (!posts.Any()) { var result = await BlogPostService.GetPublishedPostsAsync(page: 1, pageSize: 1); posts = result.Posts; } _latestPost = posts.FirstOrDefault(); } catch { _latestPost = null; } StateHasChanged(); } private async Task LoadUserProfile() { try { _userProfile = await UserContract.GetUserForCustomerAsync(new()); _updateUserRequest = new UpdateCustomerProfileRequest { FirstName = _userProfile.FirstName, LastName = _userProfile.LastName, Email = _userProfile.Email, NationalCode = _userProfile.NationalCode, }; if (_userProfile.BirthDate != null) { _date = _userProfile.BirthDate.ToDateTime(); _updateUserRequest.BirthDate = _userProfile.BirthDate; } } catch (Exception ex) { // Handle the case when user is not authenticated or API fails _userProfile = new GetUserForCustomerResponse(); } StateHasChanged(); } private async Task SavePersonalInfo() { if (_personalForm is null) return; await _personalForm.Validate(); if (!_personalForm.IsValid) return; _isPersonalSaving = true; try { if (!string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode)) _updateUserRequest.NationalCode = _updateUserRequest.NationalCode.PersianToEnglish(); if (_date != null) _updateUserRequest.BirthDate = _date.Value.DateTimeToTimestamp(); await UserContract.UpdateCustomerProfileAsync(request: _updateUserRequest); await LoadUserProfile(); Snackbar.Add("اطلاعات شخصی با موفقیت ذخیره شد.", Severity.Success); } catch (Exception ex) { Snackbar.Add($"خطا در ذخیره اطلاعات: {ex.Message}", Severity.Error); } finally { _isPersonalSaving = false; await InvokeAsync(StateHasChanged); } } private async Task SaveSettings() { _isSettingsSaving = true; try { await SavePersonalInfo(); } catch (Exception ex) { Snackbar.Add($"خطا در ذخیره تنظیمات: {ex.Message}", Severity.Error); } finally { _isSettingsSaving = false; await InvokeAsync(StateHasChanged); } } private async Task CopyReferralCode() { try { await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", $"{Navigation.BaseUri}?ref={_userProfile.ReferralCode}"); _copyMessage = "کد دعوت کپی شد!"; Snackbar.Add("کد دعوت در کلیپ‌بورد کپی شد.", Severity.Success); // Clear message after 3 seconds await Task.Delay(3000); _copyMessage = string.Empty; await InvokeAsync(StateHasChanged); } catch (Exception ex) { Snackbar.Add("خطا در کپی کردن کد دعوت.", Severity.Error); } } private async Task ShareReferralCode() { var shareText = $"کد دعوت من در کارا بازار سلامت: {_userProfile.ReferralCode}\nبرای عضویت از این لینک استفاده کنید:"; try { // Try to use Web Share API if available await JSRuntime.InvokeVoidAsync("navigator.share", new { title = "کد دعوت کارا بازار سلامت", text = shareText, url = $"{Navigation.BaseUri}?ref={_userProfile.ReferralCode}" }); } catch { // Fallback: copy to clipboard await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", $"{Navigation.BaseUri}?ref={_userProfile.ReferralCode}"); Snackbar.Add("لینک دعوت در کلیپ‌بورد کپی شد.", Severity.Success); } } // Address management methods private async Task LoadAddresses() { _isLoadingAddresses = true; try { var response = await UserAddressContract.GetCustomerAddressesAsync(request: new()); if (response?.Models?.Any() == true) { _addresses = response.Models.ToList(); } else { _addresses = new List(); } } catch (Exception ex) { Snackbar.Add($"خطا در بارگذاری آدرس‌ها: {ex.Message}", Severity.Error); _addresses = new List(); } finally { _isLoadingAddresses = false; await InvokeAsync(StateHasChanged); } } private async Task OpenAddAddressDialog() { var dialog = await DialogService.ShowAsync("افزودن آدرس جدید"); var result = await dialog.Result; if (!result.Canceled) { await LoadAddresses(); } } private async Task OpenEditAddressDialog(CustomerAddressModel address) { var dialog = await DialogService.ShowAsync("ویرایش آدرس", new DialogParameters { { x => x.Model, address } }); var result = await dialog.Result; if (!result.Canceled) { await LoadAddresses(); } } private async Task SetAsDefaultAddress(long addressId) { try { await UserAddressContract.SetAddressAsDefaultAsync(request: new() { Id = addressId }); Snackbar.Add("آدرس پیش‌فرض با موفقیت تغییر کرد.", Severity.Success); await LoadAddresses(); } catch (Exception ex) { Snackbar.Add($"خطا در تغییر آدرس پیش‌فرض: {ex.Message}", Severity.Error); } } private async Task DeleteAddress(long addressId) { var result = await DialogService.ShowMessageBox( "تأیید حذف", "آیا از حذف این آدرس اطمینان دارید؟", yesText: "حذف", cancelText: "لغو"); if (result == true) { try { await UserAddressContract.DeleteUserAddressAsync(request: new() { Id = addressId }); Snackbar.Add("آدرس با موفقیت حذف شد.", Severity.Success); await LoadAddresses(); } catch (Exception ex) { Snackbar.Add($"خطا در حذف آدرس: {ex.Message}", Severity.Error); } } } private async Task OpenPurchaseOptions() { var options = new DialogOptions { MaxWidth = MaxWidth.Small, FullWidth = true, CloseOnEscapeKey = true, BackdropClick = true }; var parameters = new DialogParameters { { x => x.PurchaseCycleCount, _purchaseCycleCount } }; var dialog = await DialogService.ShowAsync( string.Empty, parameters, options); var result = await dialog.Result; if (result.Canceled) return; if (result.Data is Shared.PackagePurchaseDialog.PackagePurchaseResult purchase) { switch (purchase.Method) { case Shared.PackagePurchaseDialog.PaymentMethodType.DirectPayment: await ProcessDirectPayment(purchase.Package.Id); break; case Shared.PackagePurchaseDialog.PaymentMethodType.DayaLoan: await ProcessDayaLoanPayment(); break; } } } private async Task ProcessDirectPayment(long packageId) { if (_isProcessingPayment) return; _isProcessingPayment = true; StateHasChanged(); try { var callbackUrl = $"{Navigation.BaseUri}profile/payment-callback"; var response = await PackageContract.CustomerPurchasePackageAsync(new CustomerPurchasePackageRequest { PackageId = packageId, CallbackUrl = callbackUrl, PurchaseMethod = PurchaseMethodEnum.PurchaseMethodGateway }); if (!response.Success) { Snackbar.Add(response.Message ?? "خطا در آغاز فرآیند پرداخت", Severity.Error); return; } if (!string.IsNullOrEmpty(response.PaymentGatewayUrl)) { Navigation.NavigateTo(response.PaymentGatewayUrl, forceLoad: true); } else { Snackbar.Add("خطا در دریافت آدرس درگاه پرداخت", Severity.Error); } } catch (Exception ex) { Snackbar.Add($"خطا در فرآیند پرداخت: {ex.Message}", Severity.Error); } finally { _isProcessingPayment = false; await InvokeAsync(StateHasChanged); } } private async Task ProcessDayaLoanPayment() { if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName)) { Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error); return; } if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName)) { Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error); return; } if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode)) { Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error); return; } if (_updateUserRequest.BirthDate == null) { Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error); return; } if (!_addresses.Any()) { Snackbar.Add("آدرس محل سکونت شما الزامی است!", Severity.Error); return; } var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364"; await JSRuntime.InvokeVoidAsync("open", url, "_blank"); } }