diff --git a/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs b/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs index c2385196d..d1765bbc3 100644 --- a/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs +++ b/src/Application/Features/Products/Queries/Pagination/ProductsPaginationQuery.cs @@ -5,6 +5,7 @@ using CleanArchitecture.Blazor.Application.Features.Products.Caching; using CleanArchitecture.Blazor.Application.Features.Products.DTOs; using CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification; +using CleanArchitecture.Blazor.Domain.Entities; namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Pagination; @@ -12,28 +13,16 @@ public class ProductsWithPaginationQuery : PaginationFilterBase, ICacheableReque { public string? Name { get; set; } public string? Brand { get; set; } - public string? Unit { get; set; } public Range Price { get; set; } = new(); - - [CompareTo("Name", "Brand", "Description")] // <-- This filter will be applied to Name or Brand or Description. - [StringFilterOptions(StringFilterOption.Contains)] public string? Keyword { get; set; } - - [CompareTo(typeof(SearchProductsWithListView), "Name")] public ProductListView ListView { get; set; } = ProductListView.All; //<-- When the user selects a different ListView, + public UserProfile? CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of - // a custom query expression is executed on the backend. - // For example, if the user selects "My Products", - // the query will be x => x.CreatedBy == CurrentUser.UserId - [IgnoreFilter] - public UserProfile? - CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of + public string CacheKey => ProductCacheKey.GetPaginationCacheKey($"{this}"); - [IgnoreFilter] public string CacheKey => ProductCacheKey.GetPaginationCacheKey($"{this}"); - - [IgnoreFilter] public MemoryCacheEntryOptions? Options => ProductCacheKey.MemoryCacheEntryOptions; + public MemoryCacheEntryOptions? Options => ProductCacheKey.MemoryCacheEntryOptions; // the currently logged in user public override string ToString() @@ -41,6 +30,55 @@ public override string ToString() return $"CurrentUser:{CurrentUser?.UserId},ListView:{ListView},Search:{Keyword},Name:{Name},Brand:{Brand},Unit:{Unit},MinPrice:{Price?.Min},MaxPrice:{Price?.Max},Sort:{Sort},SortBy:{SortBy},{Page},{PerPage}"; } + + public Expression> LinqExpression() + { + Expression> initExpr = product => true; + Expression> keywordExpre = product => product.Name.Contains(Keyword) || product.Description.Contains(Keyword); + Expression> brandExpre = product => product.Brand.Contains(Brand); + Expression> unitExpre = product => product.Unit.Equals(Unit); + Expression> priceExpre = product => product.Price >= Price.Min && product.Price <= Price.Max; + var parameter = Expression.Parameter(typeof(Product)); + + switch (ListView) + { + case ProductListView.My: + Expression> myexp = product => product.CreatedBy == CurrentUser.UserId; + initExpr = initExpr.And(myexp); + break; + case ProductListView.CreatedToday: + var today = DateTime.Now; + Expression> todayexp = product => product.Created.Value.Date == today.Date; + initExpr = initExpr.And(todayexp); + break; + case ProductListView.Created30Days: + var last30day = DateTime.Now.AddDays(-30); + Expression> last30exp = product => product.Created.Value.Date >= last30day.Date; + initExpr = initExpr.And(last30exp); + break; + case ProductListView.All: + default: + break; + } + + if (!string.IsNullOrEmpty(Keyword)) + { + initExpr = initExpr.And(keywordExpre); + } + if (!string.IsNullOrEmpty(Brand)) + { + initExpr = initExpr.And(brandExpre); + } + if (!string.IsNullOrEmpty(Unit)) + { + initExpr = initExpr.And(unitExpre); + } + if (Price != null && Price.Max != null && Price.Min != null) + { + initExpr = initExpr.And(priceExpre); + } + return initExpr; + } } public class ProductsWithPaginationQueryHandler : @@ -64,7 +102,8 @@ IStringLocalizer localizer public async Task> Handle(ProductsWithPaginationQuery request, CancellationToken cancellationToken) { - var data = await _context.Products.ApplyFilterWithoutPagination(request) + var expresss = request.LinqExpression(); + var data = await _context.Products.Where(expresss) .ProjectTo(_mapper.ConfigurationProvider) .PaginatedDataAsync(request.Page, request.PerPage); return data; diff --git a/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs b/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs index 35b2ee161..ba21eec79 100644 --- a/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs +++ b/src/Application/Features/Products/Queries/Specification/SearchProductSpecification.cs @@ -22,9 +22,7 @@ public enum ProductListView [Description("All")] All, [Description("My Products")] My, [Description("Created Toady")] CreatedToday, - - [Description("Created within the last 30 days")] - Created30Days + [Description("Created within the last 30 days")] Created30Days } public class SearchProductsWithListView : FilteringOptionsBaseAttribute diff --git a/src/Blazor.Server.UI/Pages/Products/Products.razor b/src/Blazor.Server.UI/Pages/Products/Products.razor index c88699c70..dadda446a 100644 --- a/src/Blazor.Server.UI/Pages/Products/Products.razor +++ b/src/Blazor.Server.UI/Pages/Products/Products.razor @@ -1,4 +1,5 @@ @page "/pages/products" +@using CleanArchitecture.Blazor.Application.Features.Fluxor; @using CleanArchitecture.Blazor.Application.Features.Products.DTOs @using CleanArchitecture.Blazor.Application.Features.Products.Queries @using CleanArchitecture.Blazor.Application.Features.Products.Queries.Export @@ -12,7 +13,7 @@ @using CleanArchitecture.Blazor.Application.Features.Products.Queries.Specification @using Severity = MudBlazor.Severity - +@inherits FluxorComponent @inject IJSRuntime JS @inject IStringLocalizer L @attribute [Authorize(Policy = Permissions.Products.View)] @@ -255,7 +256,9 @@ private bool _exporting; private bool _pdfExporting; private int _defaultPageSize = 15; - + [Inject] + private IState UserProfileState { get; set; } = null!; + private UserProfile UserProfile => UserProfileState.Value.UserProfile; [Inject] private IMediator Mediator { get; set; } = default!; @@ -294,6 +297,7 @@ try { _loading = true; + Query.CurrentUser = UserProfile; Query.Sort = state.SortDefinitions.FirstOrDefault()?.SortBy ?? "Id"; Query.SortBy = state.SortDefinitions.FirstOrDefault()?.Descending ?? true ? Sorting.Descending : Sorting.Ascending; Query.Page = state.Page + 1;