feat: hide product prices from unauthenticated (guest) users
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 4m48s

Guests can browse products and product details for presentation purposes,
but prices are hidden behind a 'وارد شوید' prompt (lock icon).
Authenticated users see prices as before.

Affected pages:
- Landing page (Index): top-selling regular + discount sections
- Store/Products list
- Store/ProductDetail (desktop price + mobile sticky bar)
- DiscountStore/Products list
- DiscountStore/ProductDetail (full price box)

Each code-behind now checks AuthService.IsAuthenticatedAsync() on init
and stores the result in _isAuthenticated for use in the template.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
masoodafar-web
2026-05-14 19:58:28 +03:30
parent e5b1e11895
commit 2874b931df
10 changed files with 150 additions and 73 deletions
@@ -63,49 +63,58 @@
}
<!-- Price & Discount -->
<MudPaper Class="pa-4 rounded-lg discount-price-box" Elevation="0">
<MudStack Spacing="2">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت محصول:</MudText>
<MudText Typo="Typo.body1" Class="fw-bold">
@($"{_product.Price:N0}") تومان
</MudText>
</MudStack>
@if (VAT.IsEnabled)
{
@if (_isAuthenticated)
{
<MudPaper Class="pa-4 rounded-lg discount-price-box" Elevation="0">
<MudStack Spacing="2">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">مالیات ارزش افزوده (@VAT.VatPercentage%):</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
@($"{VAT.CalculateVAT(_product.Price):N0}") تومان
</MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت با مالیات:</MudText>
<MudText Typo="Typo.h5" Color="Color.Primary" Class="fw-bold">
@($"{VAT.AddVAT(_product.Price):N0}") تومان
</MudText>
</MudStack>
}
else
{
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت نهایی:</MudText>
<MudText Typo="Typo.h5" Color="Color.Primary" Class="fw-bold">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت محصول:</MudText>
<MudText Typo="Typo.body1" Class="fw-bold">
@($"{_product.Price:N0}") تومان
</MudText>
</MudStack>
}
@if (_product.MaxDiscountPercent > 0)
{
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">اعتبار از کیف اعتباری:</MudText>
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small">
@_product.MaxDiscountPercent% (@($"{_product.Price * _product.MaxDiscountPercent / 100:N0}") تومان)
</MudChip>
</MudStack>
}
</MudStack>
</MudPaper>
@if (VAT.IsEnabled)
{
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">مالیات ارزش افزوده (@VAT.VatPercentage%):</MudText>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
@($"{VAT.CalculateVAT(_product.Price):N0}") تومان
</MudText>
</MudStack>
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت با مالیات:</MudText>
<MudText Typo="Typo.h5" Color="Color.Primary" Class="fw-bold">
@($"{VAT.AddVAT(_product.Price):N0}") تومان
</MudText>
</MudStack>
}
else
{
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت نهایی:</MudText>
<MudText Typo="Typo.h5" Color="Color.Primary" Class="fw-bold">
@($"{_product.Price:N0}") تومان
</MudText>
</MudStack>
}
@if (_product.MaxDiscountPercent > 0)
{
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.body2" Class="mud-text-secondary">اعتبار از کیف اعتباری:</MudText>
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small">
@_product.MaxDiscountPercent% (@($"{_product.Price * _product.MaxDiscountPercent / 100:N0}") تومان)
</MudChip>
</MudStack>
}
</MudStack>
</MudPaper>
}
else
{
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Outlined" Icon="@Icons.Material.Filled.Lock">
برای مشاهده قیمت ابتدا وارد شوید
</MudAlert>
}
<!-- Stock & Stats -->
<MudStack Row="true" Spacing="3" Class="flex-wrap">
@@ -11,6 +11,9 @@ public partial class ProductDetail
[Inject] private DiscountCartService DiscountCartService { get; set; } = default!;
[Inject] private VATService VAT { get; set; } = default!;
[Inject] private GuestActionGate GuestGate { get; set; } = default!;
[Inject] private AuthService AuthService { get; set; } = default!;
private bool _isAuthenticated;
private DiscountProductDetail? _product;
private string _selectedImage = string.Empty;
@@ -20,6 +23,7 @@ public partial class ProductDetail
protected override async Task OnInitializedAsync()
{
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
await LoadProductAsync();
}
@@ -103,10 +103,19 @@
</div>
<div class="pa-1 flex-grow-1 d-flex flex-column justify-space-between">
<MudText Typo="Typo.subtitle1">@p.Title</MudText>
<div>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
<MudText Typo="Typo.overline" Class="mud-text-secondary" Style="font-size:0.6rem;line-height:1;">(+ ارزش افزوده)</MudText>
</div>
@if (_isAuthenticated)
{
<div>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
<MudText Typo="Typo.overline" Class="mud-text-secondary" Style="font-size:0.6rem;line-height:1;">(+ ارزش افزوده)</MudText>
</div>
}
else
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Small" Class="me-1"/>برای مشاهده قیمت وارد شوید
</MudText>
}
</div>
</MudCardContent>
<MudCardActions Class="mt-auto d-flex justify-space-between pa-2">
@@ -9,7 +9,9 @@ public partial class Products : ComponentBase, IDisposable
[Inject] private DiscountProductService ProductService { get; set; } = default!;
[Inject] private DiscountCartService DiscountCart { get; set; } = default!;
[Inject] private GuestActionGate GuestGate { get; set; } = default!;
[Inject] private AuthService AuthService { get; set; } = default!;
private bool _isAuthenticated;
private string _search = string.Empty;
private long? _selectedCategoryId;
private int _currentPage = 1;
@@ -24,6 +26,7 @@ public partial class Products : ComponentBase, IDisposable
protected override async Task OnInitializedAsync()
{
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
_loading = true;
await DiscountCart.EnsureInitializedAsync();
DiscountCart.OnChange += StateHasChanged;
+23 -5
View File
@@ -144,7 +144,16 @@ else
</div>
<div class="pa-1 flex-grow-1 d-flex flex-column justify-space-between">
<MudText Typo="Typo.subtitle1" Style="display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;">@p.Title</MudText>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
@if (_isAuthenticated)
{
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
}
else
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Small" Class="me-1"/>برای مشاهده قیمت وارد شوید
</MudText>
}
</div>
</MudCardContent>
<MudCardActions Class="mt-auto pa-2" @onclick:stopPropagation="true">
@@ -217,10 +226,19 @@ else
</div>
<div class="pa-1 flex-grow-1 d-flex flex-column justify-space-between">
<MudText Typo="Typo.subtitle1" Style="display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;">@p.Title</MudText>
<div>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatDiscountPrice(p.Price)</MudText>
<MudText Typo="Typo.overline" Class="mud-text-secondary" Style="font-size:0.6rem;line-height:1;">(+ ارزش افزوده)</MudText>
</div>
@if (_isAuthenticated)
{
<div>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatDiscountPrice(p.Price)</MudText>
<MudText Typo="Typo.overline" Class="mud-text-secondary" Style="font-size:0.6rem;line-height:1;">(+ ارزش افزوده)</MudText>
</div>
}
else
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Small" Class="me-1"/>برای مشاهده قیمت وارد شوید
</MudText>
}
</div>
</MudCardContent>
<MudCardActions Class="mt-auto pa-2" @onclick:stopPropagation="true">
@@ -17,6 +17,8 @@ public partial class Index : IDisposable
[Inject] private GuestActionGate GuestGate { get; set; } = default!;
[Inject] private VATService VAT { get; set; } = default!;
private bool _isAuthenticated;
// ── CMS page data ──
private PageSettingsDto? _pageData;
private LandingSettings? _settings;
@@ -44,6 +46,7 @@ public partial class Index : IDisposable
protected override async Task OnInitializedAsync()
{
MainService.OnChangeHandler += OnStateChanged;
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
// Load landing page settings from CMS
try
@@ -78,15 +78,24 @@ else
@* </MudStack> *@
@* } *@
<MudDivider Class="my-2"/>
<MudStack Spacing="1">
<MudText Typo="Typo.h5" Color="Color.Primary">@FormatPrice(_product.Price)</MudText>
@if (VAT.IsEnabled)
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
(شامل @VAT.VatPercentage% مالیات بر ارزش افزوده)
</MudText>
}
</MudStack>
@if (_isAuthenticated)
{
<MudStack Spacing="1">
<MudText Typo="Typo.h5" Color="Color.Primary">@FormatPrice(_product.Price)</MudText>
@if (VAT.IsEnabled)
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
(شامل @VAT.VatPercentage% مالیات بر ارزش افزوده)
</MudText>
}
</MudStack>
}
else
{
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Outlined" Icon="@Icons.Material.Filled.Lock">
برای مشاهده قیمت ابتدا وارد شوید
</MudAlert>
}
<!-- نمایش وضعیت موجودی -->
@if (IsInStock)
@@ -141,18 +150,27 @@ else
{
<MudGrid Class="align-center" Justify="Justify.SpaceBetween">
<MudItem xs="6">
<MudStack Spacing="1">
@if (HasDiscount && OriginalPrice is not null)
{
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption"
Class="mud-text-secondary mud-line-through">@FormatPrice(OriginalPrice.Value)</MudText>
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small"
Label="true">@($"٪{_product!.Discount}")</MudChip>
</MudStack>
}
<MudText Typo="Typo.h6" Color="Color.Primary">@FormatPrice(TotalPrice)</MudText>
</MudStack>
@if (_isAuthenticated)
{
<MudStack Spacing="1">
@if (HasDiscount && OriginalPrice is not null)
{
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudText Typo="Typo.caption"
Class="mud-text-secondary mud-line-through">@FormatPrice(OriginalPrice.Value)</MudText>
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small"
Label="true">@($"٪{_product!.Discount}")</MudChip>
</MudStack>
}
<MudText Typo="Typo.h6" Color="Color.Primary">@FormatPrice(TotalPrice)</MudText>
</MudStack>
}
else
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Small" Class="me-1"/>برای مشاهده قیمت وارد شوید
</MudText>
}
</MudItem>
@if (IsInCart)
@@ -13,6 +13,9 @@ public partial class ProductDetail : ComponentBase, IDisposable
[Inject] private CartService Cart { get; set; } = default!;
[Inject] private VATService VAT { get; set; } = default!;
[Inject] private GuestActionGate GuestGate { get; set; } = default!;
[Inject] private AuthService AuthService { get; set; } = default!;
private bool _isAuthenticated;
[Parameter] public long id { get; set; }
@@ -52,7 +55,7 @@ public partial class ProductDetail : ComponentBase, IDisposable
protected override async Task OnInitializedAsync()
{
// لود سبد خرید (فقط اگر کاربر لاگین کرده باشد)
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
await Cart.EnsureInitializedAsync();
Cart.OnChange += HandleCartChanged;
@@ -141,8 +141,16 @@
</div>
<div class="pa-1 flex-grow-1 d-flex flex-column justify-space-between">
<MudText Typo="Typo.subtitle1">@p.Title</MudText>
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
@if (_isAuthenticated)
{
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
}
else
{
<MudText Typo="Typo.caption" Class="mud-text-secondary">
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Small" Class="me-1"/>برای مشاهده قیمت وارد شوید
</MudText>
}
</div>
</MudCardContent>
<MudCardActions Class="mt-auto d-flex justify-space-between pa-2">
@@ -22,7 +22,9 @@ public partial class Products : ComponentBase, IDisposable
[Inject] private CartService Cart { get; set; } = default!;
[Inject] private VATService VAT { get; set; } = default!;
[Inject] private GuestActionGate GuestGate { get; set; } = default!;
[Inject] private AuthService AuthService { get; set; } = default!;
private bool _isAuthenticated;
private string _query = string.Empty;
private bool _loading;
private bool _loadingMore;
@@ -38,7 +40,7 @@ public partial class Products : ComponentBase, IDisposable
protected override async Task OnInitializedAsync()
{
// لود سبد خرید (فقط اگر کاربر لاگین کرده باشد)
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
await Cart.EnsureInitializedAsync();
Cart.OnChange += StateHasChanged;
Navigation.LocationChanged += HandleLocationChanged;