fix: resolve dashboard bugs (percentage precision, wrong title, and reading resumption)

This commit is contained in:
2026-05-10 19:09:14 +02:00
parent 2950e15633
commit 65e188b323
12 changed files with 33 additions and 12 deletions
@@ -9,4 +9,5 @@ public record UpdateReadingProgressCommand(
Guid EbookId, Guid EbookId,
double Progress, double Progress,
string? ChapterTitle, string? ChapterTitle,
int ChapterIndex,
string? ExcludedConnectionId = null) : IRequest<Result>; string? ExcludedConnectionId = null) : IRequest<Result>;
@@ -27,4 +27,5 @@ public record LastReadBookDto
public string? CoverUrl { get; init; } public string? CoverUrl { get; init; }
public double Progress { get; init; } public double Progress { get; init; }
public string? LastChapter { 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, CoverUrl = e.CoverUrl,
Progress = e.Progress, Progress = e.Progress,
LastChapter = e.LastChapter ?? "Rozpoczynanie..." LastChapter = e.LastChapter ?? "Rozpoczynanie...",
LastChapterIndex = e.LastChapterIndex
}).FirstOrDefault() }).FirstOrDefault()
}) })
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
+2
View File
@@ -39,6 +39,8 @@ public class Ebook
[MaxLength(255)] [MaxLength(255)]
public string? LastChapter { get; set; } public string? LastChapter { get; set; }
public int LastChapterIndex { get; set; } = 0;
// Relationship to NexusUser // Relationship to NexusUser
[Required] [Required]
public string UserId { get; set; } = string.Empty; public string UserId { get; set; } = string.Empty;
@@ -41,6 +41,7 @@ public class UpdateReadingProgressCommandHandler : IRequestHandler<UpdateReading
{ {
ebook.Progress = request.Progress; ebook.Progress = request.Progress;
ebook.LastChapter = request.ChapterTitle; ebook.LastChapter = request.ChapterTitle;
ebook.LastChapterIndex = request.ChapterIndex;
ebook.LastReadDate = now; ebook.LastReadDate = now;
} }
@@ -2,6 +2,7 @@ using MediatR;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using NexusReader.Application.Commands.Sync; using NexusReader.Application.Commands.Sync;
using System.Security.Claims;
namespace NexusReader.Infrastructure.RealTime; namespace NexusReader.Infrastructure.RealTime;
@@ -15,12 +16,12 @@ public class SyncHub : Hub
_mediator = mediator; _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; var userId = Context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!string.IsNullOrEmpty(userId)) 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, blockId,
ViewModel.EbookId, ViewModel.EbookId,
progress, 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.Authorization" Version="10.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" /> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" />
<PackageReference Include="MediatR" Version="12.1.1" /> <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.Extensions.Logging.Abstractions" Version="10.0.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.7" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.7" />
</ItemGroup> </ItemGroup>
@@ -56,18 +56,18 @@
<div class="progress-section"> <div class="progress-section">
<span class="chapter-label">@_profile.LastReadBook.LastChapter</span> <span class="chapter-label">@_profile.LastReadBook.LastChapter</span>
<div class="progress-container"> <div class="progress-container">
<div class="progress-bar" style="width: @(_profile.LastReadBook.Progress)%"> <div class="progress-bar" style="width: @(_profile.LastReadBook.Progress.ToString("F0", System.Globalization.CultureInfo.InvariantCulture))%">
<div class="progress-bubble">@(_profile.LastReadBook.Progress)%</div> <div class="progress-bubble">@(_profile.LastReadBook.Progress.ToString("F1"))%</div>
</div> </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> </div>
<p class="reading-desc"> <p class="reading-desc">
Kontynuuj odkrywanie wiedzy w książce "@_profile.LastReadBook.Title". 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. Twój cyfrowy asystent Nexus jest gotowy do analizy kolejnych rozdziałów i generowania interaktywnych map myśli.
</p> </p>
<div class="card-actions"> <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> <button class="btn-nexus secondary" @onclick='() => NavigationManager.NavigateTo("/library")'>Moja Biblioteka</button>
</div> </div>
</div> </div>
@@ -6,6 +6,8 @@
@inject IQuizStateService QuizState @inject IQuizStateService QuizState
@inject IFocusModeService FocusMode @inject IFocusModeService FocusMode
@inject IJSRuntime JS @inject IJSRuntime JS
@inject NavigationManager NavManager
@inject IReaderNavigationService NavService
<PageTitle>Nexus E-Reader</PageTitle> <PageTitle>Nexus E-Reader</PageTitle>
<div class="home-reader-container"> <div class="home-reader-container">
@@ -26,6 +28,16 @@
QuizState.OnQuizRequested += HandleQuizRequestedAsync; QuizState.OnQuizRequested += HandleQuizRequestedAsync;
FocusMode.OnFocusModeChanged += HandleUpdate; FocusMode.OnFocusModeChanged += HandleUpdate;
await FocusMode.InitializeAsync(); 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) protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -5,7 +5,7 @@ namespace NexusReader.UI.Shared.Services;
public interface ISyncService public interface ISyncService
{ {
Task<Result> InitializeAsync(); 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; event Func<string, DateTime, Task> OnProgressReceived;
Task DisposeAsync(); Task DisposeAsync();
} }
@@ -64,7 +64,7 @@ public class SyncService : ISyncService, IAsyncDisposable
private string? _lastSentPageId; 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(); if (pageId == _lastSentPageId) return Result.Ok();