feat: enhance product detail loading and initialization logic
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m50s

- Introduced an `_initialized` flag to manage product loading state more effectively.
- Updated `OnParametersSetAsync` to conditionally load product details based on the initialization state and valid product ID.
- Refactored product retrieval logic in `ProductService` to handle invalid IDs and improve fallback mechanisms for fetching product details.

These changes improve the reliability and performance of the product detail component, ensuring that product information is loaded correctly and efficiently.
This commit is contained in:
masoodafar-web
2026-07-01 21:21:57 +03:30
parent 454d27f37e
commit 5d58d354d7
2 changed files with 67 additions and 27 deletions
@@ -21,6 +21,7 @@ public partial class ProductDetail : ComponentBase, IDisposable
private Product? _product; private Product? _product;
private bool _loading; private bool _loading;
private bool _initialized;
private int _qty = 1; private int _qty = 1;
private const int MinQty = 1; private const int MinQty = 1;
@@ -48,29 +49,35 @@ public partial class ProductDetail : ComponentBase, IDisposable
private bool IsInCart => CurrentCartItem is not null; private bool IsInCart => CurrentCartItem is not null;
private int CurrentCartQuantity => CurrentCartItem?.Quantity ?? 0; private int CurrentCartQuantity => CurrentCartItem?.Quantity ?? 0;
protected override async Task OnParametersSetAsync()
{
}
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_isAuthenticated = await AuthService.IsAuthenticatedAsync(); _isAuthenticated = await AuthService.IsAuthenticatedAsync();
await Cart.EnsureInitializedAsync(); await Cart.EnsureInitializedAsync();
Cart.OnChange += HandleCartChanged; Cart.OnChange += HandleCartChanged;
_initialized = true;
}
protected override async Task OnParametersSetAsync()
{
if (!_initialized || id <= 0)
return;
await LoadProductAsync();
}
private async Task LoadProductAsync()
{
_loading = true; _loading = true;
_product = await ProductService.GetByIdAsync(id); _product = await ProductService.GetByIdAsync(id);
_loading = false; _loading = false;
if (_product is not null) if (_product is not null)
{ {
_galleryItems = BuildGalleryItems(_product); _galleryItems = BuildGalleryItems(_product);
_selectedGalleryImage = _galleryItems.FirstOrDefault(); _selectedGalleryImage = _galleryItems.FirstOrDefault();
_categoryPaths = _product.Categories; _categoryPaths = _product.Categories;
UpdateBreadcrumb(); UpdateBreadcrumb();
_qty = Math.Clamp(CurrentCartItem?.Quantity ?? _qty, MinQty, MaxQty); _qty = Math.Clamp(CurrentCartItem?.Quantity ?? MinQty, MinQty, Math.Max(MinQty, MaxQty));
} }
else else
{ {
@@ -78,19 +85,16 @@ public partial class ProductDetail : ComponentBase, IDisposable
_categoryPaths = Array.Empty<ProductCategoryPathInfo>(); _categoryPaths = Array.Empty<ProductCategoryPathInfo>();
_breadcrumbItems.Clear(); _breadcrumbItems.Clear();
} }
StateHasChanged();
await base.OnInitializedAsync();
} }
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
await base.OnAfterRenderAsync(firstRender);
if (firstRender) if (firstRender)
{ {
// بارگذاری نرخ VAT
await VAT.LoadAsync(); await VAT.LoadAsync();
} }
await base.OnAfterRenderAsync(firstRender);
} }
private async Task AddToCart() private async Task AddToCart()
@@ -137,30 +137,66 @@ public class ProductService
public async Task<Product?> GetByIdAsync(long id) public async Task<Product?> GetByIdAsync(long id)
{ {
if (TryGetCachedProduct(id, out var cached) && HasDetailedData(cached)) if (id <= 0)
{ return null;
return cached;
}
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 try
{ {
var resp = await _client.GetProductsAsync(new GetProductsRequest { Id = id }); var resp = await _client.GetProductsAsync(new GetProductsRequest { Id = id });
if (resp == null) if (resp is null || resp.Id <= 0)
{
return null; return null;
}
return MapAndCache(resp); return MapAndCache(resp);
} }
catch catch
{ {
if (cached is not null) return null;
{ }
return cached; }
}
TryGetCachedProduct(id, out var result); private async Task<Product?> TryFetchByFilterIdAsync(long id)
return result; {
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;
} }
} }