diff --git a/library_service/static/books.js b/library_service/static/books.js index e5f8d9f..938709e 100644 --- a/library_service/static/books.js +++ b/library_service/static/books.js @@ -1,6 +1,9 @@ $(document).ready(function () { - let selectedAuthors = new Set(); - let selectedGenres = new Set(); + let selectedAuthors = new Map(); // Map + let selectedGenres = new Map(); // Map + let currentPage = 1; + let pageSize = 20; + let totalBooks = 0; Promise.all([ fetch("/api/authors").then((response) => response.json()), @@ -11,7 +14,8 @@ $(document).ready(function () { authorsData.authors.forEach((author) => { $("
") .addClass("p-2 hover:bg-gray-100 cursor-pointer author-item") - .attr("data-value", author.name) + .attr("data-id", author.id) + .attr("data-name", author.name) .text(author.name) .appendTo($dropdown); }); @@ -22,7 +26,7 @@ $(document).ready(function () { .addClass("mb-1") .html( ``, @@ -32,9 +36,271 @@ $(document).ready(function () { initializeAuthorDropdown(); initializeFilters(); + + // Загружаем книги при старте + loadBooks(); }) .catch((error) => console.error("Error loading data:", error)); + // === Функция загрузки книг === + function loadBooks() { + const searchQuery = $("#book-search-input").val().trim(); + + // Формируем URL с параметрами + const params = new URLSearchParams(); + + // Добавляем поиск (минимум 3 символа) + if (searchQuery.length >= 3) { + params.append("q", searchQuery); + } + + // Добавляем авторов + selectedAuthors.forEach((name, id) => { + params.append("author_ids", id); + }); + + // Добавляем жанры + selectedGenres.forEach((name, id) => { + params.append("genre_ids", id); + }); + + // Пагинация + params.append("page", currentPage); + params.append("size", pageSize); + + const url = `/api/books/filter?${params.toString()}`; + + // Показываем индикатор загрузки + showLoadingState(); + + fetch(url) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + totalBooks = data.total; + renderBooks(data.books); + renderPagination(); + }) + .catch((error) => { + console.error("Error loading books:", error); + showErrorState(); + }); + } + + // === Отображение книг === + function renderBooks(books) { + const $container = $("#books-container"); + $container.empty(); + + if (books.length === 0) { + $container.html(` +
+ + + +

Книги не найдены

+

Попробуйте изменить параметры поиска или фильтры

+
+ `); + return; + } + + books.forEach((book) => { + const authorsText = + book.authors.map((a) => a.name).join(", ") || "Автор неизвестен"; + const genresText = + book.genres.map((g) => g.name).join(", ") || "Без жанра"; + + const $bookCard = $(` +
+
+
+

+ ${escapeHtml(book.title)} +

+

+ Авторы: ${escapeHtml(authorsText)} +

+

+ ${escapeHtml(book.description || "Описание отсутствует")} +

+
+ ${book.genres + .map( + (g) => ` + + ${escapeHtml(g.name)} + + `, + ) + .join("")} +
+
+
+
+ `); + + $container.append($bookCard); + }); + + // Обработчик клика на карточку книги + $container.on("click", ".book-card", function () { + const bookId = $(this).data("id"); + window.location.href = `/books/${bookId}`; + }); + } + + // === Пагинация === + function renderPagination() { + // Удаляем старую пагинацию + $("#pagination-container").remove(); + + const totalPages = Math.ceil(totalBooks / pageSize); + + if (totalPages <= 1) return; + + const $pagination = $(` +
+ +
+ +
+ `); + + const $pageNumbers = $pagination.find("#page-numbers"); + + // Генерируем номера страниц + const pages = generatePageNumbers(currentPage, totalPages); + + pages.forEach((page) => { + if (page === "...") { + $pageNumbers.append(`...`); + } else { + const isActive = page === currentPage; + $pageNumbers.append(` + + `); + } + }); + + $("#books-container").after($pagination); + + // Обработчики пагинации + $("#prev-page").on("click", function () { + if (currentPage > 1) { + currentPage--; + loadBooks(); + scrollToTop(); + } + }); + + $("#next-page").on("click", function () { + if (currentPage < totalPages) { + currentPage++; + loadBooks(); + scrollToTop(); + } + }); + + $(".page-btn").on("click", function () { + const page = parseInt($(this).data("page")); + if (page !== currentPage) { + currentPage = page; + loadBooks(); + scrollToTop(); + } + }); + } + + function generatePageNumbers(current, total) { + const pages = []; + const delta = 2; + + for (let i = 1; i <= total; i++) { + if ( + i === 1 || + i === total || + (i >= current - delta && i <= current + delta) + ) { + pages.push(i); + } else if (pages[pages.length - 1] !== "...") { + pages.push("..."); + } + } + + return pages; + } + + function scrollToTop() { + $("html, body").animate({ scrollTop: 0 }, 300); + } + + // === Состояния загрузки === + function showLoadingState() { + const $container = $("#books-container"); + $container.html(` +
+ ${Array(3) + .fill() + .map( + () => ` +
+
+
+
+
+
+
+
+
+ `, + ) + .join("")} +
+ `); + } + + function showErrorState() { + const $container = $("#books-container"); + $container.html(` +
+ + + +

Ошибка загрузки

+

Не удалось загрузить список книг

+ +
+ `); + + $("#retry-btn").on("click", loadBooks); + } + + // === Экранирование HTML === + function escapeHtml(text) { + if (!text) return ""; + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; + } + + // === Dropdown авторов === function initializeAuthorDropdown() { const $input = $("#author-search-input"); const $dropdown = $("#author-dropdown"); @@ -42,8 +308,8 @@ $(document).ready(function () { function updateHighlights() { $dropdown.find(".author-item").each(function () { - const value = $(this).attr("data-value"); - const isSelected = selectedAuthors.has(value); + const id = $(this).attr("data-id"); + const isSelected = selectedAuthors.has(parseInt(id)); $(this) .toggleClass("bg-gray-300 text-gray-600", isSelected) .toggleClass("hover:bg-gray-100", !isSelected); @@ -59,10 +325,10 @@ $(document).ready(function () { function renderChips() { $container.find(".author-chip").remove(); - selectedAuthors.forEach((author) => { + selectedAuthors.forEach((name, id) => { $(` - ${author} -

Жанры

-
    +
      + + +
      -
      -
      -
      -

      Product Title 1

      -

      - A short description of the product, highlighting its key - features and benefits. -

      -
      - $29.99 -
      - -
      -
      -

      Product Title 2

      -

      - Another great product with amazing features. You'll love it! -

      -
      - $49.99 -
      - -
      -
      -

      Product Title 3

      -

      - This product is a must-have for every modern home. High - quality and durable. -

      -
      - $19.99 +
      +
      +
      +
      {% endblock %} {% block scripts %}