feat(ui): Hub Navigation, Profile Dashboard and Auth Stability Fixes #31
@@ -9,4 +9,5 @@ public record UpdateReadingProgressCommand(
|
||||
Guid EbookId,
|
||||
double Progress,
|
||||
string? ChapterTitle,
|
||||
int ChapterIndex,
|
||||
string? ExcludedConnectionId = null) : IRequest<Result>;
|
||||
|
||||
@@ -27,4 +27,5 @@ public record LastReadBookDto
|
||||
public string? CoverUrl { get; init; }
|
||||
public double Progress { get; init; }
|
||||
public string? LastChapter { get; init; }
|
||||
public int LastChapterIndex { get; init; }
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ public class GetUserProfileQueryHandler : IRequestHandler<GetUserProfileQuery, R
|
||||
},
|
||||
CoverUrl = e.CoverUrl,
|
||||
Progress = e.Progress,
|
||||
LastChapter = e.LastChapter ?? "Rozpoczynanie..."
|
||||
LastChapter = e.LastChapter ?? "Rozpoczynanie...",
|
||||
LastChapterIndex = e.LastChapterIndex
|
||||
}).FirstOrDefault()
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
@@ -39,6 +39,8 @@ public class Ebook
|
||||
[MaxLength(255)]
|
||||
public string? LastChapter { get; set; }
|
||||
|
||||
public int LastChapterIndex { get; set; } = 0;
|
||||
|
||||
// Relationship to NexusUser
|
||||
[Required]
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
@@ -41,6 +41,7 @@ public class UpdateReadingProgressCommandHandler : IRequestHandler<UpdateReading
|
||||
{
|
||||
ebook.Progress = request.Progress;
|
||||
ebook.LastChapter = request.ChapterTitle;
|
||||
ebook.LastChapterIndex = request.ChapterIndex;
|
||||
ebook.LastReadDate = now;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using NexusReader.Application.Commands.Sync;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace NexusReader.Infrastructure.RealTime;
|
||||
|
||||
@@ -15,12 +16,12 @@ public class SyncHub : Hub
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public async Task UpdateProgress(string pageId, Guid ebookId, double progress, string? chapterTitle)
|
||||
public async Task UpdateProgress(string pageId, Guid ebookId, double progress, string? chapterTitle, int chapterIndex)
|
||||
{
|
||||
var userId = Context.UserIdentifier;
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
var userId = Context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (userId != null)
|
||||
{
|
||||
await _mediator.Send(new UpdateReadingProgressCommand(pageId, userId, ebookId, progress, chapterTitle, Context.ConnectionId));
|
||||
await _mediator.Send(new UpdateReadingProgressCommand(pageId, userId, ebookId, progress, chapterTitle, chapterIndex, Context.ConnectionId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@
|
||||
blockId,
|
||||
ViewModel.EbookId,
|
||||
progress,
|
||||
ViewModel.ChapterTitle);
|
||||
ViewModel.ChapterTitle,
|
||||
ViewModel.CurrentChapterIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" />
|
||||
<PackageReference Include="MediatR" Version="12.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -56,18 +56,18 @@
|
||||
<div class="progress-section">
|
||||
<span class="chapter-label">@_profile.LastReadBook.LastChapter</span>
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar" style="width: @(_profile.LastReadBook.Progress)%">
|
||||
<div class="progress-bubble">@(_profile.LastReadBook.Progress)%</div>
|
||||
<div class="progress-bar" style="width: @(_profile.LastReadBook.Progress.ToString("F0", System.Globalization.CultureInfo.InvariantCulture))%">
|
||||
<div class="progress-bubble">@(_profile.LastReadBook.Progress.ToString("F1"))%</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="progress-detail">Postęp: @(_profile.LastReadBook.Progress)% - @_profile.LastReadBook.Author.Name</span>
|
||||
<span class="progress-detail">Postęp: @(_profile.LastReadBook.Progress.ToString("F2"))% - @_profile.LastReadBook.Author.Name</span>
|
||||
</div>
|
||||
<p class="reading-desc">
|
||||
Kontynuuj odkrywanie wiedzy w książce "@_profile.LastReadBook.Title".
|
||||
Twój cyfrowy asystent Nexus jest gotowy do analizy kolejnych rozdziałów i generowania interaktywnych map myśli.
|
||||
</p>
|
||||
<div class="card-actions">
|
||||
<button class="btn-nexus primary" @onclick='() => NavigationManager.NavigateTo("/reader")'>Kontynuuj Czytanie</button>
|
||||
<button class="btn-nexus primary" @onclick='() => NavigationManager.NavigateTo($"/reader?chapter={_profile.LastReadBook.LastChapterIndex}")'>Kontynuuj Czytanie</button>
|
||||
<button class="btn-nexus secondary" @onclick='() => NavigationManager.NavigateTo("/library")'>Moja Biblioteka</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
@inject IQuizStateService QuizState
|
||||
@inject IFocusModeService FocusMode
|
||||
@inject IJSRuntime JS
|
||||
@inject NavigationManager NavManager
|
||||
@inject IReaderNavigationService NavService
|
||||
<PageTitle>Nexus E-Reader</PageTitle>
|
||||
|
||||
<div class="home-reader-container">
|
||||
@@ -26,6 +28,16 @@
|
||||
QuizState.OnQuizRequested += HandleQuizRequestedAsync;
|
||||
FocusMode.OnFocusModeChanged += HandleUpdate;
|
||||
await FocusMode.InitializeAsync();
|
||||
|
||||
// Handle deep-linking to a specific chapter
|
||||
var uri = NavManager.ToAbsoluteUri(NavManager.Uri);
|
||||
if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("chapter", out var chapterValue))
|
||||
{
|
||||
if (int.TryParse(chapterValue, out var chapterIndex))
|
||||
{
|
||||
await NavService.GoToChapter(chapterIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace NexusReader.UI.Shared.Services;
|
||||
public interface ISyncService
|
||||
{
|
||||
Task<Result> InitializeAsync();
|
||||
Task<Result> UpdateProgressAsync(string pageId, Guid ebookId, double progress, string? chapterTitle);
|
||||
Task<Result> UpdateProgressAsync(string pageId, Guid ebookId, double progress, string? chapterTitle, int chapterIndex);
|
||||
event Func<string, DateTime, Task> OnProgressReceived;
|
||||
Task DisposeAsync();
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class SyncService : ISyncService, IAsyncDisposable
|
||||
|
||||
private string? _lastSentPageId;
|
||||
|
||||
public async Task<Result> UpdateProgressAsync(string pageId, Guid ebookId, double progress, string? chapterTitle)
|
||||
public async Task<Result> UpdateProgressAsync(string pageId, Guid ebookId, double progress, string? chapterTitle, int chapterIndex)
|
||||
{
|
||||
if (pageId == _lastSentPageId) return Result.Ok();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user