bcd5daa3a0
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>
153 lines
5.6 KiB
Plaintext
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);
|
|
}
|
|
}
|