Rated people panel added
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Common.Model.Movies;
|
||||
using WatchIt.Common.Model.Persons;
|
||||
using WatchIt.Common.Model.Series;
|
||||
using WatchIt.Common.Services.HttpClient;
|
||||
using WatchIt.Website.Services.Configuration;
|
||||
@@ -135,6 +136,20 @@ public class AccountsClientService(IHttpClientService httpClientService, IConfig
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task GetAccountRatedPersons(long id, PersonRatedQueryParameters query, Action<IEnumerable<PersonRatedResponse>>? successAction = null, Action? notFoundAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Accounts.GetAccountRatedPersons, id);
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Get, url)
|
||||
{
|
||||
Query = query
|
||||
};
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor404NotFound(notFoundAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Common.Model.Movies;
|
||||
using WatchIt.Common.Model.Persons;
|
||||
using WatchIt.Common.Model.Series;
|
||||
|
||||
namespace WatchIt.Website.Services.Client.Accounts;
|
||||
@@ -15,4 +16,5 @@ public interface IAccountsClientService
|
||||
Task PutAccountInfo(AccountRequest data, Action<AccountResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null, Action? notFoundAction = null);
|
||||
Task GetAccountRatedMovies(long id, MovieRatedQueryParameters query, Action<IEnumerable<MovieRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
Task GetAccountRatedSeries(long id, SeriesRatedQueryParameters query, Action<IEnumerable<SeriesRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
Task GetAccountRatedPersons(long id, PersonRatedQueryParameters query, Action<IEnumerable<PersonRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
}
|
||||
@@ -12,4 +12,5 @@ public class Accounts
|
||||
public string PutAccountInfo { get; set; }
|
||||
public string GetAccountRatedMovies { get; set; }
|
||||
public string GetAccountRatedSeries { get; set; }
|
||||
public string GetAccountRatedPersons { get; set; }
|
||||
}
|
||||
@@ -60,7 +60,8 @@
|
||||
PosterPlaceholder="@(PosterPlaceholder)"
|
||||
PosterDownloadingTask="@(action => PictureDownloadingTask(id, action))"
|
||||
GlobalRating="@(RatingSource(item))"
|
||||
SecondaryRating="@(SecondaryRatingSource?.Invoke(item))"
|
||||
SecondaryRatingSingle="@(SecondaryRatingSingleSource?.Invoke(item))"
|
||||
SecondaryRatingMultiple="@(SecondaryRatingMultipleSource?.Invoke(item))"
|
||||
SecondaryRatingTitle="@(SecondaryRatingTitle)"
|
||||
GetGlobalRatingMethod="@(action => GetGlobalRatingMethod(id, action))"
|
||||
GetUserRatingMethod="@(GetUserRatingMethod is not null ? (user, actionSuccess, actionNotFound) => GetUserRatingMethod(id, user, actionSuccess, actionNotFound) : null)"
|
||||
|
||||
@@ -23,7 +23,8 @@ public partial class ListComponent<TItem, TQuery> : ComponentBase where TItem :
|
||||
[Parameter] public required Func<TItem, string> NameSource { get; set; }
|
||||
[Parameter] public Func<TItem, string?> AdditionalNameInfoSource { get; set; } = _ => null;
|
||||
[Parameter] public required Func<TItem, RatingResponse> RatingSource { get; set; }
|
||||
[Parameter] public Func<TItem, short?>? SecondaryRatingSource { get; set; }
|
||||
[Parameter] public Func<TItem, short?>? SecondaryRatingSingleSource { get; set; }
|
||||
[Parameter] public Func<TItem, RatingResponse?>? SecondaryRatingMultipleSource { get; set; }
|
||||
[Parameter] public string? SecondaryRatingTitle { get; set; }
|
||||
[Parameter] public required string UrlIdTemplate { get; set; }
|
||||
[Parameter] public required Func<long, Action<Picture>, Task> PictureDownloadingTask { get; set; }
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<th scope="col">
|
||||
<span class="rating-name-text">Global rating:</span>
|
||||
</th>
|
||||
@if (SecondaryRating is not null)
|
||||
@if (SecondaryRatingSingle is not null || SecondaryRatingMultiple is not null)
|
||||
{
|
||||
<th scope="col">
|
||||
<span class="rating-name-text">@(SecondaryRatingTitle):</span>
|
||||
@@ -39,10 +39,11 @@
|
||||
EmptyMode="DisplayRatingComponent.DisplayRatingComponentEmptyMode.DoubleDash"
|
||||
Scale="0.85"/>
|
||||
</td>
|
||||
@if (SecondaryRating is not null)
|
||||
@if (SecondaryRatingSingle is not null || SecondaryRatingMultiple is not null)
|
||||
{
|
||||
<td>
|
||||
<DisplayRatingComponent SingleRating="@(SecondaryRating)"
|
||||
<DisplayRatingComponent SingleRating="@(SecondaryRatingSingle)"
|
||||
Rating="@(SecondaryRatingMultiple)"
|
||||
EmptyMode="DisplayRatingComponent.DisplayRatingComponentEmptyMode.DoubleDash"
|
||||
Scale="0.85"/>
|
||||
</td>
|
||||
@@ -53,18 +54,18 @@
|
||||
<div class="d-inline-flex align-items-center h-100">
|
||||
@if (_user is null)
|
||||
{
|
||||
<span id="ratingLoginInfoText">You must be logged in to rate</span>
|
||||
<span id="ratingLoginInfoText">You must be logged in to rate</span>
|
||||
}
|
||||
else if (!_userRatingLoaded)
|
||||
{
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Rating Color="Color.Light" MaxValue="10" @bind-SelectedValue="@(_userRating)" @onclick="@(RatingChanged)"/>
|
||||
<Rating Color="Color.Light" MaxValue="10" @bind-SelectedValue="@(_userRating)" @onclick="@(RatingChanged)"/>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -27,7 +27,8 @@ public partial class ListItemComponent : ComponentBase
|
||||
[Parameter] public required Func<Action<Picture>, Task> PosterDownloadingTask { get; set; }
|
||||
|
||||
[Parameter] public RatingResponse? GlobalRating { get; set; }
|
||||
[Parameter] public short? SecondaryRating { get; set; }
|
||||
[Parameter] public short? SecondaryRatingSingle { get; set; }
|
||||
[Parameter] public RatingResponse? SecondaryRatingMultiple { get; set; }
|
||||
[Parameter] public string? SecondaryRatingTitle { get; set; }
|
||||
[Parameter] public required Func<Action<RatingResponse>, Task> GetGlobalRatingMethod { get; set; }
|
||||
[Parameter] public Func<long, Action<short>, Action, Task>? GetUserRatingMethod { get; set; }
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
@using WatchIt.Common.Model.Genders
|
||||
|
||||
@inherits WatchIt.Website.Components.Common.ListComponent.FilterFormComponent<WatchIt.Common.Model.Persons.PersonRatedResponse, WatchIt.Common.Model.Persons.PersonRatedQueryParameters>
|
||||
|
||||
|
||||
|
||||
<EditForm Model="@(Query)">
|
||||
<div class="container-grid">
|
||||
<div class="row mb-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Name</span>
|
||||
<InputText class="col form-control" placeholder="Search with regex" @bind-Value="@(Query.Name)"></InputText>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Full name</span>
|
||||
<InputText class="col form-control" placeholder="Search with regex" @bind-Value="@(Query.FullName)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Description</span>
|
||||
<InputText class="col form-control" placeholder="Search with regex" @bind-Value="@(Query.Description)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Birth date</span>
|
||||
<InputDate TValue="DateOnly?" class="col form-control" @bind-Value="@(Query.BirthDateFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<InputDate TValue="DateOnly?" class="col form-control" @bind-Value="@(Query.BirthDateTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Death date</span>
|
||||
<InputDate TValue="DateOnly?" class="col form-control" @bind-Value="@(Query.DeathDateFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<InputDate TValue="DateOnly?" class="col form-control" @bind-Value="@(Query.DeathDateTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Gender</span>
|
||||
<InputSelect TValue="short?" class="col form-control" @bind-Value="@(Query.GenderId)">
|
||||
<option @onclick="() => Query.GenderId = null">No choice</option>
|
||||
@foreach (GenderResponse gender in _genders)
|
||||
{
|
||||
<option value="@(gender.Id)">@(gender.Name)</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Rating (count)</span>
|
||||
<NumericEdit TValue="long?" Class="col form-control" Min="0" @bind-Value="@(Query.RatingCountFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<NumericEdit TValue="long?" Class="col form-control" Min="0" @bind-Value="@(Query.RatingCountTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">Rating (average)</span>
|
||||
<NumericEdit TValue="decimal?" Class="col form-control" Min="0" Max="10" Step="@(0.01M)" @bind-Value="@(Query.RatingAverageFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<NumericEdit TValue="decimal?" Class="col form-control" Min="0" Max="10" Step="@(0.01M)" @bind-Value="@(Query.RatingAverageTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">User rating (count)</span>
|
||||
<NumericEdit TValue="long?" Class="col form-control" Min="0" @bind-Value="@(Query.UserRatingCountFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<NumericEdit TValue="long?" Class="col form-control" Min="0" @bind-Value="@(Query.UserRatingCountTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="col-3 input-group-text">User rating (average)</span>
|
||||
<NumericEdit TValue="decimal?" Class="col form-control" Min="0" Max="10" Step="@(0.01M)" @bind-Value="@(Query.UserRatingAverageFrom)"/>
|
||||
<span class="col-auto input-group-text">-</span>
|
||||
<NumericEdit TValue="decimal?" Class="col form-control" Min="0" Max="10" Step="@(0.01M)" @bind-Value="@(Query.UserRatingAverageTo)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</EditForm>
|
||||
@@ -0,0 +1,49 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Common.Model.Genders;
|
||||
using WatchIt.Common.Model.Persons;
|
||||
using WatchIt.Website.Components.Common.ListComponent;
|
||||
using WatchIt.Website.Services.Client.Genders;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages.UserPage.Subcomponents;
|
||||
|
||||
public partial class PersonsRatedFilterFormComponent : FilterFormComponent<PersonRatedResponse, PersonRatedQueryParameters>
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IGendersClientService GendersClientService { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private IEnumerable<GenderResponse> _genders = [];
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
List<Task> endTasks = new List<Task>();
|
||||
|
||||
// STEP 0
|
||||
endTasks.AddRange(
|
||||
[
|
||||
GendersClientService.GetAllGenders(successAction: data => _genders = data)
|
||||
]);
|
||||
|
||||
// END
|
||||
await Task.WhenAll(endTasks);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
@using System.Text
|
||||
@using WatchIt.Common.Model.Movies
|
||||
@using WatchIt.Common.Model.Persons
|
||||
@using WatchIt.Common.Model.Series
|
||||
@using WatchIt.Website.Components.Pages.UserPage.Panels
|
||||
@using WatchIt.Website.Components.Common.ListComponent
|
||||
@using WatchIt.Website.Components.Pages.UserPage.Subcomponents
|
||||
@using WatchIt.Website.Services.Client.Persons
|
||||
|
||||
@page "/user/{id:long?}"
|
||||
|
||||
@@ -60,7 +62,6 @@
|
||||
<Tab Name="movies">Movies</Tab>
|
||||
<Tab Name="series">TV Series</Tab>
|
||||
<Tab Name="people">People</Tab>
|
||||
<Tab Name="roles">Roles</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="summary">
|
||||
@@ -75,7 +76,7 @@
|
||||
NameSource="@(item => item.Title)"
|
||||
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
RatingSource="@(item => item.Rating)"
|
||||
SecondaryRatingSource="@(item => _owner ? null : item.UserRating)"
|
||||
SecondaryRatingSingleSource="@(item => _owner ? null : item.UserRating)"
|
||||
SecondaryRatingTitle="User rating"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PictureDownloadingTask="@((id, action) => MediaClientService.GetMediaPoster(id, action))"
|
||||
@@ -99,7 +100,7 @@
|
||||
NameSource="@(item => item.Title)"
|
||||
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
RatingSource="@(item => item.Rating)"
|
||||
SecondaryRatingSource="@(item => _owner ? null : item.UserRating)"
|
||||
SecondaryRatingSingleSource="@(item => _owner ? null : item.UserRating)"
|
||||
SecondaryRatingTitle="User rating"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PictureDownloadingTask="@((id, action) => MediaClientService.GetMediaPoster(id, action))"
|
||||
@@ -115,10 +116,33 @@
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel Name="people">
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel Name="roles">
|
||||
|
||||
<div class="mt-default">
|
||||
<ListComponent TItem="PersonRatedResponse"
|
||||
TQuery="PersonRatedQueryParameters"
|
||||
Title="Rated people"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.Name)"
|
||||
RatingSource="@(item => item.Rating)"
|
||||
SecondaryRatingMultipleSource="@(item => item.UserRating)"
|
||||
SecondaryRatingTitle="User rating"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PictureDownloadingTask="@((id, action) => PersonsClientService.GetPersonPhoto(id, action))"
|
||||
ItemDownloadingTask="@((query, action) => AccountsClientService.GetAccountRatedPersons(Id!.Value, query, action))"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "user_rating.average", "Average user rating" },
|
||||
{ "user_rating.count", "Number of user ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "name", "Name" },
|
||||
{ "birth_date", "Birth date" },
|
||||
{ "death_date", "Death date" },
|
||||
})"
|
||||
PosterPlaceholder="/assets/person_poster.png"
|
||||
GetGlobalRatingMethod="@((id, action) => PersonsClientService.GetPersonGlobalRating(id, action))">
|
||||
<PersonsRatedFilterFormComponent/>
|
||||
</ListComponent>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
|
||||
@@ -4,6 +4,7 @@ using WatchIt.Website.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
using WatchIt.Website.Services.Client.Accounts;
|
||||
using WatchIt.Website.Services.Client.Media;
|
||||
using WatchIt.Website.Services.Client.Persons;
|
||||
|
||||
namespace WatchIt.Website.Pages;
|
||||
|
||||
@@ -15,6 +16,7 @@ public partial class UserPage : ComponentBase
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = default!;
|
||||
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
|
||||
[Inject] private IMediaClientService MediaClientService { get; set; } = default!;
|
||||
[Inject] private IPersonsClientService PersonsClientService { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
"GetAccountInfo": "/{0}/info",
|
||||
"PutAccountInfo": "/info",
|
||||
"GetAccountRatedMovies": "/{0}/movies",
|
||||
"GetAccountRatedSeries": "/{0}/series"
|
||||
"GetAccountRatedSeries": "/{0}/series",
|
||||
"GetAccountRatedPersons": "/{0}/persons"
|
||||
},
|
||||
"Genders": {
|
||||
"Base": "/genders",
|
||||
|
||||
Reference in New Issue
Block a user