feat: add payment callback and referral link features
Build and Deploy / build (push) Failing after 1m21s

This commit is contained in:
masoodafar-web
2025-12-16 02:33:56 +03:30
parent 3c528aba48
commit 3af564be73
7 changed files with 425 additions and 33 deletions
+6 -1
View File
@@ -14,7 +14,7 @@
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" /> <PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" />
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" /> <PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" />
<PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" /> <PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" />
<PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.113" /> <!-- <PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.113" /> -->
<PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.17" /> <PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.17" />
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.112" /> <PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.112" />
<PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.13" /> <PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.13" />
@@ -34,6 +34,11 @@
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
</ItemGroup> </ItemGroup>
<!-- Local Proto Project Reference for development -->
<ItemGroup>
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />
</ItemGroup>
<!-- New Proto Projects (local references until NuGet publish) --> <!-- New Proto Projects (local references until NuGet publish) -->
<!-- <ItemGroup>--> <!-- <ItemGroup>-->
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />--> <!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />-->
@@ -1,4 +1,5 @@
using FrontOffice.Main.Utilities; using FrontOffice.Main.Utilities;
using FrontOffice.BFF.User.Protobuf.Protos.User;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using MudBlazor; using MudBlazor;
@@ -7,6 +8,8 @@ namespace FrontOffice.Main.Pages.Club.Components;
public partial class ActivationSection : ComponentBase public partial class ActivationSection : ComponentBase
{ {
[Inject] private ClubMembershipService ClubService { get; set; } = default!; [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; } [Parameter] public EventCallback OnActivationSuccess { get; set; }
@@ -39,6 +42,19 @@ public partial class ActivationSection : ComponentBase
if (result.Success) if (result.Success)
{ {
Snackbar.Add($"عضویت فعال شد! مبلغ پرداختی: {result.AmountPaid:N0} تومان", Severity.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(); await OnActivationSuccess.InvokeAsync();
} }
else else
+125 -30
View File
@@ -21,43 +21,74 @@
</div> </div>
</MudStack> </MudStack>
<MudSpacer/> <MudSpacer/>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Financing">تامین اعتبار خرید</MudButton> @* <MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.ShoppingCart"
OnClick="OpenPurchaseOptions">تامین اعتبار</MudButton> *@
</MudStack> </MudStack>
<!-- Referral Code Section --> <!-- Referral Code Section -->
<MudDivider /> <MudDivider />
<MudStack Spacing="3">
<MudStack Row="true" AlignItems="AlignItems.Center">
<MudText Typo="Typo.subtitle1">کد دعوت شما</MudText>
<MudSpacer />
<MudButton Variant="Variant.Outlined"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Share"
OnClick="ShareReferralCode">
اشتراک‌گذاری
</MudButton>
</MudStack>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
</MudText>
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center"> @if (CanShowReferralLink)
<MudTextField @bind-Value="_userProfile.ReferralCode" {
Label="کد دعوت" <MudStack Spacing="3">
Variant="Variant.Outlined" <MudStack Row="true" AlignItems="AlignItems.Center">
ReadOnly="true" <MudText Typo="Typo.subtitle1">کد دعوت شما</MudText>
Class="flex-grow-1" <MudSpacer />
Adornment="Adornment.End" <MudButton Variant="Variant.Outlined"
AdornmentIcon="@Icons.Material.Filled.ContentCopy" Color="Color.Primary"
OnAdornmentClick="CopyReferralCode" /> StartIcon="@Icons.Material.Filled.Share"
</MudStack> OnClick="ShareReferralCode">
اشتراک‌گذاری
</MudButton>
</MudStack>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
</MudText>
@if (!string.IsNullOrWhiteSpace(_copyMessage)) <MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
{ <MudTextField @bind-Value="_userProfile.ReferralCode"
<MudText Typo="Typo.caption" Color="Color.Success">@(_copyMessage)</MudText> Label="کد دعوت"
} Variant="Variant.Outlined"
</MudStack> ReadOnly="true"
Class="flex-grow-1"
Adornment="Adornment.End"
AdornmentIcon="@Icons.Material.Filled.ContentCopy"
OnAdornmentClick="CopyReferralCode" />
</MudStack>
@if (!string.IsNullOrWhiteSpace(_copyMessage))
{
<MudText Typo="Typo.caption" Color="Color.Success">@(_copyMessage)</MudText>
}
</MudStack>
}
else
{
<MudPaper Class="my-3 pa-3 border border-secondary">
<MudStack Spacing="3" AlignItems="AlignItems.Center">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Large" Color="Color.Info" />
<MudText Typo="Typo.h6" Align="Align.Center" Color="Color.Info">
لینک دعوت شما هنوز فعال نشده است
</MudText>
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary">
برای فعال‌سازی لینک دعوت و دعوت دوستان خود به جمع مشتریان ویژه کارابازار، کافی است ابتدا <strong>پکیج پایه ۵۶ میلیونی</strong> را تهیه کنید و سپس در <strong>باشگاه مشتریان</strong> عضو شوید.
</MudText>
<MudText Typo="Typo.body2" Align="Align.Center" Class="mud-text-secondary">
پس از تکمیل این مراحل، می‌توانید از مزایای ویژه عضویت در شبکه فروش بهره‌مند شده و با معرفی دوستان، کمیسیون دریافت کنید.
</MudText>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Size="Size.Large"
StartIcon="@Icons.Material.Filled.ShoppingCart"
OnClick="OpenPurchaseOptions">
شروع فرآیند تامین اعتبار
</MudButton>
</MudStack>
</MudPaper>
}
</MudStack> </MudStack>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
@@ -199,3 +230,67 @@
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudContainer> </MudContainer>
<!-- Purchase Options Bottom Sheet -->
<MudDialog @bind-Visible="_showPurchaseBottomSheet">
<DialogContent>
<MudStack Spacing="3" Class="pa-2">
<MudText Typo="Typo.h6" Align="Align.Center">
خرید پکیج پایه ۵۶ میلیون تومان
</MudText>
<MudDivider />
<MudText Typo="Typo.body2" Class="mud-text-secondary">
برای خرید پکیج پایه، یکی از روش‌های زیر را انتخاب کنید:
</MudText>
<!-- Direct Payment Option -->
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-primary);">
<MudStack Spacing="2">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.CreditCard" Color="Color.Primary" Size="Size.Medium" />
<MudText Typo="Typo.subtitle1" Color="Color.Primary"><b>پرداخت مستقیم</b></MudText>
</MudStack>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
پرداخت آنی از طریق درگاه بانکی
</MudText>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
FullWidth="true"
StartIcon="@Icons.Material.Filled.Payment"
OnClick="DirectPayment">
پرداخت با کارت بانکی
</MudButton>
</MudStack>
</MudPaper>
<!-- Daya Loan Option -->
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-tertiary);">
<MudStack Spacing="2">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.Diamond" Color="Color.Tertiary" Size="Size.Medium" />
<MudText Typo="Typo.subtitle1" Color="Color.Tertiary"><b>اعتبار الماسی دایا</b></MudText>
</MudStack>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
تأمین اعتبار از طریق خرید توکن الماس و دریافت وام
</MudText>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
FullWidth="true"
StartIcon="@Icons.Material.Filled.AccountBalance"
OnClick="DayaLoanPayment">
تأمین اعتبار الماسی
</MudButton>
</MudStack>
</MudPaper>
<MudButton Variant="Variant.Text"
Color="Color.Default"
FullWidth="true"
OnClick="ClosePurchaseOptions">
بستن
</MudButton>
</MudStack>
</DialogContent>
</MudDialog>
@@ -3,6 +3,7 @@ using FrontOffice.BFF.User.Protobuf.Protos.User;
using FrontOffice.BFF.User.Protobuf.Validator; using FrontOffice.BFF.User.Protobuf.Validator;
using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress; using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress;
using FrontOffice.BFF.UserAddress.Protobuf.Validator; using FrontOffice.BFF.UserAddress.Protobuf.Validator;
using FrontOffice.BFF.Package.Protobuf.Protos.Package;
using FrontOffice.Main.Pages.Profile.Components; using FrontOffice.Main.Pages.Profile.Components;
using FrontOffice.Main.Utilities; using FrontOffice.Main.Utilities;
using Mapster; using Mapster;
@@ -18,6 +19,8 @@ public partial class Index
{ {
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!; [Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { 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 GetUserResponse _userProfile = new();
private UpdateUserRequest _updateUserRequest = new(); private UpdateUserRequest _updateUserRequest = new();
@@ -32,6 +35,15 @@ public partial class Index
private DateTime? _date; 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 // Address management
private List<GetAllUserAddressByFilterResponseModel> _addresses = new(); private List<GetAllUserAddressByFilterResponseModel> _addresses = new();
private bool _isLoadingAddresses; private bool _isLoadingAddresses;
@@ -44,12 +56,29 @@ public partial class Index
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
if (firstRender) if (firstRender)
{ {
await LoadUserAuthInfo();
await LoadUserProfile(); await LoadUserProfile();
await LoadAddresses(); await LoadAddresses();
await LoadWallet(); 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 _walletCredit = "-";
private string _walletDiscount = "-"; private string _walletDiscount = "-";
private string _walletNetwork = "-"; 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)) if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName))
{ {
_showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error); Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
return; return;
} }
if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName)) if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName))
{ {
_showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error); Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
return; return;
} }
if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode)) if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode))
{ {
_showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error); Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
return; return;
} }
if (_updateUserRequest.BirthDate == null) if (_updateUserRequest.BirthDate == null)
{ {
_showPurchaseBottomSheet = false;
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error); Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
return; return;
} }
if (!_addresses.Any()) if (!_addresses.Any())
{ {
Snackbar.Add($"آدرس محل سکونت شما الزمای است!", Severity.Error); _showPurchaseBottomSheet = false;
Snackbar.Add($"آدرس محل سکونت شما الزامی است!", Severity.Error);
return; return;
} }
_showPurchaseBottomSheet = false;
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364"; var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
await JSRuntime.InvokeVoidAsync("open", url, "_blank"); await JSRuntime.InvokeVoidAsync("open", url, "_blank");
} }
@@ -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
<PageTitle>نتیجه پرداخت | کارا بازار سلامت</PageTitle>
<MudContainer MaxWidth="MaxWidth.Small" Class="py-8">
<MudPaper Class="pa-6 text-center">
@if (_isLoading)
{
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
<MudText Typo="Typo.h6" Class="mt-4">در حال بررسی وضعیت پرداخت...</MudText>
}
else if (_isSuccess)
{
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Large" Style="font-size: 80px" />
<MudText Typo="Typo.h5" Color="Color.Success" Class="mt-4">پرداخت موفق</MudText>
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
@if (!string.IsNullOrEmpty(_refId))
{
<MudText Typo="Typo.body2" Class="mt-3">
<strong>کد پیگیری:</strong> @_refId
</MudText>
}
<MudDivider Class="my-4" />
<MudText Typo="Typo.body2" Color="Color.Secondary">
موجودی کیف پول: @FormatPrice(_walletBalance)
</MudText>
<MudText Typo="Typo.body2" Color="Color.Secondary">
موجودی اعتبار تخفیف: @FormatPrice(_discountBalance)
</MudText>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
Href="/profile">
بازگشت به پروفایل
</MudButton>
}
else
{
<MudIcon Icon="@Icons.Material.Filled.Error" Color="Color.Error" Size="Size.Large" Style="font-size: 80px" />
<MudText Typo="Typo.h5" Color="Color.Error" Class="mt-4">پرداخت ناموفق</MudText>
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
Href="/profile">
بازگشت به پروفایل
</MudButton>
<MudButton Color="Color.Secondary" Variant="Variant.Outlined" Class="mt-3 mr-2"
OnClick="RetryPayment">
تلاش مجدد
</MudButton>
}
</MudPaper>
</MudContainer>
@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");
}
/// <summary>
/// Refresh token after successful payment to update PackagePurchaseMethod claim
/// </summary>
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);
}
@@ -60,16 +60,23 @@ public class AuthService
{ {
var claims = await GetTokenClaimsAsync(); var claims = await GetTokenClaimsAsync();
_userAuthInfo.UserClaims= claims; _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 firstName = claims.FirstOrDefault(c => c.key == "FirstName").value;
var lastName = claims.FirstOrDefault(c => c.key == "LastName").value; var lastName = claims.FirstOrDefault(c => c.key == "LastName").value;
var nationalCode = claims.FirstOrDefault(c => c.key == "NationalCode").value; var nationalCode = claims.FirstOrDefault(c => c.key == "NationalCode").value;
var mobileNumber = claims.FirstOrDefault(c => c.key == "MobileNumber").value; var mobileNumber = claims.FirstOrDefault(c => c.key == "MobileNumber").value;
var isSignMainContractStr = claims.FirstOrDefault(c => c.key == "IsSignMainContract").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.FirstName = firstName ?? string.Empty;
_userAuthInfo.LastName = lastName ?? string.Empty; _userAuthInfo.LastName = lastName ?? string.Empty;
_userAuthInfo.NationalCode = nationalCode ?? string.Empty; _userAuthInfo.NationalCode = nationalCode ?? string.Empty;
_userAuthInfo.MobileNumber = mobileNumber ?? string.Empty; _userAuthInfo.MobileNumber = mobileNumber ?? string.Empty;
_userAuthInfo.IsSignMainContract = bool.TryParse(isSignMainContractStr, out var isSignMainContract) && isSignMainContract; _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<List<(string key, string value)>?> GetTokenClaimsAsync() private async Task<List<(string key, string value)>?> GetTokenClaimsAsync()
@@ -3,9 +3,12 @@ namespace FrontOffice.Main.Utilities;
public class UserAuthInfo public class UserAuthInfo
{ {
public List<(string key, string value)> UserClaims { get; set; } public List<(string key, string value)> UserClaims { get; set; }
public long UserId { get; set; }
public string? FirstName { get; set; } public string? FirstName { get; set; }
public string? LastName { get; set; } public string? LastName { get; set; }
public string? NationalCode { get; set; } public string? NationalCode { get; set; }
public string? MobileNumber { get; set; } public string? MobileNumber { get; set; }
public bool IsSignMainContract { get; set; } public bool IsSignMainContract { get; set; }
public bool HasPurchasedPackage { get; set; }
public bool IsClubMemberActive { get; set; }
} }