diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor
index 3527a69..6cb49e8 100644
--- a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor
+++ b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor
@@ -64,7 +64,7 @@
در حال بارگذاری...
}
- else if (_result.Products.Count == 0)
+ else if (_products.Count == 0)
{
محصولی یافت نشد.
}
@@ -72,7 +72,7 @@
{
- @foreach (var p in _result.Products)
+ @foreach (var p in _products)
{
@@ -119,15 +119,29 @@
}
-
- @if (_result.TotalPages > 1)
+ @* Lazy Load — بارگذاری بیشتر *@
+ @if (_loadingMore)
{
-
-
+
+
+ بارگذاری بیشتر...
+
+ }
+ else if (_hasMore)
+ {
+
+
+ نمایش محصولات بیشتر
+
}
+ else if (_products.Count > 0)
+ {
+
+ همه @(_products.Count) محصول نمایش داده شد
+
+ }
}
diff --git a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor.cs b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor.cs
index e84463c..9bdf7e9 100644
--- a/src/FrontOffice.Main/Pages/DiscountStore/Products.razor.cs
+++ b/src/FrontOffice.Main/Pages/DiscountStore/Products.razor.cs
@@ -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
_products = new();
private List _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)
diff --git a/src/FrontOffice.Main/Pages/Store/Products.razor b/src/FrontOffice.Main/Pages/Store/Products.razor
index 370abbc..a00d6f3 100644
--- a/src/FrontOffice.Main/Pages/Store/Products.razor
+++ b/src/FrontOffice.Main/Pages/Store/Products.razor
@@ -94,7 +94,7 @@
{
- @(_products.Count) محصول
+ @(_totalCount) محصول
}
@@ -159,5 +159,30 @@
}
+
+ @* Lazy Load — بارگذاری بیشتر *@
+ @if (_loadingMore)
+ {
+
+
+ بارگذاری بیشتر...
+
+ }
+ else if (_hasMore)
+ {
+
+
+ نمایش محصولات بیشتر
+
+
+ }
+ else if (_products.Count > 0)
+ {
+
+ همه @(_products.Count) محصول نمایش داده شد
+
+ }
}
diff --git a/src/FrontOffice.Main/Pages/Store/Products.razor.cs b/src/FrontOffice.Main/Pages/Store/Products.razor.cs
index 5c8163d..4394fa2 100644
--- a/src/FrontOffice.Main/Pages/Store/Products.razor.cs
+++ b/src/FrontOffice.Main/Pages/Store/Products.razor.cs
@@ -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 _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()
diff --git a/src/FrontOffice.Main/Utilities/ProductService.cs b/src/FrontOffice.Main/Utilities/ProductService.cs
index 81309ad..0640bee 100644
--- a/src/FrontOffice.Main/Utilities/ProductService.cs
+++ b/src/FrontOffice.Main/Utilities/ProductService.cs
@@ -26,6 +26,13 @@ public record Product(
= [];
}
+public record ProductListResult(
+ List Products,
+ int TotalCount,
+ int TotalPages,
+ int CurrentPage,
+ bool HasNext);
+
public record ProductGalleryImage(
long ProductGalleryId,
long ProductImageId,
@@ -59,11 +66,24 @@ public class ProductService
}
public async Task> GetProductsAsync(string? query = null, long? categoryId = null, string? sortBy = null)
+ {
+ var result = await GetProductsPagedAsync(query: query, categoryId: categoryId, sortBy: sortBy, page: 1, pageSize: 500);
+ return result.Products;
+ }
+
+ public async Task GetProductsPagedAsync(
+ string? query = null, long? categoryId = null, string? sortBy = null,
+ int page = 1, int pageSize = 12)
{
try
{
var request = new GetAllProductsByFilterRequest
{
+ PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
+ {
+ PageNumber = page,
+ PageSize = pageSize
+ },
Filter = new GetAllProductsByFilterFilter
{
Title = query ?? string.Empty,
@@ -84,7 +104,12 @@ public class ProductService
}
var resp = await _client.GetAllProductsByFilterAsync(request);
- return MapAndCache(resp.Models);
+ var products = MapAndCache(resp.Models);
+ var totalCount = (int)(resp.MetaData?.TotalCount ?? 0);
+ var totalPages = (int)(resp.MetaData?.TotalPage ?? 0);
+ var hasNext = resp.MetaData?.HasNext ?? false;
+
+ return new ProductListResult(products, totalCount, totalPages, page, hasNext);
}
catch
{
@@ -97,7 +122,8 @@ public class ProductService
p.Description.Contains(q, StringComparison.OrdinalIgnoreCase));
}
- return list.OrderBy(p => p.Id).ToList();
+ var all = list.OrderBy(p => p.Id).ToList();
+ return new ProductListResult(all, all.Count, 1, 1, false);
}
}