diff --git a/src/api/framework/Core/Paging/PaginationFilter.cs b/src/api/framework/Core/Paging/PaginationFilter.cs index 04bfc1a7c..13be4026e 100644 --- a/src/api/framework/Core/Paging/PaginationFilter.cs +++ b/src/api/framework/Core/Paging/PaginationFilter.cs @@ -7,3 +7,9 @@ public class PaginationFilter : BaseFilter public int PageSize { get; set; } = int.MaxValue; public string[]? OrderBy { get; set; } } + +public static class PaginationFilterExtensions +{ + public static bool HasOrderBy(this PaginationFilter filter) => + filter.OrderBy?.Any() is true; +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs new file mode 100644 index 000000000..6d9ee52a0 --- /dev/null +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductSpecs.cs @@ -0,0 +1,16 @@ +using Ardalis.Specification; +using FSH.Framework.Core.Paging; +using FSH.Framework.Core.Specifications; +using FSH.Starter.WebApi.Catalog.Application.Products.Get.v1; +using FSH.Starter.WebApi.Catalog.Domain; + +namespace FSH.Starter.WebApi.Catalog.Application.Products.Search.v1; +public class SearchProductSpecs : EntitiesByPaginationFilterSpec +{ + public SearchProductSpecs(SearchProductsCommand command) + : base(command) => + Query + .OrderBy(c => c.Name, !command.HasOrderBy()) + .Where(p => p.Price >= command.MinimumRate!.Value, command.MinimumRate.HasValue) + .Where(p => p.Price <= command.MaximumRate!.Value, command.MaximumRate.HasValue); +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs index 79664dcef..ed19c2f95 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsCommand.cs @@ -4,4 +4,9 @@ namespace FSH.Starter.WebApi.Catalog.Application.Products.Search.v1; -public record SearchProductsCommand(PaginationFilter filter) : IRequest>; +public class SearchProductsCommand : PaginationFilter, IRequest> +{ + public Guid? BrandId { get; set; } + public decimal? MinimumRate { get; set; } + public decimal? MaximumRate { get; set; } +} diff --git a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs index 51a3b03d7..7c6c290df 100644 --- a/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs +++ b/src/api/modules/Catalog/Catalog.Application/Products/Search/v1/SearchProductsHandler.cs @@ -1,6 +1,5 @@ using FSH.Framework.Core.Paging; using FSH.Framework.Core.Persistence; -using FSH.Framework.Core.Specifications; using FSH.Starter.WebApi.Catalog.Application.Products.Get.v1; using FSH.Starter.WebApi.Catalog.Domain; using MediatR; @@ -16,12 +15,12 @@ public async Task> Handle(SearchProductsCommand reque { ArgumentNullException.ThrowIfNull(request); - var spec = new EntitiesByPaginationFilterSpec(request.filter); + var spec = new SearchProductSpecs(request); var items = await repository.ListAsync(spec, cancellationToken).ConfigureAwait(false); var totalCount = await repository.CountAsync(spec, cancellationToken).ConfigureAwait(false); - return new PagedList(items, request.filter.PageNumber, request.filter.PageSize, totalCount); + return new PagedList(items, request!.PageNumber, request!.PageSize, totalCount); } } diff --git a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchProductsEndpoint.cs b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchProductsEndpoint.cs index 7c0ac5fb4..e3d058006 100644 --- a/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchProductsEndpoint.cs +++ b/src/api/modules/Catalog/Catalog.Infrastructure/Endpoints/v1/SearchProductsEndpoint.cs @@ -15,9 +15,9 @@ public static class SearchProductsEndpoint internal static RouteHandlerBuilder MapGetProductListEndpoint(this IEndpointRouteBuilder endpoints) { return endpoints - .MapPost("/search", async (ISender mediator, [FromBody] PaginationFilter filter) => + .MapPost("/search", async (ISender mediator, [FromBody] SearchProductsCommand command) => { - var response = await mediator.Send(new SearchProductsCommand(filter)); + var response = await mediator.Send(command); return Results.Ok(response); }) .WithName(nameof(SearchProductsEndpoint)) diff --git a/src/apps/blazor/client/Pages/Catalog/Products.razor.cs b/src/apps/blazor/client/Pages/Catalog/Products.razor.cs index cc4ad32e4..2cbcaa8ff 100644 --- a/src/apps/blazor/client/Pages/Catalog/Products.razor.cs +++ b/src/apps/blazor/client/Pages/Catalog/Products.razor.cs @@ -31,8 +31,9 @@ protected override void OnInitialized() => idFunc: prod => prod.Id!.Value, searchFunc: async filter => { - var productFilter = filter.Adapt(); - + var productFilter = filter.Adapt(); + productFilter.MinimumRate = Convert.ToDouble(SearchMinimumRate); + productFilter.MaximumRate = Convert.ToDouble(SearchMaximumRate); var result = await _client.SearchProductsEndpointAsync("1", productFilter); return result.Adapt>(); }, @@ -84,4 +85,4 @@ private decimal SearchMaximumRate public class ProductViewModel : UpdateProductCommand { -} \ No newline at end of file +} diff --git a/src/apps/blazor/infrastructure/Api/ApiClient.cs b/src/apps/blazor/infrastructure/Api/ApiClient.cs index 385805c41..b3e9b0bcc 100644 --- a/src/apps/blazor/infrastructure/Api/ApiClient.cs +++ b/src/apps/blazor/infrastructure/Api/ApiClient.cs @@ -127,7 +127,7 @@ public partial interface IApiClient /// The requested API version /// OK /// A server side error occurred. - System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, PaginationFilter body); + System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, SearchProductsCommand body); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// @@ -139,7 +139,7 @@ public partial interface IApiClient /// The requested API version /// OK /// A server side error occurred. - System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, PaginationFilter body, System.Threading.CancellationToken cancellationToken); + System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, SearchProductsCommand body, System.Threading.CancellationToken cancellationToken); /// /// Get role details by ID @@ -1312,7 +1312,7 @@ public virtual async System.Threading.Tasks.Task DeleteProductEndpointAsync(stri /// The requested API version /// OK /// A server side error occurred. - public virtual System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, PaginationFilter body) + public virtual System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, SearchProductsCommand body) { return SearchProductsEndpointAsync(version, body, System.Threading.CancellationToken.None); } @@ -1327,7 +1327,7 @@ public virtual System.Threading.Tasks.Task SearchProdu /// The requested API version /// OK /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, PaginationFilter body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SearchProductsEndpointAsync(string version, SearchProductsCommand body, System.Threading.CancellationToken cancellationToken) { if (version == null) throw new System.ArgumentNullException("version"); @@ -5151,6 +5151,39 @@ public partial class Search } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SearchProductsCommand + { + + [System.Text.Json.Serialization.JsonPropertyName("advancedSearch")] + public Search AdvancedSearch { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("keyword")] + public string? Keyword { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("advancedFilter")] + public Filter AdvancedFilter { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageNumber")] + public int PageNumber { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("pageSize")] + public int PageSize { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("orderBy")] + public System.Collections.Generic.ICollection? OrderBy { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("brandId")] + public System.Guid? BrandId { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("minimumRate")] + public double? MinimumRate { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("maximumRate")] + public double? MaximumRate { get; set; } = default!; + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class TenantDetail {