add header in profile page

This commit is contained in:
2024-10-30 23:28:47 +01:00
Unverified
parent 017b3ac185
commit 2f6eb33518
17 changed files with 213 additions and 31 deletions

View File

@@ -14,6 +14,15 @@ public class AccountResponse : Account
[JsonPropertyName("gender")] [JsonPropertyName("gender")]
public GenderResponse? Gender { get; set; } public GenderResponse? Gender { get; set; }
[JsonPropertyName("last_active")]
public DateTime LastActive { get; set; }
[JsonPropertyName("creation_date")]
public DateTime CreationDate { get; set; }
[JsonPropertyName("is_admin")]
public bool IsAdmin { get; set; }
#endregion #endregion
@@ -31,6 +40,9 @@ public class AccountResponse : Account
Email = account.Email; Email = account.Email;
Description = account.Description; Description = account.Description;
Gender = account.Gender is not null ? new GenderResponse(account.Gender) : null; Gender = account.Gender is not null ? new GenderResponse(account.Gender) : null;
LastActive = account.LastActive;
CreationDate = account.CreationDate;
IsAdmin = account.IsAdmin;
} }
#endregion #endregion

View File

@@ -62,6 +62,9 @@ public class AccountsControllerService(
RefreshToken = await refreshTokenTask, RefreshToken = await refreshTokenTask,
}; };
account.LastActive = DateTime.UtcNow;
await database.SaveChangesAsync();
logger.LogInformation($"Account with ID {account.Id} was authenticated"); logger.LogInformation($"Account with ID {account.Id} was authenticated");
return RequestResult.Ok(response); return RequestResult.Ok(response);
} }
@@ -91,6 +94,9 @@ public class AccountsControllerService(
string accessToken = await tokensService.CreateAccessTokenAsync(token.Account); string accessToken = await tokensService.CreateAccessTokenAsync(token.Account);
token.Account.LastActive = DateTime.UtcNow;
await database.SaveChangesAsync();
logger.LogInformation($"Account with ID {token.AccountId} was authenticated by token refreshing"); logger.LogInformation($"Account with ID {token.AccountId} was authenticated by token refreshing");
return RequestResult.Ok(new AuthenticateResponse return RequestResult.Ok(new AuthenticateResponse
{ {

View File

@@ -13,7 +13,7 @@
<link rel="stylesheet" href="css/panel.css?version=0.3.0.3"/> <link rel="stylesheet" href="css/panel.css?version=0.3.0.3"/>
<link rel="stylesheet" href="css/main_button.css?version=0.3.0.0"/> <link rel="stylesheet" href="css/main_button.css?version=0.3.0.0"/>
<link rel="stylesheet" href="css/gaps.css?version=0.3.0.1"/> <link rel="stylesheet" href="css/gaps.css?version=0.3.0.1"/>
<link rel="stylesheet" href="WatchIt.Website.styles.css?version=0.3.0.22"/> <link rel="stylesheet" href="WatchIt.Website.styles.css?version=0.4.0.4"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- BOOTSTRAP --> <!-- BOOTSTRAP -->

View File

@@ -1,4 +1,4 @@
<div class="container-grid mt-grid"> <div class="container-grid mt-header">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<PictureComponent Picture="@(_poster)" Placeholder="@(PosterPlaceholder)" AlternativeText="poster" Height="350"/> <PictureComponent Picture="@(_poster)" Placeholder="@(PosterPlaceholder)" AlternativeText="poster" Height="350"/>

View File

@@ -1,9 +1,5 @@
/* CLASSES */ /* CLASSES */
.mt-grid {
margin-top: 9rem !important;
}
.title-shadow { .title-shadow {
text-shadow: 2px 2px 2px #000; text-shadow: 2px 2px 2px #000;
} }

View File

@@ -0,0 +1 @@
<img class="rounded-circle object-fit-cover @(Class)" alt="avatar" height="@(Size)" src="@(_picture is null ? "assets/user_placeholder.png" : _picture.ToString())"/>

View File

@@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model.Accounts;
using WatchIt.Website.Services.Client.Accounts;
namespace WatchIt.Website.Components.Common.Subcomponents;
public partial class AccountPictureComponent : ComponentBase
{
#region SERVICES
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
#endregion
#region PARAMETERS
[Parameter] public required long Id { get; set; }
[Parameter] public required int Size { get; set; }
[Parameter] public string Class { get; set; } = string.Empty;
#endregion
#region FIELDS
private AccountProfilePictureResponse? _picture;
#endregion
#region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
List<Task> endTasks = new List<Task>();
// STEP 0
endTasks.AddRange(
[
AccountsClientService.GetAccountProfilePicture(Id, data => _picture = data)
]);
// END
await Task.WhenAll(endTasks);
StateHasChanged();
}
}
#endregion
}

View File

@@ -33,7 +33,6 @@ public partial class DatabasePageComponent<TItem, TQuery> : ComponentBase where
[Parameter] public Func<long, RatingRequest, Task>? PutRatingMethod { get; set; } [Parameter] public Func<long, RatingRequest, Task>? PutRatingMethod { get; set; }
[Parameter] public Func<long, Task>? DeleteRatingMethod { get; set; } [Parameter] public Func<long, Task>? DeleteRatingMethod { get; set; }
[Parameter] public required string PosterPlaceholder { get; set; } [Parameter] public required string PosterPlaceholder { get; set; }
#endregion #endregion

View File

@@ -0,0 +1,30 @@
<div id="base" class="vstack">
<AccountPictureComponent Class="shadow position-absolute z-1 start-50 translate-middle" Id="@(AccountData.Id)" Size="240"/>
<div class="panel z-0">
<div class="vstack gap-3">
<div id="space" class="container-grid"></div>
<div class="d-flex justify-content-center">
<h3 class="fw-bold">@(AccountData.Username)</h3>
</div>
@if (!string.IsNullOrWhiteSpace(AccountData.Description))
{
<span>
@(AccountData.Description)
</span>
}
<div class="d-flex flex-wrap justify-content-center metadata-pill-container">
<div class="metadata-pill"><strong>Email:</strong> @(AccountData.Email)</div>
@if (!string.IsNullOrWhiteSpace(AccountData.Gender?.Name))
{
<div class="metadata-pill"><strong>Gender:</strong> @(AccountData.Gender?.Name)</div>
}
<div class="metadata-pill"><strong>Account created:</strong> @(AccountData.CreationDate.ToShortDateString())</div>
<div class="metadata-pill"><strong>Last active:</strong> @(AccountData.LastActive.ToShortDateString())</div>
@if (AccountData.IsAdmin)
{
<div class="metadata-pill"><strong>Admin</strong></div>
}
</div>
</div>
</div>
</div>

View File

@@ -1,7 +1,57 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using WatchIt.Common.Model.Accounts;
using WatchIt.Website.Services.Authentication;
using WatchIt.Website.Services.Client.Accounts;
namespace WatchIt.Website.Components.Pages.UserPage.Panels; namespace WatchIt.Website.Components.Pages.UserPage.Panels;
public partial class UserPageHeaderPanelComponent : ComponentBase public partial class UserPageHeaderPanelComponent : ComponentBase
{ {
#region SERVICES
[Inject] private IAuthenticationService AuthenticationService { get; set; } = default!;
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
#endregion
#region PARAMETERS
[Parameter] public required AccountResponse AccountData { get; set; }
#endregion
#region FIELDS
private AccountProfilePictureResponse? _accountProfilePicture;
#endregion
#region PRIVATE METHODS
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
List<Task> endTasks = new List<Task>();
// STEP 0
endTasks.AddRange(
[
AccountsClientService.GetAccountProfilePicture(AccountData.Id, data => _accountProfilePicture = data),
]);
// END
await Task.WhenAll(endTasks);
StateHasChanged();
}
}
#endregion
} }

View File

@@ -0,0 +1,9 @@
/* IDS */
#base {
margin-top: 120px;
}
#space {
height: 100px;
}

View File

@@ -53,14 +53,14 @@
else else
{ {
<Dropdown RightAligned> <Dropdown RightAligned>
<Button Color="Color.Default"> <Button Color="Color.Default" Clicked="@(() => NavigationManager.NavigateTo("/user"))">
<div class="d-flex gap-2 align-items-center"> <div class="d-flex gap-2 align-items-center">
<img class="rounded-circle" alt="avatar" height="30" src="@(_userProfilePicture is null ? "assets/user_placeholder.png" : _userProfilePicture.ToString())"/> <AccountPictureComponent Id="@(_user.Id)" Size="30"/>
<span>@(_user.Username)</span> <span>@(_user.Username)</span>
</div> </div>
</Button> </Button>
<DropdownToggle Color="Color.Default" Split /> <DropdownToggle Color="Color.Default" Split />
<DropdownMenu > <DropdownMenu>
<DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/user"))">Your profile</DropdownItem> <DropdownItem Clicked="@(() => NavigationManager.NavigateTo("/user"))">Your profile</DropdownItem>
@if (_user.IsAdmin) @if (_user.IsAdmin)
{ {

View File

@@ -18,7 +18,6 @@ public partial class MainLayout : LayoutComponentBase
[Inject] public NavigationManager NavigationManager { get; set; } = default!; [Inject] public NavigationManager NavigationManager { get; set; } = default!;
[Inject] public ITokensService TokensService { get; set; } = default!; [Inject] public ITokensService TokensService { get; set; } = default!;
[Inject] public IAuthenticationService AuthenticationService { get; set; } = default!; [Inject] public IAuthenticationService AuthenticationService { get; set; } = default!;
[Inject] public IAccountsClientService AccountsClientService { get; set; } = default!;
[Inject] public IMediaClientService MediaClientService { get; set; } = default!; [Inject] public IMediaClientService MediaClientService { get; set; } = default!;
[Inject] public IPhotosClientService PhotosClientService { get; set; } = default!; [Inject] public IPhotosClientService PhotosClientService { get; set; } = default!;
@@ -32,7 +31,6 @@ public partial class MainLayout : LayoutComponentBase
private User? _user; private User? _user;
private PhotoResponse? _defaultBackgroundPhoto; private PhotoResponse? _defaultBackgroundPhoto;
private AccountProfilePictureResponse? _userProfilePicture;
private bool _searchbarVisible; private bool _searchbarVisible;
private string _searchbarText = string.Empty; private string _searchbarText = string.Empty;
@@ -67,28 +65,14 @@ public partial class MainLayout : LayoutComponentBase
if (firstRender) if (firstRender)
{ {
List<Task> endTasks = new List<Task>(); List<Task> endTasks = new List<Task>();
List<Task> step1Tasks = new List<Task>();
// STEP 0 // STEP 0
step1Tasks.AddRange(
[
Task.Run(async () => _user = await AuthenticationService.GetUserAsync())
]);
endTasks.AddRange( endTasks.AddRange(
[ [
Task.Run(async () => _user = await AuthenticationService.GetUserAsync()),
PhotosClientService.GetPhotoRandomBackground(data => _defaultBackgroundPhoto = data) PhotosClientService.GetPhotoRandomBackground(data => _defaultBackgroundPhoto = data)
]); ]);
// STEP 1
await Task.WhenAll(step1Tasks);
if (_user is not null)
{
endTasks.AddRange(
[
AccountsClientService.GetAccountProfilePicture(_user.Id, data => _userProfilePicture = data)
]);
}
// END // END
await Task.WhenAll(endTasks); await Task.WhenAll(endTasks);

View File

@@ -169,7 +169,7 @@ else
<Tabs Pills <Tabs Pills
RenderMode="TabsRenderMode.LazyLoad" RenderMode="TabsRenderMode.LazyLoad"
SelectedTab="actors" SelectedTab="actors"
Class="panel panel-menu panel-background-menu"> Class="panel panel-menu panel-background-menu justify-content-center">
<Items> <Items>
<Tab Name="actors">Actors</Tab> <Tab Name="actors">Actors</Tab>
<Tab Name="creators">Creators</Tab> <Tab Name="creators">Creators</Tab>

View File

@@ -44,7 +44,7 @@
<Tabs Pills <Tabs Pills
RenderMode="TabsRenderMode.LazyLoad" RenderMode="TabsRenderMode.LazyLoad"
SelectedTab="actor" SelectedTab="actor"
Class="panel panel-menu panel-background-menu"> Class="panel panel-menu panel-background-menu justify-content-center">
<Items> <Items>
<Tab Name="actor">Actor</Tab> <Tab Name="actor">Actor</Tab>
<Tab Name="creator">Creator</Tab> <Tab Name="creator">Creator</Tab>

View File

@@ -40,9 +40,42 @@
} }
else else
{ {
<div class="row"> <div class="row mt-header">
<div class="col"> <div class="col">
<UserPageHeaderPanelComponent/> <UserPageHeaderPanelComponent AccountData="@(_accountData)"/>
</div>
</div>
<div class="row mt-over-panel-menu">
<div class="col">
<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="people">Roles</Tab>
</Items>
<Content>
<TabPanel Name="summary">
</TabPanel>
<TabPanel Name="movies">
</TabPanel>
<TabPanel Name="series">
</TabPanel>
<TabPanel Name="people">
</TabPanel>
<TabPanel Name="roles">
</TabPanel>
</Content>
</Tabs>
</div> </div>
</div> </div>
} }

View File

@@ -1,5 +1,9 @@
/* DEFAULT */ /* DEFAULT */
.mt-header {
margin-top: 9rem !important;
}
.mt-default { .mt-default {
margin-top: 1rem !important; margin-top: 1rem !important;
} }