Refactoring, database structure changed
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
@inherits Component
|
||||
|
||||
<Image Class="@(Class)"
|
||||
Height="Size"
|
||||
Circle="true"
|
||||
Shadow="false"
|
||||
Placeholder="assets/placeholders/user.png"
|
||||
AlternativeText="avatar"
|
||||
Content="@(ProfilePictureIncluded ? Item.ProfilePicture : _picture)"/>
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Controllers.Accounts.Account;
|
||||
using WatchIt.DTO.Models.Generics.Image;
|
||||
using WatchIt.Website.Clients;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class AccountPicture : Component
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAccountsClient AccountsClient { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required AccountResponse Item { get; set; }
|
||||
[Parameter] public bool ProfilePictureIncluded { get; set; }
|
||||
[Parameter] public required int Size { get; set; }
|
||||
[Parameter] public string Class { get; set; } = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private ImageResponse? _picture;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
if (ProfilePictureIncluded)
|
||||
{
|
||||
_picture = Item.ProfilePicture;
|
||||
}
|
||||
else
|
||||
{
|
||||
IApiResponse<ImageResponse> response = await AccountsClient.GetAccountProfilePicture(Item.Id);
|
||||
if (response.IsSuccessful)
|
||||
{
|
||||
_picture = response.Content;
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
@inherits Component
|
||||
|
||||
@if (BaseLayout.AuthorizationLoaded)
|
||||
{
|
||||
if (BaseLayout.AuthorizedAccount is null || (Admin && !BaseLayout.AuthorizedAccount.IsAdmin))
|
||||
{
|
||||
if (NotAuthorized is not null)
|
||||
{
|
||||
@(NotAuthorized)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Authorized is not null)
|
||||
{
|
||||
@(Authorized)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Loading is not null)
|
||||
{
|
||||
@(Loading)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class Authorization : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[CascadingParameter] public required BaseLayout BaseLayout { get; set; }
|
||||
|
||||
[Parameter] public RenderFragment? NotAuthorized { get; set; }
|
||||
[Parameter] public RenderFragment? Authorized { get; set; }
|
||||
[Parameter] public RenderFragment? Loading { get; set; }
|
||||
[Parameter] public bool Admin { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
@using Blazorise.Extensions
|
||||
@using WatchIt.DTO.Models.Generics.Rating
|
||||
|
||||
@inherits Component
|
||||
|
||||
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
@if (Rating is not IRatingOverallResponse overallRating || overallRating.Count > 0 || EmptyMode == DisplayRatingComponentEmptyMode.DoubleDash)
|
||||
{
|
||||
<i id="star" class="fas fa-star"></i>
|
||||
}
|
||||
<div class="vstack">
|
||||
@switch (Rating)
|
||||
{
|
||||
case RatingUserResponse userRating:
|
||||
<span id="ratingSingleLine">@($"{userRating.Rating}/10")</span>
|
||||
break;
|
||||
case IRatingOverallResponse { Count: > 0 } overallResponse:
|
||||
<span id="ratingAverage">@($"{Math.Round(overallResponse.Rating!.Value, 2)}/10")</span>
|
||||
<span id="ratingCount">@(overallResponse.Count)</span>
|
||||
break;
|
||||
default:
|
||||
<div id="ratingSingleLine">
|
||||
@switch (EmptyMode)
|
||||
{
|
||||
case DisplayRatingComponentEmptyMode.NoRatings: @("no ratings"); break;
|
||||
case DisplayRatingComponentEmptyMode.DoubleDash: @("--/10"); break;
|
||||
}
|
||||
</div>
|
||||
break;
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#star {
|
||||
font-size: @((2 * Scale).ToCultureInvariantString())rem;
|
||||
}
|
||||
|
||||
#ratingAverage {
|
||||
margin-top: @((-5 * Scale).ToCultureInvariantString())px;
|
||||
font-size: @((1.3 * Scale).ToCultureInvariantString())rem;
|
||||
}
|
||||
|
||||
#ratingSingleLine {
|
||||
font-size: @((1.3 * Scale).ToCultureInvariantString())rem;
|
||||
}
|
||||
|
||||
#ratingCount {
|
||||
margin-top: @((-5 * Scale).ToCultureInvariantString())px;
|
||||
font-size: @((0.8 * Scale).ToCultureInvariantString())rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,27 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.DTO.Models.Generics.Rating;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class DisplayRating : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required IRatingResponse? Rating { get; set; }
|
||||
[Parameter] public DisplayRatingComponentEmptyMode EmptyMode { get; set; } = DisplayRatingComponentEmptyMode.NoRatings;
|
||||
[Parameter] public double Scale { get; set; } = 1;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ENUMS
|
||||
|
||||
public enum DisplayRatingComponentEmptyMode
|
||||
{
|
||||
NoRatings,
|
||||
DoubleDash,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
@inherits Component
|
||||
|
||||
<div class="d-flex flex-column align-items-center gap-2 h-100">
|
||||
<Image Class="w-100" Content="@(_poster)" Placeholder="@(PosterPlaceholder)" AlternativeText="poster"/>
|
||||
<div class="container-grid">
|
||||
<div class="row">
|
||||
@if (Place.HasValue)
|
||||
{
|
||||
<div class="col-auto">
|
||||
<div class="text-center border border-2 border-light rounded-circle place-circle fw-bold">@(Place)</div>
|
||||
</div>
|
||||
}
|
||||
<div class="col">
|
||||
<div class="d-flex justify-content-@(Place.HasValue ? "end" : "center")">
|
||||
<div class="pt-05 @(Place.HasValue ? "text-end" : "text-center")">@(Name)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Refit;
|
||||
using WatchIt.DTO.Models.Generics.Image;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class HorizontalListItem : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public int? Place { get; set; }
|
||||
[Parameter] public required string Name { get; set; }
|
||||
[Parameter] public required string PosterPlaceholder { get; set; }
|
||||
[Parameter] public required Func<Task<ImageResponse?>> GetPosterAction { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private ImageResponse? _poster;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
_poster = await GetPosterAction();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* CLASSES */
|
||||
|
||||
.border-2 {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.place-circle {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
vertical-align: middle;
|
||||
line-height: 25px;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@inherits Component
|
||||
|
||||
<img class="@(Circle ? "rounded-circle" : "rounded-2") @(Shadow ? "shadow" : string.Empty) object-fit-cover @(Class)" src="@(Content?.ToString() ?? Placeholder)" alt="@(AlternativeText)" @attributes="@(_attributes)" style="aspect-ratio: @(AspectRatio.ToString());"/>
|
||||
@@ -0,0 +1,95 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.DTO.Models.Generics.Image;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class Image : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public ImageBase? Content { get; set; }
|
||||
[Parameter] public required string Placeholder { get; set; }
|
||||
[Parameter] public ImageComponentAspectRatio AspectRatio { get; set; } = ImageComponentAspectRatio.Default;
|
||||
[Parameter] public string AlternativeText { get; set; } = "picture";
|
||||
[Parameter] public string Class { get; set; } = string.Empty;
|
||||
[Parameter] public int? Height { get; set; }
|
||||
[Parameter] public int? Width { get; set; }
|
||||
[Parameter] public bool Circle { get; set; }
|
||||
[Parameter] public bool Shadow { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private Dictionary<string, object> _attributes = [];
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_attributes.Clear();
|
||||
if (Height.HasValue)
|
||||
{
|
||||
_attributes.Add("height", Height.Value);
|
||||
}
|
||||
else if (Width.HasValue)
|
||||
{
|
||||
_attributes.Add("width", Width.Value);
|
||||
}
|
||||
|
||||
if (Circle)
|
||||
{
|
||||
AspectRatio = ImageComponentAspectRatio.Square;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region STRUCTS
|
||||
|
||||
public struct ImageComponentAspectRatio
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public int Vertical { get; set; }
|
||||
public int Horizontal { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ImageComponentAspectRatio() : this(3, 5) {}
|
||||
|
||||
public ImageComponentAspectRatio(int horizontal, int vertical)
|
||||
{
|
||||
Horizontal = horizontal;
|
||||
Vertical = vertical;
|
||||
}
|
||||
|
||||
public static readonly ImageComponentAspectRatio Default = new ImageComponentAspectRatio();
|
||||
public static readonly ImageComponentAspectRatio Photo = new ImageComponentAspectRatio(16, 9);
|
||||
public static readonly ImageComponentAspectRatio Square = new ImageComponentAspectRatio(1, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public methods
|
||||
|
||||
public override string ToString() => $"{Horizontal}/{Vertical}";
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
@inherits Component
|
||||
|
||||
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div id="spinner" class="spinner-border text-@(GetColor())"></div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center">
|
||||
<p id="text" class="text-@(GetColor())" m-0>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class Loading : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public Colors Color { get; set; } = Colors.Dark;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private string GetColor()
|
||||
{
|
||||
DescriptionAttribute? attribute = Color.GetType()
|
||||
.GetTypeInfo()
|
||||
.GetMember(Color.ToString())
|
||||
.FirstOrDefault(member => member.MemberType == MemberTypes.Field)!
|
||||
.GetCustomAttributes(typeof(DescriptionAttribute), false)
|
||||
.SingleOrDefault()
|
||||
as DescriptionAttribute;
|
||||
return attribute!.Description;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ENUMS
|
||||
|
||||
public enum Colors
|
||||
{
|
||||
[Description("dark")]
|
||||
Dark,
|
||||
|
||||
[Description("light")]
|
||||
Light,
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* IDS */
|
||||
|
||||
#spinner {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
|
||||
#text {
|
||||
font-size: 25px;
|
||||
border-width: 0.4rem;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
@if (IsLoading)
|
||||
{
|
||||
<LoadingInline Content="@(LoadingContent)"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ChildContent is null)
|
||||
{
|
||||
<span>@Content</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@(ChildContent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class LoadingButtonContent : ComponentBase
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public bool IsLoading { get; set; }
|
||||
[Parameter] public string? LoadingContent { get; set; }
|
||||
[Parameter] public string Content { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@inherits Component
|
||||
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<span class="spinner-border spinner-border-sm" role="status"></span>
|
||||
<span>@(Content)</span>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class LoadingInline : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public string Content { get; set; } = "Loading...";
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@inherits Component
|
||||
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<div class="input-group input-group-sm">
|
||||
<InputText class="form-control" placeholder="Search" @bind-Value="@(_searchText)"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" @onclick="@(Search)">⌕</button>
|
||||
<button type="button" class="btn btn-sm" @onclick="@(() => OnCloseButtonClicked?.Invoke())">❌︎</button>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class Searchbar : Component
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public Action? OnCloseButtonClicked { get; set; }
|
||||
[Parameter] public Action? OnSearchButtonClicked { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private string? _searchText;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
public void Search()
|
||||
{
|
||||
OnSearchButtonClicked?.Invoke();
|
||||
if (!string.IsNullOrWhiteSpace(_searchText))
|
||||
{
|
||||
string query = WebUtility.UrlEncode(_searchText);
|
||||
NavigationManager.NavigateTo($"/search/{query}", true);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
@inherits Component
|
||||
|
||||
|
||||
|
||||
<div class="container-grid">
|
||||
<div class="row gx-3">
|
||||
<div class="col">
|
||||
<span id="title" class="fw-bold">@(Title)</span>
|
||||
</div>
|
||||
<div class="col-auto align-self-center">
|
||||
<DisplayRating Rating="@(Rating)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.DTO.Models.Generics.Rating;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class TitledDisplayRating : Component
|
||||
{
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required IRatingResponse? Rating { get; set; }
|
||||
[Parameter] public required string Title { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* IDS */
|
||||
|
||||
#title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
@inherits Component
|
||||
|
||||
|
||||
|
||||
<div class="container-grid">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<a class="text-reset text-decoration-none" href="@(ItemUrl)">
|
||||
<Image Content="@(_picture)" Placeholder="@(PicturePlaceholder)" AlternativeText="poster" Height="@(PictureHeight)"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-start flex-column h-100">
|
||||
<div class="mb-auto">
|
||||
<a style="font-size: @(NameSize)px" class="text-reset text-decoration-none" href="@(ItemUrl)">
|
||||
<strong>@(Name)</strong>@(string.IsNullOrWhiteSpace(AdditionalInfo) ? string.Empty : AdditionalInfo)
|
||||
</a>
|
||||
</div>
|
||||
<table id="ratingTable" class="table table-transparent table-bordered align-middle m-0">
|
||||
<thead>
|
||||
<tr>
|
||||
@if (GlobalRating is not null)
|
||||
{
|
||||
<th scope="col">
|
||||
<span class="rating-name-text">Global rating:</span>
|
||||
</th>
|
||||
}
|
||||
@if (_secondaryRating is not null)
|
||||
{
|
||||
<th scope="col">
|
||||
<span class="rating-name-text">@(SecondaryRatingTitle):</span>
|
||||
</th>
|
||||
}
|
||||
@if (GetYourRatingMethod is not null && PutYourRatingMethod is not null && DeleteYourRatingMethod is not null)
|
||||
{
|
||||
<th class scope="col">
|
||||
<span class="rating-name-text">Your rating:</span>
|
||||
</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
@if (GlobalRating is not null)
|
||||
{
|
||||
<td>
|
||||
@switch (_globalRatingLoaded)
|
||||
{
|
||||
case true: <DisplayRating Rating="@(GlobalRating)"
|
||||
EmptyMode="DisplayRating.DisplayRatingComponentEmptyMode.DoubleDash"
|
||||
Scale="0.85"/> break;
|
||||
case false: <LoadingInline/> break;
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@if (_secondaryRating is not null)
|
||||
{
|
||||
<td>
|
||||
@switch (_secondaryRatingLoaded)
|
||||
{
|
||||
case true: <DisplayRating Rating="@(_secondaryRating)"
|
||||
EmptyMode="DisplayRating.DisplayRatingComponentEmptyMode.DoubleDash"
|
||||
Scale="0.85"/> break;
|
||||
case false: <LoadingInline/> break;
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@if (GetYourRatingMethod is not null && PutYourRatingMethod is not null && DeleteYourRatingMethod is not null)
|
||||
{
|
||||
<td>
|
||||
<div class="d-inline-flex align-items-center h-100">
|
||||
<Authorization>
|
||||
<Loading>
|
||||
<LoadingInline/>
|
||||
</Loading>
|
||||
<NotAuthorized>
|
||||
<span id="ratingLoginInfoText">You must be logged in to rate</span>
|
||||
</NotAuthorized>
|
||||
<Authorized>
|
||||
@switch (_yourRatingLoaded)
|
||||
{
|
||||
case true: <Blazorise.Rating Color="Blazorise.Color.Light" MaxValue="10" @bind-SelectedValue="@(_yourRating)" @onclick="@(RatingChanged)"/> break;
|
||||
case false: <LoadingInline/> break;
|
||||
}
|
||||
</Authorized>
|
||||
</Authorization>
|
||||
</div>
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,132 @@
|
||||
using Blazorise.Snackbar;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using WatchIt.DTO.Models.Generics.Image;
|
||||
using WatchIt.DTO.Models.Generics.Rating;
|
||||
using WatchIt.Website.Components.Layout;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class VerticalListItem : Component
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required string Name { get; set; }
|
||||
[Parameter] public string? AdditionalInfo { get; set; }
|
||||
|
||||
[Parameter] public int NameSize { get; set; } = 25;
|
||||
|
||||
[Parameter] public required string PicturePlaceholder { get; set; }
|
||||
[Parameter] public int PictureHeight { get; set; } = 150;
|
||||
[Parameter] public required Func<Task<ImageResponse?>> PictureFunc { get; set; }
|
||||
|
||||
[Parameter] public string? SecondaryRatingTitle { get; set; }
|
||||
|
||||
[Parameter] public RatingOverallResponse? GlobalRating { get; set; }
|
||||
[Parameter] public required Func<Task<RatingOverallResponse?>> GetGlobalRatingMethod { get; set; }
|
||||
[Parameter] public Func<Task<IRatingResponse?>>? GetSecondaryRatingMethod { get; set; }
|
||||
[Parameter] public Func<long, Task<int?>>? GetYourRatingMethod { get; set; }
|
||||
[Parameter] public Func<RatingRequest, Task>? PutYourRatingMethod { get; set; }
|
||||
[Parameter] public Func<Task>? DeleteYourRatingMethod { get; set; }
|
||||
[Parameter] public Action? OnRatingChanged { get; set; }
|
||||
|
||||
[Parameter] public required string ItemUrl { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private ImageResponse? _picture;
|
||||
|
||||
private IRatingResponse? _secondaryRating;
|
||||
private int _yourRating;
|
||||
|
||||
private bool _globalRatingLoaded;
|
||||
private bool _secondaryRatingLoaded;
|
||||
private bool _yourRatingLoaded;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnFirstRenderAsync()
|
||||
{
|
||||
await base.OnFirstRenderAsync();
|
||||
|
||||
List<Task> tasks =
|
||||
[
|
||||
Task.Run(async () => _picture = await PictureFunc()),
|
||||
];
|
||||
if (GlobalRating is null)
|
||||
{
|
||||
tasks.Add(UpdateGlobalRating());
|
||||
}
|
||||
else
|
||||
{
|
||||
_globalRatingLoaded = true;
|
||||
}
|
||||
if (GetSecondaryRatingMethod is not null && !string.IsNullOrWhiteSpace(SecondaryRatingTitle))
|
||||
{
|
||||
tasks.Add(GetSecondaryRatingMethod());
|
||||
}
|
||||
if (GetYourRatingMethod is not null && Base.AuthorizedAccount is not null)
|
||||
{
|
||||
tasks.Add(GetUserRating());
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task GetUserRating()
|
||||
{
|
||||
int? rating = await GetYourRatingMethod!(Base.AuthorizedAccount!.Id);
|
||||
_yourRating = rating ?? 0;
|
||||
_yourRatingLoaded = true;
|
||||
}
|
||||
|
||||
private async Task RatingChanged()
|
||||
{
|
||||
if (Base.AuthorizedAccount is null)
|
||||
{
|
||||
await Base.SnackbarStack.PushAsync("An error has occurred. You are not logged in.", SnackbarColor.Danger);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_yourRating == 0)
|
||||
{
|
||||
await DeleteYourRatingMethod!();
|
||||
}
|
||||
else
|
||||
{
|
||||
await PutYourRatingMethod!(new RatingRequest
|
||||
{
|
||||
Rating = (byte)_yourRating,
|
||||
});
|
||||
}
|
||||
|
||||
await UpdateGlobalRating();
|
||||
OnRatingChanged?.Invoke();
|
||||
}
|
||||
|
||||
private async Task UpdateGlobalRating()
|
||||
{
|
||||
_globalRatingLoaded = false;
|
||||
GlobalRating = await GetGlobalRatingMethod();
|
||||
_globalRatingLoaded = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* TAGS */
|
||||
|
||||
tbody, td, tfoot, th, thead, tr {
|
||||
border-color: inherit;
|
||||
border-style: unset;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* IDS */
|
||||
|
||||
#ratingLoginInfoText {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#ratingTable {
|
||||
width: fit-content;
|
||||
border-spacing: unset;
|
||||
border-collapse: separate;
|
||||
margin-left: -0.5rem !important;
|
||||
}
|
||||
|
||||
#ratingTable > thead > tr > th:not(:last-child) {
|
||||
border-right: 1px solid #444;
|
||||
}
|
||||
|
||||
#ratingTable > tbody > tr > td:not(:last-child) {
|
||||
border-right: 1px solid #444;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* CLASSES */
|
||||
|
||||
.rating-name-text {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@inherits Component
|
||||
|
||||
|
||||
|
||||
<div class="d-flex align-items-center gap-4" role="button" @onclick="@(() => NavigationManager.NavigateTo($"/users/{Item.Id}", true))">
|
||||
<AccountPicture Item="@(Item)"
|
||||
ProfilePictureIncluded="@(ProfilePictureIncluded)"
|
||||
Size="@(PictureSize)"/>
|
||||
<h4 class="fw-bold">@(Item.Username)</h4>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.DTO.Models.Controllers.Accounts.Account;
|
||||
|
||||
namespace WatchIt.Website.Components.Subcomponents.Common;
|
||||
|
||||
public partial class VerticalListUserItem : Component
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
[Parameter] public required AccountResponse Item { get; set; }
|
||||
[Parameter] public bool ProfilePictureIncluded { get; set; }
|
||||
[Parameter] public int PictureSize { get; set; } = 90;
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user