Book Search App with OpenLibrary API and LocalStorage

Classified in Computers

Written on in English with a size of 8.38 KB

Obtener elementos del DOM

const resultsContainer = document.getElementById('results');
const favoritesContainer = document.getElementById('favorites');
const readContainer = document.getElementById('read');

Buscar libros en OpenLibrary usando fetch().then()

function fetchBooks(query, limit = 10, callback) {
  fetch(`https://openlibrary.org/search.json?q=${encodeURIComponent(query)}&limit=${limit}`)
    .then(res => res.json())
    .then(data => {
      const books = data.docs || [];
      callback(books);
    })
    .catch(err => {
      console.error("Error fetching books:", err);
    });
}

Guardar en localStorage si no está duplicado

function saveToLocalStorage(key, book) {
  const stored = getFromLocalStorage(key);
  if (!stored.some(b => b.key === book.key)) {
    stored.push(book);
    localStorage.setItem(key, JSON.stringify(stored));
  }
}

Obtener libros del localStorage

function getFromLocalStorage(key) {
  return JSON.parse(localStorage.getItem(key)) || [];
}

Eliminar un libro por su key

function removeFromLocalStorage(key, bookKey) {
  const updated = getFromLocalStorage(key).filter(b => b.key !== bookKey);
  localStorage.setItem(key, JSON.stringify(updated));
}

Renderizar una lista (favoritos o leídos)

function renderStoredBooks(container, key) {
  const books = getFromLocalStorage(key);
  container.innerHTML = '';

  books.forEach(book => {
    const card = document.createElement('div');
    card.className = 'book-card';

    const title = document.createElement('h3');
    title.textContent = book.title || 'No Title';
    card.appendChild(title);

    const author = document.createElement('p');
    author.innerHTML = `<em>${book.author_name?.join(', ') || 'Unknown Author'}</em>`;
    card.appendChild(author);

    const coverId = book.cover_i;
    const img = document.createElement('img');
    img.src = coverId
      ? `https://covers.openlibrary.org/b/id/${coverId}-M.jpg`
      : 'https://via.placeholder.com/150x200?text=No+Cover';
    img.alt = book.title;
    card.appendChild(img);

    const buttons = document.createElement('div');
    buttons.className = 'card-buttons';

    const delBtn = document.createElement('button');
    delBtn.textContent = '❌ Remove';
    delBtn.addEventListener('click', () => {
      removeFromLocalStorage(key, book.key);
      renderStoredBooks(container, key);
    });

    buttons.appendChild(delBtn);
    card.appendChild(buttons);
    container.appendChild(card);
  });
}

Renderizar libros obtenidos de búsqueda

function renderBooks(books) {
  resultsContainer.innerHTML = "";

  books.forEach(book => {
    const card = document.createElement('div');
    card.className = 'book-card';

    const title = document.createElement('h3');
    title.textContent = book.title || 'No Title';
    card.appendChild(title);

    const author = document.createElement('p');
    author.innerHTML = `<em>${book.author_name?.join(', ') || 'Unknown Author'}</em>`;
    card.appendChild(author);

    const coverId = book.cover_i;
    const img = document.createElement('img');
    img.src = coverId
      ? `https://covers.openlibrary.org/b/id/${coverId}-M.jpg`
      : 'https://via.placeholder.com/150x200?text=No+Cover';
    img.alt = book.title;
    card.appendChild(img);

    const buttons = document.createElement('div');
    buttons.className = 'card-buttons';

    const favBtn = document.createElement('button');
    favBtn.textContent = '❤️ Favorite';
    favBtn.addEventListener('click', () => {
      const bookData = {
        key: book.key,
        title: book.title,
        author_name: book.author_name,
        cover_i: book.cover_i
      };
      saveToLocalStorage('favorites', bookData);
      renderStoredBooks(favoritesContainer, 'favorites');
    });

    const readBtn = document.createElement('button');
    readBtn.textContent = '✅ Read';
    readBtn.addEventListener('click', () => {
      const bookData = {
        key: book.key,
        title: book.title,
        author_name: book.author_name,
        cover_i: book.cover_i
      };
      saveToLocalStorage('read', bookData);
      renderStoredBooks(readContainer, 'read');
    });

    buttons.appendChild(favBtn);
    buttons.appendChild(readBtn);

    card.appendChild(buttons);
    resultsContainer.appendChild(card);
  });
}

Obtener una letra aleatoria

function getRandomLetter() {
  const letters = 'abcdefghijklmnopqrstuvwxyz';
  return letters[Math.floor(Math.random() * letters.length)];
}

Evento del formulario de búsqueda

document.getElementById('searchForm').addEventListener('submit', function (e) {
  e.preventDefault();
  const query = document.getElementById('searchInput').value.trim();
  const limit = parseInt(document.getElementById('limitInput').value) || 10;

  if (query === '') return;

  fetchBooks(query, limit, renderBooks);
});

Evento del botón de libros aleatorios

document.getElementById('randomBtn').addEventListener('click', function () {
  const randomLetter = getRandomLetter();
  fetchBooks(randomLetter, 5, renderBooks);
});

Al cargar la página

window.onload = function () {
  renderStoredBooks(favoritesContainer, 'favorites');
  renderStoredBooks(readContainer, 'read');
};

Related entries: