Selasa, 06 Januari 2026

ePerpustakaan

 






1.58 59
7.26 35
11.31 27
13.37 85

59352785

Code.gs

// ==================== KONFIGURASI ====================
const SPREADSHEET_ID = '1FTLbiPwBR9y4x63RhsdlR5jfKimejhPt3AMz1kyFabE';// <<< GANTI DENGAN ID SPREADSHEET ANDA
const DRIVE_FOLDER_ID = '1E3YGMUwzqf8yFkle7EsFrAv9_DekXdAo'; // <<< GANTI DENGAN ID FOLDER GOOGLE DRIVE ANDA



function getSpreadsheet() {
  return SpreadsheetApp.openById(SPREADSHEET_ID);
}

// ==================== INITIALIZE SHEETS ====================
/**
 * Fungsi untuk membuat sheet dan mengisi data sampel
 * Jalankan fungsi ini HANYA SEKALI saat pertama kali setup
 */
function initializeSheets() {
  const ss = getSpreadsheet();
 
  // ========== SHEET USERS ==========
  let usersSheet = ss.getSheetByName('Users');
  if (usersSheet) {
    ss.deleteSheet(usersSheet);
  }
  usersSheet = ss.insertSheet('Users');
 
  // Header
  usersSheet.getRange('A1:D1').setValues([['email', 'password', 'role', 'nama']]);
  usersSheet.getRange('A1:D1').setFontWeight('bold').setBackground('#1e40af').setFontColor('#ffffff');
 
  // Data sampel
  const usersData = [
    ['admin@perpus.com', 'admin123', 'Admin', 'Administrator Perpustakaan'],
    ['guru@sekolah.com', 'guru123', 'Admin', 'Ibu Siti Rahayu'],
    ['siswa1@sekolah.com', 'siswa123', 'Siswa', 'Ahmad Rizki Maulana'],
    ['siswa2@sekolah.com', 'siswa123', 'Siswa', 'Siti Nurhaliza'],
    ['siswa3@sekolah.com', 'siswa123', 'Siswa', 'Budi Santoso'],
    ['siswa4@sekolah.com', 'siswa123', 'Siswa', 'Dewi Lestari'],
    ['siswa5@sekolah.com', 'siswa123', 'Siswa', 'Rian Pratama']
  ];
  usersSheet.getRange(2, 1, usersData.length, 4).setValues(usersData);
  usersSheet.setFrozenRows(1);
  usersSheet.autoResizeColumns(1, 4);
 
  // ========== SHEET BOOKS ==========
  let booksSheet = ss.getSheetByName('Books');
  if (booksSheet) {
    ss.deleteSheet(booksSheet);
  }
  booksSheet = ss.insertSheet('Books');
 
  // Header
  booksSheet.getRange('A1:E1').setValues([['id', 'judul', 'penulis', 'stok', 'coverURL']]);
  booksSheet.getRange('A1:E1').setFontWeight('bold').setBackground('#1e40af').setFontColor('#ffffff');
 
  // Data sampel
  const booksData = [
    ['BK001', 'Laskar Pelangi', 'Andrea Hirata', 8, 'https://images.tokopedia.net/img/cache/500-square/VqbcmM/2021/5/28/d7e6c0e5-c6e7-4e7e-8e0d-0e5c7f4d6e7d.jpg'],
    ['BK002', 'Bumi Manusia', 'Pramoedya Ananta Toer', 5, 'https://cdn.gramedia.com/uploads/items/9789799731234.jpg'],
    ['BK003', 'Sang Pemimpi', 'Andrea Hirata', 6, 'https://cdn.gramedia.com/uploads/items/Sang_Pemimpi.jpg'],
    ['BK004', 'Negeri 5 Menara', 'Ahmad Fuadi', 7, 'https://cdn.gramedia.com/uploads/items/9786020331188_Negeri-5-Menara.jpg'],
    ['BK005', 'Perahu Kertas', 'Dee Lestari', 4, 'https://cdn.gramedia.com/uploads/items/9786024246945_Perahu-Kertas.jpg'],
    ['BK006', 'Ronggeng Dukuh Paruk', 'Ahmad Tohari', 5, 'https://cdn.gramedia.com/uploads/items/9789799101488.jpg'],
    ['BK007', 'Ayat-Ayat Cinta', 'Habiburrahman El Shirazy', 10, 'https://cdn.gramedia.com/uploads/items/9789793062792.jpg'],
    ['BK008', 'Saman', 'Ayu Utami', 3, 'https://cdn.gramedia.com/uploads/items/9786024803520.jpg'],
    ['BK009', 'Pulang', 'Leila S. Chudori', 6, 'https://cdn.gramedia.com/uploads/items/9786024246037.jpg'],
    ['BK010', 'Cantik Itu Luka', 'Eka Kurniawan', 4, 'https://cdn.gramedia.com/uploads/items/9786024246105.jpg'],
    ['BK011', 'The Da Vinci Code', 'Dan Brown', 5, 'https://cdn.gramedia.com/uploads/items/9780307474278.jpg'],
    ['BK012', 'Harry Potter and the Philosopher Stone', 'J.K. Rowling', 8, 'https://cdn.gramedia.com/uploads/items/9781408855652.jpg'],
    ['BK013', 'The Alchemist', 'Paulo Coelho', 7, 'https://cdn.gramedia.com/uploads/items/9780062315007.jpg'],
    ['BK014', '1984', 'George Orwell', 6, 'https://cdn.gramedia.com/uploads/items/9780451524935.jpg'],
    ['BK015', 'To Kill a Mockingbird', 'Harper Lee', 5, 'https://cdn.gramedia.com/uploads/items/9780061120084.jpg']
  ];
  booksSheet.getRange(2, 1, booksData.length, 5).setValues(booksData);
  booksSheet.setFrozenRows(1);
  booksSheet.autoResizeColumns(1, 5);
 
  // ========== SHEET BORROW ==========
  let borrowSheet = ss.getSheetByName('Borrow');
  if (borrowSheet) {
    ss.deleteSheet(borrowSheet);
  }
  borrowSheet = ss.insertSheet('Borrow');
 
  // Header
  borrowSheet.getRange('A1:G1').setValues([['id', 'siswa', 'bukuId', 'judulBuku', 'tanggalPinjam', 'tanggalKembali', 'status']]);
  borrowSheet.getRange('A1:G1').setFontWeight('bold').setBackground('#1e40af').setFontColor('#ffffff');
 
  // Data sampel peminjaman
  const today = new Date();
  const yesterday = new Date(today);
  yesterday.setDate(yesterday.getDate() - 1);
  const twoDaysAgo = new Date(today);
  twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
  const threeDaysAgo = new Date(today);
  threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
  const weekAgo = new Date(today);
  weekAgo.setDate(weekAgo.getDate() - 7);
 
  const borrowData = [
    ['BR001', 'siswa1@sekolah.com', 'BK001', 'Laskar Pelangi', Utilities.formatDate(threeDaysAgo, Session.getScriptTimeZone(), 'dd/MM/yyyy'), '', 'Pending'],
    ['BR002', 'siswa2@sekolah.com', 'BK002', 'Bumi Manusia', Utilities.formatDate(twoDaysAgo, Session.getScriptTimeZone(), 'dd/MM/yyyy'), '', 'Approved'],
    ['BR003', 'siswa3@sekolah.com', 'BK003', 'Sang Pemimpi', Utilities.formatDate(yesterday, Session.getScriptTimeZone(), 'dd/MM/yyyy'), '', 'Pending'],
    ['BR004', 'siswa1@sekolah.com', 'BK004', 'Negeri 5 Menara', Utilities.formatDate(weekAgo, Session.getScriptTimeZone(), 'dd/MM/yyyy'), Utilities.formatDate(yesterday, Session.getScriptTimeZone(), 'dd/MM/yyyy'), 'Returned'],
    ['BR005', 'siswa4@sekolah.com', 'BK005', 'Perahu Kertas', Utilities.formatDate(twoDaysAgo, Session.getScriptTimeZone(), 'dd/MM/yyyy'), '', 'Approved'],
    ['BR006', 'siswa5@sekolah.com', 'BK007', 'Ayat-Ayat Cinta', Utilities.formatDate(today, Session.getScriptTimeZone(), 'dd/MM/yyyy'), '', 'Pending']
  ];
  borrowSheet.getRange(2, 1, borrowData.length, 7).setValues(borrowData);
  borrowSheet.setFrozenRows(1);
  borrowSheet.autoResizeColumns(1, 7);
 
  // Pindahkan sheet ke urutan yang benar
  ss.setActiveSheet(usersSheet);
  ss.moveActiveSheet(1);
  ss.setActiveSheet(booksSheet);
  ss.moveActiveSheet(2);
  ss.setActiveSheet(borrowSheet);
  ss.moveActiveSheet(3);
 
  // Hapus sheet default jika ada
  const defaultSheet = ss.getSheetByName('Sheet1');
  if (defaultSheet && ss.getSheets().length > 3) {
    ss.deleteSheet(defaultSheet);
  }
 
  Logger.log('✅ INISIALISASI BERHASIL!');
  Logger.log('Sheet Users, Books, dan Borrow telah dibuat dengan data sampel.');
  Logger.log('');
  Logger.log('Login Admin:');
  Logger.log('• Email: admin@perpus.com');
  Logger.log('• Password: admin123');
  Logger.log('');
  Logger.log('Login Siswa:');
  Logger.log('• Email: siswa1@sekolah.com');
  Logger.log('• Password: siswa123');
  Logger.log('');
  Logger.log('Silakan deploy aplikasi sebagai Web App!');
 
  return 'Inisialisasi berhasil! Lihat log untuk detail.';
}

// ==================== RENDER HTML ====================
function doGet() {
  return HtmlService.createHtmlOutputFromFile('index')
    .setTitle('Perpustakaan Digital')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
    .addMetaTag("viewport", "width=device-width, initial-scale=1.0")
    .setFaviconUrl('https://w7.pngwing.com/pngs/184/833/png-transparent-exam-test-checklist-online-learning-education-online-document-online-learning-icon.png');
}

// ==================== AUTENTIKASI ====================
function login(email, password) {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
  const data = usersSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === email && data[i][1] === password) {
      return {
        success: true,
        user: {
          email: data[i][0],
          role: data[i][2],
          nama: data[i][3]
        }
      };
    }
  }
 
  return { success: false, message: 'Email atau password salah' };
}

// ==================== FUNGSI BUKU ====================
function getBooks() {
  const ss = getSpreadsheet();
  const booksSheet = ss.getSheetByName('Books');
  const data = booksSheet.getDataRange().getValues();
  const books = [];
 
  for (let i = 1; i < data.length; i++) {
    books.push({
      id: data[i][0],
      judul: data[i][1],
      penulis: data[i][2],
      stok: data[i][3],
      coverURL: data[i][4]
    });
  }
 
  return books;
}

// --- FUNGSI BANTUAN UNTUK UPLOAD KE DRIVE ---
function processFileUpload(fileData) {
  try {
    let folder;
    if (DRIVE_FOLDER_ID) {
      try {
        folder = DriveApp.getFolderById(DRIVE_FOLDER_ID);
      } catch (e) {
        folder = DriveApp.getRootFolder();
      }
    } else {
      folder = DriveApp.getRootFolder();
    }

    const contentType = fileData.mimeType;
    const check = contentType.split('/');
    if (check[0] !== 'image') {
      throw new Error('File harus berupa gambar');
    }

    // Decode base64 string ke blob
    const decoded = Utilities.base64Decode(fileData.data);
    const blob = Utilities.newBlob(decoded, contentType, fileData.fileName);
   
    // Simpan file ke Drive
    const file = folder.createFile(blob);
   
    // PENTING: Set permission agar gambar bisa dilihat di tag <img> HTML
    file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
   
    // Mengembalikan URL yang bisa di-render oleh tag <img>
    return "https://lh3.googleusercontent.com/d/" + file.getId();
   
  } catch (error) {
    throw new Error('Gagal upload gambar: ' + error.toString());
  }
}

// --- MODIFIKASI FUNGSI ADD BOOK ---
function addBook(judul, penulis, stok, coverURL, fileData) {
  const ss = getSpreadsheet();
  const booksSheet = ss.getSheetByName('Books');
 
  // Jika ada file yang diupload, proses upload dulu
  let finalCoverURL = coverURL;
  if (fileData && fileData.data) {
    finalCoverURL = processFileUpload(fileData);
  } else if (!finalCoverURL) {
    // Default image jika tidak ada URL dan tidak ada upload
    finalCoverURL = 'https://via.placeholder.com/200x300/667eea/ffffff?text=No+Cover';
  }

  const lastRow = booksSheet.getLastRow();
  // Generate ID unik yang lebih aman
  const newId = 'BK' + (lastRow + Math.floor(Math.random() * 1000)).toString().padStart(3, '0');
 
  booksSheet.appendRow([newId, judul, penulis, stok, finalCoverURL]);
  return { success: true, message: 'Buku berhasil ditambahkan' };
}

// --- MODIFIKASI FUNGSI UPDATE BOOK ---
function updateBook(id, judul, penulis, stok, coverURL, fileData) {
  const ss = getSpreadsheet();
  const booksSheet = ss.getSheetByName('Books');
  const data = booksSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === id) {
     
      // Logika URL Gambar:
      // 1. Jika ada upload baru (fileData), pakai itu.
      // 2. Jika tidak ada upload, tapi ada coverURL (dari input hidden/text), pakai itu (url lama).
      let finalCoverURL = coverURL;
     
      if (fileData && fileData.data) {
        finalCoverURL = processFileUpload(fileData);
      }
     
      booksSheet.getRange(i + 1, 2, 1, 4).setValues([[judul, penulis, stok, finalCoverURL]]);
      return { success: true, message: 'Buku berhasil diupdate' };
    }
  }
 
  return { success: false, message: 'Buku tidak ditemukan' };
}
function deleteBook(id) {
  const ss = getSpreadsheet();
  const booksSheet = ss.getSheetByName('Books');
  const data = booksSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === id) {
      booksSheet.deleteRow(i + 1);
      return { success: true, message: 'Buku berhasil dihapus' };
    }
  }
 
  return { success: false, message: 'Buku tidak ditemukan' };
}

// ==================== FUNGSI SISWA ====================
function getStudents() {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
  const data = usersSheet.getDataRange().getValues();
  const students = [];
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][2] === 'Siswa') {
      students.push({
        email: data[i][0],
        nama: data[i][3]
      });
    }
  }
 
  return students;
}

function addStudent(email, password, nama) {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
 
  usersSheet.appendRow([email, "'" + password, 'Siswa', nama]);
  return { success: true, message: 'Siswa berhasil ditambahkan' };
}

function updateStudent(oldEmail, newEmail, password, nama) {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
  const data = usersSheet.getDataRange().getValues();
  let studentFound = false;

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === oldEmail && data[i][2] === 'Siswa') {
      // Update nama dan password jika ada
      if (password) {
        usersSheet.getRange(i + 1, 2).setValue("'" + password);
      }
      usersSheet.getRange(i + 1, 4).setValue(nama);
     
      // Jika email juga diubah, panggil fungsi terpisah
      if (oldEmail !== newEmail) {
        updateStudentEmail(oldEmail, newEmail);
      }
     
      studentFound = true;
      return { success: true, message: 'Data siswa berhasil diupdate' };
    }
  }
 
  if (!studentFound) {
    return { success: false, message: 'Siswa tidak ditemukan' };
  }
}

function updateStudentEmail(oldEmail, newEmail) {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
  const borrowSheet = ss.getSheetByName('Borrow');

  // 1. Update di Sheet Users
  const usersData = usersSheet.getDataRange().getValues();
  for (let i = 1; i < usersData.length; i++) {
    if (usersData[i][0] === oldEmail && usersData[i][2] === 'Siswa') {
      usersSheet.getRange(i + 1, 1).setValue(newEmail);
      break;
    }
  }

  // 2. Update di Sheet Borrow
  const borrowData = borrowSheet.getDataRange().getValues();
  for (let i = 1; i < borrowData.length; i++) {
    if (borrowData[i][1] === oldEmail) {
      borrowSheet.getRange(i + 1, 2).setValue(newEmail);
    }
  }
}

function deleteStudent(email) {
  const ss = getSpreadsheet();
  const usersSheet = ss.getSheetByName('Users');
  const data = usersSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === email && data[i][2] === 'Siswa') {
      usersSheet.deleteRow(i + 1);
      return { success: true, message: 'Siswa berhasil dihapus' };
    }
  }
 
  return { success: false, message: 'Siswa tidak ditemukan' };
}

// ==================== FUNGSI PEMINJAMAN ====================
function borrowBook(siswa, bukuId) {
  const ss = getSpreadsheet();
  const borrowSheet = ss.getSheetByName('Borrow');
  const booksSheet = ss.getSheetByName('Books');
 
  // Cek stok buku
  const booksData = booksSheet.getDataRange().getValues();
  let bookFound = false;
  let bookTitle = '';
 
  for (let i = 1; i < booksData.length; i++) {
    if (booksData[i][0] === bukuId) {
      bookFound = true;
      bookTitle = booksData[i][1];
      if (booksData[i][3] <= 0) {
        return { success: false, message: 'Stok buku tidak tersedia' };
      }
      break;
    }
  }
 
  if (!bookFound) {
    return { success: false, message: 'Buku tidak ditemukan' };
  }
 
  const lastRow = borrowSheet.getLastRow();
  const newId = 'BR' + (lastRow).toString().padStart(3, '0');
  const today = new Date();
 
  borrowSheet.appendRow([
    newId,
    siswa,
    bukuId,
    bookTitle,
    Utilities.formatDate(today, Session.getScriptTimeZone(), 'dd/MM/yyyy'),
    '',
    'Pending'
  ]);
 
  return { success: true, message: 'Pengajuan peminjaman berhasil diajukan' };
}

function getBorrowHistory(email, role) {
  const ss = getSpreadsheet();
  const borrowSheet = ss.getSheetByName('Borrow');
  const data = borrowSheet.getDataRange().getDisplayValues();
  const history = [];
 
  for (let i = 1; i < data.length; i++) {
    if (role === 'Siswa' && data[i][1] !== email) continue;
   
    history.push({
      id: data[i][0],
      siswa: data[i][1],
      bukuId: data[i][2],
      judulBuku: data[i][3],
      tanggalPinjam: data[i][4],
      tanggalKembali: data[i][5],
      status: data[i][6]
    });
  }
 
  return history;
}

function approveBorrow(borrowId) {
  const ss = getSpreadsheet();
  const borrowSheet = ss.getSheetByName('Borrow');
  const booksSheet = ss.getSheetByName('Books');
  const data = borrowSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === borrowId) {
      const bukuId = data[i][2];
     
      // Kurangi stok buku
      const booksData = booksSheet.getDataRange().getValues();
      for (let j = 1; j < booksData.length; j++) {
        if (booksData[j][0] === bukuId) {
          const currentStok = booksData[j][3];
          booksSheet.getRange(j + 1, 4).setValue(currentStok - 1);
          break;
        }
      }
     
      borrowSheet.getRange(i + 1, 7).setValue('Approved');
      return { success: true, message: 'Peminjaman disetujui' };
    }
  }
 
  return { success: false, message: 'Data peminjaman tidak ditemukan' };
}

function rejectBorrow(borrowId) {
  const ss = getSpreadsheet();
  const borrowSheet = ss.getSheetByName('Borrow');
  const data = borrowSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === borrowId) {
      borrowSheet.getRange(i + 1, 7).setValue('Rejected');
      return { success: true, message: 'Peminjaman ditolak' };
    }
  }
 
  return { success: false, message: 'Data peminjaman tidak ditemukan' };
}

function returnBook(borrowId) {
  const ss = getSpreadsheet();
  const borrowSheet = ss.getSheetByName('Borrow');
  const booksSheet = ss.getSheetByName('Books');
  const data = borrowSheet.getDataRange().getValues();
 
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === borrowId) {
      const bukuId = data[i][2];
      const today = new Date();
     
      // Tambah stok buku
      const booksData = booksSheet.getDataRange().getValues();
      for (let j = 1; j < booksData.length; j++) {
        if (booksData[j][0] === bukuId) {
          const currentStok = booksData[j][3];
          booksSheet.getRange(j + 1, 4).setValue(currentStok + 1);
          break;
        }
      }
     
      borrowSheet.getRange(i + 1, 6).setValue(Utilities.formatDate(today, Session.getScriptTimeZone(), 'dd/MM/yyyy'));
      borrowSheet.getRange(i + 1, 7).setValue('Returned');
      return { success: true, message: 'Buku berhasil dikembalikan' };
    }
  }
 
  return { success: false, message: 'Data peminjaman tidak ditemukan' };
}

// ==================== STATISTIK ====================
function getStatistics() {
  const ss = getSpreadsheet();
  const booksSheet = ss.getSheetByName('Books');
  const borrowSheet = ss.getSheetByName('Borrow');
  const usersSheet = ss.getSheetByName('Users');
 
  const booksData = booksSheet.getDataRange().getValues();
  const borrowData = borrowSheet.getDataRange().getDisplayValues();
  const usersData = usersSheet.getDataRange().getValues();

  let totalBooks = booksData.length - 1;
  let totalStok = 0;
  for (let i = 1; i < booksData.length; i++) {
    totalStok += booksData[i][3];
  }

  let totalStudents = 0;
  for (let i = 1; i < usersData.length; i++) {
    if (usersData[i][2] === 'Siswa') {
      totalStudents++;
    }
  }
 
  let pending = 0;
  let waitingReturn = 0;
  let returned = 0;
  let rejected = 0;
 
  for (let i = 1; i < borrowData.length; i++) {
    const status = borrowData[i][6];
    if (status === 'Approved') {
      waitingReturn++;
    } else if (status === 'Pending') {
      pending++;
    } else if (status === 'Returned') {
      returned++;
    } else if (status === 'Rejected') {
      rejected++;
    }
  }
 
  return {
    totalBooks: totalBooks,
    totalStok: totalStok,
    totalStudents: totalStudents,
    pending: pending,
    waitingReturn: waitingReturn,
    returned: returned,
    rejected: rejected
  };
}

// ==================== FUNGSI OTORISASI ====================
/**
 * Jalankan fungsi ini sekali dari editor Apps Script untuk memberikan izin akses ke Google Drive.
 */
function authorizeDrive() {
  try {
    DriveApp.getRootFolder();
    Logger.log('✅ Otorisasi Google Drive berhasil!');
  } catch (e) {
    Logger.log('🛑 Gagal memberikan otorisasi: ' + e.toString());
    Logger.log('Silakan jalankan fungsi ini lagi dan pastikan Anda menyetujui semua izin yang diminta.');
  }
}


Index.html


<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Perpustakaan Digital</title>
  <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Inter', sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
    }

    /* ==================== LOGIN PAGE ==================== */
    .login-container {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      padding: 20px;
      position: relative;
      overflow: hidden;
    }

    .login-container::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: url('https://images.unsplash.com/photo-1521587760476-6c12a4b040da?ixlib=rb-4.0.3&auto=format&fit=crop&w=2070&q=80') center/cover no-repeat;
      filter: brightness(0.4);
      z-index: 0;
    }

    .login-container::after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 1;
    }

    .login-box {
      position: relative;
      z-index: 2;
      background: rgba(255, 255, 255, 0.15);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
      border: 1px solid rgba(255, 255, 255, 0.3);
      padding: 50px 40px;
      border-radius: 24px;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 
                  inset 0 1px 0 rgba(255, 255, 255, 0.3);
      width: 100%;
      max-width: 440px;
      animation: fadeInUp 0.6s ease-out;
    }

    @keyframes fadeInUp {
      from {
        opacity: 0;
        transform: translateY(30px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .login-header {
      text-align: center;
      margin-bottom: 40px;
    }

    .login-header::before {
      content: '📚';
      font-size: 64px;
      display: block;
      margin-bottom: 16px;
      animation: float 3s ease-in-out infinite;
    }

    @keyframes float {
      0%, 100% {
        transform: translateY(0px);
      }
      50% {
        transform: translateY(-10px);
      }
    }

    .login-header h1 {
      color: white;
      font-size: 32px;
      margin-bottom: 8px;
      font-weight: 700;
      text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
      letter-spacing: -0.5px;
    }

    .login-header p {
      color: rgba(255, 255, 255, 0.9);
      font-size: 15px;
      text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
    }

    .form-group {
      margin-bottom: 24px;
    }

    .form-group label {
      display: block;
      margin-bottom: 10px;
      color: white;
      font-weight: 600;
      font-size: 14px;
      text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
      letter-spacing: 0.3px;
    }

    .form-group input {
      width: 100%;
      padding: 14px 20px;
      border: 2px solid rgba(255, 255, 255, 0.3);
      background: rgba(255, 255, 255, 0.2);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      border-radius: 12px;
      font-size: 15px;
      transition: all 0.3s;
      color: white;
      font-weight: 500;
    }

    .form-group input::placeholder {
      color: rgba(255, 255, 255, 0.6);
    }

    .form-group input:focus {
      outline: none;
      border-color: rgba(255, 255, 255, 0.6);
      background: rgba(255, 255, 255, 0.25);
      box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.1),
                  0 8px 20px rgba(0, 0, 0, 0.2);
      transform: translateY(-2px);
    }
    
    /* MODAL FORM OVERRIDES */
    .modal .form-group label {
        color: #475569;
        text-shadow: none;
    }
    .modal .form-group input {
        color: #1e293b;
        background: #f8fafc;
        border: 1px solid #e2e8f0;
        backdrop-filter: none;
    }
    .modal .form-group input::placeholder {
      color: #94a3b8;
    }
    .modal .form-group input:focus {
        border-color: #667eea;
        background: white;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
        transform: none;
    }
    .modal .btn-primary {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
    }
    .modal .btn-primary:hover {
        background: linear-gradient(135deg, #5a6fd8 0%, #683a92 100%);
    }

    .btn {
      width: 100%;
      padding: 14px;
      border: none;
      border-radius: 12px;
      font-size: 16px;
      font-weight: 700;
      cursor: pointer;
      transition: all 0.3s;
      letter-spacing: 0.5px;
      text-transform: uppercase;
    }

    .btn-primary {
      background: rgba(255, 255, 255, 0.95);
      color: #667eea;
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
      position: relative;
      overflow: hidden;
    }

    .btn-primary::before {
      content: '';
      position: absolute;
      top: 0;
      left: -100%;
      width: 100%;
      height: 100%;
      background: linear-gradient(90deg, transparent, rgba(102, 126, 234, 0.3), transparent);
      transition: left 0.5s;
    }

    .btn-primary:hover {
      transform: translateY(-3px);
      box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
      background: white;
    }

    .btn-primary:hover::before {
      left: 100%;
    }

    .btn-primary:active {
      transform: translateY(-1px);
    }

    .btn-loading {
        cursor: not-allowed !important;
        background: #ccc !important;
        box-shadow: none !important;
        transform: none !important;
    }

    .btn-loading .btn-text {
        visibility: hidden;
        opacity: 0;
    }

    .btn-loading .spinner {
        display: inline-block;
        opacity: 1;
    }

    .spinner {
        display: none;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 20px;
        height: 20px;
        border: 2px solid rgba(102, 126, 234, 0.5);
        border-top-color: #667eea;
        border-radius: 50%;
        animation: spin 1s linear infinite;
        opacity: 0;
        transition: opacity 0.3s;
    }

    @keyframes spin {
        to {
            transform: translate(-50%, -50%) rotate(360deg);
        }
    }

    /* ==================== DASHBOARD LAYOUT ==================== */
    .dashboard {
      display: none;
      min-height: 100vh;
      background: #f1f5f9;
    }

    body.dashboard-open {
      overflow: hidden; /* Prevent scrolling when dashboard is open */
    }
    
    .wrapper {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
        background: #f1f5f9;
    }

    .sidebar {
      position: fixed;
      left: 0;
      top: 0;
      bottom: 0;
      width: 260px;
      background: linear-gradient(180deg, #2c3e95 0%, #1e2b6f 100%);
      padding: 0;
      overflow-y: auto;
      z-index: 1000;
      box-shadow: 4px 0 12px rgba(0, 0, 0, 0.15);
      transition: width 0.3s ease;
    }

    .main-header {
      position: fixed;
      top: 0;
      left: 260px;
      right: 0;
      background: white;
      padding: 20px;
      z-index: 999;
      display: flex;
      justify-content: space-between;
      align-items: center;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      transition: left 0.3s ease;
    }

    .content-wrapper {
      margin-left: 260px;
      margin-top: 100px; /* Height of main-header + some padding */
      padding: 20px;
      transition: margin-left 0.3s ease;
    }
    
    /* Collapsed state */
    body.sidebar-collapsed .sidebar {
      width: 80px;
    }
    
    body.sidebar-collapsed .sidebar .sidebar-header h2,
    body.sidebar-collapsed .sidebar .sidebar-header p,
    body.sidebar-collapsed .sidebar .menu-item span:not(.material-icons),
    body.sidebar-collapsed .sidebar .menu-label,
    body.sidebar-collapsed .sidebar .menu-badge {
      display: none;
    }

    body.sidebar-collapsed .sidebar .menu-item {
      justify-content: center;
    }
    
    body.sidebar-collapsed .sidebar .menu-item .material-icons {
      margin-right: 0;
    }

    body.sidebar-collapsed .main-header {
      left: 80px;
    }
    
    body.sidebar-collapsed .content-wrapper {
      margin-left: 80px;
    }

    .sidebar-toggle {
        background: none;
        border: none;
        color: #334155;
        cursor: pointer;
        font-size: 24px;
        margin-right: 16px;
    }

    .header-left {
        display: flex;
        align-items: center;
    }

    .top-bar-left { /* Keep for backward compatibility */
        display: flex;
        align-items: center;
    }

    .sidebar-header {
      background: linear-gradient(135deg, #4154b3 0%, #2c3e95 100%);
      color: white;
      padding: 24px 20px;
      border-bottom: 1px solid rgba(255, 255, 255, 0.1);
      margin-bottom: 8px;
      text-align: center;
    }

    .sidebar-logo {
      width: 50px;
      height: 50px;
      background: white;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0 auto 12px;
      font-size: 28px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    }

    .sidebar-header h2 {
      font-size: 18px;
      margin-bottom: 4px;
      font-weight: 700;
      letter-spacing: 0.3px;
    }

    .sidebar-header p {
      font-size: 12px;
      opacity: 0.85;
      font-weight: 400;
    }

    .menu-section {
      padding: 0 12px;
      margin-bottom: 8px;
    }

    .menu-label {
      color: rgba(255, 255, 255, 0.5);
      font-size: 11px;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 1px;
      padding: 16px 16px 8px;
    }

    .menu-item {
      display: flex;
      align-items: center;
      padding: 13px 16px;
      color: rgba(255, 255, 255, 0.85);
      text-decoration: none;
      border-radius: 10px;
      margin-bottom: 4px;
      transition: all 0.3s;
      cursor: pointer;
      font-size: 14px;
      font-weight: 500;
      position: relative;
    }

    .menu-item:hover {
      background: rgba(255, 255, 255, 0.1);
      color: white;
      transform: translateX(4px);
    }

    .menu-item.active {
      background: linear-gradient(135deg, #5b6fd8 0%, #4154b3 100%);
      color: white;
      box-shadow: 0 4px 12px rgba(91, 111, 216, 0.4);
    }

    .menu-item.active::before {
      content: '';
      position: absolute;
      left: 0;
      top: 50%;
      transform: translateY(-50%);
      width: 4px;
      height: 70%;
      background: white;
      border-radius: 0 4px 4px 0;
    }

    .menu-item .material-icons {
      margin-right: 14px;
      font-size: 22px;
    }

    .menu-badge {
      margin-left: auto;
      background: #ef4444;
      color: white;
      font-size: 11px;
      font-weight: 700;
      padding: 2px 8px;
      border-radius: 10px;
      min-width: 20px;
      text-align: center;
    }



    .top-bar-left h3 {
      color: #1e293b;
      font-size: 26px;
      font-weight: 700;
      margin-bottom: 4px;
    }

    .top-bar-subtitle {
      color: #64748b;
      font-size: 14px;
      display: flex;
      align-items: center;
      gap: 6px;
    }

    .top-bar-subtitle .material-icons {
      font-size: 16px;
    }

    .user-info {
      display: flex;
      align-items: center;
      gap: 16px;
      background: #f8fafc;
      padding: 10px 16px;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
      cursor: pointer;
      transition: background-color 0.2s;
    }
    
    .user-info:hover {
        background-color: #f1f5f9;
    }

    .user-menu-container {
      position: relative;
    }

    .dropdown-menu {
      display: none;
      position: absolute;
      top: 110%;
      right: 0;
      background: white;
      border-radius: 8px;
      box-shadow: 0 4px 20px rgba(0,0,0,0.15);
      padding: 8px;
      z-index: 1200;
      width: 100%;
    }
    
    .user-menu-container.open .dropdown-menu {
      display: block;
    }

    .dropdown-menu .logout-btn {
        width: 100%;
        justify-content: center;
    }


    .user-avatar {
      width: 42px;
      height: 42px;
      border-radius: 50%;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: 700;
      font-size: 16px;
      box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
    }

    .user-details {
      display: flex;
      flex-direction: column;
    }

    .user-name {
      font-weight: 600;
      color: #1e293b;
      font-size: 14px;
    }

    .user-role {
      font-size: 12px;
      color: #64748b;
      display: flex;
      align-items: center;
      gap: 4px;
    }

    .user-role .material-icons {
      font-size: 14px;
      color: #10b981;
    }

    .logout-btn {
      padding: 10px 20px;
      background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
      color: white;
      border: none;
      border-radius: 10px;
      cursor: pointer;
      font-size: 14px;
      font-weight: 600;
      transition: all 0.3s;
      display: flex;
      align-items: center;
      gap: 6px;
      box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
    }

    .logout-btn:hover {
      background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
      transform: translateY(-2px);
      box-shadow: 0 6px 16px rgba(239, 68, 68, 0.4);
    }

    .logout-btn .material-icons {
      font-size: 18px;
    }

    /* ==================== STATS CARDS ==================== */
    .stats-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
      gap: 20px;
      margin-bottom: 24px;
    }

    .stat-card {
      background: white;
      padding: 24px;
      border-radius: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
      display: flex;
      align-items: center;
      gap: 16px;
      transition: all 0.3s;
    }

    .stat-card:hover {
      transform: translateY(-4px);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    }

    .stat-icon {
      width: 60px;
      height: 60px;
      border-radius: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 28px;
    }

    .stat-icon.blue {
      background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
      color: white;
    }

    .stat-icon.green {
      background: linear-gradient(135deg, #10b981 0%, #059669 100%);
      color: white;
    }

    .stat-icon.red {
      background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
      color: white;
    }

    .stat-icon.purple {
      background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
      color: white;
    }

    .stat-icon.orange {
      background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
      color: white;
    }

    .stat-icon.teal {
      background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%);
      color: white;
    }

    .stat-icon.cyan {
      background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%);
      color: white;
    }

    .stat-icon.pink {
      background: linear-gradient(135deg, #ec4899 0%, #d946ef 100%);
      color: white;
    }

    .stat-info h4 {
      color: #64748b;
      font-size: 13px;
      font-weight: 500;
      margin-bottom: 4px;
    }

    .stat-info .stat-value {
      color: #1e293b;
      font-size: 28px;
      font-weight: 700;
    }

    /* ==================== CONTENT CARD ==================== */
    .content-card {
      background: white;
      padding: 24px;
      border-radius: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
      margin-bottom: 24px;
    }

    .card-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
    }

    .card-header h4 {
      color: #1e293b;
      font-size: 18px;
      font-weight: 600;
    }

    .btn-add {
      padding: 10px 20px;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 14px;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 6px;
      transition: all 0.3s;
    }

    .btn-add:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
    }

    .table-controls {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 16px;
      flex-wrap: wrap;
      gap: 12px;
    }

    .search-container {
      position: relative;
    }

    .search-container input {
      padding: 8px 12px 8px 36px;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 14px;
    }

    .search-container .material-icons {
      position: absolute;
      left: 10px;
      top: 50%;
      transform: translateY(-50%);
      color: #94a3b8;
      font-size: 20px;
    }

    .page-size-container {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 14px;
      color: #475569;
    }

    .page-size-container select {
      padding: 8px 12px;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      font-size: 14px;
    }

    .table-footer {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-top: 16px;
      padding-top: 16px;
      border-top: 1px solid #e2e8f0;
      flex-wrap: wrap;
      gap: 12px;
    }

    .pagination-info {
      font-size: 14px;
      color: #475569;
    }

    .pagination-controls button {
      padding: 6px 12px;
      border: 1px solid #e2e8f0;
      background: white;
      border-radius: 6px;
      cursor: pointer;
      margin-left: 4px;
      transition: background-color 0.2s;
    }

    .pagination-controls button:hover:not(:disabled) {
      background-color: #f8fafc;
    }

    .pagination-controls button:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }

    /* ==================== TABLE ==================== */
    .table-container {
      overflow-x: auto;
    }

    table {
      width: 100%;
      border-collapse: collapse;
    }

    thead {
      background: #f8fafc;
    }

    th {
      padding: 12px;
      text-align: left;
      color: #475569;
      font-weight: 600;
      font-size: 13px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    td {
      padding: 12px;
      border-top: 1px solid #e2e8f0;
      color: #334155;
      font-size: 14px;
    }

    tr:hover {
      background: #f8fafc;
    }

    /* ==================== BADGES ==================== */
    .badge {
      display: inline-block;
      padding: 4px 12px;
      border-radius: 12px;
      font-size: 12px;
      font-weight: 600;
    }

    .badge.pending {
      background: #fef3c7;
      color: #92400e;
    }

    .badge.approved {
      background: #d1fae5;
      color: #065f46;
    }

    .badge.rejected {
      background: #fee2e2;
      color: #991b1b;
    }

    .badge.returned {
      background: #dbeafe;
      color: #1e40af;
    }

    /* ==================== ACTION BUTTONS ==================== */
    .action-btn {
      padding: 6px 12px;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 12px;
      font-weight: 500;
      margin-right: 6px;
      transition: all 0.3s;
    }

    .btn-approve {
      background: #10b981;
      color: white;
    }

    .btn-approve:hover {
      background: #059669;
    }

    .btn-reject {
      background: #ef4444;
      color: white;
    }

    .btn-reject:hover {
      background: #dc2626;
    }

    .btn-edit {
      background: #3b82f6;
      color: white;
    }

    .btn-edit:hover {
      background: #2563eb;
    }

    .btn-delete {
      background: #ef4444;
      color: white;
    }

    .btn-delete:hover {
      background: #dc2626;
    }

    .btn-return {
      background: #8b5cf6;
      color: white;
    }

    .btn-return:hover {
      background: #7c3aed;
    }

    .btn-borrow {
      background: #10b981;
      color: white;
    }

    .btn-borrow:hover {
      background: #059669;
    }

    /* ==================== MODAL ==================== */
    .modal {
      display: none;
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.5);
      z-index: 2000;
      align-items: center;
      justify-content: center;
    }

    .modal-content {
      background: white;
      padding: 30px;
      border-radius: 16px;
      width: 90%;
      max-width: 500px;
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
      max-height: 80vh; /* Add this line */
      overflow-y: auto; /* Add this line */
    }

    .modal-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
    }

    .modal-header h3 {
      color: #1e293b;
      font-size: 20px;
    }

    .close-modal {
      background: none;
      border: none;
      font-size: 24px;
      cursor: pointer;
      color: #64748b;
    }

    /* ==================== BOOKS GRID ==================== */
    .books-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
      gap: 20px;
    }

    .book-card {
      background: white;
      border-radius: 12px;
      overflow: hidden;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
      transition: all 0.3s;
    }

    .book-card:hover {
      transform: translateY(-4px);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    }

    .book-cover {
      width: 100%;
      height: 250px;
      object-fit: cover;
      background: #e2e8f0;
    }

    .book-info {
      padding: 16px;
    }

    .book-info h5 {
      color: #1e293b;
      font-size: 16px;
      margin-bottom: 6px;
      font-weight: 600;
    }

    .book-info p {
      color: #64748b;
      font-size: 13px;
      margin-bottom: 4px;
    }

    .book-stok {
      display: flex;
      align-items: center;
      gap: 6px;
      color: #10b981;
      font-size: 13px;
      font-weight: 600;
      margin-top: 8px;
    }

    .hidden {
      display: none !important;
    }

    /* ==================== LOADING ==================== */
    .loading {
      text-align: center;
      padding: 40px;
      color: #64748b;
    }

    /* ==================== RESPONSIVE ==================== */
    .sidebar-overlay {
      display: none;
    }

    @media (max-width: 768px) {
      body.sidebar-mobile-active .sidebar-overlay {
        display: block;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0,0,0,0.5);
        z-index: 1099; /* Below sidebar but above content */
      }
    
      .main-header {
        position: static;
        left: 0;
        width: 100%;
      }
      
      .content-wrapper {
        margin-left: 0;
        margin-top: 20px;
      }
      
      .sidebar {
        transform: translateX(-100%);
        z-index: 1100; /* Ensure sidebar is on top */
      }
      
      body.sidebar-mobile-active .sidebar {
        transform: translateX(0);
      }

      body.sidebar-collapsed .sidebar {
          transform: translateX(-100%); /* Ensure it's hidden when toggling on desktop then resizing */
      }
      
      body.sidebar-collapsed .main-header, body.sidebar-collapsed .content-wrapper {
        left: 0;
        margin-left: 0;
      }

      .stats-grid {
        grid-template-columns: 1fr;
      }
    }
  </style>
</head>
<body>
  <!-- ==================== LOGIN PAGE ==================== -->
  <div id="loginPage" class="login-container">
    <div class="login-box">
      <div class="login-header">
        <h1>Perpustakaan Digital</h1>
        <p>Silakan masuk untuk melanjutkan</p>
      </div>
      <form id="loginForm">
        <div class="form-group">
          <label>Email</label>
          <input type="email" id="emailInput" required placeholder="nama@email.com">
        </div>
        <div class="form-group">
          <label>Password</label>
          <input type="password" id="passwordInput" required placeholder="Masukkan password">
        </div>
        <button type="submit" class="btn btn-primary">
          <span class="btn-text">Masuk</span>
          <span class="spinner"></span>
        </button>
      </form>
    </div>
  </div>

  <!-- ==================== ADMIN DASHBOARD ==================== -->
  <div id="adminDashboard" class="dashboard">
    <div class="wrapper">
      <div class="sidebar-overlay" onclick="toggleSidebar()"></div>
      <div class="sidebar">
        <div class="sidebar-header">
          <div class="sidebar-logo">📚</div>
          <h2>Perpustakaan Digital</h2>
          <p>Admin Panel</p>
        </div>
        <div class="menu-section">
          <div class="menu-label">Menu Utama</div>
          <div class="menu-item active" onclick="showSection('dashboard')">
            <span class="material-icons">dashboard</span>
            <span>Dashboard</span>
          </div>
          <div class="menu-item" onclick="showSection('borrowRequests')">
            <span class="material-icons">pending_actions</span>
            <span>Peminjaman Pending</span>
            <span class="menu-badge" id="pendingBadge">0</span>
          </div>
          <div class="menu-item" onclick="showSection('allBorrows')">
            <span class="material-icons">history</span>
            <span>Riwayat Peminjaman</span>
          </div>
        </div>
        <div class="menu-section">
          <div class="menu-label">Kelola Data</div>
          <div class="menu-item" onclick="showSection('masterBooks')">
            <span class="material-icons">menu_book</span>
            <span>Master Buku</span>
          </div>
          <div class="menu-item" onclick="showSection('masterStudents')">
            <span class="material-icons">people</span>
            <span>Master Siswa</span>
          </div>
        </div>
      </div>

      <header class="main-header">
        <div class="header-left">
          <button class="sidebar-toggle" onclick="toggleSidebar()">
            <span class="material-icons">menu</span>
          </button>
          <div class="top-bar-left">
            <h3 id="pageTitle">Dashboard</h3>
          </div>
        </div>
        <div class="user-menu-container">
          <div class="user-info" onclick="toggleUserMenu()">
            <div class="user-avatar" id="adminAvatar">A</div>
            <div class="user-details">
              <span class="user-name" id="adminName">Administrator</span>
              <span class="user-role">
                <span class="material-icons">verified</span>
                Admin
              </span>
            </div>
          </div>
          <div class="dropdown-menu" id="adminUserMenu">
            <button class="logout-btn" onclick="logout()">
              <span class="material-icons">logout</span>
              <span>Keluar</span>
            </button>
          </div>
        </div>
      </header>

      <main class="content-wrapper">
        <!-- Dashboard Stats -->
        <div id="dashboardSection">
          <div class="stats-grid">
            <div class="stat-card">
              <div class="stat-icon blue">
                <span class="material-icons">menu_book</span>
              </div>
              <div class="stat-info">
                <h4>Total Judul Buku</h4>
                <div class="stat-value" id="totalBooks">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon cyan">
                <span class="material-icons">inventory_2</span>
              </div>
              <div class="stat-info">
                <h4>Total Stok Buku</h4>
                <div class="stat-value" id="totalStock">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon orange">
                <span class="material-icons">groups</span>
              </div>
              <div class="stat-info">
                <h4>Total Siswa</h4>
                <div class="stat-value" id="totalStudents">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon red">
                <span class="material-icons">pending</span>
              </div>
              <div class="stat-info">
                <h4>Peminjaman Pending</h4>
                <div class="stat-value" id="pendingBorrows">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon purple">
                <span class="material-icons">assignment_turned_in</span>
              </div>
              <div class="stat-info">
                <h4>Menunggu Pengembalian</h4>
                <div class="stat-value" id="waitingReturn">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon green">
                <span class="material-icons">assignment_return</span>
              </div>
              <div class="stat-info">
                <h4>Buku Dikembalikan</h4>
                <div class="stat-value" id="returnedBooks">0</div>
              </div>
            </div>
            <div class="stat-card">
              <div class="stat-icon pink">
                <span class="material-icons">cancel</span>
              </div>
              <div class="stat-info">
                <h4>Peminjaman Ditolak</h4>
                <div class="stat-value" id="rejectedBorrows">0</div>
              </div>
            </div>
          </div>
        </div>

        <!-- Borrow Requests -->
        <div id="borrowRequestsSection" class="hidden">
          <div class="content-card">
            <div class="card-header">
              <h4>Pengajuan Peminjaman</h4>
              <div class="table-controls">
                <div class="search-container">
                  <span class="material-icons">search</span>
                  <input type="text" id="borrowRequestsSearch" placeholder="Cari...">
                </div>
                <div class="page-size-container">
                  <span>Tampilkan:</span>
                  <select id="borrowRequestsPageSize">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                    <option value="all">Semua</option>
                  </select>
                </div>
              </div>
            </div>
            <div class="table-container">
              <table id="borrowRequestsTable">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Siswa</th>
                    <th>Buku</th>
                    <th>Tanggal Pinjam</th>
                    <th>Status</th>
                    <th>Aksi</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            </div>
            <div class="table-footer">
              <div id="borrowRequestsPaginationInfo" class="pagination-info"></div>
              <div class="pagination-controls">
                <button id="borrowRequestsPrevPage">Sebelumnya</button>
                <button id="borrowRequestsNextPage">Berikutnya</button>
              </div>
            </div>
          </div>
        </div>

        <!-- All Borrows -->
        <div id="allBorrowsSection" class="hidden">
          <div class="content-card">
            <div class="card-header">
              <h4>Riwayat Peminjaman</h4>
              <div class="table-controls">
                <div class="search-container">
                  <span class="material-icons">search</span>
                  <input type="text" id="allBorrowsSearch" placeholder="Cari...">
                </div>
                <div class="page-size-container">
                  <span>Tampilkan:</span>
                  <select id="allBorrowsPageSize">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                    <option value="all">Semua</option>
                  </select>
                </div>
              </div>
            </div>
            <div class="table-container">
              <table id="allBorrowsTable">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Siswa</th>
                    <th>Buku</th>
                    <th>Tanggal Pinjam</th>
                    <th>Tanggal Kembali</th>
                    <th>Status</th>
                    <th>Aksi</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            </div>
            <div class="table-footer">
              <div id="allBorrowsPaginationInfo" class="pagination-info"></div>
              <div class="pagination-controls">
                <button id="allBorrowsPrevPage">Sebelumnya</button>
                <button id="allBorrowsNextPage">Berikutnya</button>
              </div>
            </div>
          </div>
        </div>

        <!-- Master Books -->
        <div id="masterBooksSection" class="hidden">
          <div class="content-card">
            <div class="card-header">
              <h4>Master Buku</h4>
               <div class="table-controls">
                <div class="search-container">
                  <span class="material-icons">search</span>
                  <input type="text" id="masterBooksSearch" placeholder="Cari...">
                </div>
                <div class="page-size-container">
                  <span>Tampilkan:</span>
                  <select id="masterBooksPageSize">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                    <option value="all">Semua</option>
                  </select>
                </div>
                 <button class="btn-add" onclick="openAddBookModal()">
                    <span class="material-icons">add</span>
                    Tambah Buku
                </button>
              </div>
            </div>
            <div class="table-container">
              <table id="masterBooksTable">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Judul</th>
                    <th>Penulis</th>
                    <th>Stok</th>
                    <th>Aksi</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            </div>
            <div class="table-footer">
                <div id="masterBooksPaginationInfo" class="pagination-info"></div>
                <div class="pagination-controls">
                    <button id="masterBooksPrevPage">Sebelumnya</button>
                    <button id="masterBooksNextPage">Berikutnya</button>
                </div>
            </div>
          </div>
        </div>

        <!-- Master Students -->
        <div id="masterStudentsSection" class="hidden">
          <div class="content-card">
            <div class="card-header">
              <h4>Master Siswa</h4>
              <div class="table-controls">
                <div class="search-container">
                  <span class="material-icons">search</span>
                  <input type="text" id="masterStudentsSearch" placeholder="Cari...">
                </div>
                <div class="page-size-container">
                  <span>Tampilkan:</span>
                  <select id="masterStudentsPageSize">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                    <option value="all">Semua</option>
                  </select>
                </div>
                <button class="btn-add" onclick="openAddStudentModal()">
                    <span class="material-icons">add</span>
                    Tambah Siswa
                </button>
              </div>
            </div>
            <div class="table-container">
              <table id="masterStudentsTable">
                <thead>
                  <tr>
                    <th>Email</th>
                    <th>Nama</th>
                    <th>Aksi</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            </div>
             <div class="table-footer">
                <div id="masterStudentsPaginationInfo" class="pagination-info"></div>
                <div class="pagination-controls">
                    <button id="masterStudentsPrevPage">Sebelumnya</button>
                    <button id="masterStudentsNextPage">Berikutnya</button>
                </div>
            </div>
          </div>
        </div>
      </main>
    </div>
  </div>

  <!-- ==================== STUDENT DASHBOARD ==================== -->
  <div id="studentDashboard" class="dashboard">
    <div class="wrapper">
      <div class="sidebar-overlay" onclick="toggleSidebar()"></div>
      <div class="sidebar">
        <div class="sidebar-header">
          <div class="sidebar-logo">📚</div>
          <h2>Perpustakaan Digital</h2>
          <p>Siswa Panel</p>
        </div>
        <div class="menu-section">
          <div class="menu-label">Menu Utama</div>
          <div class="menu-item active" onclick="showStudentSection('studentBooks')">
            <span class="material-icons">menu_book</span>
            <span>Daftar Buku</span>
          </div>
          <div class="menu-item" onclick="showStudentSection('studentBorrows')">
            <span class="material-icons">history</span>
            <span>Riwayat Peminjaman</span>
          </div>
        </div>
      </div>

      <header class="main-header">
        <div class="header-left">
          <button class="sidebar-toggle" onclick="toggleSidebar()">
            <span class="material-icons">menu</span>
          </button>
          <div class="top-bar-left">
            <h3 id="studentPageTitle">Daftar Buku</h3>
          </div>
        </div>
        <div class="user-menu-container">
          <div class="user-info" onclick="toggleUserMenu()">
            <div class="user-avatar" id="studentAvatar">S</div>
            <div class="user-details">
              <span class="user-name" id="studentName">Siswa</span>
              <span class="user-role">
                <span class="material-icons">school</span>
                Siswa
              </span>
            </div>
          </div>
          <div class="dropdown-menu" id="studentUserMenu">
            <button class="logout-btn" onclick="logout()">
              <span class="material-icons">logout</span>
              <span>Keluar</span>
            </button>
          </div>
        </div>
      </header>

      <main class="content-wrapper">
        <!-- Student Books -->
        <div id="studentBooksSection">
          <div class="content-card">
            <div class="card-header">
              <h4>Daftar Buku Tersedia</h4>
            </div>
            <div class="books-grid" id="studentBooksGrid"></div>
          </div>
        </div>

        <!-- Student Borrows -->
        <div id="studentBorrowsSection" class="hidden">
          <div class="content-card">
            <div class="card-header">
              <h4>Riwayat Peminjaman Saya</h4>
            </div>
            <div class="table-container">
              <table id="studentBorrowsTable">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Buku</th>
                    <th>Tanggal Pinjam</th>
                    <th>Tanggal Kembali</th>
                    <th>Status</th>
                  </tr>
                </thead>
                <tbody></tbody>
              </table>
            </div>
          </div>
        </div>
      </main>
    </div>
  </div>

  <!-- ==================== MODALS ==================== -->
  <!-- Add/Edit Book Modal -->
  <div id="bookModal" class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <h3 id="bookModalTitle">Tambah Buku</h3>
        <button class="close-modal" onclick="closeModal('bookModal')">&times;</button>
      </div>
<form id="bookForm">
  <input type="hidden" id="bookId">
  <input type="hidden" id="currentBookUrl"> 
  
  <div class="form-group">
    <label>Judul Buku</label>
    <input type="text" id="bookJudul" required>
  </div>
  <div class="form-group">
    <label>Penulis</label>
    <input type="text" id="bookPenulis" required>
  </div>
  <div class="form-group">
    <label>Stok</label>
    <input type="number" id="bookStok" required min="0">
  </div>
  
  <div class="form-group">
    <label>Cover Buku (Upload Gambar)</label>
    <input type="file" id="bookCoverFile" accept="image/*">
    <div style="margin-top: 5px; font-size: 12px; color: #64748b;">
       Atau masukkan URL manual (opsional):
    </div>
    <input type="text" id="bookCoverUrlInput" placeholder="https://...">
    
    <div id="imagePreviewContainer" style="margin-top: 10px; display: none;">
        <p style="font-size: 12px; margin-bottom: 5px;">Preview:</p>
        <img id="imagePreview" src="" style="max-width: 100px; max-height: 150px; border-radius: 8px; border: 1px solid #ddd;">
    </div>
  </div>

  <button type="submit" class="btn btn-primary">Simpan</button>
</form>
    </div>
  </div>

  <!-- Add/Edit Student Modal -->
  <div id="studentModal" class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <h3 id="studentModalTitle">Tambah Siswa</h3>
        <button class="close-modal" onclick="closeModal('studentModal')">&times;</button>
      </div>
      <form id="studentForm">
        <input type="hidden" id="studentEmailOld">
        <div class="form-group">
          <label>Email</label>
          <input type="email" id="studentEmail" required>
        </div>
        <div class="form-group">
          <label>Password</label>
          <input type="password" id="studentPassword" required>
        </div>
        <div class="form-group">
          <label>Nama Lengkap</label>
          <input type="text" id="studentNama" required>
        </div>
<button type="submit" class="btn btn-primary">
          <span class="btn-text">Simpan</span>
          <span class="spinner"></span>
        </button>
      </form>
    </div>
  </div>

<script>
    // ==================== GLOBAL VARIABLES ====================
    let currentUser = null;

    // ==================== UTILITY FUNCTIONS ====================
    function toggleUserMenu() {
      const menuContainer = event.currentTarget.closest('.user-menu-container');
      if (menuContainer) {
        menuContainer.classList.toggle('open');
      }
    }

    window.addEventListener('click', function(e) {
      document.querySelectorAll('.user-menu-container.open').forEach(function(menu) {
        if (!menu.contains(e.target)) {
          menu.classList.remove('open');
        }
      });
    });

    function updateCurrentDate() {
      const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
      const date = new Date().toLocaleDateString('id-ID', options);
      const dateElement = document.getElementById('currentDate'); // Pastikan ID ini ada di HTML header jika ingin tampil
      // Opsional: Tampilkan tanggal di elemen lain jika ada
    }

    function toggleSidebar() {
      if (window.innerWidth <= 768) {
        document.body.classList.toggle('sidebar-mobile-active');
      } else {
        document.body.classList.toggle('sidebar-collapsed');
      }
    }

    function showResultAlert(result) {
        Swal.fire({
            title: result.success ? 'Berhasil' : 'Gagal',
            text: result.message,
            icon: result.success ? 'success' : 'error',
            timer: result.success ? 1500 : 3000,
            showConfirmButton: false,
        });
    }

    function closeModal(modalId) {
      document.getElementById(modalId).style.display = 'none';
    }

    // Close modal when clicking outside
    window.onclick = function(event) {
      if (event.target.classList.contains('modal')) {
        event.target.style.display = 'none';
      }
    }

    // ==================== IMAGE UPLOAD UTILITIES ====================
    // Fungsi mengubah File menjadi Base64 String
    function getBase64(file) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
          // Ambil string setelah tanda koma (hapus prefix data:image/...)
          resolve(reader.result.split(',')[1]);
        };
        reader.onerror = error => reject(error);
      });
    }

    // Event listener untuk preview gambar saat file dipilih
    const fileInput = document.getElementById('bookCoverFile');
    if(fileInput){
        fileInput.addEventListener('change', function(e) {
            const file = e.target.files[0];
            const previewContainer = document.getElementById('imagePreviewContainer');
            const previewImage = document.getElementById('imagePreview');
            
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    previewImage.src = e.target.result;
                    previewContainer.style.display = 'block';
                }
                reader.readAsDataURL(file);
            }
        });
    }

    // ==================== SESSION MANAGEMENT ====================
    function checkSession() {
      const storedUser = sessionStorage.getItem('currentUser');
      if (storedUser) {
        currentUser = JSON.parse(storedUser);
        document.getElementById('loginPage').style.display = 'none';
        
        if (currentUser.role === 'Admin') {
          document.getElementById('adminDashboard').style.display = 'block';
          document.getElementById('adminName').textContent = currentUser.nama;
          document.getElementById('adminAvatar').textContent = currentUser.nama.charAt(0).toUpperCase();
          updateCurrentDate();
          loadAdminDashboard();
        } else {
          document.getElementById('studentDashboard').style.display = 'block';
          document.getElementById('studentName').textContent = currentUser.nama;
          document.getElementById('studentAvatar').textContent = currentUser.nama.charAt(0).toUpperCase();
          updateCurrentDate();
          loadStudentDashboard();
        }
      }
    }

    document.addEventListener('DOMContentLoaded', checkSession);

    // ==================== LOGIN & LOGOUT ====================
    document.getElementById('loginForm').addEventListener('submit', function(e) {
      e.preventDefault();
      const email = document.getElementById('emailInput').value;
      const password = document.getElementById('passwordInput').value;
      const loginButton = this.querySelector('button[type="submit"]');

      loginButton.disabled = true;
      loginButton.classList.add('btn-loading');

      const handleLoginResponse = (result) => {
        loginButton.disabled = false;
        loginButton.classList.remove('btn-loading');

        if (result && result.success) {
          sessionStorage.setItem('currentUser', JSON.stringify(result.user));
          currentUser = result.user;
          document.getElementById('loginPage').style.display = 'none';
          
          if (result.user.role === 'Admin') {
            document.getElementById('adminDashboard').style.display = 'block';
            document.getElementById('adminName').textContent = result.user.nama;
            document.getElementById('adminAvatar').textContent = result.user.nama.charAt(0).toUpperCase();
            loadAdminDashboard();
          } else {
            document.getElementById('studentDashboard').style.display = 'block';
            document.getElementById('studentName').textContent = result.user.nama;
            document.getElementById('studentAvatar').textContent = result.user.nama.charAt(0).toUpperCase();
            loadStudentDashboard();
          }
        } else {
          Swal.fire({
            title: 'Gagal Masuk',
            text: result.message || 'Terjadi kesalahan.',
            icon: 'error'
          });
        }
      };
      
      const handleLoginError = (err) => {
        loginButton.disabled = false;
        loginButton.classList.remove('btn-loading');
        Swal.fire({
            title: 'Error',
            text: 'Koneksi bermasalah: ' + err,
            icon: 'error'
        });
      };

      google.script.run
        .withSuccessHandler(handleLoginResponse)
        .withFailureHandler(handleLoginError)
        .login(email, password);
    });

    function logout() {
      sessionStorage.removeItem('currentUser');
      currentUser = null;
      document.getElementById('loginPage').style.display = 'flex';
      document.getElementById('adminDashboard').style.display = 'none';
      document.getElementById('studentDashboard').style.display = 'none';
      document.getElementById('emailInput').value = '';
      document.getElementById('passwordInput').value = '';
    }

    // ==================== ADMIN DASHBOARD LOGIC ====================
    function loadAdminDashboard() {
      loadStatistics();
      loadBorrowRequests();
      loadAllBorrows();
      loadMasterBooks();
      loadMasterStudents();
    }

    function showSection(section) {
      // Hide all sections
      document.querySelectorAll('.content-wrapper > div').forEach(div => div.classList.add('hidden'));
      
      // Remove active class from menu
      document.querySelectorAll('#adminDashboard .menu-item').forEach(item => item.classList.remove('active'));
      
      // Show selected section & Activate menu
      // Note: Mapping manual based on order or ID logic
      const menuItems = document.querySelectorAll('#adminDashboard .menu-item');
      
      if (section === 'dashboard') {
        document.getElementById('dashboardSection').classList.remove('hidden');
        document.getElementById('pageTitle').textContent = 'Dashboard';
        menuItems[0].classList.add('active');
        loadStatistics();
      } else if (section === 'borrowRequests') {
        document.getElementById('borrowRequestsSection').classList.remove('hidden');
        document.getElementById('pageTitle').textContent = 'Peminjaman Pending';
        menuItems[1].classList.add('active');
        loadBorrowRequests();
      } else if (section === 'allBorrows') {
        document.getElementById('allBorrowsSection').classList.remove('hidden');
        document.getElementById('pageTitle').textContent = 'Riwayat Peminjaman';
        menuItems[2].classList.add('active');
        loadAllBorrows();
      } else if (section === 'masterBooks') {
        document.getElementById('masterBooksSection').classList.remove('hidden');
        document.getElementById('pageTitle').textContent = 'Master Buku';
        menuItems[3].classList.add('active');
        loadMasterBooks();
      } else if (section === 'masterStudents') {
        document.getElementById('masterStudentsSection').classList.remove('hidden');
        document.getElementById('pageTitle').textContent = 'Master Siswa';
        menuItems[4].classList.add('active');
        loadMasterStudents();
      }
    }

    function loadStatistics() {
      google.script.run.withSuccessHandler(function(stats) {
          document.getElementById('totalBooks').textContent = stats.totalBooks;
          document.getElementById('totalStock').textContent = stats.totalStok;
          document.getElementById('totalStudents').textContent = stats.totalStudents;
          document.getElementById('pendingBorrows').textContent = stats.pending;
          document.getElementById('waitingReturn').textContent = stats.waitingReturn;
          document.getElementById('returnedBooks').textContent = stats.returned;
          document.getElementById('rejectedBorrows').textContent = stats.rejected;
          
          const badge = document.getElementById('pendingBadge');
          if (badge) {
            badge.textContent = stats.pending;
            badge.style.display = stats.pending > 0 ? 'block' : 'none';
          }
      }).getStatistics();
    }

    // ==================== BORROW REQUESTS TABLE ====================
    let pendingBorrowsData = [];
    let borrowRequestsCurrentPage = 1;
    let borrowRequestsPageSize = 10;
    let borrowRequestsSearchQuery = '';

    function loadBorrowRequests() {
      google.script.run.withSuccessHandler(function(history) {
          pendingBorrowsData = history.filter(h => h.status === 'Pending');
          borrowRequestsCurrentPage = 1;
          renderBorrowRequestsTable();
      }).getBorrowHistory(currentUser.email, currentUser.role);
    }

    function renderBorrowRequestsTable() {
      const query = borrowRequestsSearchQuery.toLowerCase();
      const filteredData = pendingBorrowsData.filter(item => {
        return item.id.toLowerCase().includes(query) ||
               item.siswa.toLowerCase().includes(query) ||
               item.judulBuku.toLowerCase().includes(query);
      });

      const totalItems = filteredData.length;
      const pageSize = borrowRequestsPageSize === 'all' ? totalItems : parseInt(borrowRequestsPageSize);
      const totalPages = Math.ceil(totalItems / pageSize);
      const start = (borrowRequestsCurrentPage - 1) * pageSize;
      const end = start + pageSize;
      const paginatedData = filteredData.slice(start, end);

      const tbody = document.querySelector('#borrowRequestsTable tbody');
      tbody.innerHTML = '';

      if (paginatedData.length === 0) {
        tbody.innerHTML = '<tr><td colspan="6" style="text-align: center; padding: 40px;">Tidak ada data</td></tr>';
      } else {
        paginatedData.forEach(item => {
          const row = tbody.insertRow();
          row.innerHTML = `
            <td>${item.id}</td>
            <td>${item.siswa}</td>
            <td>${item.judulBuku}</td>
            <td>${item.tanggalPinjam}</td>
            <td><span class="badge pending">Pending</span></td>
            <td>
              <button class="action-btn btn-approve" onclick="approveBorrow('${item.id}')"><span class="material-icons" style="font-size:14px">check</span></button>
              <button class="action-btn btn-reject" onclick="rejectBorrow('${item.id}')"><span class="material-icons" style="font-size:14px">close</span></button>
            </td>
          `;
        });
      }
      
      // Pagination Controls
      document.getElementById('borrowRequestsPaginationInfo').textContent = `Menampilkan ${totalItems > 0 ? start + 1 : 0}-${Math.min(end, totalItems)} dari ${totalItems}`;
      document.getElementById('borrowRequestsPrevPage').disabled = borrowRequestsCurrentPage === 1;
      document.getElementById('borrowRequestsNextPage').disabled = borrowRequestsCurrentPage === totalPages || totalItems === 0;
    }

    // Event Listeners for Borrow Request Table
    document.getElementById('borrowRequestsSearch').addEventListener('input', (e) => { borrowRequestsSearchQuery = e.target.value; borrowRequestsCurrentPage = 1; renderBorrowRequestsTable(); });
    document.getElementById('borrowRequestsPageSize').addEventListener('change', (e) => { borrowRequestsPageSize = e.target.value; borrowRequestsCurrentPage = 1; renderBorrowRequestsTable(); });
    document.getElementById('borrowRequestsPrevPage').addEventListener('click', () => { if(borrowRequestsCurrentPage > 1) { borrowRequestsCurrentPage--; renderBorrowRequestsTable(); }});
    document.getElementById('borrowRequestsNextPage').addEventListener('click', () => { borrowRequestsCurrentPage++; renderBorrowRequestsTable(); });

    // ==================== ALL BORROWS TABLE ====================
    let allBorrowsData = [];
    let allBorrowsCurrentPage = 1;
    let allBorrowsPageSize = 10;
    let allBorrowsSearchQuery = '';

    function loadAllBorrows() {
        google.script.run.withSuccessHandler(function(history) {
            allBorrowsData = history;
            allBorrowsCurrentPage = 1;
            renderAllBorrowsTable();
        }).getBorrowHistory(currentUser.email, currentUser.role);
    }

    function renderAllBorrowsTable() {
        const query = allBorrowsSearchQuery.toLowerCase();
        const filteredData = allBorrowsData.filter(item => {
            return item.id.toLowerCase().includes(query) || item.siswa.toLowerCase().includes(query) || item.judulBuku.toLowerCase().includes(query) || item.status.toLowerCase().includes(query);
        });
        
        const totalItems = filteredData.length;
        const pageSize = allBorrowsPageSize === 'all' ? totalItems : parseInt(allBorrowsPageSize);
        const totalPages = Math.ceil(totalItems / pageSize);
        const start = (allBorrowsCurrentPage - 1) * pageSize;
        const end = start + pageSize;
        const paginatedData = filteredData.slice(start, end);

        const tbody = document.querySelector('#allBorrowsTable tbody');
        tbody.innerHTML = '';

        if (paginatedData.length === 0) {
             tbody.innerHTML = '<tr><td colspan="7" style="text-align: center; padding: 40px;">Tidak ada data</td></tr>';
        } else {
            paginatedData.forEach(item => {
                const row = tbody.insertRow();
                let statusBadge = `<span class="badge ${item.status.toLowerCase()}">${item.status}</span>`;
                let actionBtn = '';
                if (item.status === 'Approved') {
                    actionBtn = `<button class="action-btn btn-return" onclick="returnBook('${item.id}')">Kembalikan</button>`;
                }
                row.innerHTML = `<td>${item.id}</td><td>${item.siswa}</td><td>${item.judulBuku}</td><td>${item.tanggalPinjam}</td><td>${item.tanggalKembali || '-'}</td><td>${statusBadge}</td><td>${actionBtn}</td>`;
            });
        }
        
        document.getElementById('allBorrowsPaginationInfo').textContent = `Menampilkan ${totalItems > 0 ? start + 1 : 0}-${Math.min(end, totalItems)} dari ${totalItems}`;
        document.getElementById('allBorrowsPrevPage').disabled = allBorrowsCurrentPage === 1;
        document.getElementById('allBorrowsNextPage').disabled = allBorrowsCurrentPage === totalPages || totalItems === 0;
    }
    
    // Event Listeners for All Borrows
    document.getElementById('allBorrowsSearch').addEventListener('input', (e) => { allBorrowsSearchQuery = e.target.value; allBorrowsCurrentPage = 1; renderAllBorrowsTable(); });
    document.getElementById('allBorrowsPageSize').addEventListener('change', (e) => { allBorrowsPageSize = e.target.value; allBorrowsCurrentPage = 1; renderAllBorrowsTable(); });
    document.getElementById('allBorrowsPrevPage').addEventListener('click', () => { if(allBorrowsCurrentPage > 1) { allBorrowsCurrentPage--; renderAllBorrowsTable(); }});
    document.getElementById('allBorrowsNextPage').addEventListener('click', () => { allBorrowsCurrentPage++; renderAllBorrowsTable(); });


    // ==================== MASTER BOOKS LOGIC (WITH UPLOAD) ====================
    let masterBooksData = [];
    let masterBooksCurrentPage = 1;
    let masterBooksPageSize = 10;
    let masterBooksSearchQuery = '';

    function loadMasterBooks() {
      google.script.run.withSuccessHandler(function(books) {
          masterBooksData = books;
          masterBooksCurrentPage = 1;
          renderMasterBooksTable();
      }).getBooks();
    }

    function renderMasterBooksTable() {
        const query = masterBooksSearchQuery.toLowerCase();
        const filteredData = masterBooksData.filter(item => {
            return item.id.toLowerCase().includes(query) || item.judul.toLowerCase().includes(query) || item.penulis.toLowerCase().includes(query);
        });

        const totalItems = filteredData.length;
        const pageSize = masterBooksPageSize === 'all' ? totalItems : parseInt(masterBooksPageSize);
        const totalPages = Math.ceil(totalItems / pageSize);
        const start = (masterBooksCurrentPage - 1) * pageSize;
        const end = start + pageSize;
        const paginatedData = filteredData.slice(start, end);

        const tbody = document.querySelector('#masterBooksTable tbody');
        tbody.innerHTML = '';

        if (paginatedData.length === 0) {
            tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px;">Tidak ada data</td></tr>';
        } else {
            paginatedData.forEach(book => {
                const row = tbody.insertRow();
                row.innerHTML = `
                    <td>${book.id}</td>
                    <td>${book.judul}</td>
                    <td>${book.penulis}</td>
                    <td>${book.stok}</td>
                    <td>
                        <button class="action-btn btn-edit" onclick="openEditBookModal('${book.id}')">Edit</button>
                        <button class="action-btn btn-delete" onclick="deleteBook('${book.id}')">Hapus</button>
                    </td>
                `;
            });
        }
        
        document.getElementById('masterBooksPaginationInfo').textContent = `Menampilkan ${totalItems > 0 ? start + 1 : 0}-${Math.min(end, totalItems)} dari ${totalItems}`;
        document.getElementById('masterBooksPrevPage').disabled = masterBooksCurrentPage === 1;
        document.getElementById('masterBooksNextPage').disabled = masterBooksCurrentPage === totalPages || totalItems === 0;
    }

    // Event Listeners for Master Books
    document.getElementById('masterBooksSearch').addEventListener('input', (e) => { masterBooksSearchQuery = e.target.value; masterBooksCurrentPage = 1; renderMasterBooksTable(); });
    document.getElementById('masterBooksPageSize').addEventListener('change', (e) => { masterBooksPageSize = e.target.value; masterBooksCurrentPage = 1; renderMasterBooksTable(); });
    document.getElementById('masterBooksPrevPage').addEventListener('click', () => { if(masterBooksCurrentPage > 1) { masterBooksCurrentPage--; renderMasterBooksTable(); }});
    document.getElementById('masterBooksNextPage').addEventListener('click', () => { masterBooksCurrentPage++; renderMasterBooksTable(); });


    function openAddBookModal() {
        document.getElementById('bookForm').reset();
        document.getElementById('bookId').value = '';
        document.getElementById('bookModalTitle').textContent = 'Tambah Buku';
        document.getElementById('imagePreviewContainer').style.display = 'none';
        document.getElementById('imagePreview').src = '';
        document.getElementById('bookModal').style.display = 'flex';
    }

    function openEditBookModal(id) {
        const book = masterBooksData.find(b => b.id === id);
        if (book) {
            document.getElementById('bookId').value = book.id;
            document.getElementById('bookJudul').value = book.judul;
            document.getElementById('bookPenulis').value = book.penulis;
            document.getElementById('bookStok').value = book.stok;
            document.getElementById('currentBookUrl').value = book.coverURL;
            document.getElementById('bookCoverUrlInput').value = book.coverURL;
            
            const previewContainer = document.getElementById('imagePreviewContainer');
            const previewImage = document.getElementById('imagePreview');
            if (book.coverURL) {
              previewImage.src = book.coverURL;
              previewContainer.style.display = 'block';
            } else {
              previewContainer.style.display = 'none';
            }

            document.getElementById('bookModalTitle').textContent = 'Edit Buku';
            document.getElementById('bookModal').style.display = 'flex';
        }
    }

    function deleteBook(id) {
        Swal.fire({
            title: 'Anda yakin?',
            text: "Data buku akan dihapus permanen!",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#d33',
            cancelButtonColor: '#3085d6',
            confirmButtonText: 'Ya, hapus!',
            cancelButtonText: 'Batal'
        }).then((result) => {
            if (result.isConfirmed) {
                google.script.run.withSuccessHandler(function(res) {
                    showResultAlert(res);
                    if(res.success) {
                        loadMasterBooks();
                    }
                }).deleteBook(id);
            }
        });
    }

    document.getElementById('bookForm').addEventListener('submit', async function(e) {
        e.preventDefault();
        const id = document.getElementById('bookId').value;
        const judul = document.getElementById('bookJudul').value;
        const penulis = document.getElementById('bookPenulis').value;
        const stok = document.getElementById('bookStok').value;
        const coverUrlInput = document.getElementById('bookCoverUrlInput').value;
        const coverFile = document.getElementById('bookCoverFile').files[0];

        let fileData = null;
        if (coverFile) {
          const base64Data = await getBase64(coverFile);
          fileData = {
            fileName: coverFile.name,
            mimeType: coverFile.type,
            data: base64Data
          };
        }
        
        let coverURL = document.getElementById('currentBookUrl').value;
        if(coverUrlInput !== coverURL) {
            coverURL = coverUrlInput;
        }

        const handler = function(res) {
            showResultAlert(res);
            if(res.success) {
                closeModal('bookModal');
                loadMasterBooks();
                loadStatistics();
            }
        };

        if (id) {
            google.script.run.withSuccessHandler(handler).updateBook(id, judul, penulis, stok, coverURL, fileData);
        } else {
            google.script.run.withSuccessHandler(handler).addBook(judul, penulis, stok, coverURL, fileData);
        }
    });


    function loadMasterBooks() {
      google.script.run.withSuccessHandler(function(books) {
          masterBooksData = books;
          masterBooksCurrentPage = 1;
          renderMasterBooksTable();
      }).getBooks();
    }

    function renderMasterBooksTable() {
        const query = masterBooksSearchQuery.toLowerCase();
        const filteredData = masterBooksData.filter(item => item.judul.toLowerCase().includes(query) || item.penulis.toLowerCase().includes(query));
        
        const totalItems = filteredData.length;
        const pageSize = masterBooksPageSize === 'all' ? totalItems : parseInt(masterBooksPageSize);
        const totalPages = Math.ceil(totalItems / pageSize);
        const start = (masterBooksCurrentPage - 1) * pageSize;
        const end = start + pageSize;
        const paginatedData = filteredData.slice(start, end);
        
        const tbody = document.querySelector('#masterBooksTable tbody');
        tbody.innerHTML = '';
        
        if(paginatedData.length === 0){
             tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px;">Tidak ada data</td></tr>';
        } else {
            paginatedData.forEach(book => {
                const row = tbody.insertRow();
                row.innerHTML = `
                    <td>${book.id}</td>
                    <td>${book.judul}</td>
                    <td>${book.penulis}</td>
                    <td>${book.stok}</td>
                    <td>
                        <button class="action-btn btn-edit" onclick='editBook(${JSON.stringify(book)})'>Edit</button>
                        <button class="action-btn btn-delete" onclick="deleteBook('${book.id}')">Hapus</button>
                    </td>
                `;
            });
        }
        document.getElementById('masterBooksPaginationInfo').textContent = `Menampilkan ${totalItems > 0 ? start + 1 : 0}-${Math.min(end, totalItems)} dari ${totalItems}`;
        document.getElementById('masterBooksPrevPage').disabled = masterBooksCurrentPage === 1;
        document.getElementById('masterBooksNextPage').disabled = masterBooksCurrentPage === totalPages || totalItems === 0;
    }

    // Event Listeners Master Books
    document.getElementById('masterBooksSearch').addEventListener('input', (e) => { masterBooksSearchQuery = e.target.value; masterBooksCurrentPage = 1; renderMasterBooksTable(); });
    document.getElementById('masterBooksPageSize').addEventListener('change', (e) => { masterBooksPageSize = e.target.value; masterBooksCurrentPage = 1; renderMasterBooksTable(); });
    document.getElementById('masterBooksPrevPage').addEventListener('click', () => { if(masterBooksCurrentPage > 1) { masterBooksCurrentPage--; renderMasterBooksTable(); }});
    document.getElementById('masterBooksNextPage').addEventListener('click', () => { if(masterBooksCurrentPage * parseInt(masterBooksPageSize) < masterBooksData.length) { masterBooksCurrentPage++; renderMasterBooksTable(); }});

    // --- BOOK MODAL & FORM SUBMIT ---
    function openAddBookModal() {
      document.getElementById('bookForm').reset();
      document.getElementById('bookModalTitle').textContent = 'Tambah Buku';
      document.getElementById('bookId').value = '';
      document.getElementById('currentBookUrl').value = '';
      
      // Reset Preview
      document.getElementById('imagePreviewContainer').style.display = 'none';
      document.getElementById('imagePreview').src = '';
      
      document.getElementById('bookModal').style.display = 'flex';
    }

    function editBook(book) {
      document.getElementById('bookModalTitle').textContent = 'Edit Buku';
      document.getElementById('bookId').value = book.id;
      document.getElementById('bookJudul').value = book.judul;
      document.getElementById('bookPenulis').value = book.penulis;
      document.getElementById('bookStok').value = book.stok;
      
      // Reset file input
      document.getElementById('bookCoverFile').value = '';

      // Handle URL & Preview
      const urlInput = document.getElementById('bookCoverUrlInput');
      const currentUrlHidden = document.getElementById('currentBookUrl');
      const previewContainer = document.getElementById('imagePreviewContainer');
      const previewImage = document.getElementById('imagePreview');

      if (book.coverURL && book.coverURL !== 'null' && book.coverURL !== '') {
        urlInput.value = book.coverURL;
        currentUrlHidden.value = book.coverURL;
        previewImage.src = book.coverURL;
        previewContainer.style.display = 'block';
      } else {
        urlInput.value = '';
        currentUrlHidden.value = '';
        previewContainer.style.display = 'none';
      }

      document.getElementById('bookModal').style.display = 'flex';
    }

    // SUBMIT BUKU (ASYNC UPLOAD)
    document.getElementById('bookForm').addEventListener('submit', async function(e) {
      e.preventDefault();
      
      const bookId = document.getElementById('bookId').value;
      const judul = document.getElementById('bookJudul').value;
      const penulis = document.getElementById('bookPenulis').value;
      const stok = parseInt(document.getElementById('bookStok').value);
      
      const manualUrl = document.getElementById('bookCoverUrlInput').value;
      const oldUrl = document.getElementById('currentBookUrl').value;
      // Prioritaskan URL manual jika diisi, jika tidak gunakan URL lama
      const coverURL = manualUrl || oldUrl;

      const fileInput = document.getElementById('bookCoverFile');
      let fileData = null;

      const submitButton = this.querySelector('button[type="submit"]');
      submitButton.disabled = true;
      submitButton.classList.add('btn-loading');

      try {
          // Proses File Upload jika ada
          if (fileInput.files.length > 0) {
              const file = fileInput.files[0];
              // Batasi ukuran file (misal 2MB) agar tidak timeout
              if (file.size > 2 * 1024 * 1024) {
                  throw new Error("Ukuran gambar terlalu besar (Maks 2MB)");
              }
              
              const base64 = await getBase64(file);
              fileData = {
                  data: base64,
                  mimeType: file.type,
                  fileName: file.name
              };
          }

          const handleResponse = (result) => {
            submitButton.disabled = false;
            submitButton.classList.remove('btn-loading');
            if (result.success) {
              Swal.fire('Berhasil!', result.message, 'success');
              closeModal('bookModal');
              loadMasterBooks();
            } else {
              Swal.fire('Gagal!', result.message, 'error');
            }
          };

          const handleError = (err) => {
            submitButton.disabled = false;
            submitButton.classList.remove('btn-loading');
            Swal.fire('Error!', 'Terjadi kesalahan: ' + err.message, 'error');
          };

          // Panggil Fungsi Google Apps Script
          if (bookId) {
              // Update: Kirim data termasuk fileData
              google.script.run
                .withSuccessHandler(handleResponse)
                .withFailureHandler(handleError)
                .updateBook(bookId, judul, penulis, stok, coverURL, fileData);
          } else {
              // Add: Kirim data termasuk fileData
              google.script.run
                .withSuccessHandler(handleResponse)
                .withFailureHandler(handleError)
                .addBook(judul, penulis, stok, coverURL, fileData);
          }

      } catch (error) {
          submitButton.disabled = false;
          submitButton.classList.remove('btn-loading');
          Swal.fire('Error Upload!', error.message, 'error');
      }
    });

    function deleteBook(id) {
        Swal.fire({
            title: 'Hapus Buku?',
            text: "Data tidak bisa dikembalikan!",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#d33',
            confirmButtonText: 'Hapus'
        }).then((result) => {
            if (result.isConfirmed) {
                google.script.run.withSuccessHandler(function(res){
                    showResultAlert(res);
                    if(res.success) loadMasterBooks();
                }).deleteBook(id);
            }
        });
    }

    // ==================== MASTER STUDENTS LOGIC ====================
    let masterStudentsData = [];
    let masterStudentsCurrentPage = 1;
    let masterStudentsPageSize = 10;
    let masterStudentsSearchQuery = '';

    function loadMasterStudents() {
      google.script.run.withSuccessHandler(function(students) {
          masterStudentsData = students;
          masterStudentsCurrentPage = 1;
          renderMasterStudentsTable();
      }).getStudents();
    }

    function renderMasterStudentsTable() {
        const query = masterStudentsSearchQuery.toLowerCase();
        const filteredData = masterStudentsData.filter(item => item.email.toLowerCase().includes(query) || item.nama.toLowerCase().includes(query));
        
        const totalItems = filteredData.length;
        const pageSize = masterStudentsPageSize === 'all' ? totalItems : parseInt(masterStudentsPageSize);
        const totalPages = Math.ceil(totalItems / pageSize);
        const start = (masterStudentsCurrentPage - 1) * pageSize;
        const end = start + pageSize;
        const paginatedData = filteredData.slice(start, end);
        
        const tbody = document.querySelector('#masterStudentsTable tbody');
        tbody.innerHTML = '';
        
        if(paginatedData.length === 0){
             tbody.innerHTML = '<tr><td colspan="3" style="text-align: center; padding: 40px;">Tidak ada data</td></tr>';
        } else {
            paginatedData.forEach(student => {
                const row = tbody.insertRow();
                row.innerHTML = `
                    <td>${student.email}</td>
                    <td>${student.nama}</td>
                    <td>
                        <button class="action-btn btn-edit" onclick='editStudent(${JSON.stringify(student)})'>Edit</button>
                        <button class="action-btn btn-delete" onclick="deleteStudent('${student.email}')">Hapus</button>
                    </td>
                `;
            });
        }
        document.getElementById('masterStudentsPaginationInfo').textContent = `Menampilkan ${totalItems > 0 ? start + 1 : 0}-${Math.min(end, totalItems)} dari ${totalItems}`;
        document.getElementById('masterStudentsPrevPage').disabled = masterStudentsCurrentPage === 1;
        document.getElementById('masterStudentsNextPage').disabled = masterStudentsCurrentPage === totalPages || totalItems === 0;
    }
    
    // Event Listeners Master Students
    document.getElementById('masterStudentsSearch').addEventListener('input', (e) => { masterStudentsSearchQuery = e.target.value; masterStudentsCurrentPage = 1; renderMasterStudentsTable(); });
    document.getElementById('masterStudentsPageSize').addEventListener('change', (e) => { masterStudentsPageSize = e.target.value; masterStudentsCurrentPage = 1; renderMasterStudentsTable(); });
    document.getElementById('masterStudentsPrevPage').addEventListener('click', () => { if(masterStudentsCurrentPage > 1) { masterStudentsCurrentPage--; renderMasterStudentsTable(); }});
    document.getElementById('masterStudentsNextPage').addEventListener('click', () => { masterStudentsCurrentPage++; renderMasterStudentsTable(); });

    function openAddStudentModal() {
      document.getElementById('studentModalTitle').textContent = 'Tambah Siswa';
      document.getElementById('studentEmailOld').value = '';
      document.getElementById('studentEmail').value = '';
      document.getElementById('studentPassword').value = '';
      document.getElementById('studentNama').value = '';
      document.getElementById('studentModal').style.display = 'flex';
    }

    function editStudent(student) {
      document.getElementById('studentModalTitle').textContent = 'Edit Siswa';
      document.getElementById('studentEmailOld').value = student.email;
      document.getElementById('studentEmail').value = student.email;
      document.getElementById('studentPassword').value = '';
      document.getElementById('studentPassword').required = false;
      document.getElementById('studentNama').value = student.nama;
      document.getElementById('studentModal').style.display = 'flex';
    }

    document.getElementById('studentForm').addEventListener('submit', function(e) {
      e.preventDefault();
      const oldEmail = document.getElementById('studentEmailOld').value;
      const email = document.getElementById('studentEmail').value;
      const password = document.getElementById('studentPassword').value;
      const nama = document.getElementById('studentNama').value;
      const submitButton = this.querySelector('button[type="submit"]');

      submitButton.disabled = true;
      submitButton.classList.add('btn-loading');
      
      const handler = (result) => {
          submitButton.disabled = false;
          submitButton.classList.remove('btn-loading');
          showResultAlert(result);
          if(result.success) { closeModal('studentModal'); loadMasterStudents(); }
      };

      if (oldEmail) {
        google.script.run.withSuccessHandler(handler).updateStudent(oldEmail, email, password, nama);
      } else {
        google.script.run.withSuccessHandler(handler).addStudent(email, password, nama);
      }
    });

    function deleteStudent(email) {
        Swal.fire({
            title: 'Hapus Siswa?',
            text: "Data tidak bisa dikembalikan!",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#d33',
            confirmButtonText: 'Hapus'
        }).then((result) => {
            if (result.isConfirmed) {
                google.script.run.withSuccessHandler(function(res){
                    showResultAlert(res);
                    if(res.success) loadMasterStudents();
                }).deleteStudent(email);
            }
        });
    }

    // ==================== APPROVE / REJECT / RETURN LOGIC ====================
    function approveBorrow(borrowId) {
      Swal.fire({ title: 'Setujui?', text: "Stok buku akan berkurang.", icon: 'question', showCancelButton: true, confirmButtonText: 'Ya' }).then((result) => {
        if (result.isConfirmed) {
          google.script.run.withSuccessHandler(function(res) {
              showResultAlert(res);
              if (res.success) { loadBorrowRequests(); loadAllBorrows(); loadStatistics(); }
            }).approveBorrow(borrowId);
        }
      });
    }

    function rejectBorrow(borrowId) {
      Swal.fire({ title: 'Tolak?', icon: 'warning', showCancelButton: true, confirmButtonText: 'Ya', confirmButtonColor: '#d33' }).then((result) => {
        if (result.isConfirmed) {
          google.script.run.withSuccessHandler(function(res) {
              showResultAlert(res);
              if (res.success) { loadBorrowRequests(); loadAllBorrows(); loadStatistics(); }
            }).rejectBorrow(borrowId);
        }
      });
    }

    function returnBook(borrowId) {
      Swal.fire({ title: 'Buku Kembali?', text: "Stok akan bertambah.", icon: 'question', showCancelButton: true, confirmButtonText: 'Ya' }).then((result) => {
        if (result.isConfirmed) {
          google.script.run.withSuccessHandler(function(res) {
              showResultAlert(res);
              if (res.success) { loadAllBorrows(); loadStatistics(); }
            }).returnBook(borrowId);
        }
      });
    }

    // ==================== STUDENT DASHBOARD LOGIC ====================
    function loadStudentDashboard() {
      loadStudentBooks();
      loadStudentBorrows();
    }

    function showStudentSection(section) {
      document.getElementById('studentBooksSection').classList.add('hidden');
      document.getElementById('studentBorrowsSection').classList.add('hidden');
      
      document.querySelectorAll('#studentDashboard .menu-item').forEach(item => item.classList.remove('active'));
      
      const menuItems = document.querySelectorAll('#studentDashboard .menu-item');

      if (section === 'studentBooks') {
        document.getElementById('studentBooksSection').classList.remove('hidden');
        document.getElementById('studentPageTitle').textContent = 'Daftar Buku';
        menuItems[0].classList.add('active');
        loadStudentBooks();
      } else if (section === 'studentBorrows') {
        document.getElementById('studentBorrowsSection').classList.remove('hidden');
        document.getElementById('studentPageTitle').textContent = 'Riwayat Peminjaman';
        menuItems[1].classList.add('active');
        loadStudentBorrows();
      }
    }

    function loadStudentBooks() {
      google.script.run.withSuccessHandler(function(books) {
          const grid = document.getElementById('studentBooksGrid');
          grid.innerHTML = '';
          
          if (books.length === 0) {
            grid.innerHTML = '<p style="text-align: center; padding: 40px; grid-column: 1/-1;">Belum ada buku tersedia</p>';
            return;
          }
          
          books.forEach(book => {
            const card = document.createElement('div');
            card.className = 'book-card';
            // Gunakan placeholder jika coverURL kosong/null
            const imgUrl = (book.coverURL && book.coverURL !== 'null') ? book.coverURL : 'https://via.placeholder.com/200x300/667eea/ffffff?text=Buku';
            
            card.innerHTML = `
              <img src="${imgUrl}" alt="${book.judul}" class="book-cover">
              <div class="book-info">
                <h5>${book.judul}</h5>
                <p>Penulis: ${book.penulis}</p>
                <div class="book-stok">
                  <span class="material-icons" style="font-size: 16px;">inventory_2</span>
                  Stok: ${book.stok}
                </div>
                <button class="action-btn btn-borrow" onclick="borrowBookStudent('${book.id}')" ${book.stok <= 0 ? 'disabled' : ''} style="margin-top: 12px; width: 100%;">
                  ${book.stok > 0 ? 'Pinjam Buku' : 'Stok Habis'}
                </button>
              </div>
            `;
            grid.appendChild(card);
          });
      }).getBooks();
    }

    function loadStudentBorrows() {
      google.script.run.withSuccessHandler(function(history) {
          const tbody = document.querySelector('#studentBorrowsTable tbody');
          tbody.innerHTML = '';
          
          if (history.length === 0) {
            tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px;">Belum ada riwayat</td></tr>';
            return;
          }
          
          history.forEach(item => {
            const row = tbody.insertRow();
            let statusBadge = `<span class="badge ${item.status.toLowerCase()}">${item.status}</span>`;
            
            row.innerHTML = `
              <td>${item.id}</td>
              <td>${item.judulBuku}</td>
              <td>${item.tanggalPinjam}</td>
              <td>${item.tanggalKembali || '-'}</td>
              <td>${statusBadge}</td>
            `;
          });
      }).getBorrowHistory(currentUser.email, currentUser.role);
    }

    function borrowBookStudent(bukuId) {
      Swal.fire({ title: 'Pinjam Buku?', icon: 'question', showCancelButton: true, confirmButtonText: 'Ya' }).then((result) => {
        if (result.isConfirmed) {
          google.script.run.withSuccessHandler(function(res) {
              showResultAlert(res);
              if (res.success) { loadStudentBooks(); loadStudentBorrows(); }
            }).borrowBook(currentUser.email, bukuId);
        }
      });
    }
  </script>
</body>
</html>

Tidak ada komentar:

Posting Komentar

Desain UI Template

  https://www.hyperui.dev/ https://htmlrev.com/ https://github.com/tailwindtoolbox/Landing-Page https://www.w3schools.com/css/css_rwd_templa...