@page "/book/{BookId:guid}/concepts" @page "/concepts-map" @using Microsoft.AspNetCore.Authorization @using NexusReader.UI.Shared.Components.Atoms @using NexusReader.UI.Shared.Components.Organisms @using NexusReader.UI.Shared.Services @using NexusReader.Application.Queries.Graph @using NexusReader.Application.Queries.Concepts @using System.Net.Http.Json @using NexusReader.Application.Abstractions.Services @using NexusReader.Application.Utilities @inject IConceptsMapService ConceptsMapService @inject NavigationManager NavigationManager @inject IIdentityService IdentityService @inject ISyncService SyncService @attribute [Authorize] @implements IAsyncDisposable Mapa Pojęć | Nexus Reader
@if (_isLoading) {

Inicjalizowanie mapy pojęć...

} else if (!string.IsNullOrEmpty(_errorMessage)) {

Wystąpił Błąd

@_errorMessage

} else if (!BookId.HasValue || BookId.Value == Guid.Empty || Nodes == null || !Nodes.Any()) {

Brak Aktywnych Książek

Nie wybrano żadnej książki lub ta książka nie ma jeszcze wygenerowanej mapy pojęć przez Nexus AI.

Przejdź do Moich Książek
} else {

Mapa Pojęć

Interaktywna ścieżka rozwoju Twoich postępów nauki

Ścieżka Rozwoju Wiedzy

@if (SelectedNode == null) {

Wybierz węzeł na mapie

Kliknij dowolne pojęcie z lewego panelu, aby uruchomić głęboką analizę i prześledzić szczegóły wygenerowane przez sztuczną inteligencję.

} else { var isSelectedNodeUnlocked = IsUnlocked(SelectedNode.Id);
@SelectedNode.Id.ToUpper() @if (isSelectedNodeUnlocked) { Odblokowane } else { Zablokowane }

@SelectedNode.Label

@if (!isSelectedNodeUnlocked) {
Ten etap jest zablokowany

Kontynuuj czytanie książki, aby odblokować to pojęcie. Po przeczytaniu rozdziału, postęp zsynchronizuje się automatycznie.

} @if (SelectedNode.KeyTerms != null && SelectedNode.KeyTerms.Any()) { }
}
}
@code { [Parameter] public Guid? BookId { get; set; } private List Nodes { get; set; } = new(); private string LastReadBlockId { get; set; } = string.Empty; private GraphNodeDto? SelectedNode { get; set; } private bool _isLoading = true; private string _errorMessage = string.Empty; protected override async Task OnInitializedAsync() { IdentityService.OnStateInvalidated += HandleStateInvalidatedAsync; await SyncService.InitializeAsync(); SyncService.OnProgressReceived += HandleProgressReceivedAsync; await LoadDataAsync(); } private async Task LoadDataAsync() { _isLoading = true; _errorMessage = string.Empty; StateHasChanged(); try { if (!BookId.HasValue || BookId.Value == Guid.Empty) { var profileResult = await IdentityService.GetProfileAsync(); if (profileResult.IsSuccess && profileResult.Value.LastReadBook != null) { BookId = profileResult.Value.LastReadBook.Id; } } if (BookId.HasValue && BookId.Value != Guid.Empty) { var result = await ConceptsMapService.GetConceptsMapAsync(BookId.Value); if (result.IsSuccess) { Nodes = result.Value.Nodes; LastReadBlockId = result.Value.LastReadBlockId; if (Nodes.Any()) { SelectedNode = Nodes.FirstOrDefault(n => IsUnlocked(n.Id)) ?? Nodes.First(); } } else { _errorMessage = result.Errors.FirstOrDefault()?.Message ?? "Brak odpowiedzi od serwera."; } } } catch (Exception ex) { _errorMessage = $"Błąd podczas pobierania danych: {ex.Message}"; } finally { _isLoading = false; StateHasChanged(); } } private bool IsUnlocked(string nodeId) { if (string.IsNullOrEmpty(nodeId)) return false; var nodeSeq = SegmentIdParser.Parse(nodeId); var minNodeSeq = Nodes.Any() ? Nodes.Min(n => SegmentIdParser.Parse(n.Id)) : 0; if (nodeSeq == minNodeSeq) return true; if (string.IsNullOrEmpty(LastReadBlockId)) return false; var progressSeq = SegmentIdParser.Parse(LastReadBlockId); return nodeSeq <= progressSeq; } private void HandleNodeSelected(GraphNodeDto node) { SelectedNode = node; StateHasChanged(); } private void GoBackToLibrary() { NavigationManager.NavigateTo("/my-books"); } private void GoToReader() { if (BookId.HasValue) { NavigationManager.NavigateTo($"/reader/{BookId.Value}"); } } private void GoToSelectedChapter() { if (BookId.HasValue && SelectedNode != null) { var chapterIndex = SegmentIdParser.Parse(SelectedNode.Id); NavigationManager.NavigateTo($"/reader/{BookId.Value}?chapter={chapterIndex}"); } } private async Task HandleStateInvalidatedAsync() { await InvokeAsync(async () => { await LoadDataAsync(); }); } private async Task HandleProgressReceivedAsync(string pageId, DateTime timestamp) { await InvokeAsync(() => { LastReadBlockId = pageId; StateHasChanged(); return Task.CompletedTask; }); } public ValueTask DisposeAsync() { IdentityService.OnStateInvalidated -= HandleStateInvalidatedAsync; SyncService.OnProgressReceived -= HandleProgressReceivedAsync; return ValueTask.CompletedTask; } }