Files
Nexus.Reader/src/NexusReader.UI.Shared/Pages/MyBooks.razor
T
Antigravity bcd5daa3a0 feat: Refactor dashboard screens to Modern Deep Dark style (#74)
Refactored Pulpit, Katalog, Moje, Konto screens to a unified, premium Modern Deep Dark style.

Resolves #73.

---------

Co-authored-by: Marek Jasiński <jasins.marek@gmail.com>
Reviewed-on: #74
Co-authored-by: Antigravity <antigravity@google.com>
Co-committed-by: Antigravity <antigravity@google.com>
2026-06-06 07:58:59 +00:00

153 lines
5.6 KiB
Plaintext

@page "/my-books"
@attribute [Authorize]
@using NexusReader.UI.Shared.Components.Organisms
@using NexusReader.Application.DTOs.User
@using NexusReader.UI.Shared.Services
@using System.Net.Http.Json
@inject HttpClient Http
@inject IReaderNavigationService ReaderNavigation
<div class="my-books-page">
<header class="my-books-header">
<div class="header-title-section">
<h1>Moje Książki</h1>
<p class="subtitle">Twoje aktywne lektury i postępy w nauce z Nexus AI</p>
</div>
<AuthorizeView Roles="Admin, ContentManager">
<button class="btn-nexus add-book-trigger" @onclick="() => _isModalOpen = true">
<span class="btn-icon">+</span> Dodaj E-book
</button>
</AuthorizeView>
</header>
<BookIngestionModal @bind-IsOpen="_isModalOpen" @bind-IsOpen:after="RefreshLibrary" />
<div class="my-books-content">
@if (_isLoading)
{
<div class="my-books-loading-container">
<div class="loader-card">
<div class="spinner-glow small"></div>
<span class="loader-text">Wczytywanie biblioteki...</span>
</div>
<div class="loading-grid">
@for (int i = 0; i < 3; i++)
{
<div class="skeleton-card">
<div class="skeleton-cover"></div>
<div class="skeleton-details">
<div class="skeleton-line title"></div>
<div class="skeleton-line author"></div>
<div class="skeleton-line progress"></div>
</div>
</div>
}
</div>
</div>
}
else if (_books == null || !_books.Any())
{
<div class="empty-state-container">
<div class="empty-icon-pulse">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
</svg>
</div>
<h3>Pusta biblioteka</h3>
<p>Nie masz jeszcze żadnych książek na swojej półce. Przejdź do katalogu, aby rozpocząć kurs.</p>
<a href="/catalog" class="btn-nexus catalog-btn">Przeglądaj Katalog</a>
</div>
}
else
{
<div class="books-grid">
@foreach (var book in _books)
{
<div class="book-card" @onclick="() => OpenBook(book.Id)">
<div class="book-cover-container">
<img src="@(book.CoverUrl ?? "https://api.dicebear.com/7.x/identicon/svg?seed=" + book.Title)" alt="@book.Title" class="book-cover" />
<div class="cover-overlay">
<span class="read-action">Czytaj teraz</span>
</div>
</div>
<div class="book-details">
<h3 class="book-title" title="@book.Title">@book.Title</h3>
<p class="book-author">@book.Author.Name</p>
@if (book.Progress > 0)
{
<div class="book-progress-section">
<div class="progress-bar">
<div class="progress-fill" style="width: @(book.Progress.ToString("F0"))%"></div>
</div>
<span class="progress-text">Postęp: @(book.Progress.ToString("F0"))% (@book.LastChapter)</span>
</div>
}
else
{
<span class="new-badge">Nowa</span>
}
<div class="card-actions">
<button class="btn-nexus primary-accent-btn">
KONTYNUUJ KURS
</button>
</div>
</div>
</div>
}
</div>
}
</div>
</div>
@code {
private bool _isModalOpen;
private bool _isLoading = true;
private List<LastReadBookDto>? _books;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await LoadBooksAsync();
}
}
private async Task LoadBooksAsync()
{
_isLoading = true;
StateHasChanged();
try
{
_books = await Http.GetFromJsonAsync<List<LastReadBookDto>>("api/library/books");
_isLoading = false;
}
catch (Exception ex)
{
Console.WriteLine($"[MyBooks] Failed to load books: {ex.Message}");
if (OperatingSystem.IsBrowser())
{
_isLoading = false;
}
}
finally
{
StateHasChanged();
}
}
private async Task RefreshLibrary()
{
await LoadBooksAsync();
}
private void OpenBook(Guid bookId)
{
ReaderNavigation.NavigateToBook(bookId);
}
}