Merge pull request #126 from mateuszskoczek/features/person_database_page

people database page created
This commit is contained in:
2024-10-21 21:45:50 +02:00
committed by GitHub
Unverified
6 changed files with 225 additions and 85 deletions

View File

@@ -48,29 +48,40 @@
{ {
if (string.IsNullOrWhiteSpace(_error)) if (string.IsNullOrWhiteSpace(_error))
{ {
foreach (TItem item in _items) if (_items.Count > 0)
{ {
<div role="button" class="rounded-3 panel panel-regular p-2" @onclick="@(() => NavigationManager.NavigateTo(string.Format(UrlIdTemplate, IdSource(item))))"> foreach (TItem item in _items)
<ListItemComponent Id="@(IdSource(item))" {
Name="@(NameSource(item))" <div role="button" class="rounded-3 panel panel-regular p-2" @onclick="@(() => NavigationManager.NavigateTo(string.Format(UrlIdTemplate, IdSource(item))))">
AdditionalNameInfo="@(AdditionalNameInfoSource(item))" <ListItemComponent Id="@(IdSource(item))"
Rating="@(RatingSource(item))" Name="@(NameSource(item))"
PictureDownloadingTask="@(PictureDownloadingTask)"/> AdditionalNameInfo="@(AdditionalNameInfoSource(item))"
</div> Rating="@(RatingSource(item))"
PictureDownloadingTask="@(PictureDownloadingTask)"/>
</div>
}
if (!_allItemsLoaded)
{
<div role="button" class="rounded-3 panel panel-regular p-3" @onclick="DownloadItems">
<div class="d-flex justify-content-center">
@if (!_itemsLoading)
{
<strong>Load more</strong>
}
else
{
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<strong>Loading...</strong>
}
</div>
</div>
}
} }
if (!_allItemsLoaded) else
{ {
<div role="button" class="rounded-3 panel panel-regular p-3" @onclick="DownloadItems"> <div class="panel">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
@if (!_itemsLoading) <span>No items found</span>
{
<strong>Load more</strong>
}
else
{
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<strong>Loading...</strong>
}
</div> </div>
</div> </div>
} }

View File

@@ -0,0 +1,71 @@
@using WatchIt.Common.Model.Genders
@inherits FilterFormComponent<WatchIt.Common.Model.Persons.PersonResponse, WatchIt.Common.Model.Persons.PersonQueryParameters>
<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>
</EditForm>

View File

@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model.Genders;
using WatchIt.Common.Model.Persons;
using WatchIt.Website.Services.WebAPI.Genders;
namespace WatchIt.Website.Components.Pages.DatabasePage.Subcomponents;
public partial class PersonsFilterFormComponent : FilterFormComponent<PersonResponse, PersonQueryParameters>
{
#region SERVICES
[Inject] private IGendersWebAPIService GendersWebAPIService { 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(
[
GendersWebAPIService.GetAllGenders(successAction: data => _genders = data)
]);
// END
await Task.WhenAll(endTasks);
StateHasChanged();
}
}
#endregion
}

View File

@@ -37,6 +37,7 @@
<DropdownMenu> <DropdownMenu>
<DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/database/movies"))">Movies</DropdownItem> <DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/database/movies"))">Movies</DropdownItem>
<DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/database/series"))">TV Series</DropdownItem> <DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/database/series"))">TV Series</DropdownItem>
<DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/database/people"))">People</DropdownItem>
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
<button type="button" class="btn btn-sm" @onclick="@(() => _searchbarVisible = true)">⌕</button> <button type="button" class="btn btn-sm" @onclick="@(() => _searchbarVisible = true)">⌕</button>

View File

@@ -1,4 +1,5 @@
@using WatchIt.Common.Model.Movies @using WatchIt.Common.Model.Movies
@using WatchIt.Common.Model.Persons
@using WatchIt.Common.Model.Series @using WatchIt.Common.Model.Series
@using WatchIt.Website.Components.Pages.DatabasePage @using WatchIt.Website.Components.Pages.DatabasePage
@using WatchIt.Website.Components.Pages.DatabasePage.Subcomponents @using WatchIt.Website.Components.Pages.DatabasePage.Subcomponents
@@ -17,63 +18,78 @@
case "series": case "series":
@("Series"); @("Series");
break; break;
case "people":
@("People");
break;
} }
@(" database") @(" database")
</PageTitle> </PageTitle>
@if (_loaded)
{
switch (Type)
{
case "movies":
<DatabasePageComponent TItem="MovieResponse"
TQuery="MovieQueryParameters"
Title="Movies database"
IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)"
UrlIdTemplate="/media/{0}"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"
ItemDownloadingTask="@(MoviesWebAPIService.GetAllMovies)"
SortingOptions="@(new Dictionary<string, string>
{
{ "rating.count", "Number of ratings" },
{ "rating.average", "Average rating" },
{ "title", "Title" },
{ "release_date", "Release date" },
})">
<MoviesFilterFormComponent/>
</DatabasePageComponent>
break;
case "series":
<DatabasePageComponent TItem="SeriesResponse"
TQuery="SeriesQueryParameters"
Title="TV series database"
IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)"
UrlIdTemplate="/media/{0}"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"
ItemDownloadingTask="@(SeriesWebAPIService.GetAllSeries)"
SortingOptions="@(new Dictionary<string, string>
{
{ "rating.count", "Number of ratings" },
{ "rating.average", "Average rating" },
{ "title", "Title" },
{ "release_date", "Release date" },
})">
<SeriesFilterFormComponent/>
</DatabasePageComponent>
break;
}
} @switch (Type)
else
{ {
<div class="m-5"> case "movies":
<LoadingComponent/> <DatabasePageComponent TItem="MovieResponse"
</div> TQuery="MovieQueryParameters"
Title="Movies database"
IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)"
UrlIdTemplate="/media/{0}"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"
ItemDownloadingTask="@(MoviesWebAPIService.GetAllMovies)"
SortingOptions="@(new Dictionary<string, string>
{
{ "rating.count", "Number of ratings" },
{ "rating.average", "Average rating" },
{ "title", "Title" },
{ "release_date", "Release date" },
})">
<MoviesFilterFormComponent/>
</DatabasePageComponent>
break;
case "series":
<DatabasePageComponent TItem="SeriesResponse"
TQuery="SeriesQueryParameters"
Title="TV series database"
IdSource="@(item => item.Id)"
NameSource="@(item => item.Title)"
AdditionalNameInfoSource="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
RatingSource="@(item => item.Rating)"
UrlIdTemplate="/media/{0}"
PictureDownloadingTask="@((id, action) => MediaWebAPIService.GetMediaPoster(id, action))"
ItemDownloadingTask="@(SeriesWebAPIService.GetAllSeries)"
SortingOptions="@(new Dictionary<string, string>
{
{ "rating.count", "Number of ratings" },
{ "rating.average", "Average rating" },
{ "title", "Title" },
{ "release_date", "Release date" },
})">
<SeriesFilterFormComponent/>
</DatabasePageComponent>
break;
case "people":
<DatabasePageComponent TItem="PersonResponse"
TQuery="PersonQueryParameters"
Title="People database"
IdSource="@(item => item.Id)"
NameSource="@(item => item.Name)"
RatingSource="@(item => item.Rating)"
UrlIdTemplate="/person/{0}"
PictureDownloadingTask="@((id, action) => PersonsWebAPIService.GetPersonPhoto(id, action))"
ItemDownloadingTask="@(PersonsWebAPIService.GetAllPersons)"
SortingOptions="@(new Dictionary<string, string>
{
{ "rating.count", "Number of ratings" },
{ "rating.average", "Average rating" },
{ "name", "Name" },
{ "birth_date", "Birth date" },
{ "death_date", "Death date" },
})">
<PersonsFilterFormComponent/>
</DatabasePageComponent>
break;
} }

View File

@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Media;
using WatchIt.Website.Services.WebAPI.Movies; using WatchIt.Website.Services.WebAPI.Movies;
using WatchIt.Website.Services.WebAPI.Persons;
using WatchIt.Website.Services.WebAPI.Series; using WatchIt.Website.Services.WebAPI.Series;
namespace WatchIt.Website.Pages; namespace WatchIt.Website.Pages;
@@ -13,6 +14,7 @@ public partial class DatabasePage : ComponentBase
[Inject] private IMediaWebAPIService MediaWebAPIService { get; set; } = default!; [Inject] private IMediaWebAPIService MediaWebAPIService { get; set; } = default!;
[Inject] private IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!; [Inject] private IMoviesWebAPIService MoviesWebAPIService { get; set; } = default!;
[Inject] private ISeriesWebAPIService SeriesWebAPIService { get; set; } = default!; [Inject] private ISeriesWebAPIService SeriesWebAPIService { get; set; } = default!;
[Inject] private IPersonsWebAPIService PersonsWebAPIService { get; set; } = default!;
#endregion #endregion
@@ -28,9 +30,7 @@ public partial class DatabasePage : ComponentBase
#region FIELDS #region FIELDS
private static IEnumerable<string> _databaseTypes = ["movies", "series"]; private static IEnumerable<string> _databaseTypes = ["movies", "series", "people"];
private bool _loaded;
#endregion #endregion
@@ -38,18 +38,11 @@ public partial class DatabasePage : ComponentBase
#region PRIVATE METHODS #region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender) protected override void OnParametersSet()
{ {
if (firstRender) if (!_databaseTypes.Contains(Type))
{ {
// INIT NavigationManager.NavigateTo($"/database/{_databaseTypes.First()}");
if (!_databaseTypes.Contains(Type))
{
NavigationManager.NavigateTo($"/database/{_databaseTypes.First()}");
}
_loaded = true;
StateHasChanged();
} }
} }