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:
@@ -64,7 +64,7 @@
|
||||
<MudText Class="mt-2 mud-text-secondary">در حال بارگذاری...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_result.Products.Count == 0)
|
||||
else if (_products.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Class="my-4">محصولی یافت نشد.</MudAlert>
|
||||
}
|
||||
@@ -72,7 +72,7 @@
|
||||
{
|
||||
<!-- Products Grid -->
|
||||
<MudGrid Spacing="1">
|
||||
@foreach (var p in _result.Products)
|
||||
@foreach (var p in _products)
|
||||
{
|
||||
<MudItem xs="6" sm="6" md="3"
|
||||
onclick="@(() => NavigateToProduct(p.Id))">
|
||||
@@ -119,15 +119,29 @@
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
<!-- Pagination -->
|
||||
@if (_result.TotalPages > 1)
|
||||
@* Lazy Load — بارگذاری بیشتر *@
|
||||
@if (_loadingMore)
|
||||
{
|
||||
<div class="d-flex justify-center mt-4">
|
||||
<MudPagination Count="@_result.TotalPages" Selected="@_currentPage"
|
||||
SelectedChanged="OnPageChanged"
|
||||
Color="Color.Primary" Variant="Variant.Filled"
|
||||
BoundaryCount="1" MiddleCount="3" />
|
||||
<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>
|
||||
|
||||
@@ -13,9 +13,12 @@ public partial class Products : ComponentBase, IDisposable
|
||||
private long? _selectedCategoryId;
|
||||
private int _currentPage = 1;
|
||||
private bool _loading;
|
||||
private bool _loadingMore;
|
||||
private bool _hasMore = true;
|
||||
private int _totalCount;
|
||||
private const int PageSize = 12;
|
||||
|
||||
private DiscountProductListResult _result = new(new(), 0, 0, 1);
|
||||
private List<DiscountProductCard> _products = new();
|
||||
private List<DiscountCategoryNode> _categories = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -27,45 +30,66 @@ public partial class Products : ComponentBase, IDisposable
|
||||
var productsTask = ProductService.GetProductsAsync(page: 1, pageSize: PageSize);
|
||||
await Task.WhenAll(categoriesTask, productsTask);
|
||||
_categories = categoriesTask.Result;
|
||||
_result = productsTask.Result;
|
||||
var result = productsTask.Result;
|
||||
_products = result.Products;
|
||||
_totalCount = result.TotalCount;
|
||||
_hasMore = result.CurrentPage < result.TotalPages;
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
private async Task LoadProductsAsync()
|
||||
private async Task LoadInitial()
|
||||
{
|
||||
_loading = true;
|
||||
_currentPage = 1;
|
||||
_products.Clear();
|
||||
StateHasChanged();
|
||||
_result = await ProductService.GetProductsAsync(
|
||||
|
||||
var result = await ProductService.GetProductsAsync(
|
||||
page: 1,
|
||||
pageSize: PageSize,
|
||||
search: string.IsNullOrWhiteSpace(_search) ? null : _search,
|
||||
categoryId: _selectedCategoryId);
|
||||
_products = result.Products;
|
||||
_totalCount = result.TotalCount;
|
||||
_hasMore = result.CurrentPage < result.TotalPages;
|
||||
_loading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadMore()
|
||||
{
|
||||
if (_loadingMore || !_hasMore) return;
|
||||
|
||||
_loadingMore = true;
|
||||
StateHasChanged();
|
||||
|
||||
_currentPage++;
|
||||
var result = await ProductService.GetProductsAsync(
|
||||
page: _currentPage,
|
||||
pageSize: PageSize,
|
||||
search: string.IsNullOrWhiteSpace(_search) ? null : _search,
|
||||
categoryId: _selectedCategoryId);
|
||||
_loading = false;
|
||||
_products.AddRange(result.Products);
|
||||
_hasMore = result.CurrentPage < result.TotalPages;
|
||||
|
||||
_loadingMore = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SearchProducts() => await LoadProductsAsync();
|
||||
private async Task SearchProducts() => await LoadInitial();
|
||||
|
||||
private async Task OnSearchKeyUp(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
_currentPage = 1;
|
||||
await LoadProductsAsync();
|
||||
await LoadInitial();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnCategoryChanged(long? value)
|
||||
{
|
||||
_selectedCategoryId = value;
|
||||
_currentPage = 1;
|
||||
await LoadProductsAsync();
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int page)
|
||||
{
|
||||
_currentPage = page;
|
||||
await LoadProductsAsync();
|
||||
await LoadInitial();
|
||||
}
|
||||
|
||||
private async Task AddToCart(DiscountProductCard p)
|
||||
|
||||
Reference in New Issue
Block a user