Display no element and nb element (#47)
All checks were successful
Game Ideas build for PR / build_test (pull_request) Successful in 43s

This commit is contained in:
Maxime Adler
2025-05-15 14:34:55 +02:00
parent 3c3448dee0
commit 7a7863f789
13 changed files with 92 additions and 28 deletions

View File

@@ -23,12 +23,22 @@
<div class="content"> <div class="content">
@if (!IsLoading) @if (!IsLoading)
{ {
@foreach (var game in GamesDto) @if (GamesDto.NumberOfGames != 0)
{
<div class="games-number">@string.Format(ResourcesKey.GamesNumberFormat, GamesDto.NumberOfGames)</div>
@foreach (var game in GamesDto.Games)
{ {
<GameRow GameDto="game" OnDelete="HandleDeleteGame" OnEdit="HandleEditGame" /> <GameRow GameDto="game" OnDelete="HandleDeleteGame" OnEdit="HandleEditGame" />
} }
} }
else else
{
<div class="no-games">@ResourcesKey.NoGames</div>
}
}
else
{ {
@for (int i = 0; i < 20; i++) @for (int i = 0; i < 20; i++)
{ {

View File

@@ -12,7 +12,7 @@ public partial class Games : GameBaseComponent
{ {
private DisplayType DisplayType = DisplayType.List; private DisplayType DisplayType = DisplayType.List;
private GameFilterParams GameFilter = new(); private GameFilterParams GameFilter = new();
private IEnumerable<GameDto> GamesDto = []; private GameListDto GamesDto = new();
private int CurrentPage; private int CurrentPage;
private Popup? DeletePopup; private Popup? DeletePopup;
private GameDto? GameToDelete; private GameDto? GameToDelete;
@@ -47,6 +47,7 @@ public partial class Games : GameBaseComponent
finally finally
{ {
IsLoading = false; IsLoading = false;
StateHasChanged();
} }
} }
private async Task HandleFilterChanged(GameFilterParams args) private async Task HandleFilterChanged(GameFilterParams args)

View File

@@ -35,7 +35,7 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway
} }
} }
public async Task<IEnumerable<GameDto>> FetchGames(GameFilterParams filterParams, int currentPage) public async Task<GameListDto> FetchGames(GameFilterParams filterParams, int currentPage)
{ {
try try
{ {
@@ -52,9 +52,11 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway
PropertyIds = filterParams.Properties?.Select(d => d.Id ?? 0).ToList(), PropertyIds = filterParams.Properties?.Select(d => d.Id ?? 0).ToList(),
ReleaseYears = filterParams.ReleaseYears, ReleaseYears = filterParams.ReleaseYears,
TagIds = filterParams.Tags?.Select(d => d.Id ?? 0).ToList(), TagIds = filterParams.Tags?.Select(d => d.Id ?? 0).ToList(),
SortPropertyName = filterParams.SortProperty?.PropertyName,
SortType = filterParams.SortType?.SortType
}; };
var result = await httpClientService.FetchDataAsync<IEnumerable<GameDto>>(Endpoints.Game.Fetch(filter)); var result = await httpClientService.FetchDataAsync<GameListDto>(Endpoints.Game.Fetch(filter));
return result ?? throw new InvalidOperationException(ResourcesKey.ErrorFetchGames); return result ?? throw new InvalidOperationException(ResourcesKey.ErrorFetchGames);
} }
catch (Exception) catch (Exception)

View File

@@ -7,7 +7,7 @@ public interface IGameGateway
{ {
Task<CategoriesDto> FetchCategories(); Task<CategoriesDto> FetchCategories();
Task<int> CreateGame(GameDetailDto game); Task<int> CreateGame(GameDetailDto game);
Task<IEnumerable<GameDto>> FetchGames(GameFilterParams filter, int currentPage); Task<GameListDto> FetchGames(GameFilterParams filter, int currentPage);
Task<GameDetailDto> GetGameById(int gameId); Task<GameDetailDto> GetGameById(int gameId);
Task<bool> DeleteGame(int gameIdToDelete); Task<bool> DeleteGame(int gameIdToDelete);
Task<int> UpdateGame(GameDetailDto gameDto); Task<int> UpdateGame(GameDetailDto gameDto);

View File

@@ -28,12 +28,21 @@
<div class="content"> <div class="content">
@if (!IsLoading) @if (!IsLoading)
{ {
@if (UserList.UsersCount != 0)
{
<div class="user-number">@string.Format(ResourcesKey.UsersNumberFormat, UserList.UsersCount)</div>
@foreach (var user in UserList.Users ?? []) @foreach (var user in UserList.Users ?? [])
{ {
<UserRow User="user" Roles="Roles.ToList()" OnRemove="HandleOpenConfirmationPopup" OnSubmit="HandleUpdateUser" Validator="@(new UserUpdateValidator())" CanDelete=@(user.Id != currentUserId) /> <UserRow User="user" Roles="Roles.ToList()" OnRemove="HandleOpenConfirmationPopup" OnSubmit="HandleUpdateUser" Validator="@(new UserUpdateValidator())" CanDelete=@(user.Id != currentUserId) />
} }
} }
else else
{
<div class="no-users">@ResourcesKey.NoUsers</div>
}
}
else
{ {
@for (int i = 0; i < 20; i++) @for (int i = 0; i < 20; i++)
{ {

View File

@@ -36,20 +36,36 @@ public partial class Users
} }
await FetchData(); await FetchUsers();
await FetchRoles();
await base.OnInitializedAsync(); 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 try
{ {
IsLoading = true; IsLoading = true;
if (fetchRoles)
Roles = await UserGateway.GetRoles(); Roles = await UserGateway.GetRoles();
UserList = await UserGateway.GetUsers(FilterParams, CurrentPage);
} }
catch (Exception) catch (Exception)
{ {
@@ -68,7 +84,7 @@ public partial class Users
IsLoading = true; IsLoading = true;
await UserGateway.CreateUser(user); await UserGateway.CreateUser(user);
await FetchData(false); await FetchUsers();
} }
catch (Exception) catch (Exception)
{ {
@@ -89,7 +105,7 @@ public partial class Users
IsLoading = true; IsLoading = true;
await UserGateway.UpdateUser(user); await UserGateway.UpdateUser(user);
await FetchData(false); await FetchUsers();
} }
catch (Exception) catch (Exception)
{ {
@@ -115,7 +131,7 @@ public partial class Users
IsLoading = true; IsLoading = true;
await UserGateway.DeleteUser(UserDelete.Id); await UserGateway.DeleteUser(UserDelete.Id);
await FetchData(false); await FetchUsers();
} }
catch (Exception) catch (Exception)
{ {
@@ -134,7 +150,7 @@ public partial class Users
} }
private async Task HandleFilterChanged() private async Task HandleFilterChanged()
{ {
await FetchData(false); await FetchUsers(false);
} }
private void HandleCancelPopupClicked() private void HandleCancelPopupClicked()
{ {

View File

@@ -74,6 +74,10 @@ public class Translations (TranslationService translationService)
public string Detail => translationService.Translate(nameof(Detail)); public string Detail => translationService.Translate(nameof(Detail));
public string Edit => translationService.Translate(nameof(Edit)); public string Edit => translationService.Translate(nameof(Edit));
public string Delete => translationService.Translate(nameof(Delete)); 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 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 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 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 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.");
} }

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class GameListDto
{
public IEnumerable<GameDto> Games { get; set; } = [];
public int NumberOfGames { get; set; }
}

View File

@@ -17,7 +17,7 @@ public class GameController(
private readonly ILogger<GameController> logger = loggerFactory.CreateLogger<GameController>(); private readonly ILogger<GameController> logger = loggerFactory.CreateLogger<GameController>();
[HttpGet] [HttpGet]
public async Task<ActionResult<IEnumerable<GameDto>>> SearchGames([FromQuery] GameFilterDto filter) public async Task<ActionResult<GameListDto>> SearchGames([FromQuery] GameFilterDto filter)
{ {
try try
{ {

View File

@@ -69,5 +69,9 @@
"ReadLess": "Réduire", "ReadLess": "Réduire",
"Detail": "Détail", "Detail": "Détail",
"Edit": "Modifier", "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}"
} }

View File

@@ -12,7 +12,7 @@ namespace GameIdeas.WebAPI.Services.Games;
public class GameReadService(GameIdeasContext context, IMapper mapper, ICategoryService categoryService) : IGameReadService public class GameReadService(GameIdeasContext context, IMapper mapper, ICategoryService categoryService) : IGameReadService
{ {
public async Task<IEnumerable<GameDto>> GetGames(GameFilterDto filter) public async Task<GameListDto> GetGames(GameFilterDto filter)
{ {
var query = context.Games var query = context.Games
.Include(g => g.GamePlatforms).ThenInclude(gp => gp.Platform) .Include(g => g.GamePlatforms).ThenInclude(gp => gp.Platform)
@@ -26,13 +26,19 @@ public class GameReadService(GameIdeasContext context, IMapper mapper, ICategory
ApplyOrder(ref query, filter); ApplyOrder(ref query, filter);
var games = await query.Skip((filter.CurrentPage - 1) * GlobalConstants.NUMBER_PER_PAGE) var games = await query.ToListAsync();
.Take(GlobalConstants.NUMBER_PER_PAGE)
.ToListAsync();
ApplyStaticFilter(ref games, filter); ApplyStaticFilter(ref games, filter);
return mapper.Map<IEnumerable<GameDto>>(games); games = [.. games
.Skip((filter.CurrentPage - 1) * GlobalConstants.NUMBER_PER_PAGE)
.Take(GlobalConstants.NUMBER_PER_PAGE)];
return new()
{
Games = mapper.Map<IEnumerable<GameDto>>(games),
NumberOfGames = games.Count
};
} }
public async Task<GameDetailDto> GetGameById(int gameId) public async Task<GameDetailDto> GetGameById(int gameId)

View File

@@ -4,6 +4,6 @@ namespace GameIdeas.WebAPI.Services.Games;
public interface IGameReadService public interface IGameReadService
{ {
Task<IEnumerable<GameDto>> GetGames(GameFilterDto filter); Task<GameListDto> GetGames(GameFilterDto filter);
Task<GameDetailDto> GetGameById(int gameId); Task<GameDetailDto> GetGameById(int gameId);
} }

View File

@@ -33,9 +33,10 @@ public class UserReadService(
.OrderBy(u => u.UserName) .OrderBy(u => u.UserName)
.ToListAsync(); .ToListAsync();
var count = users.Count;
ApplyStaticFilter(ref users, filter); ApplyStaticFilter(ref users, filter);
var count = users.Count;
var usersDto = mapper.Map<IEnumerable<UserDto>>(users); var usersDto = mapper.Map<IEnumerable<UserDto>>(users);
usersDto = await ApplyRoles(usersDto, filter); usersDto = await ApplyRoles(usersDto, filter);