diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor index 73b7dc7..4d87077 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor @@ -23,10 +23,20 @@
@if (!IsLoading) { - @foreach (var game in GamesDto) + @if (GamesDto.NumberOfGames != 0) { - +
@string.Format(ResourcesKey.GamesNumberFormat, GamesDto.NumberOfGames)
+ + @foreach (var game in GamesDto.Games) + { + + } } + else + { +
@ResourcesKey.NoGames
+ } + } else { diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor.cs index dc72481..8c23184 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Games.razor.cs @@ -12,7 +12,7 @@ public partial class Games : GameBaseComponent { private DisplayType DisplayType = DisplayType.List; private GameFilterParams GameFilter = new(); - private IEnumerable GamesDto = []; + private GameListDto GamesDto = new(); private int CurrentPage; private Popup? DeletePopup; private GameDto? GameToDelete; @@ -47,6 +47,7 @@ public partial class Games : GameBaseComponent finally { IsLoading = false; + StateHasChanged(); } } private async Task HandleFilterChanged(GameFilterParams args) 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 0affe3f..f2f4b8c 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs @@ -35,7 +35,7 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway } } - public async Task> FetchGames(GameFilterParams filterParams, int currentPage) + public async Task FetchGames(GameFilterParams filterParams, int currentPage) { try { @@ -52,9 +52,11 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway PropertyIds = filterParams.Properties?.Select(d => d.Id ?? 0).ToList(), ReleaseYears = filterParams.ReleaseYears, TagIds = filterParams.Tags?.Select(d => d.Id ?? 0).ToList(), + SortPropertyName = filterParams.SortProperty?.PropertyName, + SortType = filterParams.SortType?.SortType }; - var result = await httpClientService.FetchDataAsync>(Endpoints.Game.Fetch(filter)); + 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 ac8cb99..7c1825e 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs @@ -7,7 +7,7 @@ public interface IGameGateway { Task FetchCategories(); Task CreateGame(GameDetailDto game); - Task> FetchGames(GameFilterParams filter, int currentPage); + Task FetchGames(GameFilterParams filter, int currentPage); Task GetGameById(int gameId); Task DeleteGame(int gameIdToDelete); Task UpdateGame(GameDetailDto gameDto); diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor index 0fbc631..08e129f 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor @@ -16,7 +16,7 @@
+ Items="Roles.ToList()" GetLabel="@(role => role.Name)" Theme="SelectTheme.Filter" />
@@ -28,9 +28,18 @@
@if (!IsLoading) { - @foreach (var user in UserList.Users ?? []) + @if (UserList.UsersCount != 0) { - +
@string.Format(ResourcesKey.UsersNumberFormat, UserList.UsersCount)
+ + @foreach (var user in UserList.Users ?? []) + { + + } + } + else + { +
@ResourcesKey.NoUsers
} } else diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor.cs index 7bd0a6b..4898e87 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Users/Users.razor.cs @@ -36,20 +36,36 @@ public partial class Users } - await FetchData(); + await FetchUsers(); + await FetchRoles(); await base.OnInitializedAsync(); } - private async Task FetchData(bool fetchRoles = true) + private async Task FetchUsers(bool displayLoading = true) + { + try + { + IsLoading = displayLoading; + + UserList = await UserGateway.GetUsers(FilterParams, CurrentPage); + } + catch (Exception) + { + throw; + } + finally + { + IsLoading = false; + } + } + + private async Task FetchRoles() { try { IsLoading = true; - if (fetchRoles) - Roles = await UserGateway.GetRoles(); - - UserList = await UserGateway.GetUsers(FilterParams, CurrentPage); + Roles = await UserGateway.GetRoles(); } catch (Exception) { @@ -68,7 +84,7 @@ public partial class Users IsLoading = true; await UserGateway.CreateUser(user); - await FetchData(false); + await FetchUsers(); } catch (Exception) { @@ -89,7 +105,7 @@ public partial class Users IsLoading = true; await UserGateway.UpdateUser(user); - await FetchData(false); + await FetchUsers(); } catch (Exception) { @@ -115,7 +131,7 @@ public partial class Users IsLoading = true; await UserGateway.DeleteUser(UserDelete.Id); - await FetchData(false); + await FetchUsers(); } catch (Exception) { @@ -134,7 +150,7 @@ public partial class Users } private async Task HandleFilterChanged() { - await FetchData(false); + await FetchUsers(false); } private void HandleCancelPopupClicked() { diff --git a/src/GameIdeas/GameIdeas.Resources/CreateStaticResourceKey.cs b/src/GameIdeas/GameIdeas.Resources/CreateStaticResourceKey.cs index 59d4532..587a37a 100644 --- a/src/GameIdeas/GameIdeas.Resources/CreateStaticResourceKey.cs +++ b/src/GameIdeas/GameIdeas.Resources/CreateStaticResourceKey.cs @@ -74,6 +74,10 @@ public class Translations (TranslationService translationService) public string Detail => translationService.Translate(nameof(Detail)); public string Edit => translationService.Translate(nameof(Edit)); public string Delete => translationService.Translate(nameof(Delete)); + public string NoGames => translationService.Translate(nameof(NoGames)); + public string NoUsers => translationService.Translate(nameof(NoUsers)); + public string GamesNumberFormat => translationService.Translate(nameof(GamesNumberFormat)); + public string UsersNumberFormat => translationService.Translate(nameof(UsersNumberFormat)); } public static class ResourcesKey @@ -156,4 +160,8 @@ public static class ResourcesKey public static string Detail => _instance?.Detail ?? throw new InvalidOperationException("ResourcesKey.Detail is not initialized."); public static string Edit => _instance?.Edit ?? throw new InvalidOperationException("ResourcesKey.Edit is not initialized."); public static string Delete => _instance?.Delete ?? throw new InvalidOperationException("ResourcesKey.Delete is not initialized."); + public static string NoGames => _instance?.NoGames ?? throw new InvalidOperationException("ResourcesKey.NoGames is not initialized."); + public static string NoUsers => _instance?.NoUsers ?? throw new InvalidOperationException("ResourcesKey.NoUsers is not initialized."); + public static string GamesNumberFormat => _instance?.GamesNumberFormat ?? throw new InvalidOperationException("ResourcesKey.GamesNumberFormat is not initialized."); + public static string UsersNumberFormat => _instance?.UsersNumberFormat ?? throw new InvalidOperationException("ResourcesKey.UsersNumberFormat is not initialized."); } \ No newline at end of file diff --git a/src/GameIdeas/GameIdeas.Shared/Dto/GameListDto.cs b/src/GameIdeas/GameIdeas.Shared/Dto/GameListDto.cs new file mode 100644 index 0000000..fe573e9 --- /dev/null +++ b/src/GameIdeas/GameIdeas.Shared/Dto/GameListDto.cs @@ -0,0 +1,7 @@ +namespace GameIdeas.Shared.Dto; + +public class GameListDto +{ + public IEnumerable Games { get; set; } = []; + public int NumberOfGames { get; set; } +} diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs index 8ec0eac..d71b1e6 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Controllers/GameController.cs @@ -17,7 +17,7 @@ public class GameController( private readonly ILogger logger = loggerFactory.CreateLogger(); [HttpGet] - public async Task>> SearchGames([FromQuery] GameFilterDto filter) + public async Task> SearchGames([FromQuery] GameFilterDto filter) { try { diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Files/GameIdeas.fr.json b/src/GameIdeas/Server/GameIdeas.WebAPI/Files/GameIdeas.fr.json index 631c233..0d07dfc 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Files/GameIdeas.fr.json +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Files/GameIdeas.fr.json @@ -69,5 +69,9 @@ "ReadLess": "Réduire", "Detail": "Détail", "Edit": "Modifier", - "Delete": "Supprimer" + "Delete": "Supprimer", + "NoGames": "Pas de jeux disponible", + "NoUsers": "Pas d'utilisateurs disponible", + "GamesNumberFormat": "Nombre de jeux : {0}", + "UsersNumberFormat": "Nombre d'utilisateurs : {0}" } \ No newline at end of file diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/GameReadService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/GameReadService.cs index 3320f74..d65f12d 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/GameReadService.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/GameReadService.cs @@ -12,7 +12,7 @@ namespace GameIdeas.WebAPI.Services.Games; public class GameReadService(GameIdeasContext context, IMapper mapper, ICategoryService categoryService) : IGameReadService { - public async Task> GetGames(GameFilterDto filter) + public async Task GetGames(GameFilterDto filter) { var query = context.Games .Include(g => g.GamePlatforms).ThenInclude(gp => gp.Platform) @@ -26,13 +26,19 @@ public class GameReadService(GameIdeasContext context, IMapper mapper, ICategory ApplyOrder(ref query, filter); - var games = await query.Skip((filter.CurrentPage - 1) * GlobalConstants.NUMBER_PER_PAGE) - .Take(GlobalConstants.NUMBER_PER_PAGE) - .ToListAsync(); + var games = await query.ToListAsync(); ApplyStaticFilter(ref games, filter); - return mapper.Map>(games); + games = [.. games + .Skip((filter.CurrentPage - 1) * GlobalConstants.NUMBER_PER_PAGE) + .Take(GlobalConstants.NUMBER_PER_PAGE)]; + + return new() + { + Games = mapper.Map>(games), + NumberOfGames = games.Count + }; } public async Task GetGameById(int gameId) diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/IGameReadService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/IGameReadService.cs index 4c814d3..49d5050 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/IGameReadService.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Games/IGameReadService.cs @@ -4,6 +4,6 @@ namespace GameIdeas.WebAPI.Services.Games; public interface IGameReadService { - Task> GetGames(GameFilterDto filter); + Task GetGames(GameFilterDto filter); Task GetGameById(int gameId); } diff --git a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserReadService.cs b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserReadService.cs index 1c377fa..6342c6a 100644 --- a/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserReadService.cs +++ b/src/GameIdeas/Server/GameIdeas.WebAPI/Services/Users/UserReadService.cs @@ -33,8 +33,9 @@ public class UserReadService( .OrderBy(u => u.UserName) .ToListAsync(); - var count = users.Count; ApplyStaticFilter(ref users, filter); + + var count = users.Count; var usersDto = mapper.Map>(users); usersDto = await ApplyRoles(usersDto, filter);