feat: add payment callback and referral link features
Build and Deploy / build (push) Failing after 1m21s
Build and Deploy / build (push) Failing after 1m21s
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -21,12 +21,18 @@
|
|||||||
</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 />
|
||||||
|
|
||||||
|
@if (CanShowReferralLink)
|
||||||
|
{
|
||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||||
<MudText Typo="Typo.subtitle1">کد دعوت شما</MudText>
|
<MudText Typo="Typo.subtitle1">کد دعوت شما</MudText>
|
||||||
@@ -58,6 +64,31 @@
|
|||||||
<MudText Typo="Typo.caption" Color="Color.Success">@(_copyMessage)</MudText>
|
<MudText Typo="Typo.caption" Color="Color.Success">@(_copyMessage)</MudText>
|
||||||
}
|
}
|
||||||
</MudStack>
|
</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; }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user