Refactor: Web Consolidation and Identity Stabilization (#40)
## Overview This PR completes the architectural consolidation of the web project and stabilizes the Identity-based authentication flow for the NexusReader application. It also refines the UI aesthetic for the Book Ingestion Modal as requested in #33. ## Key Changes - **Project Consolidation**: Fully merged `NexusReader.Web.New` into `NexusReader.Web`. This includes updating all namespace references, VS Code launch/task configurations, and CI/CD (`Dockerfile`). - **Identity Stabilization**: - Implemented `IIdentityService` on the server using `SignInManager<NexusUser>` and `UserManager<NexusUser>`. - Fixed registration logic to include mandatory fields (`SubscriptionPlanId`, `TenantId`). - Updated `Login.razor` to force a page reload on successful login, ensuring proper synchronization of authentication cookies between SignalR and the browser. - **UI/UX Refinement**: - Updated `BookIngestionModal` styling to follow the **Nexus Neon** design system. - Added premium button styles with hover effects and glows. - Improved modal layout and interaction feedback (shimmer effects, spinner colors). - **Cleanup**: Removed obsolete interfaces and constants that were superseded by newer Application layer implementations. ## Verification - Successfully built the solution: `dotnet build NexusReader.slnx --no-restore` - Verified project structure and file moves. - Validated server-side authentication logic. Fixes #33 --------- Co-authored-by: Marek Jasiński <jasins.marek@gmail.com> Reviewed-on: #40 Co-authored-by: Antigravity <antigravity@google.com> Co-committed-by: Antigravity <antigravity@google.com>
This commit was merged in pull request #40.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
@using NexusReader.UI.Shared.Components.Atoms
|
||||
@inject IIdentityService IdentityService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<div class="login-page-container">
|
||||
<div class="mesh-bg"></div>
|
||||
@@ -90,6 +91,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="nexusLoginForm" method="post" action="/account/login-form" style="display:none">
|
||||
<input type="hidden" name="email" value="@_loginModel.Email" />
|
||||
<input type="hidden" name="password" value="@_loginModel.Password" />
|
||||
<input type="hidden" name="rememberMe" value="@(_loginModel.RememberMe ? "true" : "false")" />
|
||||
</form>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
[SupplyParameterFromQuery(Name = "error")]
|
||||
@@ -125,7 +132,8 @@
|
||||
var result = await IdentityService.LoginAsync(_loginModel.Email, _loginModel.Password, _loginModel.RememberMe);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
NavigationManager.NavigateTo("/");
|
||||
// Trigger hidden form submission to perform cookie-based sign-in
|
||||
await JS.InvokeVoidAsync("eval", "document.getElementById('nexusLoginForm').submit()");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private UserProfile? _profile;
|
||||
private UserProfileDto? _profile;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -133,6 +133,6 @@
|
||||
private async Task HandleLogout()
|
||||
{
|
||||
await IdentityService.LogoutAsync();
|
||||
NavigationManager.NavigateTo("/account/login");
|
||||
NavigationManager.NavigateTo("/account/logout-form", true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
@using NexusReader.UI.Shared.Components.Atoms
|
||||
@inject IIdentityService IdentityService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<div class="login-page-container">
|
||||
<div class="mesh-bg"></div>
|
||||
@@ -69,6 +70,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="nexusLoginForm" method="post" action="/account/login-form" style="display:none">
|
||||
<input type="hidden" name="email" value="@_registerModel.Email" />
|
||||
<input type="hidden" name="password" value="@_registerModel.Password" />
|
||||
<input type="hidden" name="rememberMe" value="false" />
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private RegisterModel _registerModel = new();
|
||||
private string? _errorMessage;
|
||||
@@ -87,7 +94,8 @@
|
||||
var loginResult = await IdentityService.LoginAsync(_registerModel.Email, _registerModel.Password);
|
||||
if (loginResult.IsSuccess)
|
||||
{
|
||||
NavigationManager.NavigateTo("/");
|
||||
// Trigger hidden form submission to perform cookie-based sign-in
|
||||
await JS.InvokeVoidAsync("eval", "document.getElementById('nexusLoginForm').submit()");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private UserProfile? _profile;
|
||||
private UserProfileDto? _profile;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
@page "/library"
|
||||
@attribute [Authorize]
|
||||
@using NexusReader.UI.Shared.Components.Organisms
|
||||
|
||||
<div class="library-page">
|
||||
<header class="library-header">
|
||||
<h1>Biblioteka</h1>
|
||||
<AuthorizeView Roles="Admin, ContentManager">
|
||||
<NexusButton Class="add-book-trigger">
|
||||
<NexusButton Class="add-book-trigger" OnClick="() => _isModalOpen = true">
|
||||
[+] Add New Book
|
||||
</NexusButton>
|
||||
</AuthorizeView>
|
||||
</header>
|
||||
|
||||
<BookIngestionModal @bind-IsOpen="_isModalOpen" />
|
||||
|
||||
<div class="library-content glass-panel">
|
||||
<div class="empty-state">
|
||||
<p>Twoja kolekcja książek i dokumentów pojawi się tutaj wkrótce.</p>
|
||||
@@ -51,3 +54,7 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private bool _isModalOpen;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user