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,
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);
+2
View File
@@ -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();