diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/UrlHelper.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/UrlHelper.cs new file mode 100644 index 0000000..2ffd849 --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Helpers/UrlHelper.cs @@ -0,0 +1,38 @@ +using System.Collections; + +namespace GameIdeas.BlazorApp.Helpers; + +public static class UrlHelper +{ + public static string BuildUrlParams(object? model) + { + if (model == null) + return string.Empty; + + var properties = model.GetType().GetProperties(); + var queryParams = properties + .Select(p => + { + var value = p.GetValue(model); + + switch (value) + { + case null: + return null; + case DateTime dateTime: + return $"{p.Name}={Uri.EscapeDataString(dateTime.ToString("yyyy-MM-dd HH:mm:ss"))}"; + } + + if (value is IEnumerable enumerable and not string) + { + var items = enumerable.Cast() + .Select(item => $"{p.Name}={Uri.EscapeDataString(item?.ToString() ?? string.Empty)}"); + return string.Join("&", items); + } + + return $"{p.Name}={Uri.EscapeDataString(value.ToString() ?? string.Empty)}"; + }) + .ToArray(); + return string.Join("&", queryParams.Where(p => p != null)); + } +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor.cs index 9447fe8..be03b6b 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor.cs @@ -6,9 +6,9 @@ namespace GameIdeas.BlazorApp.Pages.Games.Filter; public partial class AdvancedGameFilter { - [Parameter] public GameFilterDto GameFilter { get; set; } = new(); + [Parameter] public GameFilterParams GameFilter { get; set; } = new(); [Parameter] public CategoriesDto? Categories { get; set; } - [Parameter] public EventCallback GameFilterChanged { get; set; } + [Parameter] public EventCallback GameFilterChanged { get; set; } private readonly SelectTheme Theme = SelectTheme.AdvancedFilter; diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor index 0f2b88a..f864301 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor @@ -31,6 +31,7 @@
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor.cs index c5f2c1e..749f0f5 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor.cs @@ -10,8 +10,8 @@ namespace GameIdeas.BlazorApp.Pages.Games.Filter; public partial class GameFilter { - [Parameter] public GameFilterDto Value { get; set; } = new(); - [Parameter] public EventCallback ValueChanged { get; set; } + [Parameter] public GameFilterParams Value { get; set; } = new(); + [Parameter] public EventCallback ValueChanged { get; set; } [Parameter] public DisplayType DisplayType { get; set; } [Parameter] public EventCallback DisplayTypeChanged { get; set; } [Parameter] public CategoriesDto? Categories { get; set; } @@ -23,8 +23,10 @@ public partial class GameFilter ]; private readonly List GameProperties = [ - new() { SortProperty = game => game.Title!, Label = "Titre" }, - new() { SortProperty = game => game.ReleaseDate!, Label = "Date de parution" } + new() { PropertyName = nameof(GameDetailDto.Title), Label = "Titre" }, + new() { PropertyName = nameof(GameDetailDto.ReleaseDate), Label = "Date de parution" }, + new() { PropertyName = nameof(GameDetailDto.StorageSpace), Label = "Espace de stockage" }, + new() { PropertyName = nameof(GameDetailDto.Interest), Label = "Interêt" } ]; private SelectParams SelectParams = new(); @@ -39,7 +41,7 @@ public partial class GameFilter DefaultHeaders = SortTypes.Where(h => h.SortType == SortType.Ascending).ToList(), Items = GameProperties, GetItemLabel = item => item.Label, - DefaultItems = GameProperties.Where(p => p.Label == "Titre").ToList() + DefaultItems = GameProperties.Where(p => p.PropertyName == nameof(GameDetailDto.Title)).ToList() }; } diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs new file mode 100644 index 0000000..1fc1f1b --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs @@ -0,0 +1,19 @@ + +namespace GameIdeas.Shared.Dto; + +public class GameFilterParams +{ + public SortTypeDto? SortType { get; set; } + public SortPropertyDto? SortProperty { get; set; } + public string? Title { get; set; } + public List? Platforms { get; set; } + public List? Properties { get; set; } + public List? Tags { get; set; } + public List? Publishers { get; set; } + public List? Developers { get; set; } + public int MinInterest { get; set; } = 1; + public int MaxInterest { get; set; } = 5; + public List? ReleaseYears { get; set; } + public int? MinStorageSize { get; set; } + public int? MaxStorageSize { get; set; } +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor index 8841706..d5011b5 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor @@ -14,7 +14,7 @@ + Value=GameFilter ValueChanged="HandleFilterChanged" />
@@ -36,7 +36,7 @@
- + diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor.cs index f586315..198eeba 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Game.razor.cs @@ -11,14 +11,16 @@ public partial class Game [Inject] private IGameGateway GameGateway { get; set; } = default!; private DisplayType DisplayType = DisplayType.List; - private GameFilterDto GameFilter = new(); + private GameFilterParams GameFilter = new(); private Popup? ManualAddPopup; private bool IsLoading = false; private CategoriesDto? Categories; private IEnumerable GamesDto = []; + private int CurrentPage; protected override async Task OnInitializedAsync() { + CurrentPage = 1; await HandleFetchDatas(); await base.OnInitializedAsync(); } @@ -46,7 +48,28 @@ public partial class Game IsLoading = true; Categories = await GameGateway.FetchCategories(); - GamesDto = await GameGateway.FetchGames(new PaggingDto() { CurrentPage = 1, NumberPerPage = 50 }); + GamesDto = await GameGateway.FetchGames(GameFilter, CurrentPage); + } + catch (Exception) + { + throw; + } + finally + { + IsLoading = false; + } + } + private async Task HandleFilterChanged(GameFilterParams args) + { + GameFilter = args; + + + + try + { + IsLoading = true; + + GamesDto = await GameGateway.FetchGames(GameFilter, CurrentPage); } catch (Exception) { diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs index ff68e56..0cbf89b 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs @@ -34,11 +34,29 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway } } - public async Task> FetchGames(PaggingDto pagging) + public async Task> FetchGames(GameFilterParams filterParams, int currentPage) { try { - var result = await httpClientService.FetchDataAsync>(Endpoints.Game.Fetch(pagging)); + GameFilterDto filter = new() + { + CurrentPage = currentPage, + Title = filterParams.Title, + MaxInterest = filterParams.MaxInterest, + MinInterest = filterParams.MinInterest, + MaxStorageSize = filterParams.MaxStorageSize, + MinStorageSize = filterParams.MinStorageSize, + ReleaseYears = filterParams.ReleaseYears, + DeveloperIds = filterParams.Developers?.Select(d => d.Id ?? 0).ToList(), + PublisherIds = filterParams.Publishers?.Select(d => d.Id ?? 0).ToList(), + PlatformIds = filterParams.Platforms?.Select(d => d.Id ?? 0).ToList(), + PropertyIds = filterParams.Properties?.Select(d => d.Id ?? 0).ToList(), + TagIds = filterParams.Tags?.Select(d => d.Id ?? 0).ToList(), + SortType = filterParams.SortType?.SortType, + SortPropertyName = filterParams.SortProperty?.PropertyName + }; + + var result = await httpClientService.FetchDataAsync>(Endpoints.Game.Fetch(filter)); return result ?? throw new InvalidOperationException(ResourcesKey.ErrorFetchGames); } catch (Exception) diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs index 645a988..cbb8439 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs @@ -6,5 +6,5 @@ public interface IGameGateway { Task FetchCategories(); Task CreateGame(GameDetailDto game); - Task> FetchGames(PaggingDto pagging); + Task> FetchGames(GameFilterParams filter, int currentPage); } diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Constants/Endpoints.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Constants/Endpoints.cs index 3e6289d..0665ffa 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Constants/Endpoints.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Constants/Endpoints.cs @@ -1,4 +1,5 @@ -using GameIdeas.Shared.Dto; +using GameIdeas.BlazorApp.Helpers; +using GameIdeas.Shared.Dto; namespace GameIdeas.BlazorApp.Shared.Constants; @@ -7,8 +8,7 @@ public static class Endpoints public static class Game { public static readonly string Create = "api/Game/Create"; - public static string Fetch(PaggingDto pagging) => - $"api/Game?{nameof(pagging.CurrentPage)}={pagging.CurrentPage}&{nameof(pagging.NumberPerPage)}={pagging.NumberPerPage}"; + public static string Fetch(GameFilterDto filter) => $"api/Game?{UrlHelper.BuildUrlParams(filter)}"; } public static class Category diff --git a/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs b/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs index 373c8b2..ff8ddf9 100644 --- a/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs +++ b/src/GameIdeas/GameIdeas.Shared/Constants/GlobalConstants.cs @@ -2,6 +2,6 @@ public class GlobalConstants { - + public static int NUMBER_PER_PAGE = 50; } \ No newline at end of file diff --git a/src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs b/src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs index d2922c2..7c1fcb2 100644 --- a/src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs +++ b/src/GameIdeas/GameIdeas.Shared/Dto/GameFilterDto.cs @@ -1,16 +1,18 @@ - +using GameIdeas.Shared.Enum; + namespace GameIdeas.Shared.Dto; public class GameFilterDto { - public SortTypeDto? SortType { get; set; } - public SortPropertyDto? SortProperty { get; set; } + public int CurrentPage { get; set; } = 1; + public SortType? SortType { get; set; } + public string? SortPropertyName { get; set; } public string? Title { get; set; } - public List? Platforms { get; set; } - public List? Properties { get; set; } - public List? Tags { get; set; } - public List? Publishers { get; set; } - public List? Developers { get; set; } + public List? PlatformIds { get; set; } + public List? PropertyIds { get; set; } + public List? TagIds { get; set; } + public List? PublisherIds { get; set; } + public List? DeveloperIds { get; set; } public int MinInterest { get; set; } = 1; public int MaxInterest { get; set; } = 5; public List? ReleaseYears { get; set; } diff --git a/src/GameIdeas/GameIdeas.Shared/Dto/PaggingDto.cs b/src/GameIdeas/GameIdeas.Shared/Dto/PaggingDto.cs deleted file mode 100644 index c006966..0000000 --- a/src/GameIdeas/GameIdeas.Shared/Dto/PaggingDto.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GameIdeas.Shared.Dto; - -public class PaggingDto -{ - public int CurrentPage { get; set; } - public int NumberPerPage { get; set; } -} diff --git a/src/GameIdeas/GameIdeas.Shared/Dto/SortPropertyDto.cs b/src/GameIdeas/GameIdeas.Shared/Dto/SortPropertyDto.cs index 9d6343e..1261e67 100644 --- a/src/GameIdeas/GameIdeas.Shared/Dto/SortPropertyDto.cs +++ b/src/GameIdeas/GameIdeas.Shared/Dto/SortPropertyDto.cs @@ -2,6 +2,6 @@ public class SortPropertyDto { - public Func? SortProperty { get; set; } + public string PropertyName { get; set; } = string.Empty; public string Label { get; set; } = string.Empty; } diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs index ba68265..fd0e9a6 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs @@ -12,11 +12,11 @@ public class GameController(IGameService gameService, ILoggerFactory loggerFacto private readonly ILogger logger = loggerFactory.CreateLogger(); [HttpGet] - public async Task>> SearchGames([FromQuery] PaggingDto pagging) + public async Task>> SearchGames([FromQuery] GameFilterDto filter) { try { - return Ok(await gameService.GetGames(pagging)); + return Ok(await gameService.GetGames(filter)); } catch (Exception e) { diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs index 91625ce..b3afab7 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/GameService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using GameIdeas.Shared.Constants; using GameIdeas.Shared.Dto; using GameIdeas.Shared.Exceptions; using GameIdeas.Shared.Model; @@ -10,12 +11,12 @@ namespace GameIdeas.WebAPI.Services; public class GameService(GameIdeasContext context, IMapper mapper) : IGameService { - public async Task> GetGames(PaggingDto pagging) + public async Task> GetGames(GameFilterDto filter) { var games = await SelectGames() .OrderBy(g => g.Title) - .Skip((pagging.CurrentPage - 1) * pagging.NumberPerPage) - .Take(pagging.NumberPerPage) + .Skip((filter.CurrentPage - 1) * GlobalConstants.NUMBER_PER_PAGE) + .Take(GlobalConstants.NUMBER_PER_PAGE) .ToListAsync(); return mapper.Map>(games); diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Interfaces/IGameService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Interfaces/IGameService.cs index 0b3e974..ff2749d 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Interfaces/IGameService.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Interfaces/IGameService.cs @@ -4,7 +4,7 @@ namespace GameIdeas.WebAPI.Services.Interfaces; public interface IGameService { - Task> GetGames(PaggingDto pagging); + Task> GetGames(GameFilterDto filter); Task GetGameById(int gameId); Task CreateGame(GameDetailDto gameDto); Task UpdateGame(GameDetailDto gameDto);