Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Has been cancelled

This commit is contained in:
masoodafar-web
2026-07-01 21:31:49 +03:30
2 changed files with 67 additions and 27 deletions
@@ -21,6 +21,7 @@ public partial class ProductDetail : ComponentBase, IDisposable
private Product? _product;
private bool _loading;
private bool _initialized;
private int _qty = 1;
private const int MinQty = 1;
@@ -48,29 +49,35 @@ public partial class ProductDetail : ComponentBase, IDisposable
private bool IsInCart => CurrentCartItem is not null;
private int CurrentCartQuantity => CurrentCartItem?.Quantity ?? 0;
protected override async Task OnParametersSetAsync()
{
}
protected override async Task OnInitializedAsync()
{
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
await Cart.EnsureInitializedAsync();
Cart.OnChange += HandleCartChanged;
_initialized = true;
}
protected override async Task OnParametersSetAsync()
{
if (!_initialized || id <= 0)
return;
await LoadProductAsync();
}
private async Task LoadProductAsync()
{
_loading = true;
_product = await ProductService.GetByIdAsync(id);
_loading = false;
if (_product is not null)
{
_galleryItems = BuildGalleryItems(_product);
_selectedGalleryImage = _galleryItems.FirstOrDefault();
_categoryPaths = _product.Categories;
UpdateBreadcrumb();
_qty = Math.Clamp(CurrentCartItem?.Quantity ?? _qty, MinQty, MaxQty);
_qty = Math.Clamp(CurrentCartItem?.Quantity ?? MinQty, MinQty, Math.Max(MinQty, MaxQty));
}
else
{
@@ -78,19 +85,16 @@ public partial class ProductDetail : ComponentBase, IDisposable
_categoryPaths = Array.Empty<ProductCategoryPathInfo>();
_breadcrumbItems.Clear();
}
StateHasChanged();
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
// بارگذاری نرخ VAT
await VAT.LoadAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task AddToCart()
@@ -137,30 +137,66 @@ public class ProductService
public async Task<Product?> GetByIdAsync(long id)
{
if (TryGetCachedProduct(id, out var cached) && HasDetailedData(cached))
{
return cached;
}
if (id <= 0)
return null;
TryGetCachedProduct(id, out var cached);
if (cached is not null && HasDetailedData(cached))
return cached;
// جزئیات کامل (گالری + دسته‌بندی)
var detailed = await TryFetchDetailAsync(id);
if (detailed is not null)
return detailed;
// fallback: همان API لیست محصولات — ناموجودها را هم برمی‌گرداند
var fromFilter = await TryFetchByFilterIdAsync(id);
if (fromFilter is not null)
return fromFilter;
return cached;
}
private async Task<Product?> TryFetchDetailAsync(long id)
{
try
{
var resp = await _client.GetProductsAsync(new GetProductsRequest { Id = id });
if (resp == null)
{
if (resp is null || resp.Id <= 0)
return null;
}
return MapAndCache(resp);
}
catch
{
if (cached is not null)
{
return cached;
}
return null;
}
}
TryGetCachedProduct(id, out var result);
return result;
private async Task<Product?> TryFetchByFilterIdAsync(long id)
{
try
{
var resp = await _client.GetAllProductsByFilterAsync(new GetAllProductsByFilterRequest
{
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
{
PageNumber = 1,
PageSize = 1
},
Filter = new GetAllProductsByFilterFilter { Id = id }
});
var model = resp.Models.FirstOrDefault(m => m.Id == id);
if (model is null)
return null;
return MapAndCache(resp.Models).FirstOrDefault(p => p.Id == id);
}
catch
{
return null;
}
}