@page "/creator" @attribute [Authorize] @using System.Net.Http.Json @using Microsoft.Extensions.Logging @using System.ComponentModel.DataAnnotations @using NexusReader.Application.DTOs.Creator @inject HttpClient Http @inject NavigationManager NavigationManager @inject ILogger Logger Creator Dashboard | Nexus Reader

Panel Autora

Monitoruj zaangażowanie czytelników i publikuj wersje zamrożone z poziomu kontroli wersji.

@if (_isLoading) { @for (int i = 0; i < 4; i++) {
} } else if (_dashboardData != null) {
Całkowite Odczyty

@_dashboardData.Metrics.TotalReads

System stabilny
Średni Czas Czytania

@_dashboardData.Metrics.AvgReadTimeMinutes min

Na rozdział
Aktywni Czytelnicy
Live Now

@_dashboardData.Metrics.ActiveReaders

Ruch w czasie rzeczywistym
Przychód Gross

@_dashboardData.Metrics.GrossRevenue.ToString("C2")

Rozliczenia w toku
}

Twoje Publikacje

@if (_isLoading) {
@for (int i = 0; i < 3; i++) {
}
} else if (_dashboardData == null || !_dashboardData.Books.Any()) {

Brak publikacji

Nie utworzyłeś jeszcze żadnych książek do autorskiej edycji.

} else {
@foreach (var book in _dashboardData.Books) {

@book.Title

@if (book.LivePublishedRevision != null) { Live @book.LivePublishedRevision.VersionString } @if (book.CurrentDraftRevision != null) { Szkic }
Słowa: @book.WordCount.ToString("N0")
Wyświetlenia: @book.AggregatedReads.ToString("N0")
}
}
@if (_isPublishModalOpen && _activePublishBookId.HasValue) { } @if (_isRevisionsModalOpen && _activeRevisionsBookId.HasValue) { } @if (_isCreateBookModalOpen) { } @code { private bool _isLoading = true; private CreatorDashboardDataDto? _dashboardData; // Create Book Model and state private bool _isCreateBookModalOpen; private CreateBookModel _createBookModel = new(); private bool _isCreatingBook; private string? _createBookError; // Defensively-scoped state variables for modal isolation private bool _isPublishModalOpen; private Guid? _activePublishBookId; private string _activePublishBookTitle = string.Empty; private string _customVersionString = string.Empty; private bool _isSubmitting; private string? _errorMessage; // Revisions modal state variables private bool _isRevisionsModalOpen; private Guid? _activeRevisionsBookId; private string _activeRevisionsBookTitle = string.Empty; private bool _revisionsLoading; private List _revisionsList = new(); protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await LoadDashboardDataAsync(); } } private async Task LoadDashboardDataAsync() { _isLoading = true; StateHasChanged(); try { _dashboardData = await Http.GetFromJsonAsync("api/creator/dashboard"); } catch (Exception ex) { Logger.LogError(ex, "Error loading creator dashboard data."); } finally { _isLoading = false; StateHasChanged(); } } private void NavigateToEditor(CreatorBookDto book) { if (book.FirstChapterId.HasValue) { NavigationManager.NavigateTo($"/creator/edit/{book.Id}/{book.FirstChapterId.Value}"); } else { NavigationManager.NavigateTo($"/creator/edit/{book.Id}"); } } private void OpenPublishModal(CreatorBookDto book) { // Explicitly lock context boundaries to the selected book _activePublishBookId = book.Id; _activePublishBookTitle = book.Title; _customVersionString = "v1.0.0"; _errorMessage = null; _isPublishModalOpen = true; } private void ClosePublishModal() { _isPublishModalOpen = false; _activePublishBookId = null; _activePublishBookTitle = string.Empty; _customVersionString = string.Empty; _errorMessage = null; } private async Task SubmitPublishVersionAsync() { if (!_activePublishBookId.HasValue || string.IsNullOrWhiteSpace(_customVersionString)) { return; } _isSubmitting = true; _errorMessage = null; StateHasChanged(); try { // Explicitly lock the parameters during sending execution var bookId = _activePublishBookId.Value; var response = await Http.PostAsync($"api/creator/books/{bookId}/publish?version={Uri.EscapeDataString(_customVersionString)}", null); if (response.IsSuccessStatusCode) { ClosePublishModal(); await LoadDashboardDataAsync(); } else { _errorMessage = await response.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(_errorMessage)) { _errorMessage = "Publish version endpoint returned an error."; } } } catch (Exception ex) { Logger.LogError(ex, "Exception thrown during publication."); _errorMessage = $"Mutation failed: {ex.Message}"; } finally { _isSubmitting = false; StateHasChanged(); } } private async Task OpenRevisionsModalAsync(CreatorBookDto book) { _activeRevisionsBookId = book.Id; _activeRevisionsBookTitle = book.Title; _revisionsList = new(); _revisionsLoading = true; _isRevisionsModalOpen = true; StateHasChanged(); try { _revisionsList = await Http.GetFromJsonAsync>($"api/creator/books/{book.Id}/revisions") ?? new(); } catch (Exception ex) { Logger.LogError(ex, "Failed to load revisions."); } finally { _revisionsLoading = false; StateHasChanged(); } } private void CloseRevisionsModal() { _isRevisionsModalOpen = false; _activeRevisionsBookId = null; _activeRevisionsBookTitle = string.Empty; _revisionsList.Clear(); } private void OpenCreateBookModal() { _createBookModel = new CreateBookModel(); _createBookError = null; _isCreateBookModalOpen = true; } private void CloseCreateBookModal() { _isCreateBookModalOpen = false; _createBookError = null; } private async Task SubmitCreateBookAsync() { _isCreatingBook = true; _createBookError = null; StateHasChanged(); try { var response = await Http.PostAsJsonAsync("api/creator/books", _createBookModel); if (response.IsSuccessStatusCode) { var result = await response.Content.ReadFromJsonAsync(); if (result != null) { // Reset modal state BEFORE routing to prevent it lingering in the DOM tree _isCreateBookModalOpen = false; _createBookError = null; StateHasChanged(); NavigationManager.NavigateTo($"/creator/edit/{result.BookId}"); } else { _createBookError = "Otrzymano nieprawidłową odpowiedź z serwera."; } } else { var errorMsg = await response.Content.ReadAsStringAsync(); _createBookError = !string.IsNullOrWhiteSpace(errorMsg) ? errorMsg : "Wystąpił błąd podczas tworzenia książki."; } } catch (Exception ex) { Logger.LogError(ex, "Błąd podczas tworzenia książki."); _createBookError = $"Krytyczny błąd: {ex.Message}"; } finally { _isCreatingBook = false; StateHasChanged(); } } public class CreateBookModel { [Required(ErrorMessage = "Tytuł książki jest wymagany.")] [StringLength(255, ErrorMessage = "Tytuł książki nie może przekraczać 255 znaków.")] public string Title { get; set; } = string.Empty; public string? Description { get; set; } } }