diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/GameIdeas.BlazorApp.csproj b/src/GameIdeas/Client/GameIdeas.BlazorApp/GameIdeas.BlazorApp.csproj index 4595e9d..0388002 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/GameIdeas.BlazorApp.csproj +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/GameIdeas.BlazorApp.csproj @@ -1,4 +1,4 @@ - + net9.0 diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor index f639a03..7354efa 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor @@ -1,29 +1,32 @@ @using GameIdeas.BlazorApp.Shared.Components.Select +@using GameIdeas.BlazorApp.Shared.Components.Select.Models @using GameIdeas.BlazorApp.Shared.Components.Slider @using GameIdeas.Shared.Dto - +
@ResourcesKey.Title :
- +
@ResourcesKey.ReleaseDate :
- +
-
@ResourcesKey.StorageSize :
- +
@ResourcesKey.StorageSizeMo :
+
@ResourcesKey.Developers :
- +
@ResourcesKey.Publishers :
- +
@@ -35,15 +38,19 @@
@ResourcesKey.Properties :
- +
@ResourcesKey.Genres :
- + +
@ResourcesKey.Platforms :
- +
@@ -51,4 +58,12 @@
@ResourcesKey.Description :
+
+ + +
\ No newline at end of file diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs index 4462f53..97c0854 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.cs @@ -1,3 +1,4 @@ +using GameIdeas.BlazorApp.Pages.Games.Gateways; using GameIdeas.BlazorApp.Shared.Components.Popup; using GameIdeas.BlazorApp.Shared.Components.Select.Models; using GameIdeas.BlazorApp.Shared.Components.Slider; @@ -11,26 +12,45 @@ namespace GameIdeas.BlazorApp.Pages.Games.Components; public partial class GameCreationForm { [Inject] private IJSRuntime Js { get; set; } = default!; + [Inject] private IGameGateway GameGateway { get; set; } = default!; [CascadingParameter] private Popup? Popup { get; set; } private GameDto GameDto = new(); + private CategoriesDto CategoriesDto = new(); private EditContext? EditContext; private readonly SelectListTheme SelectListTheme = SelectListTheme.Creation; private readonly SliderParams SliderParams = new() { Gap = 1, Min = 1, Max = 5 }; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { EditContext = new(GameDto); + CategoriesDto = await GameGateway.FetchCategories(); + if (Popup != null) { Popup.StateChanged += async (_, isOpen) => await HandlePopupStateChanged(); } - base.OnInitialized(); + await base.OnInitializedAsync(); } private async Task HandlePopupStateChanged() { await Js.InvokeVoidAsync("resizeGameForm"); } + + private void HandleOnCancel() + { + Popup?.Close(); + } + + private async Task HandleOnSubmit(EditContext args) + { + if (EditContext?.Validate() == false) + { + return; + } + + + } } \ No newline at end of file diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.css b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.css index 7e0f33a..b28e0a8 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.css +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Components/GameCreationForm.razor.css @@ -61,4 +61,8 @@ input { .slider { padding: 0 20px; align-content: center; +} + +input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; } \ No newline at end of file diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor index b918a9f..8c1dd8f 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/AdvancedGameFilter.razor @@ -5,13 +5,11 @@
@@ -19,31 +17,26 @@ 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 dfa5e1b..cb74ed4 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 @@ -7,56 +7,4 @@ public partial class AdvancedGameFilter { [Parameter] public GameFilterParams? GameFilterParams { get; set; } [Parameter] public EventCallback GameFilterParamsChanged { get; set; } - - - private readonly IEnumerable> Plateforms = [ - new() { Item = "Steam", Label = "Steam" }, - new() { Item = "GOG", Label = "GOG" }, - new() { Item = "Epic games", Label = "Epic games" }, - new() { Item = "Ubisoft", Label = "Ubisoft" }, - ]; - - private readonly IEnumerable> Genres = [ - new() { Item = "Rogue Like", Label = "Rogue Like" }, - new() { Item = "Aventure", Label = "Aventure" }, - new() { Item = "RPG", Label = "RPG" }, - new() { Item = "Fast FPS", Label = "Fast FPS" }, - ]; - - private readonly IEnumerable> Publishers = [ - new() { Item = "Electronic Arts", Label = "Electronic Arts" }, - new() { Item = "Ubisoft", Label = "Ubisoft" }, - new() { Item = "Activision Blizzard", Label = "Activision Blizzard" }, - new() { Item = "Bethesda", Label = "Bethesda" } - ]; - - private readonly IEnumerable> Developers = [ - new() { Item = "CD Projekt Red", Label = "CD Projekt Red" }, - new() { Item = "Naughty Dog", Label = "Naughty Dog" }, - new() { Item = "Rockstar Games", Label = "Rockstar Games" }, - new() { Item = "FromSoftware", Label = "FromSoftware" }, - ]; - - private readonly IEnumerable> StorageSizes = [ - new() { Item = "1 Go", Label = "1 Go" }, - new() { Item = "10 Go", Label = "10 Go" }, - new() { Item = "50 Go", Label = "50 Go" }, - new() { Item = "100 Go", Label = "100 Go" }, - ]; - - private readonly IEnumerable> LastModifiedDates = [ - new() { Item = "2023-12-15", Label = "15 Décembre 2023" }, - new() { Item = "2024-01-20", Label = "20 Janvier 2024" }, - new() { Item = "2024-02-05", Label = "5 Février 2024" }, - new() { Item = "2024-03-10", Label = "10 Mars 2024" }, - ]; - - private readonly IEnumerable> ReleaseDates = [ - new() { Item = "2023-11-11", Label = "11 Novembre 2023" }, - new() { Item = "2024-01-25", Label = "25 Janvier 2024" }, - new() { Item = "2024-03-03", Label = "3 Mars 2024" }, - new() { Item = "2024-04-15", Label = "15 Avril 2024" }, - ]; - - } \ No newline at end of file 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 48fca5e..414cda9 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilter.razor @@ -4,13 +4,13 @@ @using GameIdeas.BlazorApp.Shared.Components.SliderRange @using GameIdeas.BlazorApp.Shared.Models @using GameIdeas.Shared.Dto +@using GameIdeas.Shared.Enum
-
@@ -38,7 +38,6 @@
@@ -46,7 +45,6 @@
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 b97008c..8ffe951 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 @@ -15,28 +15,14 @@ public partial class GameFilter [Parameter] public DisplayType DisplayType { get; set; } [Parameter] public EventCallback DisplayTypeChanged { get; set; } - private readonly IEnumerable>> SortTypes = [ - new() { Item = _ => SortType.Ascending, Label = "Ascendant", IsSelected = true }, - new() { Item = _ => SortType.Descending, Label = "Descendant" } + private readonly IEnumerable> SortTypes = [ + new(SortType.Ascending, "Ascendant") { IsSelected = true }, + new(SortType.Descending, "Descendant") ]; private readonly IEnumerable>> GameProperties = [ - new() { Item = game => game?.Title, Label = "Nom", IsSelected = true }, - new() { Item = game => game?.ReleaseDate, Label = "Date de parution" } - ]; - - private readonly IEnumerable> Plateforms = [ - new() { Item = "Steam", Label = "Steam" }, - new() { Item = "GOG", Label = "GOG" }, - new() { Item = "Epic games", Label = "Epic games" }, - new() { Item = "Ubisoft", Label = "Ubisoft" }, - ]; - - private readonly IEnumerable> Genres = [ - new() { Item = "Rogue Like", Label = "Rogue Like" }, - new() { Item = "Aventure", Label = "Aventure" }, - new() { Item = "RPG", Label = "RPG" }, - new() { Item = "Fast FPS", Label = "Fast FPS" }, + new(game => game?.Title, "Nom") { IsSelected = true }, + new(game => game?.ReleaseDate, "Date de parution"), ]; private EditContext? EditContext; @@ -52,11 +38,6 @@ public partial class GameFilter }; } - private void HandleSortTypeChanged(Func getHeader) - { - GameFilterParams.SortType = (SortType?)getHeader(null) ?? SortType.Ascending; - } - private async Task HandleDisplayClicked(DisplayType displayType) { DisplayType = displayType; diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs index 77b9354..d95d5c4 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Filter/GameFilterParams.cs @@ -5,7 +5,7 @@ namespace GameIdeas.BlazorApp.Pages.Games.Filter; public class GameFilterParams { - public SortType? SortType { get; set; } + public SortType SortType { get; set; } = SortType.Ascending; public Func? SortProperty { get; set; } public string? SearchName { get; set; } public IEnumerable? Platforms { get; set; } diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs new file mode 100644 index 0000000..92af68b --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/GameGateway.cs @@ -0,0 +1,24 @@ +using GameIdeas.BlazorApp.Services; +using GameIdeas.BlazorApp.Shared.Constants; +using GameIdeas.BlazorApp.Shared.Exceptions; +using GameIdeas.Resources; +using GameIdeas.Shared.Dto; + +namespace GameIdeas.BlazorApp.Pages.Games.Gateways; + +public class GameGateway(IHttpClientService httpClientService) : IGameGateway +{ + public async Task FetchCategories() + { + try + { + var result = await httpClientService.FetchDataAsync(Endpoints.Category.AllCategories); + + return result ?? throw new InvalidOperationException(ResourcesKey.ErrorFetchCategories); + } + catch (Exception) + { + throw new CategoryNotFoundException(ResourcesKey.ErrorFetchCategories); + } + } +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs new file mode 100644 index 0000000..7d71440 --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Gateways/IGameGateway.cs @@ -0,0 +1,8 @@ +using GameIdeas.Shared.Dto; + +namespace GameIdeas.BlazorApp.Pages.Games.Gateways; + +public interface IGameGateway +{ + Task FetchCategories(); +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor index c948e2d..515e557 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor @@ -23,7 +23,7 @@
diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.cs index 0f5f2d9..936b5bc 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Pages/Games/Header/GameHeader.razor.cs @@ -14,12 +14,12 @@ public partial class GameHeader : ComponentBase private readonly IEnumerable> SelectElements = [ - new SelectElement { Item = AddType.Manual, Label = ResourcesKey.ManualAdd }, - new SelectElement { Item = AddType.Auto, Label = ResourcesKey.AutoAdd } + new SelectElement(AddType.Manual, ResourcesKey.ManualAdd), + new SelectElement (AddType.Auto, ResourcesKey.AutoAdd) ]; private AccountSettings? AccountSettings; - private SelectList? SelectListAdd; + private SelectList? SelectListAdd; private void HandleIconClicked() { diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Program.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Program.cs index e35dffa..98b893b 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Program.cs +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Program.cs @@ -1,5 +1,6 @@ using System.Net.Http.Json; using GameIdeas.BlazorApp; +using GameIdeas.BlazorApp.Pages.Games.Gateways; using GameIdeas.BlazorApp.Services; using GameIdeas.Resources; using Microsoft.AspNetCore.Components.Web; @@ -22,7 +23,8 @@ builder.Services.AddHttpClient( client.Timeout = TimeSpan.FromMinutes(3); }); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/AuthentificationService.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/AuthentificationService.cs deleted file mode 100644 index 380b679..0000000 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/AuthentificationService.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace GameIdeas.BlazorApp.Services; - -public class AuthentificationService -{ - private bool isLogin; - - public bool IsLogin - { - get { return isLogin; } - } - - public void Login() - { - isLogin = true; - } - - public void Logout() - { - isLogin = false; - } -} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs new file mode 100644 index 0000000..f0c39ac --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/HttpClientService.cs @@ -0,0 +1,125 @@ +using GameIdeas.Resources; +using System.Net.Http.Headers; +using System.Text.Json.Serialization; +using System.Text.Json; +using System.Text; + +namespace GameIdeas.BlazorApp.Services; + +public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory) : IHttpClientService +{ + private readonly HttpClient httpClient = httpClientFactory.CreateClient("GameIdeas.WebAPI"); + private readonly ILogger logger = loggerFactory.CreateLogger(); + + private readonly JsonSerializerOptions _optionsCamelCase = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }; + + private readonly JsonSerializerOptions _optionsCaseInsensitive = new() + { + PropertyNameCaseInsensitive = true, + ReferenceHandler = ReferenceHandler.Preserve + }; + + public async Task PostAsync(string url, object data) + { + var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase); + var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(url, content); + + return await GetResultValue(response, ResourcesKey.ErrorWhenPostingData); + } + + public async Task PutAsync(string url, object data) + { + var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase); + var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + var response = await httpClient.PutAsync(url, content); + + return await GetResultValue(response, ResourcesKey.ErrorWhenPutingData); + } + + public async Task DeleteAsync(string? url) + { + var response = await httpClient.DeleteAsync(url); + + return await GetResultValue(response, ResourcesKey.ErrorWhenDeletingData); + } + + public async Task FetchDataAsync(string? url) + { + var response = await httpClient.GetAsync(url); + + return await GetResultValue(response, ResourcesKey.ErrorWhenFetchingData); + } + + public async Task FetchBytesAsync(string? url) + { + var response = await httpClient.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + return await response.Content.ReadAsByteArrayAsync(); + } + + throw new HttpRequestException( + $"{ResourcesKey.ErrorWhenFetchingData} + StatusCode: {response.StatusCode} " + + $"+ Reason: {response.ReasonPhrase}"); + } + + public async Task FetchStreamAsync(string? url) + { + var response = await httpClient.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + return await response.Content.ReadAsStreamAsync(); + } + + throw new HttpRequestException($"{ResourcesKey.ErrorWhenFetchingData} + StatusCode: {response.StatusCode} " + + $"+ Reason: {response.ReasonPhrase}"); + } + + public async Task PostFileAsync(string? url, Stream fileStream, string fileName, string contentType) + { + using var content = new MultipartFormDataContent(); + + var streamContent = new StreamContent(fileStream); + streamContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); + content.Add(streamContent, "file", fileName); + + var response = await httpClient.PostAsync(url, content); + + return await GetResultValue(response, ResourcesKey.ErrorWhenPostingData); + } + + private async Task GetResultValue(HttpResponseMessage response, string errorMessage) + { + if (response.IsSuccessStatusCode) + { + try + { + var responseContent = await response.Content.ReadAsStringAsync(); + + if (string.IsNullOrWhiteSpace(responseContent)) + { + return default; + } + + var result = JsonSerializer.Deserialize(responseContent, _optionsCaseInsensitive); + + return result; + } + catch (Exception ex) + { + throw new JsonException(ex.Message); + } + } + + logger.LogError(ResourcesKey.RequestFailedStatusFormat, response.StatusCode); + throw new HttpRequestException( + $"{errorMessage} + StatusCode: {response.StatusCode} + Reason: {response.ReasonPhrase}"); + } +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/IHttpClientService.cs b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/IHttpClientService.cs new file mode 100644 index 0000000..299ab00 --- /dev/null +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Services/IHttpClientService.cs @@ -0,0 +1,12 @@ +namespace GameIdeas.BlazorApp.Services; + +public interface IHttpClientService +{ + Task PostAsync(string url, object data); + Task PutAsync(string url, object data); + Task DeleteAsync(string? url); + Task FetchDataAsync(string? url); + Task FetchBytesAsync(string? url); + Task FetchStreamAsync(string? url); + Task PostFileAsync(string? url, Stream fileStream, string fileName, string contentType); +} diff --git a/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Components/Account/AccountSettings.razor b/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Components/Account/AccountSettings.razor index 5b111c2..98094ae 100644 --- a/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Components/Account/AccountSettings.razor +++ b/src/GameIdeas/Client/GameIdeas.BlazorApp/Shared/Components/Account/AccountSettings.razor @@ -3,7 +3,7 @@