Add validation and gateway creation
All checks were successful
Game Ideas build for PR / build_blazor_app (pull_request) Successful in 1m14s
All checks were successful
Game Ideas build for PR / build_blazor_app (pull_request) Successful in 1m14s
This commit is contained in:
@@ -1,21 +1,23 @@
|
|||||||
@using GameIdeas.BlazorApp.Shared.Components.SelectSearch
|
@using Blazored.FluentValidation
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Components.SelectSearch
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Slider
|
@using GameIdeas.BlazorApp.Shared.Components.Slider
|
||||||
@using GameIdeas.Shared.Dto
|
@using GameIdeas.Shared.Dto
|
||||||
|
|
||||||
<EditForm EditContext="EditContext" OnSubmit="HandleOnSubmit">
|
<EditForm EditContext="EditContext" OnSubmit="HandleOnSubmit">
|
||||||
|
<FluentValidationValidator/>
|
||||||
<div class="game-form">
|
<div class="game-form">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="input-game">
|
<div class="input-game">
|
||||||
<div id="first-label" class="label">@ResourcesKey.Title :</div>
|
<div id="first-label" class="label">@ResourcesKey.Title :</div>
|
||||||
<input type="text" class="title" @bind=GameDto.Title>
|
<InputText class="title" @bind-Value=GameDto.Title />
|
||||||
</div>
|
</div>
|
||||||
<div class="input-game">
|
<div class="input-game">
|
||||||
<div class="label">@ResourcesKey.ReleaseDate :</div>
|
<div class="label">@ResourcesKey.ReleaseDate :</div>
|
||||||
<input type="date" class="date" @bind=GameDto.ReleaseDate>
|
<InputDate TValue="DateTime?" class="date" @bind-Value=GameDto.ReleaseDate />
|
||||||
</div>
|
</div>
|
||||||
<div class="input-game">
|
<div class="input-game">
|
||||||
<div class="label">@ResourcesKey.StorageSizeMo :</div>
|
<div class="label">@ResourcesKey.StorageSizeMo :</div>
|
||||||
<input type="number" class="storage" @bind=GameDto.StorageSpace>
|
<InputNumber TValue="double?" class="storage" @bind-Value=GameDto.StorageSpace />
|
||||||
</div>
|
</div>
|
||||||
<div class="input-game">
|
<div class="input-game">
|
||||||
<div class="label">@ResourcesKey.Developers :</div>
|
<div class="label">@ResourcesKey.Developers :</div>
|
||||||
@@ -61,14 +63,14 @@
|
|||||||
{
|
{
|
||||||
<div class="input-game">
|
<div class="input-game">
|
||||||
<div class="label">@platform.Label :</div>
|
<div class="label">@platform.Label :</div>
|
||||||
<input type="text" class="url" @bind=platform.Url>
|
<InputText class="url" @bind-Value=platform.Url />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="description-container">
|
<div class="description-container">
|
||||||
<div id="label-description">@ResourcesKey.Description :</div>
|
<div id="label-description">@ResourcesKey.Description :</div>
|
||||||
<input type="text" class="description" @bind-value=GameDto.Description>
|
<InputTextArea class="description" @bind-Value=GameDto.Description />
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="reset" class="cancel" @onclick=HandleOnCancel>
|
<button type="reset" class="cancel" @onclick=HandleOnCancel>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using GameIdeas.BlazorApp.Pages.Games.Gateways;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Popup;
|
using GameIdeas.BlazorApp.Shared.Components.Popup;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Slider;
|
using GameIdeas.BlazorApp.Shared.Components.Slider;
|
||||||
@@ -11,6 +12,7 @@ namespace GameIdeas.BlazorApp.Pages.Games.Components;
|
|||||||
public partial class GameCreationForm
|
public partial class GameCreationForm
|
||||||
{
|
{
|
||||||
[Inject] private IJSRuntime Js { get; set; } = default!;
|
[Inject] private IJSRuntime Js { get; set; } = default!;
|
||||||
|
[Inject] private IGameGateway GameGateway { get; set; } = default!;
|
||||||
[CascadingParameter] private Popup? Popup { get; set; }
|
[CascadingParameter] private Popup? Popup { get; set; }
|
||||||
[Parameter] public CategoriesDto? Categories { get; set; }
|
[Parameter] public CategoriesDto? Categories { get; set; }
|
||||||
|
|
||||||
@@ -48,6 +50,6 @@ public partial class GameCreationForm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await GameGateway.CreateGame(GameDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
::deep input, ::deep textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--input-secondary);
|
background: var(--input-secondary);
|
||||||
border: solid 1px var(--input-selected);
|
border: solid 1px var(--input-selected);
|
||||||
@@ -35,11 +35,16 @@ input {
|
|||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="date"]::-webkit-calendar-picker-indicator {
|
::deep input[type="date"]::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::deep textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
.description-container {
|
.description-container {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using GameIdeas.Shared.Constants;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.Games.Components;
|
||||||
|
|
||||||
|
public class GameValidation : AbstractValidator<GameDto>
|
||||||
|
{
|
||||||
|
public GameValidation()
|
||||||
|
{
|
||||||
|
RuleFor(g => g.Title)
|
||||||
|
.NotEmpty()
|
||||||
|
.NotNull()
|
||||||
|
.Matches(GlobalConstants.RegexName);
|
||||||
|
|
||||||
|
RuleFor(g => g.ReleaseDate)
|
||||||
|
.NotEmpty()
|
||||||
|
.NotNull();
|
||||||
|
|
||||||
|
RuleFor(g => g.Interest)
|
||||||
|
.NotNull()
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.LessThanOrEqualTo(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,20 @@ namespace GameIdeas.BlazorApp.Pages.Games.Gateways;
|
|||||||
|
|
||||||
public class GameGateway(IHttpClientService httpClientService) : IGameGateway
|
public class GameGateway(IHttpClientService httpClientService) : IGameGateway
|
||||||
{
|
{
|
||||||
|
public async Task<GameDto> CreateGame(GameDto game)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await httpClientService.PostAsync<GameDto>(Endpoints.Game.Create, game);
|
||||||
|
|
||||||
|
return result ?? throw new InvalidOperationException(ResourcesKey.ErrorCreateGame);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
throw new GameCreationException(ResourcesKey.ErrorCreateGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<CategoriesDto> FetchCategories()
|
public async Task<CategoriesDto> FetchCategories()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ namespace GameIdeas.BlazorApp.Pages.Games.Gateways;
|
|||||||
public interface IGameGateway
|
public interface IGameGateway
|
||||||
{
|
{
|
||||||
Task<CategoriesDto> FetchCategories();
|
Task<CategoriesDto> FetchCategories();
|
||||||
|
Task<GameDto> CreateGame(GameDto game);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
|
|
||||||
|
|
||||||
<BackdropFilter @ref="BackdropFilter" OnClick="HandleBackdropFilterClicked" CloseOnClick="@Closable"
|
<BackdropFilter @ref="BackdropFilter" OnClick="HandleBackdropFilterClicked" CloseOnClick="@Closable"
|
||||||
AllowBodyScroll="false" Color="BackdropFilterColor.Overlay" />
|
AllowBodyScroll="true" Color="BackdropFilterColor.Overlay" />
|
||||||
@@ -93,7 +93,7 @@ public partial class Select<TItem, THeader>
|
|||||||
}
|
}
|
||||||
private async Task HandleSubmitAdd()
|
private async Task HandleSubmitAdd()
|
||||||
{
|
{
|
||||||
if (Regex.IsMatch(AddLabel, GlobalConstants.RegexSelectRow) &&
|
if (Regex.IsMatch(AddLabel, GlobalConstants.RegexName) &&
|
||||||
Params.AddItem != null)
|
Params.AddItem != null)
|
||||||
{
|
{
|
||||||
Values ??= [];
|
Values ??= [];
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public static class Endpoints
|
|||||||
{
|
{
|
||||||
public static class Game
|
public static class Game
|
||||||
{
|
{
|
||||||
|
public static readonly string Create = "api/Game/Create";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Category
|
public static class Category
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace GameIdeas.BlazorApp.Shared.Exceptions;
|
||||||
|
|
||||||
|
public class GameCreationException(string message) : Exception(message);
|
||||||
@@ -41,10 +41,6 @@ html, body, #app {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.valid.modified:not([type=checkbox]) {
|
|
||||||
border: 2px solid var(--green);
|
|
||||||
}
|
|
||||||
|
|
||||||
.invalid {
|
.invalid {
|
||||||
border: 2px solid var(--red) !important;
|
border: 2px solid var(--red) !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class Translations (TranslationService translationService)
|
|||||||
public string RequestFailedStatusFormat => translationService.Translate(nameof(RequestFailedStatusFormat));
|
public string RequestFailedStatusFormat => translationService.Translate(nameof(RequestFailedStatusFormat));
|
||||||
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 static class ResourcesKey
|
public static class ResourcesKey
|
||||||
@@ -78,4 +79,5 @@ public static class ResourcesKey
|
|||||||
public static string RequestFailedStatusFormat => _instance?.RequestFailedStatusFormat ?? throw new InvalidOperationException("ResourcesKey.RequestFailedStatusFormat is not initialized.");
|
public static string RequestFailedStatusFormat => _instance?.RequestFailedStatusFormat ?? throw new InvalidOperationException("ResourcesKey.RequestFailedStatusFormat is not initialized.");
|
||||||
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.");
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
public class GlobalConstants
|
public class GlobalConstants
|
||||||
{
|
{
|
||||||
public const string RegexSelectRow = @"[a-zA-Z_ \-]*";
|
public const string RegexName = @"[\w()\-_ ]*";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,36 @@
|
|||||||
{
|
{
|
||||||
"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",
|
||||||
"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",
|
||||||
"Publishers": "Editeurs",
|
"Publishers": "Editeurs",
|
||||||
"Developers": "Développeurs",
|
"Developers": "Développeurs",
|
||||||
"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",
|
||||||
"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"
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user