Refactoring, database structure changed
This commit is contained in:
64
WatchIt.Website/Components/Pages/AdminPage.razor
Normal file
64
WatchIt.Website/Components/Pages/AdminPage.razor
Normal file
@@ -0,0 +1,64 @@
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/admin"
|
||||
|
||||
<PageTitle>Administrator panel - WatchIt</PageTitle>
|
||||
|
||||
|
||||
|
||||
<Authorization Admin="true">
|
||||
<Loading>
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
</Loading>
|
||||
<Authorized>
|
||||
<div class="vstack gap-default">
|
||||
<div class="panel panel-section-header">
|
||||
<h3 class="fw-bold m-0">Add new content</h3>
|
||||
</div>
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col">
|
||||
<a class="text-reset text-decoration-none" href="/media/new/movies">
|
||||
<div class="panel">
|
||||
<div class="d-flex flex-column align-items-center p-5">
|
||||
<img src="assets/icons/movie.png" width="100%" alt="movie"/>
|
||||
<span class="text-reset">New movie</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a class="text-reset text-decoration-none" href="/media/new/series">
|
||||
<div class="panel">
|
||||
<div class="d-flex flex-column align-items-center p-5">
|
||||
<img src="assets/icons/series.png" width="100%" alt="movie"/>
|
||||
<span class="text-center">New TV series</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a class="text-reset text-decoration-none" href="/people/new">
|
||||
<div class="panel">
|
||||
<div class="d-flex flex-column align-items-center p-5">
|
||||
<img src="assets/icons/person.png" width="100%" alt="movie"/>
|
||||
<span class="text-center">New person</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<div class="vstack">
|
||||
<ErrorPanel ErrorMessage="You do not have permission to view this site"/>
|
||||
</div>
|
||||
</NotAuthorized>
|
||||
</Authorization>
|
||||
14
WatchIt.Website/Components/Pages/AdminPage.razor.cs
Normal file
14
WatchIt.Website/Components/Pages/AdminPage.razor.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class AdminPage : Page
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[CascadingParameter] public required BaseLayout Layout { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
54
WatchIt.Website/Components/Pages/AuthPage.razor
Normal file
54
WatchIt.Website/Components/Pages/AuthPage.razor
Normal file
@@ -0,0 +1,54 @@
|
||||
@using System.Drawing
|
||||
@using System.Text
|
||||
@using WatchIt.Website.Components.Layout
|
||||
@using Blazorise.Snackbar
|
||||
@using WatchIt.Website.Components.Subcomponents.Pages.AuthPage
|
||||
|
||||
@inherits Page
|
||||
|
||||
@layout EmptyLayout
|
||||
|
||||
@page "/auth"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (_isSingUp) sb.Insert(0, $"Sing up");
|
||||
else sb.Insert(0, $"Sing in");
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
<CascadingValue Value="this">
|
||||
<div class="h-100 d-flex align-items-center justify-content-center">
|
||||
<div class="panel panel-auth">
|
||||
<div class="d-flex flex-column align-items-center gap-3">
|
||||
<a id="logo" class="logo m-0" href="/">WatchIt</a>
|
||||
@if (_isSingUp)
|
||||
{
|
||||
<RegisterForm RegisteredSuccessfully="@(() => _isSingUp = false)"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoginForm RedirectTo="@(RedirectTo)"/>
|
||||
}
|
||||
<div class="btn-group w-100">
|
||||
<input type="radio" class="btn-check" name="signtype" id="signin" autocomplete="off" checked="@(!_isSingUp)" @onclick="() => { _isSingUp = false; }">
|
||||
<label class="btn btn-outline-secondary btn-sm" for="signin">Sign in</label>
|
||||
<input type="radio" class="btn-check" name="signtype" id="signup" autocomplete="off" checked="@(_isSingUp)" @onclick="() => { _isSingUp = true; }">
|
||||
<label class="btn btn-outline-secondary btn-sm" for="signup">Sign up</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* IDS */
|
||||
|
||||
#logo {
|
||||
background-image: linear-gradient(45deg, @($"{ColorTranslator.ToHtml(Base.BackgroundSettings.FirstGradientColor)}, {ColorTranslator.ToHtml(Base.BackgroundSettings.SecondGradientColor)}"));
|
||||
}
|
||||
</style>
|
||||
</CascadingValue>
|
||||
50
WatchIt.Website/Components/Pages/AuthPage.razor.cs
Normal file
50
WatchIt.Website/Components/Pages/AuthPage.razor.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Net;
|
||||
using Blazorise.Snackbar;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
using WatchIt.Website.Services.Tokens;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class AuthPage
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] public NavigationManager NavigationManager { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[SupplyParameterFromQuery(Name = "redirect_to")]
|
||||
private string RedirectTo { get; set; } = "/";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private bool _isSingUp;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
Base.CustomBackground = null;
|
||||
if (Base.AuthorizedAccount is not null)
|
||||
{
|
||||
NavigationManager.NavigateTo(WebUtility.UrlDecode(RedirectTo));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
18
WatchIt.Website/Components/Pages/AuthPage.razor.css
Normal file
18
WatchIt.Website/Components/Pages/AuthPage.razor.css
Normal file
@@ -0,0 +1,18 @@
|
||||
/* TAGS */
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* CLASSES */
|
||||
|
||||
.logo {
|
||||
font-size: 60px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.panel-auth {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
99
WatchIt.Website/Components/Pages/GenreMediaListPage.razor
Normal file
99
WatchIt.Website/Components/Pages/GenreMediaListPage.razor
Normal file
@@ -0,0 +1,99 @@
|
||||
@using System.Net
|
||||
@using System.Text
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.Database.Model.Media
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.List
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/genres/{id:int}/media"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (_data is null) sb.Insert(0, "Error");
|
||||
else sb.Insert(0, $"\"{_data.Name}\" genre");
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (!_loaded)
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
else if (_data is null)
|
||||
{
|
||||
<ErrorPanel ErrorMessage="@($"Genre with ID {Id} was not found")"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<List TItem="MediumResponse"
|
||||
TEntity="Medium"
|
||||
TQuery="MediumFilterQuery"
|
||||
Title="@(_data.Name)"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
filterQuery.Genres = [(short)Id];
|
||||
IApiResponse<IEnumerable<MediumResponse>> response = await MediaClient.GetMedia(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. Media for genre with id {Id} could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "title", "Title" },
|
||||
{ "release_date", "Release date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for medium with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate media", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate media", SnackbarColor.Danger);
|
||||
}
|
||||
})">
|
||||
<MediaFilter/>
|
||||
</List>
|
||||
}
|
||||
56
WatchIt.Website/Components/Pages/GenreMediaListPage.razor.cs
Normal file
56
WatchIt.Website/Components/Pages/GenreMediaListPage.razor.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Genres.Genre;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class GenreMediaListPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IGenresClient GenresClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public int Id { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private bool _loaded;
|
||||
private GenreResponse? _data;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
IApiResponse<GenreResponse> response = await GenresClient.GetGenre((short)Id);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_data = response.Content;
|
||||
}
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
65
WatchIt.Website/Components/Pages/HomePage.razor
Normal file
65
WatchIt.Website/Components/Pages/HomePage.razor
Normal file
@@ -0,0 +1,65 @@
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person
|
||||
@using WatchIt.DTO.Models.Generics.Image
|
||||
@using WatchIt.DTO.Query
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@inherits Page
|
||||
|
||||
@page "/"
|
||||
|
||||
<PageTitle>WatchIt</PageTitle>
|
||||
|
||||
|
||||
|
||||
<div class="vstack gap-default">
|
||||
<HorizontalListPanel TItem="MediumMovieResponse"
|
||||
Title="Top 5 movies this week by popularity"
|
||||
GetItemsAction="@(() => MediaClient.GetMediumMovies(orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "view_count.last_week",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 5,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/media/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
|
||||
PosterPlaceholder="/assets/placeholders/medium.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"/>
|
||||
<HorizontalListPanel TItem="MediumSeriesResponse"
|
||||
Title="Top 5 TV series this week by popularity"
|
||||
GetItemsAction="@(() => MediaClient.GetMediumSeries(orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "view_count.last_week",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 5,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/media/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
|
||||
PosterPlaceholder="/assets/placeholders/medium.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"/>
|
||||
<HorizontalListPanel TItem="PersonResponse"
|
||||
Title="Top 5 people this week by popularity"
|
||||
GetItemsAction="@(() => PeopleClient.GetPeople(orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "view_count.last_week",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 5,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/people/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.Name)"
|
||||
PosterPlaceholder="/assets/placeholders/person.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"/>
|
||||
</div>
|
||||
15
WatchIt.Website/Components/Pages/HomePage.razor.cs
Normal file
15
WatchIt.Website/Components/Pages/HomePage.razor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Clients;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class HomePage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] public NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] public IMediaClient MediaClient { get; set; } = default!;
|
||||
[Inject] public IPeopleClient PeopleClient { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
}
|
||||
154
WatchIt.Website/Components/Pages/MediumEditPage.razor
Normal file
154
WatchIt.Website/Components/Pages/MediumEditPage.razor
Normal file
@@ -0,0 +1,154 @@
|
||||
@using System.Net
|
||||
@using System.Text
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Generics.Image
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.Panels.Pages.MediumEditPage
|
||||
@using Authorization = WatchIt.Website.Components.Subcomponents.Common.Authorization
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using Blazorise
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/media/{id:long}/edit"
|
||||
@page "/media/new/{type?}"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (Base.AuthorizedAccount?.IsAdmin != true) sb.Insert(0, "Error");
|
||||
else
|
||||
{
|
||||
if (_data is not null) sb.Insert(0, $"Edit \"{_data.Title}\"");
|
||||
else
|
||||
{
|
||||
if (Type == "series") sb.Insert(0, "TV series");
|
||||
else sb.Insert(0, "movie");
|
||||
sb.Insert(0, "New ");
|
||||
}
|
||||
}
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (_loaded)
|
||||
{
|
||||
<Authorization Admin="true">
|
||||
<Authorized>
|
||||
<div class="vstack gap-default">
|
||||
<HeaderPanel Data=@(_data)
|
||||
TypeIfNull="@(Type == "series" ? NullType.Series : NullType.Movie)"/>
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col-auto">
|
||||
<ImageEditorPanel Disabled="@(_data is null)"
|
||||
Image="@(_data?.Picture)"
|
||||
OnImageChanged="@(pic => _data!.Picture = pic)"
|
||||
ImageGetMethod="@(async () =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
IApiResponse<ImageResponse> response = await MediaClient.GetMediumPicture(_data.Id);
|
||||
if (response.IsSuccessful || response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return response.Content;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of edited medium could not be obtained", SnackbarColor.Danger);
|
||||
}
|
||||
return null;
|
||||
})"
|
||||
ImagePutMethod="@(async image =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse<ImageResponse> response = await MediaClient.PutMediumPicture(token, _data.Id, image);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
return response.Content;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of medium could not be changed", SnackbarColor.Danger);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. There is no medium data, needed for picture saving", SnackbarColor.Danger);
|
||||
}
|
||||
return null;
|
||||
})"
|
||||
ImageDeleteMethod="@(async () =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumPicture(token, _data.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of medium could not be deleted", SnackbarColor.Danger);
|
||||
}
|
||||
return response.IsSuccessful;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. There is no medium data, needed for picture saving", SnackbarColor.Danger);
|
||||
return false;
|
||||
})"
|
||||
ImagePlaceholder="/assets/placeholders/medium.png"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<EditFormPanel Data="@(_data)"
|
||||
TypeIfNull="@(Type == "series" ? NullType.Series : NullType.Movie)"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center"
|
||||
SelectedTab="genres">
|
||||
<Items>
|
||||
<Tab Name="genres">Genres</Tab>
|
||||
<Tab Name="actors">Actors</Tab>
|
||||
<Tab Name="creators">Creators</Tab>
|
||||
<Tab Name="photos">Photos</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="genres">
|
||||
<GenresEditPanel Data="@(_data)"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="actors">
|
||||
<ActorRolesEditPanel Data="@(_data)"
|
||||
Disabled="@(_data is null)"
|
||||
People="@(_people)"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="creators">
|
||||
<CreatorRolesEditPanel Data="@(_data)"
|
||||
Disabled="@(_data is null)"
|
||||
People="@(_people)"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="photos">
|
||||
<PhotosEditPanel Id="@(_data?.Id)"/>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<ErrorPanel ErrorMessage="You do not have permission to view this site"/>
|
||||
</NotAuthorized>
|
||||
<Loading>
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
</Loading>
|
||||
</Authorization>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
114
WatchIt.Website/Components/Pages/MediumEditPage.razor.cs
Normal file
114
WatchIt.Website/Components/Pages/MediumEditPage.razor.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using Blazorise.Snackbar;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Media.Medium.Response;
|
||||
using WatchIt.DTO.Models.Controllers.People.Person;
|
||||
using WatchIt.DTO.Models.Controllers.Photos.Photo;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class MediumEditPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long? Id { get; set; }
|
||||
[Parameter] public string? Type { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private bool _loaded;
|
||||
|
||||
private BaseMediumResponse? _data;
|
||||
private List<PersonResponse>? _people;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
await Task.WhenAll(
|
||||
[
|
||||
LoadData(),
|
||||
LoadPeople(),
|
||||
LoadBackground(),
|
||||
]);
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
if (Id.HasValue)
|
||||
{
|
||||
IApiResponse<MediumResponse> response = await MediaClient.GetMedium(Id.Value);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
switch (response.Content.Type)
|
||||
{
|
||||
case MediumResponseType.Movie:
|
||||
IApiResponse<MediumMovieResponse> responseMovie = await MediaClient.GetMediumMovie(Id.Value, true);
|
||||
_data = responseMovie.Content;
|
||||
break;
|
||||
case MediumResponseType.Series:
|
||||
IApiResponse<MediumSeriesResponse> responseSeries = await MediaClient.GetMediumSeries(Id.Value, true);
|
||||
_data = responseSeries.Content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Medium data could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadPeople()
|
||||
{
|
||||
IApiResponse<IEnumerable<PersonResponse>> response = await PeopleClient.GetPeople();
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_people = response.Content.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured during loading people.", SnackbarColor.Danger);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadBackground()
|
||||
{
|
||||
if (Id.HasValue)
|
||||
{
|
||||
IApiResponse<PhotoResponse?> response = await MediaClient.GetMediumBackgroundPhoto(Id.Value);
|
||||
if (response.IsSuccessful && response.Content is not null)
|
||||
{
|
||||
Base.CustomBackground = response.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
137
WatchIt.Website/Components/Pages/MediumPage.razor
Normal file
137
WatchIt.Website/Components/Pages/MediumPage.razor
Normal file
@@ -0,0 +1,137 @@
|
||||
@using System.Text
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.Panels.Pages.MediumPage
|
||||
@using Blazorise
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.Role.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.Role.Response
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.RoleActorType
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.RoleCreatorType
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/media/{id:long}"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (_data is null) sb.Insert(0, "Error");
|
||||
else
|
||||
{
|
||||
if (_data.ReleaseDate.HasValue) sb.Insert(0, $" ({_data.ReleaseDate.Value.Year})");
|
||||
sb.Insert(0, _data.Title);
|
||||
}
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (!_loaded)
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
else if (_data is null)
|
||||
{
|
||||
<ErrorPanel ErrorMessage="@($"Medium with ID {Id} was not found")"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="vstack gap-default">
|
||||
<ItemPageHeaderPanel Name="@(_data.Title)"
|
||||
Description="@(_data.Description)"
|
||||
Subname="@(_data.OriginalTitle)"
|
||||
Poster="@(_data.Picture)"
|
||||
PosterPlaceholder="/assets/placeholders/medium.png"/>
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col">
|
||||
<MetadataPanel Data="@(_data)"/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<RatingPanel Data="@(_data)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
SelectedTab="actors"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center">
|
||||
<Items>
|
||||
<Tab Name="actors">Actors</Tab>
|
||||
<Tab Name="creators">Creators</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="actors">
|
||||
<RolesPanel TRole="RoleActorResponse"
|
||||
TRoleParent="PersonResponse"
|
||||
Title="Actors"
|
||||
RoleParents="@(_people)"
|
||||
ParentName="People"
|
||||
ParentFunc="@((role, parents) => parents.First(x => x.Id == role.PersonId))"
|
||||
NameFunc="@((_, parent) => parent.Name)"
|
||||
AdditionalInfoFunc="@((role, _) => $" as {role.Name}")"
|
||||
PicturePlaceholder="/assets/placeholders/person.png"
|
||||
PictureFunc="@((_, parent) => Task.FromResult(parent.Picture))"
|
||||
UrlFunc="@((_, parent) => $"people/{parent.Id}")"
|
||||
GlobalRatingFunc="@((_, parent) => parent.Rating)"
|
||||
GetRoleTypesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleActorTypeResponse>> response = await RolesClient.GetRoleActorTypes();
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Actor role types could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
GetRolesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleActorResponse>> response = await RolesClient.GetRoleActors(new RoleActorFilterQuery { MediumId = _data.Id });
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Actor roles could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="creators">
|
||||
<RolesPanel TRole="RoleCreatorResponse"
|
||||
TRoleParent="PersonResponse"
|
||||
Title="Creators"
|
||||
RoleParents="@(_people)"
|
||||
ParentName="People"
|
||||
ParentFunc="@((role, parents) => parents.First(x => x.Id == role.PersonId))"
|
||||
NameFunc="@((_, parent) => parent.Name)"
|
||||
PicturePlaceholder="/assets/placeholders/person.png"
|
||||
PictureFunc="@((_, parent) => Task.FromResult(parent.Picture))"
|
||||
UrlFunc="@((_, parent) => $"people/{parent.Id}")"
|
||||
GlobalRatingFunc="@((_, parent) => parent.Rating)"
|
||||
GetRoleTypesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleCreatorTypeResponse>> response = await RolesClient.GetRoleCreatorTypes();
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Creator role types could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
GetRolesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleCreatorResponse>> response = await RolesClient.GetRoleCreators(new RoleCreatorFilterQuery { MediumId = _data.Id });
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Creator roles could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"/>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
}
|
||||
96
WatchIt.Website/Components/Pages/MediumPage.razor.cs
Normal file
96
WatchIt.Website/Components/Pages/MediumPage.razor.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Media.Medium.Response;
|
||||
using WatchIt.DTO.Models.Controllers.People.Person;
|
||||
using WatchIt.DTO.Models.Controllers.Photos.Photo;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class MediumPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
[Inject] private IPhotosClient PhotosClient { get; set; } = null!;
|
||||
[Inject] private IRolesClient RolesClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long Id { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
//private RatingPanel _ratingPanel = null!;
|
||||
|
||||
private bool _loaded;
|
||||
|
||||
private MediumResponse? _data;
|
||||
private IEnumerable<PersonResponse>? _people;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
await Task.WhenAll(
|
||||
[
|
||||
LoadData(),
|
||||
LoadPeople(),
|
||||
IncrementViewCounter(),
|
||||
LoadBackground(),
|
||||
]);
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
IApiResponse<MediumResponse> response = await MediaClient.GetMedium(Id, true);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_data = response.Content;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadPeople()
|
||||
{
|
||||
IApiResponse<IEnumerable<PersonResponse>> response = await PeopleClient.GetPeople(includePictures: true);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_people = response.Content;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task IncrementViewCounter()
|
||||
{
|
||||
await MediaClient.PutMediumViewCount(Id);
|
||||
}
|
||||
|
||||
private async Task LoadBackground()
|
||||
{
|
||||
IApiResponse<PhotoResponse?> response = await MediaClient.GetMediumBackgroundPhoto(Id);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
Base.CustomBackground = response.Content;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
74
WatchIt.Website/Components/Pages/MoviesListPage.razor
Normal file
74
WatchIt.Website/Components/Pages/MoviesListPage.razor
Normal file
@@ -0,0 +1,74 @@
|
||||
@using System.Net
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.Database.Model.Media
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.Website.Components.List
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/media/movies"
|
||||
|
||||
<PageTitle>Movies - WatchIt</PageTitle>
|
||||
|
||||
|
||||
|
||||
<List TItem="MediumMovieResponse"
|
||||
TEntity="MediumMovie"
|
||||
TQuery="MediumMovieFilterQuery"
|
||||
Title="Movies database"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumMovieResponse>> response = await MediaClient.GetMediumMovies(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. Movies could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "title", "Title" },
|
||||
{ "release_date", "Release date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for movie with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})">
|
||||
<MediumMoviesFilter/>
|
||||
</List>
|
||||
17
WatchIt.Website/Components/Pages/MoviesListPage.razor.cs
Normal file
17
WatchIt.Website/Components/Pages/MoviesListPage.razor.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class MoviesListPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
}
|
||||
16
WatchIt.Website/Components/Pages/Page.cs
Normal file
16
WatchIt.Website/Components/Pages/Page.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public abstract class Page : Component
|
||||
{
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
Base.CustomBackground = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
57
WatchIt.Website/Components/Pages/PeopleListPage.razor
Normal file
57
WatchIt.Website/Components/Pages/PeopleListPage.razor
Normal file
@@ -0,0 +1,57 @@
|
||||
@using System.Net
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.Database.Model.People
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person.Query
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.Website.Components.List
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/people"
|
||||
|
||||
<PageTitle>People - WatchIt</PageTitle>
|
||||
|
||||
|
||||
|
||||
<List TItem="PersonResponse"
|
||||
TEntity="Person"
|
||||
TQuery="PersonFilterQuery"
|
||||
Title="People database"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Name)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/people/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/person.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<PersonResponse>> response = await PeopleClient.GetPeople(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. People could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "name", "Name" },
|
||||
{ "birth_date", "Birth date" },
|
||||
{ "death_date", "Death date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await PeopleClient.GetPersonRating(x.Id)).Content)"
|
||||
SecondaryRatingTitle="Your rating"
|
||||
GetSecondaryRatingMethod="@(Base.AuthorizedAccount is null ? null : async (item) =>
|
||||
{
|
||||
IApiResponse<RatingUserOverallResponse> response = await PeopleClient.GetPersonUserRating(item.Id, Base.AuthorizedAccount.Id);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for person with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})">
|
||||
<PeopleFilter/>
|
||||
</List>
|
||||
17
WatchIt.Website/Components/Pages/PeopleListPage.razor.cs
Normal file
17
WatchIt.Website/Components/Pages/PeopleListPage.razor.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class PeopleListPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
}
|
||||
138
WatchIt.Website/Components/Pages/PersonEditPage.razor
Normal file
138
WatchIt.Website/Components/Pages/PersonEditPage.razor
Normal file
@@ -0,0 +1,138 @@
|
||||
@using System.Net
|
||||
@using System.Text
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Generics.Image
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.Panels.Pages.PersonEditPage
|
||||
@using Authorization = WatchIt.Website.Components.Subcomponents.Common.Authorization
|
||||
@using Blazorise
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/people/{id:long}/edit"
|
||||
@page "/people/new"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (Base.AuthorizedAccount?.IsAdmin == true) sb.Insert(0, "Error");
|
||||
else
|
||||
{
|
||||
if (_data is null) sb.Insert(0, "Create new person");
|
||||
else sb.Insert(0, $"Edit \"{_data.Name}\"");
|
||||
}
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (_loaded)
|
||||
{
|
||||
<Authorization Admin="true">
|
||||
<Authorized>
|
||||
<div class="vstack gap-default">
|
||||
<HeaderPanel Data=@(_data)/>
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col-auto">
|
||||
<ImageEditorPanel Disabled="@(_data is null)"
|
||||
Image="@(_data?.Picture)"
|
||||
OnImageChanged="@(pic => _data!.Picture = pic)"
|
||||
ImageGetMethod="@(async () =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
IApiResponse<ImageResponse> response = await PeopleClient.GetPersonPicture(_data.Id);
|
||||
if (response.IsSuccessful || response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return response.Content;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of edited person could not be obtained", SnackbarColor.Danger);
|
||||
}
|
||||
return null;
|
||||
})"
|
||||
ImagePutMethod="@(async image =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse<ImageResponse> response = await PeopleClient.PutPersonPicture(token, _data.Id, image);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
return response.Content;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of person could not be changed", SnackbarColor.Danger);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. There is no person data, needed for picture saving", SnackbarColor.Danger);
|
||||
}
|
||||
return null;
|
||||
})"
|
||||
ImageDeleteMethod="@(async () =>
|
||||
{
|
||||
if (_data is not null)
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await PeopleClient.DeletePersonPicture(token, _data.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Picture of person could not be deleted", SnackbarColor.Danger);
|
||||
}
|
||||
return response.IsSuccessful;
|
||||
}
|
||||
await Base.SnackbarStack.PushAsync("An error occured. There is no person data, needed for picture saving", SnackbarColor.Danger);
|
||||
return false;
|
||||
})"
|
||||
ImagePlaceholder="/assets/placeholders/person.png"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<EditFormPanel Data="@(_data)"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center"
|
||||
SelectedTab="actor">
|
||||
<Items>
|
||||
<Tab Name="actor">Actor</Tab>
|
||||
<Tab Name="creator">Creator</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="actor">
|
||||
<ActorRolesEditPanel Data="@(_data)"
|
||||
Disabled="@(_data is null)"
|
||||
Media="@(_media)"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="creator">
|
||||
<CreatorRolesEditPanel Data="@(_data)"
|
||||
Disabled="@(_data is null)"
|
||||
Media="@(_media)"/>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<ErrorPanel ErrorMessage="You do not have permission to view this site"/>
|
||||
</NotAuthorized>
|
||||
<Loading>
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
</Loading>
|
||||
</Authorization>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
93
WatchIt.Website/Components/Pages/PersonEditPage.razor.cs
Normal file
93
WatchIt.Website/Components/Pages/PersonEditPage.razor.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Blazorise.Snackbar;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Media.Medium.Response;
|
||||
using WatchIt.DTO.Models.Controllers.People.Person;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class PersonEditPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long? Id { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private bool _loaded;
|
||||
|
||||
private PersonResponse? _data;
|
||||
private List<MediumResponse>? _media;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
await Task.WhenAll(
|
||||
[
|
||||
LoadData(),
|
||||
LoadMedia(),
|
||||
]);
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task<bool> LoadData()
|
||||
{
|
||||
if (!Id.HasValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IApiResponse<PersonResponse> response = await PeopleClient.GetPerson(Id.Value, true);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_data = response.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured during loading person data.", SnackbarColor.Danger);
|
||||
}
|
||||
|
||||
return response.IsSuccessful;
|
||||
}
|
||||
|
||||
private async Task LoadMedia()
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumResponse>> response = await MediaClient.GetMedia();
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_media = response.Content.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured during loading media.", SnackbarColor.Danger);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
135
WatchIt.Website/Components/Pages/PersonPage.razor
Normal file
135
WatchIt.Website/Components/Pages/PersonPage.razor
Normal file
@@ -0,0 +1,135 @@
|
||||
@using System.Text
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.Panels.Pages.PersonPage
|
||||
@using Blazorise
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.Role.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.Role.Response
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.RoleActorType
|
||||
@using WatchIt.DTO.Models.Controllers.Roles.RoleCreatorType
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/people/{id:long}"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (_data is null) sb.Insert(0, "Error");
|
||||
else sb.Insert(0, _data.Name);
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (!_loaded)
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
else if (_data is null)
|
||||
{
|
||||
<ErrorPanel ErrorMessage="@($"Person with ID {Id} was not found")"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="vstack gap-default">
|
||||
<ItemPageHeaderPanel Name="@(_data.Name)"
|
||||
Description="@(_data.Description)"
|
||||
Subname="@(_data.FullName)"
|
||||
Poster="@(_data.Picture)"
|
||||
PosterPlaceholder="/assets/placeholders/person.png"/>
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col">
|
||||
<MetadataPanel Data="@(_data)"/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<RatingPanel @ref="@(_ratingPanel)" Data="@(_data)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
SelectedTab="actor"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center">
|
||||
<Items>
|
||||
<Tab Name="actor">Actor</Tab>
|
||||
<Tab Name="creator">Creator</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="actor">
|
||||
<RolesPanel TRole="RoleActorResponse"
|
||||
TRoleParent="MediumResponse"
|
||||
Title="Actors"
|
||||
RoleParents="@(_media)"
|
||||
ParentName="Media"
|
||||
ParentFunc="@((role, parents) => parents.First(x => x.Id == role.MediumId))"
|
||||
NameFunc="@((_, parent) => parent.Title)"
|
||||
AdditionalInfoFunc="@((role, _) => $" as {role.Name}")"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
PictureFunc="@((_, parent) => Task.FromResult(parent.Picture))"
|
||||
UrlFunc="@((_, parent) => $"media/{parent.Id}")"
|
||||
GlobalRatingFunc="@((_, parent) => parent.Rating)"
|
||||
GetRoleTypesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleActorTypeResponse>> response = await RolesClient.GetRoleActorTypes();
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Actor role types could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
GetRolesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleActorResponse>> response = await RolesClient.GetRoleActors(new RoleActorFilterQuery { PersonId = _data.Id });
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Actor roles could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
OnRatingChanged="@(async () => await _ratingPanel.Update())"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="creator">
|
||||
<RolesPanel TRole="RoleCreatorResponse"
|
||||
TRoleParent="MediumResponse"
|
||||
Title="Creators"
|
||||
RoleParents="@(_media)"
|
||||
ParentName="Media"
|
||||
ParentFunc="@((role, parents) => parents.First(x => x.Id == role.MediumId))"
|
||||
NameFunc="@((_, parent) => parent.Title)"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
PictureFunc="@((_, parent) => Task.FromResult(parent.Picture))"
|
||||
UrlFunc="@((_, parent) => $"media/{parent.Id}")"
|
||||
GlobalRatingFunc="@((_, parent) => parent.Rating)"
|
||||
GetRoleTypesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleCreatorTypeResponse>> response = await RolesClient.GetRoleCreatorTypes();
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Creator role types could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
GetRolesMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<RoleCreatorResponse>> response = await RolesClient.GetRoleCreators(new RoleCreatorFilterQuery { PersonId = _data.Id });
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Creator roles could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
OnRatingChanged="@(async () => await _ratingPanel.Update())"/>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
}
|
||||
85
WatchIt.Website/Components/Pages/PersonPage.razor.cs
Normal file
85
WatchIt.Website/Components/Pages/PersonPage.razor.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Media.Medium.Response;
|
||||
using WatchIt.DTO.Models.Controllers.People.Person;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Components.Panels.Pages.PersonPage;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class PersonPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
[Inject] private IRolesClient RolesClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long Id { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private RatingPanel _ratingPanel = null!;
|
||||
|
||||
private bool _loaded;
|
||||
|
||||
private PersonResponse? _data;
|
||||
private IEnumerable<MediumResponse>? _media;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
await Task.WhenAll(
|
||||
[
|
||||
LoadData(),
|
||||
LoadMedia(),
|
||||
IncrementViewCounter(),
|
||||
]);
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
IApiResponse<PersonResponse> response = await PeopleClient.GetPerson(Id, true);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_data = response.Content;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadMedia()
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumResponse>> response = await MediaClient.GetMedia(includePictures: true);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_media = response.Content;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task IncrementViewCounter()
|
||||
{
|
||||
await PeopleClient.PutPeopleViewCount(Id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
154
WatchIt.Website/Components/Pages/SearchPage.razor
Normal file
154
WatchIt.Website/Components/Pages/SearchPage.razor
Normal file
@@ -0,0 +1,154 @@
|
||||
@using System.Net
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person.Query
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.Website.Components.Panels.Pages.SearchPage
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/search/{query}"
|
||||
|
||||
<PageTitle>WatchIt - Searching "@(Query)"</PageTitle>
|
||||
|
||||
|
||||
|
||||
<div class="vstack gap-default">
|
||||
<div class="rounded-3 panel panel-regular p-3">
|
||||
<div class="d-flex justify-content-center">
|
||||
<h3 class="m-0">
|
||||
<strong>Search results for phrase:</strong> "@(WebUtility.UrlDecode(Query))"
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<StandardSearchResultPanel TItem="MediumMovieResponse"
|
||||
TQuery="MediumMovieFilterQuery"
|
||||
Title="Movies"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
Query="@(new MediumMovieFilterQuery { Title = WebUtility.UrlDecode(Query) })"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumMovieResponse>> response = await MediaClient.GetMediumMovies(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. Movies could not be loaded", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
PictureFunc="@(x => Task.FromResult(x.Picture))"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for movie with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})"/>
|
||||
<StandardSearchResultPanel TItem="MediumSeriesResponse"
|
||||
TQuery="MediumSeriesFilterQuery"
|
||||
Title="TV series"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
Query="@(new MediumSeriesFilterQuery { Title = WebUtility.UrlDecode(Query) })"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumSeriesResponse>> response = await MediaClient.GetMediumSeries(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. TV series could not be loaded", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
PictureFunc="@(x => Task.FromResult(x.Picture))"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for TV series with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})"/>
|
||||
<StandardSearchResultPanel TItem="PersonResponse"
|
||||
TQuery="PersonFilterQuery"
|
||||
Title="People"
|
||||
UrlIdTemplate="/people/{0}"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Name)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
Query="@(new PersonFilterQuery { Name = WebUtility.UrlDecode(Query) })"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<PersonResponse>> response = await PeopleClient.GetPeople(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. People could not be loaded", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
PictureFunc="@(x => Task.FromResult(x.Picture))"
|
||||
PicturePlaceholder="/assets/placeholders/person.png"
|
||||
GetGlobalRatingMethod="@(async x => (await PeopleClient.GetPersonRating(x.Id)).Content)"
|
||||
SecondaryRatingTitle="@(Base.AuthorizedAccount is null ? null : "Your rating")"
|
||||
GetSecondaryRatingMethod="@(Base.AuthorizedAccount is null ? null : async (item) =>
|
||||
{
|
||||
IApiResponse<RatingUserOverallResponse> response = await PeopleClient.GetPersonUserRating(item.Id, Base.AuthorizedAccount.Id);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for person with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"/>
|
||||
<UserSearchResultPanel Query="@(WebUtility.UrlDecode(Query))"/>
|
||||
</div>
|
||||
35
WatchIt.Website/Components/Pages/SearchPage.razor.cs
Normal file
35
WatchIt.Website/Components/Pages/SearchPage.razor.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class SearchPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required string Query { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private string _decodedQuery => WebUtility.UrlDecode(Query);
|
||||
|
||||
#endregion
|
||||
}
|
||||
74
WatchIt.Website/Components/Pages/SeriesListPage.razor
Normal file
74
WatchIt.Website/Components/Pages/SeriesListPage.razor
Normal file
@@ -0,0 +1,74 @@
|
||||
@using System.Net
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.Database.Model.Media
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.Website.Components.List
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/media/series"
|
||||
|
||||
<PageTitle>TV series - WatchIt</PageTitle>
|
||||
|
||||
|
||||
|
||||
<List TItem="MediumSeriesResponse"
|
||||
TEntity="MediumSeries"
|
||||
TQuery="MediumSeriesFilterQuery"
|
||||
Title="TV series database"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumSeriesResponse>> response = await MediaClient.GetMediumSeries(filterQuery, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. TV series could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "title", "Title" },
|
||||
{ "release_date", "Release date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for TV series with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})">
|
||||
<MediumSeriesFilter/>
|
||||
</List>
|
||||
17
WatchIt.Website/Components/Pages/SeriesListPage.razor.cs
Normal file
17
WatchIt.Website/Components/Pages/SeriesListPage.razor.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class SeriesListPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
}
|
||||
120
WatchIt.Website/Components/Pages/UserEditPage.razor
Normal file
120
WatchIt.Website/Components/Pages/UserEditPage.razor
Normal file
@@ -0,0 +1,120 @@
|
||||
@using System.Net
|
||||
@using System.Text
|
||||
@using WatchIt.Website.Components.Panels.Pages.UserEditPage
|
||||
@using Blazorise
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.DTO.Models.Generics.Image
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using Authorization = WatchIt.Website.Components.Subcomponents.Common.Authorization
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/user_settings"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (_data is null) sb.Insert(0, "Loading...");
|
||||
else sb.Insert(0, "User settings");
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
<Authorization>
|
||||
<Authorized>
|
||||
<div class="vstack gap-default">
|
||||
<HeaderPanel Data="@(Base.AuthorizedAccount)"/>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center"
|
||||
SelectedTab="profile">
|
||||
<Items>
|
||||
<Tab Name="profile">Profile</Tab>
|
||||
<Tab Name="account">Account</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="profile">
|
||||
<div class="vstack gap-default">
|
||||
<div class="container-grid">
|
||||
<div class="row gx-default">
|
||||
<div class="col-auto">
|
||||
<ImageEditorPanel Image="@(Base.AuthorizedAccount.ProfilePicture)"
|
||||
Class="h-100"
|
||||
ImagePlaceholder="assets/placeholders/user.png"
|
||||
Circle="true"
|
||||
ImageGetMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<ImageResponse> response = await AccountsClient.GetAccountProfilePicture(Base.AuthorizedAccount.Id);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Profile picture could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
|
||||
return response.Content;
|
||||
})"
|
||||
ImagePutMethod="@(async request =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse<ImageResponse> response = await AccountsClient.PutAccountProfilePicture(token, request);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
Base.AuthorizedAccount.ProfilePicture = response.Content;
|
||||
NavigationManager.Refresh(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Profile picture could not be saved.", SnackbarColor.Danger);
|
||||
}
|
||||
|
||||
return response.Content;
|
||||
})"
|
||||
ImageDeleteMethod="@(async () =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await AccountsClient.DeleteAccountProfilePicture(token);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
Base.AuthorizedAccount.ProfilePicture = null;
|
||||
NavigationManager.Refresh(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Profile picture could not be removed.", SnackbarColor.Danger);
|
||||
}
|
||||
|
||||
return response.IsSuccessful;
|
||||
})"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<EditFormPanel Data="@(Base.AuthorizedAccount)"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ProfileBackgroundEditorPanel Id="@(Base.AuthorizedAccount.Id)"/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel Name="account">
|
||||
<div class="vstack gap-default">
|
||||
<NewEmailPanel Data="@(Base.AuthorizedAccount)"/>
|
||||
<NewUsernamePanel Data="@(Base.AuthorizedAccount)"/>
|
||||
<NewPasswordPanel Data="@(Base.AuthorizedAccount)"/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<ErrorPanel ErrorMessage="You must be logged in to access this site."/>
|
||||
</NotAuthorized>
|
||||
<Loading>
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
</Loading>
|
||||
</Authorization>
|
||||
62
WatchIt.Website/Components/Pages/UserEditPage.razor.cs
Normal file
62
WatchIt.Website/Components/Pages/UserEditPage.razor.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Accounts.Account;
|
||||
using WatchIt.DTO.Models.Controllers.Photos.Photo;
|
||||
using WatchIt.DTO.Models.Generics.Image;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class UserEditPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IAccountsClient AccountsClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private AccountResponse? _data;
|
||||
|
||||
//private HeaderPanel _header = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
while (!Base.AuthorizationLoaded)
|
||||
{
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
if (Base.AuthorizedAccount is null)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/auth?redirect_to={WebUtility.UrlEncode("/user_settings")}");
|
||||
return;
|
||||
}
|
||||
StateHasChanged();
|
||||
|
||||
IApiResponse<PhotoResponse> backgroundResponse = await AccountsClient.GetAccountBackgroundPicture(Base.AuthorizedAccount.Id);
|
||||
if (backgroundResponse.IsSuccessful)
|
||||
{
|
||||
Base.CustomBackground = backgroundResponse.Content;
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
313
WatchIt.Website/Components/Pages/UserPage.razor
Normal file
313
WatchIt.Website/Components/Pages/UserPage.razor
Normal file
@@ -0,0 +1,313 @@
|
||||
@using System.Net
|
||||
@using System.Text
|
||||
@using WatchIt.Website.Components.Subcomponents.Common
|
||||
@using WatchIt.Website.Components.Panels.Common
|
||||
@using WatchIt.Website.Components.Panels.Pages.UserPage
|
||||
@using Blazorise
|
||||
@using Blazorise.Snackbar
|
||||
@using Refit
|
||||
@using WatchIt.Database.Model.Media
|
||||
@using WatchIt.Database.Model.People
|
||||
@using WatchIt.DTO.Models.Controllers.Accounts.Account
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Query
|
||||
@using WatchIt.DTO.Models.Controllers.Media.Medium.Response
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person
|
||||
@using WatchIt.DTO.Models.Controllers.People.Person.Query
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
@using WatchIt.DTO.Query
|
||||
@using WatchIt.Website.Components.List
|
||||
|
||||
@inherits Page
|
||||
|
||||
@page "/users/{id:long?}"
|
||||
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (!_loaded) sb.Insert(0, "Loading...");
|
||||
else if (_data is null) sb.Insert(0, "Error");
|
||||
else
|
||||
{
|
||||
if (_owner) sb.Insert(0, "Your profile");
|
||||
else sb.Insert(0, $"\"{_data.Username}\" profile");
|
||||
}
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@if (!_loaded)
|
||||
{
|
||||
<div class="m-5">
|
||||
<Loading/>
|
||||
</div>
|
||||
}
|
||||
else if (_data is null)
|
||||
{
|
||||
<ErrorPanel ErrorMessage="@($"User with ID {Id!.Value} was not found")"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="vstack mt-header gap-default">
|
||||
<HeaderPanel Data="@(_data)"
|
||||
Followers="@(_followers)"
|
||||
LoggedUserData="@(Base.AuthorizedAccount)"/>
|
||||
<Tabs Pills
|
||||
RenderMode="TabsRenderMode.LazyLoad"
|
||||
SelectedTab="summary"
|
||||
Class="panel panel-menu panel-background-menu justify-content-center">
|
||||
<Items>
|
||||
<Tab Name="summary">Summary</Tab>
|
||||
<Tab Name="movies">Movies</Tab>
|
||||
<Tab Name="series">TV Series</Tab>
|
||||
<Tab Name="people">People</Tab>
|
||||
<Tab Name="follows">Follows</Tab>
|
||||
<Tab Name="followers">Followers</Tab>
|
||||
</Items>
|
||||
<Content>
|
||||
<TabPanel Name="summary">
|
||||
<div class="vstack gap-default">
|
||||
<HorizontalListPanel TItem="MediumMovieUserRatedResponse"
|
||||
Title="Recently rated movies"
|
||||
Count="6"
|
||||
GetItemsAction="@(() => AccountsClient.GetAccountRatedMediaMovies(_data.Id, orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "rating_user.date",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 6,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/media/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
|
||||
PosterPlaceholder="/assets/placeholders/medium.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"
|
||||
HidePlace="@(true)"
|
||||
EmptyListMessage="No items"/>
|
||||
<HorizontalListPanel TItem="MediumSeriesUserRatedResponse"
|
||||
Title="Recently rated TV series"
|
||||
Count="6"
|
||||
GetItemsAction="@(() => AccountsClient.GetAccountRatedMediaSeries(_data.Id, orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "rating_user.date",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 6,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/media/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.ReleaseDate.HasValue ? $"{item.Title} ({item.ReleaseDate.Value.Year})" : item.Title)"
|
||||
PosterPlaceholder="/assets/placeholders/medium.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"
|
||||
HidePlace="@(true)"
|
||||
EmptyListMessage="No items"/>
|
||||
<HorizontalListPanel TItem="PersonUserRatedResponse"
|
||||
Title="Recently rated people"
|
||||
Count="6"
|
||||
GetItemsAction="@(() => AccountsClient.GetAccountRatedPeople(_data.Id, orderQuery: new OrderQuery
|
||||
{
|
||||
OrderBy = "rating_user.last_date",
|
||||
},
|
||||
pagingQuery: new PagingQuery
|
||||
{
|
||||
First = 6,
|
||||
},
|
||||
includePictures: true))"
|
||||
ItemUrlFormatString="/people/{0}"
|
||||
IdSource="@(item => item.Id)"
|
||||
NameSource="@(item => item.Name)"
|
||||
PosterPlaceholder="/assets/placeholders/person.png"
|
||||
GetPictureAction="@(item => Task.FromResult(item.Picture))"
|
||||
HidePlace="@(true)"
|
||||
EmptyListMessage="No items"/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel Name="movies">
|
||||
<List TItem="MediumMovieUserRatedResponse"
|
||||
TEntity="MediumMovie"
|
||||
TQuery="MediumMovieFilterQuery"
|
||||
Title="Rated movies"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumMovieUserRatedResponse>> response = await AccountsClient.GetAccountRatedMediaMovies(_data.Id, filterQuery, null, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. Movies could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating_user.date", "User rating date" },
|
||||
{ "rating_user.rating", "User rating" },
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "title", "Title" },
|
||||
{ "release_date", "Release date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for movie with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate movies", SnackbarColor.Danger);
|
||||
}
|
||||
})">
|
||||
<MediumMoviesUserRatedFilter/>
|
||||
</List>
|
||||
</TabPanel>
|
||||
<TabPanel Name="series">
|
||||
<List TItem="MediumSeriesUserRatedResponse"
|
||||
TEntity="MediumSeries"
|
||||
TQuery="MediumSeriesFilterQuery"
|
||||
Title="Rated TV series"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Title)"
|
||||
AdditionalNameInfoFunc="@(item => item.ReleaseDate.HasValue ? $" ({item.ReleaseDate.Value.Year})" : null)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/media/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/medium.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<MediumSeriesUserRatedResponse>> response = await AccountsClient.GetAccountRatedMediaSeries(_data.Id, filterQuery, null, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. TV series could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating_user.date", "User rating date" },
|
||||
{ "rating_user.rating", "User rating" },
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "title", "Title" },
|
||||
{ "release_date", "Release date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await MediaClient.GetMediumRating(x.Id)).Content)"
|
||||
GetYourRatingMethod="@(async (item, userId) =>
|
||||
{
|
||||
IApiResponse<RatingUserResponse> response = await MediaClient.GetMediumUserRating(item.Id, userId);
|
||||
if (!response.IsSuccessful && response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error has occured. Your rating for TV series with id {item.Id} could not be loaded.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content;
|
||||
})"
|
||||
PutYourRatingMethod="@(async (item, request) =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.PutMediumRating(token, item.Id, request);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})"
|
||||
DeleteYourRatingMethod="@(async item =>
|
||||
{
|
||||
string token = await AuthenticationService.GetRawAccessTokenAsync() ?? string.Empty;
|
||||
IApiResponse response = await MediaClient.DeleteMediumRating(token, item.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occured. You are not authorized to rate TV series", SnackbarColor.Danger);
|
||||
}
|
||||
})">
|
||||
<MediumSeriesUserRatedFilter/>
|
||||
</List>
|
||||
</TabPanel>
|
||||
<TabPanel Name="people">
|
||||
<List TItem="PersonUserRatedResponse"
|
||||
TEntity="Person"
|
||||
TQuery="PersonFilterQuery"
|
||||
Title="Rated people"
|
||||
IdFunc="@(item => item.Id)"
|
||||
NameFunc="@(item => item.Name)"
|
||||
GlobalRatingFunc="@(item => item.Rating)"
|
||||
PictureFunc="@(item => Task.FromResult(item.Picture))"
|
||||
UrlIdTemplate="/people/{0}"
|
||||
PicturePlaceholder="/assets/placeholders/person.png"
|
||||
GetItemsMethod="@(async (filterQuery, orderQuery, pagingQuery) =>
|
||||
{
|
||||
IApiResponse<IEnumerable<PersonUserRatedResponse>> response = await AccountsClient.GetAccountRatedPeople(_data.Id, filterQuery, null, orderQuery, pagingQuery, true);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. People could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"
|
||||
SortingOptions="@(new Dictionary<string, string>
|
||||
{
|
||||
{ "rating_user.last_date", "Last user rating date" },
|
||||
{ "rating_user.count", "Number of roles user ratings" },
|
||||
{ "rating_user.average", "User rating" },
|
||||
{ "rating.count", "Number of ratings" },
|
||||
{ "rating.average", "Average rating" },
|
||||
{ "name", "Name" },
|
||||
{ "birth_date", "Birth date" },
|
||||
})"
|
||||
GetGlobalRatingMethod="@(async x => (await PeopleClient.GetPersonRating(x.Id)).Content)">
|
||||
<PeopleUserRatedFilter/>
|
||||
</List>
|
||||
</TabPanel>
|
||||
<TabPanel Name="follows">
|
||||
<FollowListPanel Title="Follows"
|
||||
GetItemsMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<AccountResponse>> response = await AccountsClient.GetAccountFollows(_data.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. Follows could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"/>
|
||||
</TabPanel>
|
||||
<TabPanel Name="followers">
|
||||
<FollowListPanel Title="Followers"
|
||||
GetItemsMethod="@(async () =>
|
||||
{
|
||||
IApiResponse<IEnumerable<AccountResponse>> response = await AccountsClient.GetAccountFollowers(_data.Id);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync($"An error occured. Followers could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
return response.Content ?? [];
|
||||
})"/>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
</Tabs>
|
||||
</div>
|
||||
}
|
||||
127
WatchIt.Website/Components/Pages/UserPage.razor.cs
Normal file
127
WatchIt.Website/Components/Pages/UserPage.razor.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System.Net;
|
||||
using Blazorise.Snackbar;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Accounts.Account;
|
||||
using WatchIt.DTO.Models.Controllers.Photos.Photo;
|
||||
using WatchIt.Website.Clients;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages;
|
||||
|
||||
public partial class UserPage : Page
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = null!;
|
||||
[Inject] private IAccountsClient AccountsClient { get; set; } = null!;
|
||||
[Inject] private IMediaClient MediaClient { get; set; } = null!;
|
||||
[Inject] private IPeopleClient PeopleClient { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long? Id { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private bool _loaded;
|
||||
private bool _redirection;
|
||||
private bool _owner;
|
||||
|
||||
private AccountResponse? _data;
|
||||
private List<AccountResponse> _followers;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await LoadUserData();
|
||||
if (_data is not null)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
[
|
||||
LoadProfileBackground(),
|
||||
LoadFollowers()
|
||||
]);
|
||||
}
|
||||
|
||||
_loaded = !_redirection;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadUserData()
|
||||
{
|
||||
if (Id.HasValue)
|
||||
{
|
||||
IApiResponse<AccountResponse> response = await AccountsClient.GetAccount(Id.Value);
|
||||
if (!response.IsSuccessful)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Account info could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
else
|
||||
{
|
||||
_data = response.Content;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!Base.AuthorizationLoaded)
|
||||
{
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
if (Base.AuthorizedAccount is null)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/auth?redirect_to={WebUtility.UrlEncode("/user")}");
|
||||
_redirection = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Id = Base.AuthorizedAccount.Id;
|
||||
_data = Base.AuthorizedAccount;
|
||||
}
|
||||
_owner = Id.Value == Base.AuthorizedAccount?.Id;
|
||||
}
|
||||
|
||||
private async Task LoadProfileBackground()
|
||||
{
|
||||
IApiResponse<PhotoResponse> response = await AccountsClient.GetAccountBackgroundPicture(_data!.Id);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
Base.CustomBackground = response.Content;
|
||||
}
|
||||
else if (response.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Profile background loading failed.", SnackbarColor.Danger);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadFollowers()
|
||||
{
|
||||
IApiResponse<IEnumerable<AccountResponse>> response = await AccountsClient.GetAccountFollowers(_data!.Id);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_followers = response.Content.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error occured. Followers could not be obtained.", SnackbarColor.Danger);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user