leetcoder2008/libraryspark
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Books - LibrarySpark</title>7 <link rel="icon" type="image/x-icon" href="/static/favicon.ico">8 <link rel="stylesheet" href="style.css">9 <script src="https://cdn.tailwindcss.com"></script>10 <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>11 <script>12 tailwind.config = {13 theme: {14 extend: {15 colors: {16 primary: {17 50: '#eff6ff',18 100: '#dbeafe',19 200: '#bfdbfe',20 300: '#93c5fd',21 400: '#60a5fa',22 500: '#3b82f6',23 600: '#2563eb',24 700: '#1d4ed8',25 800: '#1e40af',26 900: '#1e3a8a',27 },28 secondary: {29 50: '#f0fdf4',30 100: '#dcfce7',31 200: '#bbf7d0',32 300: '#86efac',33 400: '#4ade80',34 500: '#22c55e',35 600: '#16a34a',36 700: '#15803d',37 800: '#166534',38 900: '#14532d',39 }40 }41 }42 }43 }44 </script>45</head>46<body class="bg-gray-50 min-h-screen">47 <custom-navbar></custom-navbar>48 49 <div class="container mx-auto px-4 py-8">50 <div class="flex justify-between items-center mb-8">51 <h1 class="text-3xl font-bold text-gray-800">Library Books</h1>52 <button id="add-book-btn" class="btn-primary flex items-center">53 <i data-feather="plus" class="mr-2"></i> Add Book54 </button>55 </div>56 57 <!-- Books Grid -->58 <div id="books-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">59 <!-- Books will be loaded here dynamically -->60 </div>61 62 <!-- Pagination -->63 <div id="pagination" class="flex justify-center mt-8 space-x-2">64 <!-- Pagination buttons will be added here -->65 </div>66 </div>67 68 <!-- Add Book Modal -->69 <div id="add-book-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">70 <div class="bg-white rounded-xl p-6 w-full max-w-md">71 <div class="flex justify-between items-center mb-4">72 <h2 class="text-xl font-bold">Add New Book</h2>73 <button id="close-modal" class="text-gray-500 hover:text-gray-700">74 <i data-feather="x"></i>75 </button>76 </div>77 <form id="add-book-form">78 <div class="mb-4">79 <label class="block text-gray-700 mb-2" for="title">Title</label>80 <input type="text" id="title" name="title" class="w-full px-3 py-2 border rounded-lg" required>81 </div>82 <div class="mb-4">83 <label class="block text-gray-700 mb-2" for="author">Author</label>84 <input type="text" id="author" name="author" class="w-full px-3 py-2 border rounded-lg" required>85 </div>86 <div class="mb-4">87 <label class="block text-gray-700 mb-2" for="isbn">ISBN</label>88 <input type="text" id="isbn" name="isbn" class="w-full px-3 py-2 border rounded-lg" required>89 </div>90 <div class="mb-4">91 <label class="block text-gray-700 mb-2" for="genre">Genre</label>92 <input type="text" id="genre" name="genre" class="w-full px-3 py-2 border rounded-lg">93 </div>94 <div class="mb-4">95 <label class="block text-gray-700 mb-2" for="copies">Total Copies</label>96 <input type="number" id="copies" name="total_copies" class="w-full px-3 py-2 border rounded-lg" value="1" min="1" required>97 </div>98 <div class="flex justify-end space-x-3">99 <button type="button" id="cancel-modal" class="px-4 py-2 text-gray-600 hover:text-gray-800">Cancel</button>100 <button type="submit" class="btn-primary">Add Book</button>101 </div>102 </form>103 </div>104 </div>105 106 <custom-footer></custom-footer>107 108 <script src="components/navbar.js"></script>109 <script src="components/footer.js"></script>110 <script src="script.js"></script>111 <script>112 feather.replace();113 114 // DOM Elements115 const booksContainer = document.getElementById('books-container');116 const paginationContainer = document.getElementById('pagination');117 const addBookModal = document.getElementById('add-book-modal');118 const addBookBtn = document.getElementById('add-book-btn');119 const closeModal = document.getElementById('close-modal');120 const cancelModal = document.getElementById('cancel-modal');121 const addBookForm = document.getElementById('add-book-form');122 123 // Current page state124 let currentPage = 1;125 126 // Load books127 function loadBooks(page = 1) {128 fetch(`/api/books?page=${page}&per_page=9`)129 .then(response => response.json())130 .then(data => {131 displayBooks(data.books);132 setupPagination(data.pages, data.current_page);133 })134 .catch(error => console.error('Error loading books:', error));135 }136 137 // Display books in grid138 function displayBooks(books) {139 booksContainer.innerHTML = '';140 141 books.forEach(book => {142 const bookCard = document.createElement('div');143 bookCard.className = 'bg-white rounded-xl shadow-md overflow-hidden border border-gray-100';144 bookCard.innerHTML = `145 <div class="p-6">146 <div class="flex justify-between items-start mb-4">147 <div>148 <h3 class="text-xl font-bold text-gray-800">${book.title}</h3>149 <p class="text-gray-600">by ${book.author}</p>150 </div>151 <span class="bg-primary-100 text-primary-800 text-xs font-semibold px-2.5 py-0.5 rounded">152 ${book.genre || 'N/A'}153 </span>154 </div>155 <div class="flex justify-between items-center">156 <div>157 <p class="text-sm text-gray-500">ISBN: ${book.isbn}</p>158 <p class="text-sm mt-1">159 <span class="font-medium">${book.available_copies}</span> of 160 <span class="font-medium">${book.total_copies}</span> available161 </p>162 </div>163 <button class="checkout-btn btn-primary text-sm" data-book-id="${book.id}">164 Checkout165 </button>166 </div>167 </div>168 `;169 booksContainer.appendChild(bookCard);170 });171 172 // Add event listeners to checkout buttons173 document.querySelectorAll('.checkout-btn').forEach(button => {174 button.addEventListener('click', function() {175 const bookId = this.getAttribute('data-book-id');176 alert(`Checkout functionality for book ID ${bookId} would go here`);177 });178 });179 }180 181 // Setup pagination182 function setupPagination(totalPages, currentPage) {183 paginationContainer.innerHTML = '';184 185 for (let i = 1; i <= totalPages; i++) {186 const button = document.createElement('button');187 button.className = `px-3 py-1 rounded ${i === currentPage ? 'bg-primary-500 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'}`;188 button.textContent = i;189 button.addEventListener('click', () => loadBooks(i));190 paginationContainer.appendChild(button);191 }192 }193 194 // Modal event listeners195 addBookBtn.addEventListener('click', () => {196 addBookModal.classList.remove('hidden');197 });198 199 closeModal.addEventListener('click', () => {200 addBookModal.classList.add('hidden');201 });202 203 cancelModal.addEventListener('click', () => {204 addBookModal.classList.add('hidden');205 });206 207 // Handle form submission208 addBookForm.addEventListener('submit', function(e) {209 e.preventDefault();210 211 const formData = new FormData(this);212 const bookData = {};213 formData.forEach((value, key) => {214 bookData[key] = value;215 });216 217 fetch('/api/books', {218 method: 'POST',219 headers: {220 'Content-Type': 'application/json',221 },222 body: JSON.stringify(bookData)223 })224 .then(response => response.json())225 .then(data => {226 alert('Book added successfully!');227 addBookModal.classList.add('hidden');228 loadBooks(currentPage);229 addBookForm.reset();230 })231 .catch(error => {232 console.error('Error adding book:', error);233 alert('Error adding book. Please try again.');234 });235 });236 237 // Load books on page load238 document.addEventListener('DOMContentLoaded', () => {239 loadBooks();240 });241 </script>242</body>243</html>