feat: lazy load products in both stores (infinite scroll)
Build and Deploy to Kubernetes / build-and-deploy (push) Has been cancelled
Build and Deploy to Kubernetes / build-and-deploy (push) Has been cancelled
- ProductService: add GetProductsPagedAsync with PaginationState support - Store/Products: replace load-all with page-by-page lazy loading (12 per page) - DiscountStore/Products: replace pagination with lazy load (load more button) - Both stores show 'load more' button + loading indicator + 'all shown' text
This commit is contained in:
@@ -94,7 +94,7 @@
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Inventory2" Size="Size.Small" Class="me-1"/>
|
||||
@(_products.Count) محصول
|
||||
@(_totalCount) محصول
|
||||
</MudText>
|
||||
}
|
||||
</MudItem>
|
||||
@@ -159,5 +159,30 @@
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
@* Lazy Load — بارگذاری بیشتر *@
|
||||
@if (_loadingMore)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-4">
|
||||
<MudProgressCircular Color="Color.Primary" Size="Size.Small" Indeterminate="true"/>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">بارگذاری بیشتر...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_hasMore)
|
||||
{
|
||||
<div class="d-flex justify-center py-4">
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.ExpandMore"
|
||||
OnClick="LoadMore">
|
||||
نمایش محصولات بیشتر
|
||||
</MudButton>
|
||||
</div>
|
||||
}
|
||||
else if (_products.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Align="Align.Center" Class="py-4 mud-text-secondary">
|
||||
همه @(_products.Count) محصول نمایش داده شد
|
||||
</MudText>
|
||||
}
|
||||
}
|
||||
</MudContainer>
|
||||
|
||||
@@ -24,6 +24,11 @@ public partial class Products : ComponentBase, IDisposable
|
||||
|
||||
private string _query = string.Empty;
|
||||
private bool _loading;
|
||||
private bool _loadingMore;
|
||||
private bool _hasMore = true;
|
||||
private int _currentPage = 1;
|
||||
private int _totalCount;
|
||||
private const int PageSize = 12;
|
||||
private List<Product> _products = new();
|
||||
private long? _activeCategoryId;
|
||||
private string? _activeCategoryTitle;
|
||||
@@ -36,7 +41,7 @@ public partial class Products : ComponentBase, IDisposable
|
||||
await Cart.EnsureInitializedAsync();
|
||||
Cart.OnChange += StateHasChanged;
|
||||
Navigation.LocationChanged += HandleLocationChanged;
|
||||
await Load();
|
||||
await LoadInitial();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
@@ -49,18 +54,40 @@ public partial class Products : ComponentBase, IDisposable
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
private async Task Load()
|
||||
private async Task LoadInitial()
|
||||
{
|
||||
_loading = true;
|
||||
_currentPage = 1;
|
||||
_products.Clear();
|
||||
UpdateCategoryFilterFromUri();
|
||||
var sortBy = GetSortByValue();
|
||||
_products = await ProductService.GetProductsAsync(_query, _activeCategoryId, sortBy);
|
||||
var result = await ProductService.GetProductsPagedAsync(_query, _activeCategoryId, sortBy, _currentPage, PageSize);
|
||||
_products = result.Products;
|
||||
_hasMore = result.HasNext;
|
||||
_totalCount = result.TotalCount;
|
||||
_activeCategoryTitle = _activeCategoryId is { } categoryId
|
||||
? (await CategoryService.GetByIdAsync(categoryId))?.Title
|
||||
: null;
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
private async Task LoadMore()
|
||||
{
|
||||
if (_loadingMore || !_hasMore) return;
|
||||
|
||||
_loadingMore = true;
|
||||
StateHasChanged();
|
||||
|
||||
_currentPage++;
|
||||
var sortBy = GetSortByValue();
|
||||
var result = await ProductService.GetProductsPagedAsync(_query, _activeCategoryId, sortBy, _currentPage, PageSize);
|
||||
_products.AddRange(result.Products);
|
||||
_hasMore = result.HasNext;
|
||||
|
||||
_loadingMore = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string GetSortByValue()
|
||||
{
|
||||
return _sortOption switch
|
||||
@@ -75,12 +102,12 @@ public partial class Products : ComponentBase, IDisposable
|
||||
|
||||
private async Task OnSortChanged()
|
||||
{
|
||||
await Load();
|
||||
await LoadInitial();
|
||||
}
|
||||
|
||||
private async Task OnQueryChanged(KeyboardEventArgs _)
|
||||
{
|
||||
await Load();
|
||||
await LoadInitial();
|
||||
}
|
||||
|
||||
private async Task AddToCart(Product p)
|
||||
@@ -98,7 +125,7 @@ public partial class Products : ComponentBase, IDisposable
|
||||
|
||||
private void HandleLocationChanged(object? sender, LocationChangedEventArgs args)
|
||||
{
|
||||
_ = InvokeAsync(Load);
|
||||
_ = InvokeAsync(LoadInitial);
|
||||
}
|
||||
|
||||
private void UpdateCategoryFilterFromUri()
|
||||
|
||||
Reference in New Issue
Block a user