diff --git a/WatchIt.Common/WatchIt.Common.Model/Media/MediaQueryParameters.cs b/WatchIt.Common/WatchIt.Common.Model/Media/MediaQueryParameters.cs index db968ba..3977d12 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Media/MediaQueryParameters.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Media/MediaQueryParameters.cs @@ -38,22 +38,22 @@ public class MediaQueryParameters : QueryParameters public short? LengthTo { get; set; } [FromQuery(Name = "rating_average")] - public double? RatingAverage { get; set; } + public decimal? RatingAverage { get; set; } [FromQuery(Name = "rating_average_from")] - public double? RatingAverageFrom { get; set; } + public decimal? RatingAverageFrom { get; set; } [FromQuery(Name = "rating_average_to")] - public double? RatingAverageTo { get; set; } + public decimal? RatingAverageTo { get; set; } [FromQuery(Name = "rating_count")] - public double? RatingCount { get; set; } + public long? RatingCount { get; set; } [FromQuery(Name = "rating_count_from")] - public double? RatingCountFrom { get; set; } + public long? RatingCountFrom { get; set; } [FromQuery(Name = "rating_count_to")] - public double? RatingCountTo { get; set; } + public long? RatingCountTo { get; set; } #endregion diff --git a/WatchIt.Common/WatchIt.Common.Model/Movies/MovieQueryParameters.cs b/WatchIt.Common/WatchIt.Common.Model/Movies/MovieQueryParameters.cs index ce0ad56..aec1df9 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Movies/MovieQueryParameters.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Movies/MovieQueryParameters.cs @@ -44,22 +44,22 @@ public class MovieQueryParameters : QueryParameters public decimal? BudgetTo { get; set; } [FromQuery(Name = "rating_average")] - public double? RatingAverage { get; set; } + public decimal? RatingAverage { get; set; } [FromQuery(Name = "rating_average_from")] - public double? RatingAverageFrom { get; set; } + public decimal? RatingAverageFrom { get; set; } [FromQuery(Name = "rating_average_to")] - public double? RatingAverageTo { get; set; } + public decimal? RatingAverageTo { get; set; } [FromQuery(Name = "rating_count")] - public double? RatingCount { get; set; } + public long? RatingCount { get; set; } [FromQuery(Name = "rating_count_from")] - public double? RatingCountFrom { get; set; } + public long? RatingCountFrom { get; set; } [FromQuery(Name = "rating_count_to")] - public double? RatingCountTo { get; set; } + public long? RatingCountTo { get; set; } #endregion diff --git a/WatchIt.Common/WatchIt.Common.Model/Rating/RatingResponse.cs b/WatchIt.Common/WatchIt.Common.Model/Rating/RatingResponse.cs index 2139fba..cc86fb2 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Rating/RatingResponse.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Rating/RatingResponse.cs @@ -9,7 +9,7 @@ public class RatingResponse #region PROPERTIES [JsonPropertyName("average")] - public required double Average { get; set; } + public required decimal Average { get; set; } [JsonPropertyName("count")] public required long Count { get; set; } @@ -24,10 +24,10 @@ public class RatingResponse public RatingResponse() {} [SetsRequiredMembers] - public RatingResponse(IEnumerable ratingMedia) : this(ratingMedia.Any() ? ratingMedia.Average(x => x.Rating) : 0, ratingMedia.Count()) {} + public RatingResponse(IEnumerable ratingMedia) : this(ratingMedia.Any() ? (decimal)ratingMedia.Average(x => x.Rating) : 0, ratingMedia.Count()) {} [SetsRequiredMembers] - public RatingResponse(double ratingAverage, long ratingCount) + public RatingResponse(decimal ratingAverage, long ratingCount) { Average = ratingAverage; Count = ratingCount; diff --git a/WatchIt.Common/WatchIt.Common.Model/Series/SeriesQueryParameters.cs b/WatchIt.Common/WatchIt.Common.Model/Series/SeriesQueryParameters.cs index acb9e99..f4594c0 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Series/SeriesQueryParameters.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Series/SeriesQueryParameters.cs @@ -38,22 +38,22 @@ public class SeriesQueryParameters : QueryParameters public bool? HasEnded { get; set; } [FromQuery(Name = "rating_average")] - public double? RatingAverage { get; set; } + public decimal? RatingAverage { get; set; } [FromQuery(Name = "rating_average_from")] - public double? RatingAverageFrom { get; set; } + public decimal? RatingAverageFrom { get; set; } [FromQuery(Name = "rating_average_to")] - public double? RatingAverageTo { get; set; } + public decimal? RatingAverageTo { get; set; } [FromQuery(Name = "rating_count")] - public double? RatingCount { get; set; } + public long? RatingCount { get; set; } [FromQuery(Name = "rating_count_from")] - public double? RatingCountFrom { get; set; } + public long? RatingCountFrom { get; set; } [FromQuery(Name = "rating_count_to")] - public double? RatingCountTo { get; set; } + public long? RatingCountTo { get; set; } #endregion diff --git a/WatchIt.Common/WatchIt.Common.Query/QueryParameters.cs b/WatchIt.Common/WatchIt.Common.Query/QueryParameters.cs index 77cf1ec..d946e85 100644 --- a/WatchIt.Common/WatchIt.Common.Query/QueryParameters.cs +++ b/WatchIt.Common/WatchIt.Common.Query/QueryParameters.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Globalization; +using System.Reflection; using System.Text; using System.Text.Json.Serialization; using System.Text.RegularExpressions; @@ -38,7 +39,12 @@ public abstract class QueryParameters FromQueryAttribute? attribute = property.GetCustomAttributes(true).FirstOrDefault(); if (value is not null && attribute is not null) { - string query = $"{attribute.Name}={value}"; + string valueString = (value switch + { + decimal d => d.ToString(CultureInfo.InvariantCulture), + _ => value.ToString() + })!; + string query = $"{attribute.Name}={valueString}"; queries.Add(query); } } @@ -92,7 +98,7 @@ public abstract class QueryParameters ( property is not null && - property.CompareTo(from) > 0 + property.CompareTo(from) >= 0 ) ) && diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Media/MediaControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Media/MediaControllerService.cs index 454cd97..295d923 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Media/MediaControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Media/MediaControllerService.cs @@ -107,10 +107,8 @@ public class MediaControllerService(DatabaseContext database, IUserService userS { return RequestResult.NotFound(); } - - double ratingAverage = item.RatingMedia.Any() ? item.RatingMedia.Average(x => x.Rating) : 0; - long ratingCount = item.RatingMedia.Count(); - RatingResponse ratingResponse = new RatingResponse(ratingAverage, ratingCount); + + RatingResponse ratingResponse = new RatingResponse(item.RatingMedia); return RequestResult.Ok(ratingResponse); } diff --git a/WatchIt.Website/WatchIt.Website/App.razor b/WatchIt.Website/WatchIt.Website/App.razor index 2992e8c..fb9b08f 100644 --- a/WatchIt.Website/WatchIt.Website/App.razor +++ b/WatchIt.Website/WatchIt.Website/App.razor @@ -12,6 +12,7 @@ + diff --git a/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor new file mode 100644 index 0000000..10b6ed6 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor @@ -0,0 +1,91 @@ +@typeparam TItem where TItem : WatchIt.Common.Query.IQueryOrderable +@typeparam TQuery where TQuery : WatchIt.Common.Query.QueryParameters + + + + +
+
+
+
+
+

@(Title)

+
+
+
+ Order by + + + +
+
+
+
+ + + + + + Filters + + @(ChildContent) + + + + +
+ +
+
+
+
+ @if (_loaded) + { + if (string.IsNullOrWhiteSpace(_error)) + { + foreach (TItem item in _items) + { +
+ +
+ } + if (!_allItemsLoaded) + { +
+
+ @if (!_itemsLoading) + { + Load more + } + else + { + + Loading... + } +
+
+ } + } + else + { + + } + } + else + { +
+ +
+ } +
+
+ \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor.cs b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor.cs new file mode 100644 index 0000000..84ff2b8 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor.cs @@ -0,0 +1,139 @@ +using Microsoft.AspNetCore.Components; +using WatchIt.Common.Model; +using WatchIt.Common.Model.Movies; +using WatchIt.Common.Model.Rating; +using WatchIt.Common.Query; + +namespace WatchIt.Website.Components.DatabasePage; + +public partial class DatabasePageComponent : ComponentBase where TItem : IQueryOrderable where TQuery : QueryParameters +{ + #region SERVICES + + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + + #endregion + + + + #region PARAMETERS + + [Parameter] public required string Title { get; set; } + [Parameter] public required Func IdSource { get; set; } + [Parameter] public required Func NameSource { get; set; } + [Parameter] public Func AdditionalNameInfoSource { get; set; } = _ => null; + [Parameter] public required Func RatingSource { get; set; } + [Parameter] public required string UrlIdTemplate { get; set; } + [Parameter] public required Func, Task> PictureDownloadingTask { get; set; } + [Parameter] public required Func>, Task> ItemDownloadingTask { get; set; } + [Parameter] public required Dictionary SortingOptions { get; set; } + [Parameter] public required RenderFragment ChildContent { get; set; } + + #endregion + + + + #region FIELDS + + private bool _loaded; + private string? _error; + + private List _items = new List(); + private bool _allItemsLoaded; + private bool _itemsLoading; + + #endregion + + + + #region PROPERTIES + + public TQuery Query { get; set; } = Activator.CreateInstance()!; + + #endregion + + + + #region PRIVATE METHODS + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + // INIT + Query.OrderBy = SortingOptions.Keys.First(); + Query.First = 100; + + List endTasks = new List(); + + // STEP 0 + endTasks.AddRange( + [ + ItemDownloadingTask(Query, data => + { + _items.AddRange(data); + if (data.Count() < 100) + { + _allItemsLoaded = true; + } + else + { + Query.After = 100; + } + }) + ]); + + // END + await Task.WhenAll(endTasks); + + _loaded = true; + StateHasChanged(); + } + } + + private async Task DownloadItems() + { + _itemsLoading = true; + await ItemDownloadingTask(Query, AppendNewItems); + } + + private async Task SortingAscendingChanged(ChangeEventArgs args) + { + Query.Order = (bool)args.Value! ? "asc" : "desc"; + await UpdateItems(); + } + + private async Task SortingOptionChanged(ChangeEventArgs args) + { + Query.OrderBy = args.Value!.ToString(); + await UpdateItems(); + } + + private async Task FilterApplied() => await UpdateItems(); + + private async Task UpdateItems() + { + _loaded = false; + Query.First = 100; + Query.After = null; + _items.Clear(); + await ItemDownloadingTask(Query, AppendNewItems); + _loaded = true; + } + + private void AppendNewItems(IEnumerable items) + { + _items.AddRange(items); + if (items.Count() < 100) + { + _allItemsLoaded = true; + } + else + { + Query.After += 100; + } + _itemsLoading = false; + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor.css similarity index 100% rename from WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor rename to WatchIt.Website/WatchIt.Website/Components/DatabasePage/DatabasePageComponent.razor.css diff --git a/WatchIt.Website/WatchIt.Website/Components/DatabasePage/FilterFormComponent.cs b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/FilterFormComponent.cs new file mode 100644 index 0000000..26fa16d --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/FilterFormComponent.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Components; +using WatchIt.Common.Query; + +namespace WatchIt.Website.Components.DatabasePage; + +public abstract class FilterFormComponent : ComponentBase where TItem : IQueryOrderable where TQuery : QueryParameters +{ + #region PARAMETERS + + [CascadingParameter] + protected DatabasePageComponent Parent { get; set; } + + #endregion + + + + #region FIELDS + + protected TQuery? Query => Parent?.Query; + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/DatabasePage/MoviesFilterFormComponent.razor b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/MoviesFilterFormComponent.razor new file mode 100644 index 0000000..d24e473 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/MoviesFilterFormComponent.razor @@ -0,0 +1,66 @@ +@inherits FilterFormComponent + + + + +
+
+
+ Title + +
+
+
+
+ Original title + +
+
+
+
+ Description + +
+
+
+
+ Release date + + - + +
+
+
+
+ Length + + - + +
+
+
+
+ Budget + + - + +
+
+
+
+ Rating (count) + + - + +
+
+
+
+ Rating (average) + + - + +
+
+
+
\ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/DatabasePage/SeriesFilterFormComponent.razor b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/SeriesFilterFormComponent.razor new file mode 100644 index 0000000..1bad8cc --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/DatabasePage/SeriesFilterFormComponent.razor @@ -0,0 +1,69 @@ +@inherits FilterFormComponent + + +
+
+
+ Title + +
+
+
+
+ Original title + +
+
+
+
+ Description + +
+
+
+
+ Release date + + - + +
+
+
+
+ Length + + - + +
+
+
+
+ Has ended +
+ + + + + + +
+
+
+
+
+ Rating (count) + + - + +
+
+
+
+ Rating (average) + + - + +
+
+
+
\ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor.cs b/WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor.cs deleted file mode 100644 index 7233ffe..0000000 --- a/WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Microsoft.AspNetCore.Components; - -namespace WatchIt.Website.Components.ListPage; - -public partial class ListComponent : ComponentBase -{ -} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor b/WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor index d1c94b7..6e23112 100644 --- a/WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor +++ b/WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor @@ -33,10 +33,10 @@ else { - Lists + Database - Movies - TV Series + Movies + TV Series diff --git a/WatchIt.Website/WatchIt.Website/Pages/AuthPage.razor b/WatchIt.Website/WatchIt.Website/Pages/AuthPage.razor index 39efc0c..0becab5 100644 --- a/WatchIt.Website/WatchIt.Website/Pages/AuthPage.razor +++ b/WatchIt.Website/WatchIt.Website/Pages/AuthPage.razor @@ -89,9 +89,9 @@ }
- + - +
diff --git a/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor new file mode 100644 index 0000000..c96d375 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor @@ -0,0 +1,63 @@ +@using WatchIt.Common.Model.Movies +@using WatchIt.Common.Model.Series +@using WatchIt.Website.Components.DatabasePage + +@page "/database/{type?}" + + + +@if (_loaded) +{ + switch (Type) + { + case "movies": + + + + break; + case "series": + + + + break; + } + +} +else +{ +
+ +
+} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor.cs b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor.cs new file mode 100644 index 0000000..186a3b7 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Components; +using WatchIt.Website.Components.DatabasePage; +using WatchIt.Website.Services.WebAPI.Media; +using WatchIt.Website.Services.WebAPI.Movies; +using WatchIt.Website.Services.WebAPI.Series; + +namespace WatchIt.Website.Pages; + +public partial class DatabasePage : ComponentBase +{ + #region SERVICES + + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + [Inject] private IMediaWebAPIService MediaWebAPIService { get; set; } = default!; + [Inject] private IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!; + [Inject] private ISeriesWebAPIService SeriesWebAPIService { get; set; } = default!; + + #endregion + + + + #region PARAMETERS + + [Parameter] public string? Type { get; set; } + + #endregion + + + + #region FIELDS + + private static IEnumerable _databaseTypes = ["movies", "series"]; + + private bool _loaded; + + #endregion + + + + #region PRIVATE METHODS + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + // INIT + if (!_databaseTypes.Contains(Type)) + { + NavigationManager.NavigateTo($"/database/{_databaseTypes.First()}"); + } + + _loaded = true; + StateHasChanged(); + } + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor.css b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor.css similarity index 100% rename from WatchIt.Website/WatchIt.Website/Components/ListPage/ListComponent.razor.css rename to WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor.css diff --git a/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor b/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor deleted file mode 100644 index 9a185eb..0000000 --- a/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor +++ /dev/null @@ -1,88 +0,0 @@ -@layout MainLayout - -@page "/lists/movies" -@using WatchIt.Common.Model.Movies - -
- @if (_loaded) - { - if (string.IsNullOrWhiteSpace(_error)) - { -
-
-
-
-
-
-

Movies database

-
-
- -
-
- -
-
-
-
-
-
- foreach (MovieResponse item in _items) - { -
- -
- } - if (!_allItemsLoaded) - { -
-
-
-
- @if (!_itemsLoading) - { - Load more - } - else - { - - Load more - } -
-
-
-
- } - } - else - { -
-
- -
-
- } - } - else - { -
-
-
- -
-
-
- } -
- - \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor.cs b/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor.cs deleted file mode 100644 index e97ea7a..0000000 --- a/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Microsoft.AspNetCore.Components; -using WatchIt.Common.Model.Movies; -using WatchIt.Website.Services.WebAPI.Media; -using WatchIt.Website.Services.WebAPI.Movies; - -namespace WatchIt.Website.Pages; - -public partial class ListPage : ComponentBase -{ - #region SERVICES - - [Inject] private IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!; - [Inject] private IMediaWebAPIService MediaWebAPIService { get; set; } = default!; - - #endregion - - - - #region PARAMETERS - - - - #endregion - - - - #region FIELDS - - private bool _loaded; - private string? _error; - - private MovieQueryParameters _query = new MovieQueryParameters { OrderBy = "rating.average" }; - private List _items = new List(); - private bool _allItemsLoaded; - private bool _itemsLoading; - - #endregion - - - - #region PUBLIC METHODS - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - // INIT - _query.First = 5; - - List endTasks = new List(); - - // STEP 0 - endTasks.AddRange( - [ - MoviesWebAPIService.GetAllMovies(_query, data => - { - _items.AddRange(data); - if (data.Count() < 5) - { - _allItemsLoaded = true; - } - else - { - _query.After = 5; - } - }) - ]); - - // END - await Task.WhenAll(endTasks); - - _loaded = true; - StateHasChanged(); - } - } - - private async Task DownloadItems() - { - _itemsLoading = true; - await MoviesWebAPIService.GetAllMovies(_query, data => - { - _items.AddRange(data); - if (data.Count() < 5) - { - _allItemsLoaded = true; - } - else - { - _query.After += 5; - } - _itemsLoading = false; - }); - } - - #endregion -} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor.css b/WatchIt.Website/WatchIt.Website/Pages/ListPage.razor.css deleted file mode 100644 index e69de29..0000000 diff --git a/WatchIt.Website/WatchIt.Website/_Imports.razor b/WatchIt.Website/WatchIt.Website/_Imports.razor index b8693f8..3a478f4 100644 --- a/WatchIt.Website/WatchIt.Website/_Imports.razor +++ b/WatchIt.Website/WatchIt.Website/_Imports.razor @@ -15,4 +15,5 @@ @using WatchIt.Website.Services.Utility.Authentication @using WatchIt.Website.Services.WebAPI.Accounts @using WatchIt.Website.Services.WebAPI.Media -@using Blazorise \ No newline at end of file +@using Blazorise +@using Blazorise.Bootstrap5 \ No newline at end of file