Refactor: Web Consolidation and Identity Stabilization #40

Merged
mjasin merged 37 commits from feature/issue-33 into develop 2026-05-11 19:16:31 +00:00
Showing only changes of commit 98e0e604e0 - Show all commits
@@ -2,36 +2,11 @@ using System.Net.Http.Json;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using NexusReader.Application.Abstractions.Services; using NexusReader.Application.Abstractions.Services;
using NexusReader.Application.DTOs.User; using NexusReader.Application.DTOs.User;
using NexusReader.UI.Shared.Constants; using NexusReader.Application.Constants;
using FluentResults; using FluentResults;
namespace NexusReader.UI.Shared.Services; namespace NexusReader.UI.Shared.Services;
public interface IIdentityService
{
event Func<Task>? OnStateInvalidated;
Task<Result> RegisterAsync(string email, string password);
Task<Result> LoginAsync(string email, string password, bool rememberMe = false);
Task<Result> LogoutAsync();
Task<Result<UserProfile>> GetProfileAsync();
Task<Result> RefreshTokenAsync();
}
public record UserProfile(
string Email,
int AITokensUsed,
Guid TenantId,
SubscriptionPlanDto Plan,
int AverageQuizScore,
LastReadBookDto? LastReadBook,
string[] Roles)
{
// Helper properties for UI compatibility
public string CurrentPlan => Plan?.Name ?? PlanConstants.DefaultPlanName;
public int AITokenLimit => Plan?.AITokenLimit ?? PlanConstants.DefaultTokenLimit;
public string LastReadBookTitle => LastReadBook?.Title ?? PlanConstants.DefaultActivityLabel;
}
public class IdentityService : IIdentityService public class IdentityService : IIdentityService
{ {
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
@@ -39,8 +14,8 @@ public class IdentityService : IIdentityService
private readonly AuthenticationStateProvider? _authStateProvider; private readonly AuthenticationStateProvider? _authStateProvider;
private const string TokenKey = StorageKeys.AuthToken; private const string TokenKey = StorageKeys.AuthToken;
private const string RefreshTokenKey = StorageKeys.RefreshToken; private const string RefreshTokenKey = StorageKeys.RefreshToken;
private Task<UserProfile?>? _profileTask; private Task<UserProfileDto?>? _profileTask;
private UserProfile? _cachedProfile; private UserProfileDto? _cachedProfile;
private DateTime _lastFetchAttempt = DateTime.MinValue; private DateTime _lastFetchAttempt = DateTime.MinValue;
public event Func<Task>? OnStateInvalidated; public event Func<Task>? OnStateInvalidated;
@@ -152,7 +127,7 @@ public class IdentityService : IIdentityService
} }
} }
public async Task<Result<UserProfile>> GetProfileAsync() public async Task<Result<UserProfileDto>> GetProfileAsync()
{ {
if (_cachedProfile != null) if (_cachedProfile != null)
{ {
@@ -172,7 +147,7 @@ public class IdentityService : IIdentityService
private async Task<UserProfile?> GetProfileInternalAsync() private async Task<UserProfileDto?> GetProfileInternalAsync()
{ {
if (!System.OperatingSystem.IsBrowser()) if (!System.OperatingSystem.IsBrowser())
{ {
@@ -197,7 +172,7 @@ public class IdentityService : IIdentityService
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
var profile = await response.Content.ReadFromJsonAsync<UserProfile>(); var profile = await response.Content.ReadFromJsonAsync<UserProfileDto>();
if (profile != null) if (profile != null)
{ {
_cachedProfile = profile; _cachedProfile = profile;