Update and delete games #48

Merged
Egamorf merged 10 commits from feature/update-and-delete-games into main 2025-05-13 14:13:31 +02:00
11 changed files with 144 additions and 73 deletions
Showing only changes of commit 14dc1928bc - Show all commits

View File

@@ -1,10 +1,10 @@
using GameIdeas.BlazorApp.Pages.Games.Gateways; using GameIdeas.BlazorApp.Shared.Components;
using GameIdeas.Shared.Dto; using GameIdeas.Shared.Dto;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace GameIdeas.BlazorApp.Pages.Detail; namespace GameIdeas.BlazorApp.Pages.Detail;
public partial class GameDetail public partial class GameDetail : GameBaseComponent
{ {
[Inject] private NavigationManager NavigationManager { get; set; } = default!; [Inject] private NavigationManager NavigationManager { get; set; } = default!;
[Parameter] public int GameId { get; set; } [Parameter] public int GameId { get; set; }

View File

@@ -29,7 +29,7 @@ public class GameBase : ComponentBase
switch (option) switch (option)
{ {
case DetailOptions.Detail: case DetailOptions.Detail:
NavigationManager.NavigateTo($"/Games/Detail/{GameDto.Id}"); NavigationManager.NavigateTo($"/Detail/{GameDto.Id}");
break; break;
case DetailOptions.Edit: case DetailOptions.Edit:
await OnEdit.InvokeAsync(GameDto); await OnEdit.InvokeAsync(GameDto);

View File

@@ -5,6 +5,7 @@
@using GameIdeas.BlazorApp.Shared.Components.ButtonAdd @using GameIdeas.BlazorApp.Shared.Components.ButtonAdd
@using GameIdeas.BlazorApp.Shared.Components.Header @using GameIdeas.BlazorApp.Shared.Components.Header
@using GameIdeas.BlazorApp.Shared.Components.Popup @using GameIdeas.BlazorApp.Shared.Components.Popup
@using GameIdeas.BlazorApp.Shared.Components.Popup.Components
@using GameIdeas.Resources @using GameIdeas.Resources
@inherits GameBaseComponent @inherits GameBaseComponent
@layout MainLayout @layout MainLayout
@@ -24,7 +25,7 @@
{ {
@foreach (var game in GamesDto) @foreach (var game in GamesDto)
{ {
<GameRow GameDto="game" /> <GameRow GameDto="game" OnDelete="HandleDeleteGame" OnEdit="HandleEditGame" />
} }
} }
else else
@@ -43,3 +44,7 @@
<Popup @ref=ManualAddPopup BackdropFilterClicked="HandleBackdropManualAddClicked" Closable=false> <Popup @ref=ManualAddPopup BackdropFilterClicked="HandleBackdropManualAddClicked" Closable=false>
<GameCreationForm Categories="Categories" OnSubmit="() => HandleFetchDatas()" /> <GameCreationForm Categories="Categories" OnSubmit="() => HandleFetchDatas()" />
</Popup> </Popup>
<Popup @ref=DeletePopup Closable=false>
<ConfirmDelete OnCancel="HandleCancelPopupClicked" OnConfirm="HandleRemoveGame" />
</Popup>

View File

@@ -1,5 +1,6 @@
using GameIdeas.BlazorApp.Pages.Games.Filter; using GameIdeas.BlazorApp.Pages.Games.Filter;
using GameIdeas.BlazorApp.Shared.Components; using GameIdeas.BlazorApp.Shared.Components;
using GameIdeas.BlazorApp.Shared.Components.Popup;
using GameIdeas.BlazorApp.Shared.Models; using GameIdeas.BlazorApp.Shared.Models;
using GameIdeas.Shared.Dto; using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Enum; using GameIdeas.Shared.Enum;
@@ -12,6 +13,8 @@ public partial class Games : GameBaseComponent
private GameFilterParams GameFilter = new(); private GameFilterParams GameFilter = new();
private IEnumerable<GameDto> GamesDto = []; private IEnumerable<GameDto> GamesDto = [];
private int CurrentPage; private int CurrentPage;
private Popup? DeletePopup;
private GameDto? GameToDelete;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
@@ -48,4 +51,46 @@ public partial class Games : GameBaseComponent
GameFilter = args; GameFilter = args;
await HandleFetchDatas(false); await HandleFetchDatas(false);
} }
private void HandleDeleteGame(GameDto args)
{
DeletePopup?.Open();
GameToDelete = args;
}
private void HandleCancelPopupClicked()
{
DeletePopup?.Close();
GameToDelete = null;
}
private Task HandleEditGame(GameDto args)
{
throw new NotImplementedException();
}
private async Task HandleRemoveGame()
{
DeletePopup?.Close();
if (GameToDelete?.Id == null)
{
return;
}
try
{
IsLoading = true;
await GameGateway.DeleteGame(GameToDelete?.Id ?? 0);
await HandleFetchDatas(false);
}
catch (Exception)
{
throw;
}
GameToDelete = null;
}
} }

View File

@@ -76,4 +76,16 @@ public class GameGateway(IHttpClientService httpClientService) : IGameGateway
throw new CategoryNotFoundException(ResourcesKey.ErrorFetchGames); throw new CategoryNotFoundException(ResourcesKey.ErrorFetchGames);
} }
} }
public async Task<bool> DeleteGame(int gameIdToDelete)
{
try
{
return await httpClientService.DeleteAsync<bool>(Endpoints.Game.Delete(gameIdToDelete));
}
catch (Exception)
{
throw new GameDeletionException(ResourcesKey.ErrorDeleteGame);
}
}
} }

View File

@@ -9,4 +9,5 @@ public interface IGameGateway
Task<int> CreateGame(GameDetailDto game); Task<int> CreateGame(GameDetailDto game);
Task<IEnumerable<GameDto>> FetchGames(GameFilterParams filter, int currentPage); Task<IEnumerable<GameDto>> FetchGames(GameFilterParams filter, int currentPage);
Task<GameDetailDto> GetGameById(int gameId); Task<GameDetailDto> GetGameById(int gameId);
Task<bool> DeleteGame(int gameIdToDelete);
} }

View File

@@ -10,6 +10,7 @@ public static class Endpoints
public const string Create = "api/Game/Create"; public const string Create = "api/Game/Create";
public static string Fetch(GameFilterDto filter) => $"api/Game?{UrlHelper.BuildUrlParams(filter)}"; public static string Fetch(GameFilterDto filter) => $"api/Game?{UrlHelper.BuildUrlParams(filter)}";
public static string FetchById(int gameId) => $"api/Game/{gameId}"; public static string FetchById(int gameId) => $"api/Game/{gameId}";
public static string Delete(int gameId) => $"api/Game/Delete/{gameId}";
} }
public static class Category public static class Category

View File

@@ -0,0 +1,3 @@
namespace GameIdeas.BlazorApp.Shared.Exceptions;
public class GameDeletionException(string message) : Exception(message);

View File

@@ -147,9 +147,10 @@ code {
.body-lg { .body-lg {
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
display: block;
} }
.header-1, .header-2, span, a { .header-1, .header-2 {
display: block; display: block;
color: var(--white); color: var(--white);
margin: 0; margin: 0;

View File

@@ -39,6 +39,7 @@ public class Translations (TranslationService translationService)
public string ErrorFetchCategories => translationService.Translate(nameof(ErrorFetchCategories)); public string ErrorFetchCategories => translationService.Translate(nameof(ErrorFetchCategories));
public string PlaceholderAdd => translationService.Translate(nameof(PlaceholderAdd)); public string PlaceholderAdd => translationService.Translate(nameof(PlaceholderAdd));
public string ErrorCreateGame => translationService.Translate(nameof(ErrorCreateGame)); public string ErrorCreateGame => translationService.Translate(nameof(ErrorCreateGame));
public string ErrorDeleteGame => translationService.Translate(nameof(ErrorDeleteGame));
public string InvalidTitle => translationService.Translate(nameof(InvalidTitle)); public string InvalidTitle => translationService.Translate(nameof(InvalidTitle));
public string InvalidInterest => translationService.Translate(nameof(InvalidInterest)); public string InvalidInterest => translationService.Translate(nameof(InvalidInterest));
public string Unknown => translationService.Translate(nameof(Unknown)); public string Unknown => translationService.Translate(nameof(Unknown));
@@ -118,6 +119,7 @@ public static class ResourcesKey
public static string ErrorFetchCategories => _instance?.ErrorFetchCategories ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchCategories is not initialized."); public static string ErrorFetchCategories => _instance?.ErrorFetchCategories ?? throw new InvalidOperationException("ResourcesKey.ErrorFetchCategories is not initialized.");
public static string PlaceholderAdd => _instance?.PlaceholderAdd ?? throw new InvalidOperationException("ResourcesKey.PlaceholderAdd is not initialized."); public static string PlaceholderAdd => _instance?.PlaceholderAdd ?? throw new InvalidOperationException("ResourcesKey.PlaceholderAdd is not initialized.");
public static string ErrorCreateGame => _instance?.ErrorCreateGame ?? throw new InvalidOperationException("ResourcesKey.ErrorCreateGame is not initialized."); public static string ErrorCreateGame => _instance?.ErrorCreateGame ?? throw new InvalidOperationException("ResourcesKey.ErrorCreateGame is not initialized.");
public static string ErrorDeleteGame => _instance?.ErrorDeleteGame ?? throw new InvalidOperationException("ResourcesKey.ErrorDeleteGame is not initialized.");
public static string InvalidTitle => _instance?.InvalidTitle ?? throw new InvalidOperationException("ResourcesKey.InvalidTitle is not initialized."); public static string InvalidTitle => _instance?.InvalidTitle ?? throw new InvalidOperationException("ResourcesKey.InvalidTitle is not initialized.");
public static string InvalidInterest => _instance?.InvalidInterest ?? throw new InvalidOperationException("ResourcesKey.InvalidInterest is not initialized."); public static string InvalidInterest => _instance?.InvalidInterest ?? throw new InvalidOperationException("ResourcesKey.InvalidInterest is not initialized.");
public static string Unknown => _instance?.Unknown ?? throw new InvalidOperationException("ResourcesKey.Unknown is not initialized."); public static string Unknown => _instance?.Unknown ?? throw new InvalidOperationException("ResourcesKey.Unknown is not initialized.");

View File

@@ -1,70 +1,71 @@
{ {
"GamesIdeas": "Game Ideas", "GamesIdeas": "Game Ideas",
"ManualAdd": "Manuel", "ManualAdd": "Manuel",
"AutoAdd": "Automatique", "AutoAdd": "Automatique",
"Login": "Se connecter", "Login": "Se connecter",
"Logout": "Se déconnecter", "Logout": "Se déconnecter",
"EnterUsername": "Nom d'utilisateur", "EnterUsername": "Nom d'utilisateur",
"EnterPassword": "Mot de passe", "EnterPassword": "Mot de passe",
"UserManager": "Gestion des utilisateurs", "UserManager": "Gestion des utilisateurs",
"CategoriesManager": "Gestion des catégories", "CategoriesManager": "Gestion des catégories",
"Filters": "Les filtres", "Filters": "Les filtres",
"LastAdd": "Les ajouts récents", "LastAdd": "Les ajouts récents",
"Research": "Rechercher", "Research": "Rechercher",
"Platforms": "Plateformes", "Platforms": "Plateformes",
"Tags": "Genres", "Tags": "Genres",
"Publisher": "Editeur", "Publisher": "Editeur",
"Developer": "Développeur", "Developer": "Développeur",
"StorageSize": "Taille d'espace", "StorageSize": "Taille d'espace",
"StorageSizeMo": "Taille d'espace en Mo", "StorageSizeMo": "Taille d'espace en Mo",
"LastModification": "Dernière modifications", "LastModification": "Dernière modifications",
"ReleaseDate": "Date de parution", "ReleaseDate": "Date de parution",
"CreateDate": "Date de création", "CreateDate": "Date de création",
"UpdateDate": "Date de modification", "UpdateDate": "Date de modification",
"Title": "Titre", "Title": "Titre",
"Interest": "Intérêt", "Interest": "Intérêt",
"Properties": "Propriétés", "Properties": "Propriétés",
"Description": "Description", "Description": "Description",
"Save": "Enregister", "Save": "Enregister",
"Reset": "Annuler", "Reset": "Annuler",
"ErrorWhenPostingData": "Erreur lors de la requête POST", "ErrorWhenPostingData": "Erreur lors de la requête POST",
"ErrorWhenPutingData": "Erreur lors de la requête PUT", "ErrorWhenPutingData": "Erreur lors de la requête PUT",
"ErrorWhenDeletingData": "Erreur lors de la requête DELETE", "ErrorWhenDeletingData": "Erreur lors de la requête DELETE",
"ErrorWhenFetchingData": "Erreur lors de la requête GET", "ErrorWhenFetchingData": "Erreur lors de la requête GET",
"RequestFailedStatusFormat": "Erreur lors de la réponse, code {0}", "RequestFailedStatusFormat": "Erreur lors de la réponse, code {0}",
"ErrorFetchCategories": "Erreur lors de la récupération des catégories", "ErrorFetchCategories": "Erreur lors de la récupération des catégories",
"PlaceholderAdd": "Ajouter un nouveau", "PlaceholderAdd": "Ajouter un nouveau",
"ErrorCreateGame": "Erreur lors de la création d'un jeu", "ErrorCreateGame": "Erreur lors de la création d'un jeu",
"InvalidTitle": "Le titre est incorrect", "ErrorDeleteGame": "Erreur lors de la suppression d'un jeu",
"InvalidInterest": "L'interêt est incorrect", "InvalidTitle": "Le titre est incorrect",
"Unknown": "Inconnu", "InvalidInterest": "L'interêt est incorrect",
"ErrorFetchGames": "Erreur lors de la récupération des jeux", "Unknown": "Inconnu",
"Ascending": "Ascendant", "ErrorFetchGames": "Erreur lors de la récupération des jeux",
"Descending": "Descendant", "Ascending": "Ascendant",
"ErrorStorageSpaceLabel": "Erreur lors de la génération des label de l'espace de stockage", "Descending": "Descendant",
"MinStorageSpaceFormat": "Jusqu'à {0}", "ErrorStorageSpaceLabel": "Erreur lors de la génération des label de l'espace de stockage",
"MaxStorageSpaceFormat": "Plus de {0}", "MinStorageSpaceFormat": "Jusqu'à {0}",
"MinMaxStorageSpaceFormat": "{0} à {1}", "MaxStorageSpaceFormat": "Plus de {0}",
"UserArgumentsNull": "Nom d'utilisateur ou mot de passe invalide", "MinMaxStorageSpaceFormat": "{0} à {1}",
"InvalidToken": "Le token JWT est invalide", "UserArgumentsNull": "Nom d'utilisateur ou mot de passe invalide",
"UserUnauthorized": "Utilisateur non authorisé", "InvalidToken": "Le token JWT est invalide",
"UserLoginFailed": "Authentification de l'utilisateur échoué", "UserUnauthorized": "Utilisateur non authorisé",
"UserLogoutFailed": "Déconnection de l'utilisateur échoué", "UserLoginFailed": "Authentification de l'utilisateur échoué",
"Roles": "Rôles", "UserLogoutFailed": "Déconnection de l'utilisateur échoué",
"ErrorFetchUsers": "Erreur lors de la récupération des utilisateurs", "Roles": "Rôles",
"ErrorFetchRoles": "Erreur lors de la récupération des rôles", "ErrorFetchUsers": "Erreur lors de la récupération des utilisateurs",
"MissingField": "Un champs est manquant", "ErrorFetchRoles": "Erreur lors de la récupération des rôles",
"ErrorCreateUser": "Erreur lors de la création d'un utilisateur", "MissingField": "Un champs est manquant",
"ErrorUpdateUser": "Erreur lors de la mise à jour d'un utilisateur", "ErrorCreateUser": "Erreur lors de la création d'un utilisateur",
"ErrorDeleteUser": "Erreur lors de la suppression d'un utilisateur", "ErrorUpdateUser": "Erreur lors de la mise à jour d'un utilisateur",
"Cancel": "Annuler", "ErrorDeleteUser": "Erreur lors de la suppression d'un utilisateur",
"Confirm": "Confirmer", "Cancel": "Annuler",
"ConfirmDeleteDescription": "Êtes-vous sur de vouloir supprimer cet élément ?", "Confirm": "Confirmer",
"Informations": "Informations", "ConfirmDeleteDescription": "Êtes-vous sur de vouloir supprimer cet élément ?",
"About": "À propos", "Informations": "Informations",
"ReadMore": "Afficher", "About": "À propos",
"ReadLess": "Réduire", "ReadMore": "Afficher",
"Detail": "Détail", "ReadLess": "Réduire",
"Edit": "Modifier", "Detail": "Détail",
"Delete": "Supprimer" "Edit": "Modifier",
"Delete": "Supprimer"
} }