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:
2026-05-11 19:16:30 +00:00
committed by Marek Jaisński
parent f433e3c74a
commit fe5ff81c98
61 changed files with 1092 additions and 312 deletions
@@ -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;
}