diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj
index 2431952..ed49ccd 100644
--- a/src/FrontOffice.Main/FrontOffice.Main.csproj
+++ b/src/FrontOffice.Main/FrontOffice.Main.csproj
@@ -14,7 +14,7 @@
-
+
@@ -34,6 +34,11 @@
+
+
+
+
+
diff --git a/src/FrontOffice.Main/Pages/Club/Components/ActivationSection.razor.cs b/src/FrontOffice.Main/Pages/Club/Components/ActivationSection.razor.cs
index dd7391c..2a9b0e3 100644
--- a/src/FrontOffice.Main/Pages/Club/Components/ActivationSection.razor.cs
+++ b/src/FrontOffice.Main/Pages/Club/Components/ActivationSection.razor.cs
@@ -1,4 +1,5 @@
using FrontOffice.Main.Utilities;
+using FrontOffice.BFF.User.Protobuf.Protos.User;
using Microsoft.AspNetCore.Components;
using MudBlazor;
@@ -7,6 +8,8 @@ namespace FrontOffice.Main.Pages.Club.Components;
public partial class ActivationSection : ComponentBase
{
[Inject] private ClubMembershipService ClubService { get; set; } = default!;
+ [Inject] private AuthService AuthService { get; set; } = default!;
+ [Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
[Parameter] public EventCallback OnActivationSuccess { get; set; }
@@ -39,6 +42,19 @@ public partial class ActivationSection : ComponentBase
if (result.Success)
{
Snackbar.Add($"عضویت فعال شد! مبلغ پرداختی: {result.AmountPaid:N0} تومان", Severity.Success);
+
+ // Refresh Token to update Claims (IsClubMemberActive, HasPurchasedPackage)
+ try
+ {
+ var userResponse = await UserContract.GetUserAsync(new());
+ await AuthService.InitUserAuthInfo();
+ }
+ catch
+ {
+ // Token refresh failed but activation succeeded
+ Snackbar.Add("لطفاً مجدداً وارد شوید تا تغییرات اعمال شود.", Severity.Warning);
+ }
+
await OnActivationSuccess.InvokeAsync();
}
else
diff --git a/src/FrontOffice.Main/Pages/Profile/Index.razor b/src/FrontOffice.Main/Pages/Profile/Index.razor
index 922c64e..16783bc 100644
--- a/src/FrontOffice.Main/Pages/Profile/Index.razor
+++ b/src/FrontOffice.Main/Pages/Profile/Index.razor
@@ -21,43 +21,74 @@
- تامین اعتبار خرید
+ @* تامین اعتبار *@
-
-
- کد دعوت شما
-
-
- اشتراکگذاری
-
-
-
- این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
-
+
+ @if (CanShowReferralLink)
+ {
+
+
+ کد دعوت شما
+
+
+ اشتراکگذاری
+
+
+
+ این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
+
-
-
-
+
+
+
- @if (!string.IsNullOrWhiteSpace(_copyMessage))
- {
- @(_copyMessage)
- }
-
+ @if (!string.IsNullOrWhiteSpace(_copyMessage))
+ {
+ @(_copyMessage)
+ }
+
+ }
+ else
+ {
+
+
+
+
+ لینک دعوت شما هنوز فعال نشده است
+
+
+ برای فعالسازی لینک دعوت و دعوت دوستان خود به جمع مشتریان ویژه کارابازار، کافی است ابتدا پکیج پایه ۵۶ میلیونی را تهیه کنید و سپس در باشگاه مشتریان عضو شوید.
+
+
+ پس از تکمیل این مراحل، میتوانید از مزایای ویژه عضویت در شبکه فروش بهرهمند شده و با معرفی دوستان، کمیسیون دریافت کنید.
+
+
+ شروع فرآیند تامین اعتبار
+
+
+
+ }
@@ -199,3 +230,67 @@
+
+
+
+
+
+
+ خرید پکیج پایه ۵۶ میلیون تومان
+
+
+
+
+
+ برای خرید پکیج پایه، یکی از روشهای زیر را انتخاب کنید:
+
+
+
+
+
+
+
+ پرداخت مستقیم
+
+
+ پرداخت آنی از طریق درگاه بانکی
+
+
+ پرداخت با کارت بانکی
+
+
+
+
+
+
+
+
+
+ اعتبار الماسی دایا
+
+
+ تأمین اعتبار از طریق خرید توکن الماس و دریافت وام
+
+
+ تأمین اعتبار الماسی
+
+
+
+
+
+ بستن
+
+
+
+
diff --git a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs
index e63b83f..e7e84a7 100644
--- a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs
+++ b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs
@@ -3,6 +3,7 @@ using FrontOffice.BFF.User.Protobuf.Protos.User;
using FrontOffice.BFF.User.Protobuf.Validator;
using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress;
using FrontOffice.BFF.UserAddress.Protobuf.Validator;
+using FrontOffice.BFF.Package.Protobuf.Protos.Package;
using FrontOffice.Main.Pages.Profile.Components;
using FrontOffice.Main.Utilities;
using Mapster;
@@ -18,6 +19,8 @@ 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!;
private GetUserResponse _userProfile = new();
private UpdateUserRequest _updateUserRequest = new();
@@ -32,6 +35,15 @@ public partial class Index
private DateTime? _date;
+ // Referral Link Control
+ private bool _hasPurchasedPackage;
+ private bool _isClubMemberActive;
+ private bool CanShowReferralLink => _hasPurchasedPackage && _isClubMemberActive;
+
+ // Purchase Options Bottom Sheet
+ private bool _showPurchaseBottomSheet;
+ private bool _isProcessingPayment;
+
// Address management
private List _addresses = new();
private bool _isLoadingAddresses;
@@ -44,12 +56,29 @@ public partial class Index
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
+ await LoadUserAuthInfo();
await LoadUserProfile();
await LoadAddresses();
await LoadWallet();
}
}
+ private async Task LoadUserAuthInfo()
+ {
+ try
+ {
+ var userInfo = await AuthService.GetUserAuthInfo();
+ _hasPurchasedPackage = userInfo.HasPurchasedPackage;
+ _isClubMemberActive = userInfo.IsClubMemberActive;
+ }
+ catch
+ {
+ _hasPurchasedPackage = false;
+ _isClubMemberActive = false;
+ }
+ StateHasChanged();
+ }
+
private string _walletCredit = "-";
private string _walletDiscount = "-";
private string _walletNetwork = "-";
@@ -272,33 +301,96 @@ public partial class Index
}
}
- private async Task Financing()
+ private void OpenPurchaseOptions()
{
+ _showPurchaseBottomSheet = true;
+ }
+
+ private void ClosePurchaseOptions()
+ {
+ _showPurchaseBottomSheet = false;
+ }
+
+ private async Task DirectPayment()
+ {
+ if (_isProcessingPayment) return;
+
+ _isProcessingPayment = true;
+ _showPurchaseBottomSheet = false;
+
+ try
+ {
+ // Create callback URL for payment verification
+ var callbackUrl = $"{Navigation.BaseUri}profile/payment-callback";
+
+ // Call BFF to initiate payment (UserId is taken from JWT token in BFF)
+ var response = await PackageContract.InitiateBasePackagePaymentAsync(new InitiateBasePackagePaymentRequest
+ {
+ CallbackUrl = callbackUrl
+ });
+
+ if (!response.Success)
+ {
+ Snackbar.Add(response.Message ?? "خطا در آغاز فرآیند پرداخت", Severity.Error);
+ return;
+ }
+
+ // Redirect to payment gateway
+ 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 DayaLoanPayment()
+ {
+ // Validate user info before redirecting
if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName))
{
+ _showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
return;
}
if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName))
{
+ _showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
return;
}
if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode))
{
+ _showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
return;
}
if (_updateUserRequest.BirthDate == null)
{
+ _showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
return;
}
if (!_addresses.Any())
{
- Snackbar.Add($"آدرس محل سکونت شما الزمای است!", Severity.Error);
+ _showPurchaseBottomSheet = false;
+ Snackbar.Add($"آدرس محل سکونت شما الزامی است!", Severity.Error);
return;
}
+
+ _showPurchaseBottomSheet = false;
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
}
diff --git a/src/FrontOffice.Main/Pages/Profile/PaymentCallback.razor b/src/FrontOffice.Main/Pages/Profile/PaymentCallback.razor
new file mode 100644
index 0000000..7aad246
--- /dev/null
+++ b/src/FrontOffice.Main/Pages/Profile/PaymentCallback.razor
@@ -0,0 +1,174 @@
+@page "/profile/payment-callback"
+@attribute [Authorize]
+@using Blazored.LocalStorage
+@using FrontOffice.BFF.Package.Protobuf.Protos.Package
+@using FrontOffice.BFF.User.Protobuf.Protos.User
+
+نتیجه پرداخت | کارا بازار سلامت
+
+
+
+ @if (_isLoading)
+ {
+
+ در حال بررسی وضعیت پرداخت...
+ }
+ else if (_isSuccess)
+ {
+
+ پرداخت موفق
+ @_message
+
+ @if (!string.IsNullOrEmpty(_refId))
+ {
+
+ کد پیگیری: @_refId
+
+ }
+
+
+
+
+ موجودی کیف پول: @FormatPrice(_walletBalance)
+
+
+ موجودی اعتبار تخفیف: @FormatPrice(_discountBalance)
+
+
+
+ بازگشت به پروفایل
+
+ }
+ else
+ {
+
+ پرداخت ناموفق
+ @_message
+
+
+ بازگشت به پروفایل
+
+
+
+ تلاش مجدد
+
+ }
+
+
+
+@code {
+ [Inject] private PackageContract.PackageContractClient PackageContractClient { get; set; } = default!;
+ [Inject] private UserContract.UserContractClient UserContractClient { get; set; } = default!;
+ [Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
+ [Inject] private AuthService AuthService { get; set; } = default!;
+ [Inject] private NavigationManager NavManager { get; set; } = default!;
+
+ private const string TokenStorageKey = "auth:token";
+
+ [SupplyParameterFromQuery(Name = "orderId")]
+ private long OrderId { get; set; }
+
+ [SupplyParameterFromQuery(Name = "transactionId")]
+ private long TransactionId { get; set; }
+
+ [SupplyParameterFromQuery(Name = "Authority")]
+ private string? Authority { get; set; }
+
+ [SupplyParameterFromQuery(Name = "Status")]
+ private string? Status { get; set; }
+
+ private bool _isLoading = true;
+ private bool _isSuccess;
+ private string _message = string.Empty;
+ private string? _refId;
+ private long _walletBalance;
+ private long _discountBalance;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ await VerifyPayment();
+ }
+ }
+
+ private async Task VerifyPayment()
+ {
+ try
+ {
+ if (OrderId <= 0 || TransactionId <= 0 || string.IsNullOrEmpty(Authority))
+ {
+ _isSuccess = false;
+ _message = "پارامترهای پرداخت نامعتبر است";
+ _isLoading = false;
+ StateHasChanged();
+ return;
+ }
+
+ var response = await PackageContractClient.VerifyBasePackagePaymentAsync(new VerifyBasePackagePaymentRequest
+ {
+ OrderId = OrderId,
+ TransactionId = TransactionId,
+ Authority = Authority,
+ Status = Status ?? "NOK"
+ });
+
+ _isSuccess = response.Success;
+ _message = response.Message;
+ _refId = response.RefId;
+ _walletBalance = response.WalletBalance;
+ _discountBalance = response.DiscountBalance;
+
+ // اگر پرداخت موفق بود، توکن را refresh میکنیم
+ // چون PackagePurchaseMethod تغییر کرده و باید در claims جدید باشد
+ if (_isSuccess)
+ {
+ await RefreshTokenAsync();
+ }
+ }
+ catch (Exception ex)
+ {
+ _isSuccess = false;
+ _message = $"خطا در بررسی وضعیت پرداخت: {ex.Message}";
+ }
+ finally
+ {
+ _isLoading = false;
+ StateHasChanged();
+ }
+ }
+
+ private void RetryPayment()
+ {
+ NavManager.NavigateTo("/profile");
+ }
+
+ ///
+ /// Refresh token after successful payment to update PackagePurchaseMethod claim
+ ///
+ private async Task RefreshTokenAsync()
+ {
+ try
+ {
+ var userResponse = await UserContractClient.GetUserAsync(new Google.Protobuf.WellKnownTypes.Empty());
+ if (!string.IsNullOrWhiteSpace(userResponse.Token))
+ {
+ // ذخیره توکن جدید در localStorage
+ await LocalStorage.SetItemAsync(TokenStorageKey, userResponse.Token);
+
+ // بهروزرسانی UserAuthInfo با claims جدید
+ await AuthService.InitUserAuthInfo();
+ }
+ }
+ catch
+ {
+ // اگر refresh ناموفق بود، پرداخت همچنان موفق است
+ // کاربر میتواند با logout/login دوباره token جدید بگیرد
+ }
+ }
+
+ private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
+}
diff --git a/src/FrontOffice.Main/Utilities/AuthService.cs b/src/FrontOffice.Main/Utilities/AuthService.cs
index 8aa08a9..3eaac1a 100644
--- a/src/FrontOffice.Main/Utilities/AuthService.cs
+++ b/src/FrontOffice.Main/Utilities/AuthService.cs
@@ -60,16 +60,23 @@ public class AuthService
{
var claims = await GetTokenClaimsAsync();
_userAuthInfo.UserClaims= claims;
+ var userIdStr = claims.FirstOrDefault(c => c.key == "UserId" || c.key == "sub" || c.key == "nameid").value;
var firstName = claims.FirstOrDefault(c => c.key == "FirstName").value;
var lastName = claims.FirstOrDefault(c => c.key == "LastName").value;
var nationalCode = claims.FirstOrDefault(c => c.key == "NationalCode").value;
var mobileNumber = claims.FirstOrDefault(c => c.key == "MobileNumber").value;
var isSignMainContractStr = claims.FirstOrDefault(c => c.key == "IsSignMainContract").value;
+ var hasPurchasedPackageStr = claims.FirstOrDefault(c => c.key == "HasPurchasedPackage").value;
+ var isClubMemberActiveStr = claims.FirstOrDefault(c => c.key == "IsClubMemberActive").value;
+
+ _userAuthInfo.UserId = long.TryParse(userIdStr, out var userId) ? userId : 0;
_userAuthInfo.FirstName = firstName ?? string.Empty;
_userAuthInfo.LastName = lastName ?? string.Empty;
_userAuthInfo.NationalCode = nationalCode ?? string.Empty;
_userAuthInfo.MobileNumber = mobileNumber ?? string.Empty;
_userAuthInfo.IsSignMainContract = bool.TryParse(isSignMainContractStr, out var isSignMainContract) && isSignMainContract;
+ _userAuthInfo.HasPurchasedPackage = bool.TryParse(hasPurchasedPackageStr, out var hasPurchased) && hasPurchased;
+ _userAuthInfo.IsClubMemberActive = bool.TryParse(isClubMemberActiveStr, out var isClubActive) && isClubActive;
}
private async Task?> GetTokenClaimsAsync()
diff --git a/src/FrontOffice.Main/Utilities/UserAuthInfo.cs b/src/FrontOffice.Main/Utilities/UserAuthInfo.cs
index b73845d..32ae68e 100644
--- a/src/FrontOffice.Main/Utilities/UserAuthInfo.cs
+++ b/src/FrontOffice.Main/Utilities/UserAuthInfo.cs
@@ -3,9 +3,12 @@ namespace FrontOffice.Main.Utilities;
public class UserAuthInfo
{
public List<(string key, string value)> UserClaims { get; set; }
+ public long UserId { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? NationalCode { get; set; }
public string? MobileNumber { get; set; }
public bool IsSignMainContract { get; set; }
+ public bool HasPurchasedPackage { get; set; }
+ public bool IsClubMemberActive { get; set; }
}
\ No newline at end of file