Compare commits

...

2 Commits

Author SHA1 Message Date
masoodafar-web 9203dc7924 Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Successful in 6m24s
2026-08-07 14:38:22 +03:30
masoodafar-web b64d99c5b3 feat(profile): enhance ChargeCreditWallet and Wallet components with club membership checks
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 4m42s
- Added logic to display alerts and buttons based on club membership status in the ChargeCreditWallet and Wallet components.
- Implemented user authentication checks to determine if the user is a club member and has purchased a package before allowing wallet charging.
- Updated UI to guide users on purchasing packages or signing club contracts if they are not eligible to charge their wallet.

These changes improve user experience by providing clear instructions and preventing unauthorized wallet charges.
2026-08-06 23:59:42 +03:30
6 changed files with 209 additions and 22 deletions
@@ -35,6 +35,40 @@
</MudAlert>
}
@if (_authLoaded && !_isClubMemberActive)
{
<MudAlert Severity="MudBlazor.Severity.Warning" Class="rounded-lg" Variant="Variant.Outlined">
<MudStack Spacing="2">
<MudText>
برای شارژ کیف پول اصلی ابتدا باید پکیج را خریداری کرده و قرارداد باشگاه مشتریان را امضا کنید.
</MudText>
<MudStack Row="true" Spacing="1" Class="flex-wrap">
@if (!_hasPurchasedPackage)
{
<MudButton Size="Size.Small" Variant="Variant.Filled" Color="Color.Primary"
Href="@RouteConstants.Package.List"
StartIcon="@Icons.Material.Filled.CardGiftcard">
مشاهده پکیج‌ها
</MudButton>
}
else
{
<MudButton Size="Size.Small" Variant="Variant.Filled" Color="Color.Primary"
Href="@RouteConstants.Club.Membership"
StartIcon="@Icons.Material.Filled.Handshake">
امضای قرارداد باشگاه
</MudButton>
}
<MudButton Size="Size.Small" Variant="Variant.Text"
Href="@RouteConstants.Profile.Wallet">
بازگشت به کیف پول
</MudButton>
</MudStack>
</MudStack>
</MudAlert>
}
else if (_authLoaded)
{
<MudPaper Elevation="2" Class="pa-5 rounded-lg">
<MudText Typo="Typo.h6" Class="mb-3">
<MudIcon Icon="@Icons.Material.Filled.AccountBalanceWallet" Class="ml-1" />
@@ -122,5 +156,6 @@
</MudList>
</MudExpansionPanel>
</MudExpansionPanels>
}
</MudStack>
</MudContainer>
@@ -7,10 +7,15 @@ namespace FrontOffice.Main.Pages.Profile;
public partial class ChargeCreditWallet : ComponentBase
{
[Inject] private AuthService AuthService { get; set; } = default!;
private bool _isProcessing;
private long _chargeAmount;
private string? _paymentResult;
private string? _pendingReturnUrl;
private bool _isClubMemberActive;
private bool _hasPurchasedPackage;
private bool _authLoaded;
private readonly long[] _presetAmounts = { 500_000, 1_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000 };
@@ -23,7 +28,7 @@ public partial class ChargeCreditWallet : ComponentBase
[SupplyParameterFromQuery(Name = "returnUrl")]
public string? ReturnUrlQueryParam { get; set; }
protected override void OnInitialized()
protected override async Task OnInitializedAsync()
{
_paymentResult = PaymentQueryParam;
@@ -32,11 +37,27 @@ public partial class ChargeCreditWallet : ComponentBase
if (CreditChargeNavigation.IsValidReturnUrl(ReturnUrlQueryParam))
_pendingReturnUrl = ReturnUrlQueryParam;
try
{
var userInfo = await AuthService.GetUserAuthInfo();
_isClubMemberActive = userInfo.IsClubMemberActive;
_hasPurchasedPackage = userInfo.HasPurchasedPackage;
}
catch
{
_isClubMemberActive = false;
_hasPurchasedPackage = false;
}
finally
{
_authLoaded = true;
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl))
if (firstRender && !string.IsNullOrEmpty(_pendingReturnUrl) && _isClubMemberActive)
{
await CreditChargeNavigation.SaveReturnUrlAsync(JSRuntime, _pendingReturnUrl);
}
@@ -46,6 +67,14 @@ public partial class ChargeCreditWallet : ComponentBase
private async Task StartCreditCharge()
{
if (!_isClubMemberActive)
{
Snackbar.Add(
"برای شارژ کیف پول اصلی ابتدا باید پکیج را خریداری کرده و قرارداد باشگاه مشتریان را امضا کنید.",
Severity.Warning);
return;
}
if (_chargeAmount <= 0 || _isProcessing) return;
_isProcessing = true;
@@ -39,15 +39,55 @@
</MudButton>
<!-- دکمه شارژ کیف‌پول اصلی -->
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Size="Size.Large"
FullWidth="true"
StartIcon="@Icons.Material.Filled.AccountBalanceWallet"
Href="@RouteConstants.Profile.ChargeCreditWallet"
Class="rounded-lg">
شارژ کیف‌پول اصلی
</MudButton>
@if (_isClubMemberActive)
{
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Size="Size.Large"
FullWidth="true"
StartIcon="@Icons.Material.Filled.AccountBalanceWallet"
Href="@RouteConstants.Profile.ChargeCreditWallet"
Class="rounded-lg">
شارژ کیف‌پول اصلی
</MudButton>
}
else
{
<MudPaper Elevation="0" Class="pa-3 rounded-lg" Outlined="true">
<MudStack Spacing="2">
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Size="Size.Large"
FullWidth="true"
StartIcon="@Icons.Material.Filled.AccountBalanceWallet"
Disabled="true"
Class="rounded-lg">
شارژ کیف‌پول اصلی
</MudButton>
<MudAlert Severity="Severity.Warning" Dense="true" Variant="Variant.Outlined">
برای شارژ کیف پول اصلی ابتدا باید پکیج را خریداری کرده و قرارداد باشگاه مشتریان را امضا کنید.
</MudAlert>
<MudStack Row="true" Spacing="1" Class="flex-wrap">
@if (!_hasPurchasedPackage)
{
<MudButton Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary"
Href="@RouteConstants.Package.List"
StartIcon="@Icons.Material.Filled.CardGiftcard">
مشاهده پکیج‌ها
</MudButton>
}
else
{
<MudButton Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary"
Href="@RouteConstants.Club.Membership"
StartIcon="@Icons.Material.Filled.Handshake">
امضای قرارداد باشگاه
</MudButton>
}
</MudStack>
</MudStack>
</MudPaper>
}
<!-- دکمه شارژ کیف‌پول اعتباری -->
<MudButton Variant="Variant.Filled"
@@ -6,13 +6,29 @@ namespace FrontOffice.Main.Pages.Profile;
public partial class Wallet : ComponentBase
{
[Inject] private AuthService AuthService { get; set; } = default!;
private (string Credit, string Discount, string Network) _balances = ("-", "-", "-");
private List<WalletTransaction> _txs = new();
private string? _filterReferenceId;
private string _filterType = "all";
private bool _isClubMemberActive;
private bool _hasPurchasedPackage;
protected override async Task OnInitializedAsync()
{
try
{
var userInfo = await AuthService.GetUserAuthInfo();
_isClubMemberActive = userInfo.IsClubMemberActive;
_hasPurchasedPackage = userInfo.HasPurchasedPackage;
}
catch
{
_isClubMemberActive = false;
_hasPurchasedPackage = false;
}
var b = await WalletService.GetBalancesAsync();
_balances = (FormatPrice(b.CreditBalance), FormatPrice(b.DiscountBalance), FormatPrice(b.NetworkBalance));
_txs = await WalletService.GetTransactionsAsync();
@@ -125,11 +125,26 @@ public partial class CheckoutSummary : ComponentBase
return false;
var shortfall = totalRequired - walletBalance;
var allowCharge = false;
var hasPurchasedPackage = false;
try
{
var userInfo = await AuthService.GetUserAuthInfo();
allowCharge = userInfo.IsClubMemberActive;
hasPurchasedPackage = userInfo.HasPurchasedPackage;
}
catch
{
allowCharge = false;
}
var parameters = new DialogParameters<InsufficientCreditDialog>
{
{ x => x.CurrentBalance, walletBalance },
{ x => x.RequiredAmount, totalRequired },
{ x => x.ShortfallAmount, shortfall }
{ x => x.ShortfallAmount, shortfall },
{ x => x.AllowChargeCredit, allowCharge },
{ x => x.HasPurchasedPackage, hasPurchasedPackage }
};
var dialog = await DialogService.ShowAsync<InsufficientCreditDialog>(
@@ -143,7 +158,7 @@ public partial class CheckoutSummary : ComponentBase
});
var result = await dialog.Result;
if (result is { Canceled: false } && result.Data is long chargeShortfall)
if (allowCharge && result is { Canceled: false } && result.Data is long chargeShortfall)
{
var chargeAmount = CreditChargeNavigation.NormalizeChargeAmount(chargeShortfall);
Navigation.NavigateTo(CreditChargeNavigation.BuildChargeUrl(
@@ -1,3 +1,5 @@
@using FrontOffice.Main.Utilities
<MudDialog>
<TitleContent>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
@@ -7,9 +9,19 @@
</TitleContent>
<DialogContent>
<MudStack Spacing="2">
<MudText Typo="Typo.body2" Class="mud-text-secondary">
برای تکمیل این سفارش، موجودی اصلی شما کافی نیست. می‌توانید کیف پول را شارژ کنید و سپس سفارش را ثبت کنید.
</MudText>
@if (AllowChargeCredit)
{
<MudText Typo="Typo.body2" Class="mud-text-secondary">
برای تکمیل این سفارش، موجودی اصلی شما کافی نیست. می‌توانید کیف پول را شارژ کنید و سپس سفارش را ثبت کنید.
</MudText>
}
else
{
<MudAlert Severity="Severity.Warning" Dense="true" Variant="Variant.Outlined">
برای شارژ کیف پول اصلی ابتدا باید پکیج را خریداری کرده و قرارداد باشگاه مشتریان را امضا کنید.
</MudAlert>
}
<MudPaper Outlined="true" Class="pa-3 rounded-lg">
<MudStack Spacing="1">
<MudStack Row="true" Justify="Justify.SpaceBetween">
@@ -31,12 +43,33 @@
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">بستن</MudButton>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Payment"
OnClick="GoToCharge">
شارژ حساب اصلی
</MudButton>
@if (AllowChargeCredit)
{
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Payment"
OnClick="GoToCharge">
شارژ حساب اصلی
</MudButton>
}
else if (!HasPurchasedPackage)
{
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CardGiftcard"
OnClick="GoToPackages">
مشاهده پکیج‌ها
</MudButton>
}
else
{
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Handshake"
OnClick="GoToClubMembership">
امضای قرارداد باشگاه
</MudButton>
}
</DialogActions>
</MudDialog>
@@ -53,9 +86,28 @@
[Parameter]
public long ShortfallAmount { get; set; }
/// <summary>اگر false باشد، به صفحه شارژ هدایت نمی‌شود.</summary>
[Parameter]
public bool AllowChargeCredit { get; set; } = true;
[Parameter]
public bool HasPurchasedPackage { get; set; }
private void Cancel() => MudDialog.Cancel();
private void GoToCharge() => MudDialog.Close(DialogResult.Ok(ShortfallAmount));
private void GoToPackages()
{
MudDialog.Cancel();
Navigation.NavigateTo(RouteConstants.Package.List);
}
private void GoToClubMembership()
{
MudDialog.Cancel();
Navigation.NavigateTo(RouteConstants.Club.Membership);
}
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
}