refactor(bookshelf): migrate from DOM manipulation to Alpine.js reactive state

Replace direct DOM manipulation with Alpine.js reactive state variables:
- Add isLoading and hasBooks state to bookshelf component
- Convert loadBookshelf() to update isLoading state instead of toggling DOM visibility
- Convert renderBookshelf() to use reactive state for empty state handling
- Remove redundant getElementById() calls for loading/empty-state elements

This change improves maintainability by:
- Centralizing UI state in the Alpine component
- Eliminating direct DOM manipulation scattered across functions
- Making the component's state more explicit and trackable
- Following Alpine.js reactive programming patterns

The UI will now respond to state changes automatically rather than requiring
manual DOM updates throughout the lifecycle methods.
This commit is contained in:
2026-03-15 21:02:58 -04:00
parent 855cbd1b74
commit a9bbd1ee2e
+11 -20
View File
@@ -33,13 +33,7 @@ async function loadBookshelf(libraryId: string): Promise<void> {
const token = localStorage.getItem("token");
if (!token || !libraryId) return;
const loading = document.getElementById("loading");
const booksGrid = document.getElementById("books-grid");
const emptyState = document.getElementById("empty-state");
if (loading) loading.style.display = "block";
if (booksGrid) booksGrid.classList.add("hidden");
if (emptyState) emptyState.classList.add("hidden");
this.isLoading = true;
try {
const response = await fetch(
@@ -60,8 +54,7 @@ async function loadBookshelf(libraryId: string): Promise<void> {
} catch (error) {
console.error("Error loading bookshelf:", error);
showToast("Error loading books", "error");
} finally {
if (loading) loading.style.display = "none";
this.isLoading = false;
}
}
@@ -76,21 +69,14 @@ function showEmptyState(): void {
}
function renderBookshelf(): void {
const booksGrid = document.getElementById("books-grid");
const emptyState = document.getElementById("empty-state");
const loading = document.getElementById("loading");
if (!booksGrid) return;
if (loading) loading.style.display = "none";
if (emptyState) emptyState.classList.add("hidden");
if (!mediaItems || mediaItems.length === 0) {
showEmptyState();
this.isLoading = false;
this.hasBooks = false;
return;
}
booksGrid.classList.remove("hidden");
const booksGrid = document.getElementById("books-grid");
if (!booksGrid) return;
const booksPerShelf = 6;
const shelves: unknown[][] = [];
@@ -199,6 +185,11 @@ export {
};
Alpine.data("bookshelf", () => ({
// State Variables
isLoading: true,
hasBooks: false,
// Methods
changePage,
initBookshelf,
loadBookshelf,