Lompat ke konten Lompat ke sidebar Lompat ke footer

Source Code Aplikasi Administrasi Guru Lengkap Untuk 1 Guru, 1 Mapel, Notifikasi E-mail Guru

Pekerjaan administrasi guru seringkali menyita banyak waktu yang seharusnya bisa difokuskan untuk mendidik siswa. Mulai dari merekap absensi, menghitung nilai, menyusun leger, hingga membuat jurnal mengajar harian. Untuk mengatasi hal tersebut, kami membagikan Source Code Aplikasi Administrasi Guru Lengkap yang dirancang khusus untuk 1 Guru dan 1 Mata Pelajaran, dilengkapi dengan fitur Notifikasi E-mail otomatis.

Apa Itu Google Apps Script?

Google Apps Script (GAS) adalah platform pembuatan skrip berbasis *cloud* dari Google yang memungkinkan pengembang untuk membuat aplikasi ringan secara cepat, yang terintegrasi langsung dengan layanan Google Workspace (seperti Google Sheets, Docs, Gmail, dan Drive). Script ini menggunakan bahasa pemrograman JavaScript.

Dengan GAS, kita bisa menyulap Google Spreadsheet biasa menjadi sebuah database tangguh yang dikendalikan oleh antarmuka (UI) web interaktif yang modern. Hebatnya lagi, server ini 100% gratis dari Google!

Manfaat Aplikasi Ini Bagi Guru

  • Database Terpusat: Semua data siswa, nilai, dan absensi tersimpan aman di Google Spreadsheet Anda sendiri.
  • Otomatisasi Laporan: Fitur cetak PDF resmi (lengkap dengan kop surat dan tanda tangan) untuk Leger Nilai, Jurnal Mengajar, dan Rekap Absensi.
  • Notifikasi Email Cerdas: Setiap kali Anda menginput absensi, nilai, atau bimbingan, sistem akan mengirimkan arsip/nota digital langsung ke Gmail Anda.
  • Mobile-Friendly: Bisa dibuka dan digunakan dengan sangat nyaman melalui layar HP saat berada di dalam kelas.
  • Ringan & Bebas Biaya: Tidak perlu sewa *hosting* atau beli *domain*. Sepenuhnya memanfaatkan infrastruktur Google.

Langkah-Langkah Instalasi Aplikasi

  1. Buka akun Google/Belajar.id Anda dan buat file Google Spreadsheet baru (Beri nama misalnya: "Database Guru Premium").
  2. Pada menu atas Spreadsheet, klik Ekstensi > Apps Script.
  3. Akan terbuka tab baru. Di sebelah kiri, ganti nama file Code.gs (jika ada) atau biarkan saja. Hapus semua kode bawaan, lalu Copy-Paste Kode Code.gs di bawah ini ke dalamnya.
  4. Klik ikon tambah (+) di bagian "File", pilih HTML, dan beri nama Index (huruf kapital 'I').
  5. Hapus isi bawaannya, lalu Copy-Paste Kode Index.html di bawah ini ke file tersebut.
  6. Klik ikon Simpan (Save).
  7. Untuk mempublikasikan: Klik tombol biru Terapkan (Deploy) di pojok kanan atas > Deployment Baru.
  8. Pilih jenis Aplikasi Web. Pada bagian 'Akses', pilih Siapa saja (Anyone) atau 'Hanya Saya' sesuai privasi Anda. Lalu klik Terapkan.
  9. Beri Izin Akses (Authorize) jika diminta oleh Google. Selesai! Anda akan mendapatkan URL Web App yang bisa langsung digunakan.

Source Code: Code.gs (Server)

Code.gs
/**
 * SISTEM ADMINISTRASI GURU - ULTRA PREMIUM V6.6 (STABLE - REVISED V3)
 */

function doGet() {
  return HtmlService.createTemplateFromFile('Index')
      .evaluate()
      .setTitle('Sistem Admin Guru Premium')
      .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
      .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

function getDatabase() {
  return SpreadsheetApp.getActiveSpreadsheet();
}

function setupNewDatabase(ss) {
  const configs = [
    { name: "Profil",      head: ["Key", "Value"] }, 
    { name: "DataSiswa",   head: ["No", "Nama Siswa", "Kelas"] },
    { name: "Absensi",     head: ["Waktu", "Kelas", "Nama Siswa", "Status"] },
    { name: "Nilai",       head: ["Waktu", "Jenis", "Kelas", "Nama Siswa", "Nilai", "Keterangan"] },
    { name: "Agenda",      head: ["Tanggal", "Jam", "Kelas", "Materi", "RPP", "Status", "Absen", "Keterangan"] },
    { name: "SiswaBinaan", head: ["No", "Nama Siswa", "Kelas", "Nama Ortu", "No HP"] },
    { name: "Bimbingan",   head: ["Tanggal", "Nama Siswa", "Kelas", "Permasalahan", "Penyelesaian", "Status"] }
  ];

  configs.forEach(c => {
    let sheet = ss.getSheetByName(c.name);
    if (!sheet) {
      sheet = ss.insertSheet(c.name);
      sheet.appendRow(c.head);
      if(c.name == "Profil"){
         const initialData = [
           ["NamaGuru", "Yefri Haryanto"], ["NipGuru", "-"],
           ["EmailGuru", "yefriharyanto51@guru.smp.belajar.id"], ["NamaKepsek", "Kepala Sekolah"],
           ["NipKepsek", "-"], ["Sekolah", "SMP Negeri 3 Kerinci"],
           ["Pemerintah", "PEMERINTAH KABUPATEN KERINCI"], ["Alamat", "Lempur Tengah, Kec. Gunung Raya, Kab. Kerinci, Jambi"],
           ["LogoDaerah", "https://upload.wikimedia.org/wikipedia/commons/f/f2/Coat_of_arms_of_Jambi.png"],
           ["LogoSekolah", "https://upload.wikimedia.org/wikipedia/commons/9/9c/Logo_Tut_Wuri_Handayani.png"],
           ["Mapel", "Bahasa Inggris"], ["TempatCetak", "Kerinci"]
         ];
         sheet.getRange(2, 1, initialData.length, 2).setValues(initialData);
      }
    }
  });
}

function getSheet(name) {
  const ss = getDatabase();
  let sheet = ss.getSheetByName(name);
  if (!sheet) { setupNewDatabase(ss); sheet = ss.getSheetByName(name); }
  return sheet;
}

function getProfileData() {
  const s = getSheet("Profil");
  if(s.getLastRow() < 2) return {};
  const data = s.getRange(2, 1, s.getLastRow()-1, 2).getValues();
  let p = {};
  data.forEach(r => p[r[0]] = r[1]);
  return p;
}

function saveProfileData(obj) {
  const sh = getSheet("Profil");
  const data = [["Key", "Value"]];
  for (let key in obj) { data.push([key, obj[key]]); }
  sh.clear();
  sh.getRange(1, 1, data.length, 2).setValues(data);
  return "Profil Berhasil Diperbarui!";
}

function sendDigitalNote(subject, title, detailsHtml) {
  const p = getProfileData();
  const target = p.EmailGuru || "admin@example.com";
  const htmlBody = `
    <div style="font-family: Arial; border: 2px solid #333; padding: 20px; max-width: 600px;">
      <h2 style="color: #2c3e50; border-bottom: 2px solid #ffd700;">${title}</h2>
      ${detailsHtml}
      <hr>
      <p style="font-size: 11px;">${p.Sekolah} - Digital Archive</p>
    </div>`;
  MailApp.sendEmail({ to: target, subject: subject, htmlBody: htmlBody });
}

function getKelasList() {
  const s = getSheet("DataSiswa");
  if (s.getLastRow() < 2) return [];
  const data = s.getRange(2, 3, s.getLastRow()-1, 1).getValues();
  return [...new Set(data.flat().filter(String))].sort();
}

function getSiswaByKelas(k) {
  const s = getSheet("DataSiswa"); if(s.getLastRow()<2) return [];
  const d = s.getRange(2, 2, s.getLastRow()-1, 2).getValues();
  return d.filter(r => r[1].toString().toUpperCase() === k.toString().toUpperCase()).map(r => r[0]);
}

function saveBulkSiswa(listSiswa, kelas) {
  const sheet = getSheet("DataSiswa");
  const lastRow = sheet.getLastRow();
  const data = listSiswa.split('\n').filter(n => n.trim() !== "").map((nama, i) => {
    return [lastRow + i, nama.trim(), kelas.toUpperCase()];
  });
  sheet.getRange(lastRow + 1, 1, data.length, 3).setValues(data);
  return "Berhasil simpan " + data.length + " siswa.";
}

function simpanAbsensiServer(k, d) {
  const s = getSheet("Absensi"); const t = new Date();
  const rows = d.map(x => [t, k.toUpperCase(), x.nama, x.status]);
  s.getRange(s.getLastRow()+1, 1, rows.length, 4).setValues(rows);
  let rowsHtml = d.map(x => `<li>${x.nama}: <b>${x.status}</b></li>`).join("");
  sendDigitalNote(`Nota Absensi: ${k}`, "Laporan Absensi Baru", `<p>Kelas: ${k}</p><ul>${rowsHtml}</ul>`);
  return "Absensi Berhasil Disimpan!";
}

function getRekapAbsensi(b, t, k) {
  const s = getSheet("Absensi"); if(s.getLastRow()<2) return [];
  const d = s.getRange(2, 1, s.getLastRow()-1, 4).getValues();
  return d.filter(r => {
    let dt = new Date(r[0]);
    return dt.getMonth() == (b-1) && dt.getFullYear() == t && r[1].toString().toUpperCase() == k.toString().toUpperCase();
  }).map(r => [new Date(r[0]).toLocaleDateString('id-ID'), r[1], r[2], r[3]]); 
}

function getRekapPersentase(b, t, k) {
  const s = getSheet("Absensi"); if(s.getLastRow()<2) return [];
  const d = s.getRange(2, 1, s.getLastRow()-1, 4).getValues();
  let rekap = {};
  d.filter(r => {
    let dt = new Date(r[0]);
    return dt.getMonth() == (b-1) && dt.getFullYear() == t && r[1].toString().toUpperCase() == k.toString().toUpperCase();
  }).forEach(r => {
    let n = r[2];
    let rawSt = r[3] ? r[3].toString().trim() : "";
    let st = rawSt !== "" ? rawSt.charAt(0).toUpperCase() : "-";
    
    if(!rekap[n]) rekap[n] = {H:0, S:0, I:0, A:0};
    if(rekap[n][st] !== undefined) rekap[n][st]++;
  });
  return Object.keys(rekap).map(n => {
    let o = rekap[n]; let tot = o.H + o.S + o.I + o.A;
    let p = tot > 0 ? ((o.H/tot)*100).toFixed(1)+"%" : "0%";
    return [n, o.H, o.S, o.I, o.A, p];
  });
}

function simpanNilaiServer(j, k, ket, d) {
  const s = getSheet("Nilai"); const t = new Date();
  const rows = d.map(x => [t, j.toUpperCase(), k.toUpperCase(), x.nama, x.nilai, ket]);
  s.getRange(s.getLastRow()+1, 1, rows.length, 6).setValues(rows);
  let rowsHtml = d.map(x => `<li>${x.nama}: <b>${x.nilai}</b></li>`).join("");
  sendDigitalNote(`Nota Nilai: ${k} - ${j}`, "Laporan Input Nilai", `<p>Materi: ${ket}</p><ul>${rowsHtml}</ul>`);
  return "Data Nilai Berhasil Disimpan!";
}

function getLegerData(k) {
  const s = getSheet("Nilai"); 
  if(s.getLastRow() < 2) return { headers: [], data: [] };
  
  const d = s.getRange(2, 1, s.getLastRow()-1, 6).getValues();
  let jenisSet = new Set();
  let leger = {}; 
  
  d.filter(r => r[2].toString().toUpperCase() == k.toString().toUpperCase()).forEach(r => {
    let n = r[3]; 
    let j = r[1].toString().toUpperCase(); 
    let v = parseFloat(r[4]) || 0;
    
    jenisSet.add(j);
    
    if(!leger[n]) leger[n] = { scores: {}, total: 0 };
    leger[n].scores[j] = v;
    leger[n].total += v;
  });
  
  let headers = Array.from(jenisSet).sort();
  
  let resultData = Object.keys(leger).map(n => {
    let studentRow = [n];
    let o = leger[n];
    
    headers.forEach(h => {
      studentRow.push(o.scores[h] !== undefined ? o.scores[h] : 0);
    });
    
    let rata = headers.length > 0 ? (o.total / headers.length).toFixed(1) : 0;
    studentRow.push(o.total, rata);
    return studentRow;
  });
  
  return { headers: headers, data: resultData };
}

function getRiwayatNilai(k) {
  const s = getSheet("Nilai"); if(s.getLastRow()<2) return [];
  const d = s.getRange(2, 1, s.getLastRow()-1, 6).getValues();
  return d.filter(r => r[2].toString().toUpperCase() == k.toString().toUpperCase())
          .map(r => [new Date(r[0]).toLocaleDateString('id-ID'), r[1], r[3], r[4], r[5]]);
}

function tambahAgenda(d) { 
  getSheet("Agenda").appendRow(d); 
  sendDigitalNote("Agenda Baru", "Jurnal Mengajar Disimpan", `<p>Kelas: ${d[2]} | Materi: ${d[3]}</p>`);
  return "Agenda Berhasil Disimpan!";
}

function getAgenda() {
  const s = getSheet("Agenda"); if(s.getLastRow()<2) return [];
  return s.getRange(2, 1, s.getLastRow()-1, 8).getDisplayValues();
}

function getSiswaBinaan() {
  const s = getSheet("SiswaBinaan"); if(s.getLastRow()<2) return [];
  return s.getRange(2, 1, s.getLastRow()-1, 5).getDisplayValues();
}

function getBimbingan() {
  const s = getSheet("Bimbingan"); if(s.getLastRow()<2) return [];
  return s.getRange(2, 1, s.getLastRow()-1, 6).getDisplayValues();
}

function simpanBimbinganWaliFix(nama, masalah, solusi, jenis) {
  const sBinaan = getSheet("SiswaBinaan");
  let kelas = "-";
  if(sBinaan.getLastRow() >= 2) {
    const data = sBinaan.getRange(2, 2, sBinaan.getLastRow()-1, 2).getValues();
    for(let i=0; i<data.length; i++) {
      if(data[i][0] === nama) { kelas = data[i][1]; break; }
    }
  }
  const s = getSheet("Bimbingan");
  s.appendRow([new Date(), nama, kelas, masalah, solusi, jenis]);
  sendDigitalNote("Bimbingan Wali", "Laporan Bimbingan", `<p>Siswa: ${nama} (${kelas})<br>Jenis: ${jenis}<br>Masalah: ${masalah}</p>`);
  return "Bimbingan Berhasil Disimpan!";
}

function simpanSiswaBinaanLengkap(nama, kelas, ortu, hp) {
  const s = getSheet("SiswaBinaan");
  s.appendRow([s.getLastRow(), nama, kelas.toUpperCase(), ortu, hp]);
  return "Data Siswa Wali Berhasil Disimpan!";
}

function getDashboardStats() {
  let rombel = 0, siswa = 0, binaan = 0, mapel = 1;
  
  const sSiswa = getSheet("DataSiswa");
  if(sSiswa.getLastRow() > 1) {
     siswa = sSiswa.getLastRow() - 1;
     const klsData = sSiswa.getRange(2, 3, siswa, 1).getValues();
     rombel = new Set(klsData.flat().filter(String)).size;
  }
  
  const sBinaan = getSheet("SiswaBinaan");
  if(sBinaan.getLastRow() > 1) {
     binaan = sBinaan.getLastRow() - 1;
  }
  
  const sProfil = getSheet("Profil");
  if(sProfil.getLastRow() > 1) {
     const pData = sProfil.getRange(2, 1, sProfil.getLastRow()-1, 2).getValues();
     const mapelRow = pData.find(r => r[0] === "Mapel");
     if(mapelRow && mapelRow[1]) {
        mapel = mapelRow[1].toString().split(',').filter(x => x.trim() !== '').length;
     }
  }
  return { rombel: rombel, siswa: siswa, binaan: binaan, mapel: mapel };
}

Source Code: Index.html (Tampilan UI)

Index.html
<!DOCTYPE html>
<html lang="id">
<head>
  <base target="_top">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Sistem Guru Premium V6.6</title>
  
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
  <link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@700;900&family=Lato:wght@400;700;900&display=swap" rel="stylesheet">
  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.31/jspdf.plugin.autotable.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

  <style>
    :root { --gold: #FFD700; --cyan: #00FFFF; --white: #FFFFFF; --glass: rgba(255, 255, 255, 0.95); }
    body { background-color: #f0f2f5; font-family: 'Lato', sans-serif; padding-bottom: 80px; }
    .hidden { display: none !important; }
    
    .header-premium {
      background: linear-gradient(-45deg, #000000, #141E30, #243B55, #0f2027);
      background-size: 400% 400%; animation: gradientBG 15s ease infinite;
      padding: 8px 15px;
      text-align: center; border-bottom: 4px solid var(--gold);
      box-shadow: 0 5px 15px rgba(0,0,0,0.6); position: sticky; top: 0; z-index: 1000;
    }
    @keyframes gradientBG { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
    .txt-sekolah { font-family: 'Cinzel', serif; font-size: 1.1rem; font-weight: 900; color: var(--gold); text-shadow: 1px 1px 0px #000; display: block; }
    .txt-sistem { color: var(--white); font-weight: 900; text-transform: uppercase; letter-spacing: 2px; font-size: 0.7rem;}
    .txt-guru { font-family: 'Cinzel', serif; font-size: 0.95rem; color: var(--cyan); text-shadow: 1px 1px 0px #000; display: block; }
    
    .nav-scroller { background: white; padding: 10px; overflow-x: auto; white-space: nowrap; display: flex; gap: 8px; border-bottom: 1px solid #ddd; justify-content: center; }
    .btn-nav { border-radius: 20px; border: 1px solid #e0e0e0; padding: 8px 15px; background: white; color: #555; transition: 0.3s; font-weight: bold; font-size: 0.85rem; display: flex; align-items: center; gap: 8px;}
    .btn-nav.active { background: #141E30; color: var(--gold); border-color: var(--gold); }
    .card-premium { background: var(--glass); border: none; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.05); padding: 20px; margin-bottom: 20px; }
    .container-main { max-width: 900px; margin: 20px auto; padding: 0 15px; }
    .page-title { border-left: 5px solid var(--gold); padding-left: 15px; margin-bottom: 20px; font-family: 'Cinzel', serif; font-weight: bold; }
    .card-dash { height: 100%; padding: 20px; border-radius: 15px; color: white; cursor: pointer; transition: 0.3s; box-shadow: 0 8px 20px rgba(0,0,0,0.2); text-align: center; }
    .gr-1 { background: linear-gradient(135deg, #000428, #004e92); }
    .gr-2 { background: linear-gradient(135deg, #134E5E, #71B280); }
    .gr-3 { background: linear-gradient(135deg, #870000, #190A05); }
    .gr-4 { background: linear-gradient(135deg, #514A9D, #24C6DC); }
    .gr-5 { background: linear-gradient(135deg, #C31432, #240b36); }
    .gr-6 { background: linear-gradient(135deg, #232526, #414345); }

    .stat-card { background: var(--glass); border-left: 4px solid var(--gold); padding: 12px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); text-align: center; }
    .stat-val { font-size: 1.3rem; font-weight: 900; color: #141E30; }
    .stat-label { font-size: 0.7rem; color: #555; font-weight: bold; text-transform: uppercase; }
    .accordion-button { font-weight: bold; color: #141E30; }
  </style>
</head>
<body>

<header class="header-premium">
  <span id="h-sekolah" class="txt-sekolah">LOADING...</span>
  <span class="txt-sistem">Sistem Administrasi Guru Premium</span>
  <span id="h-guru" class="txt-guru">...</span>
</header>

<div class="nav-scroller">
  <button class="btn-nav active" onclick="nav('home', this)"><i class="fas fa-home"></i> Home</button>
  <button class="btn-nav" onclick="nav('siswa', this)"><i class="fas fa-users"></i> Siswa</button>
  <button class="btn-nav" onclick="nav('absen', this)"><i class="fas fa-check-circle"></i> Absen</button>
  <button class="btn-nav" onclick="nav('nilai', this)"><i class="fas fa-star"></i> Nilai</button>
  <button class="btn-nav" onclick="nav('agenda', this)"><i class="fas fa-book"></i> Agenda</button>
  <button class="btn-nav" onclick="nav('wali', this)"><i class="fas fa-user-tie"></i> Wali</button>
  <button class="btn-nav" onclick="openProfile()"><i class="fas fa-user-gear"></i> Profil</button>
</div>

<div class="container-main">

  <div id="v-home" class="view-sec">
     
     <div class="row g-2 mb-3">
        <div class="col-6 col-md-3">
           <div class="stat-card"><div class="stat-val" id="st-rombel">-</div><div class="stat-label">Jml Rombel</div></div>
        </div>
        <div class="col-6 col-md-3">
           <div class="stat-card" style="border-left-color: var(--cyan);"><div class="stat-val" id="st-siswa">-</div><div class="stat-label">Jml Siswa</div></div>
        </div>
        <div class="col-6 col-md-3">
           <div class="stat-card" style="border-left-color: #28a745;"><div class="stat-val" id="st-binaan">-</div><div class="stat-label">Siswa Binaan</div></div>
        </div>
        <div class="col-6 col-md-3">
           <div class="stat-card" style="border-left-color: #dc3545;"><div class="stat-val" id="st-mapel">-</div><div class="stat-label">Mata Pelajaran</div></div>
        </div>
     </div>

     <div class="row g-3">
        <div class="col-6 col-md-4"><div class="card-dash gr-1" onclick="triggerNav('siswa')"><i class="fas fa-users fa-2x mb-2"></i><h5>Data Siswa</h5></div></div>
        <div class="col-6 col-md-4"><div class="card-dash gr-2" onclick="triggerNav('absen')"><i class="fas fa-calendar-check fa-2x mb-2"></i><h5>Absensi</h5></div></div>
        <div class="col-6 col-md-4"><div class="card-dash gr-3" onclick="triggerNav('nilai')"><i class="fas fa-medal fa-2x mb-2"></i><h5>Input Nilai</h5></div></div>
        <div class="col-6 col-md-4"><div class="card-dash gr-4" onclick="triggerNav('agenda')"><i class="fas fa-journal-whills fa-2x mb-2"></i><h5>Agenda</h5></div></div>
        <div class="col-6 col-md-4"><div class="card-dash gr-5" onclick="triggerNav('wali')"><i class="fas fa-user-graduate fa-2x mb-2"></i><h5>Guru Wali</h5></div></div>
        <div class="col-6 col-md-4"><div class="card-dash gr-6" onclick="openProfile()"><i class="fas fa-id-card fa-2x mb-2"></i><h5>Edit Profil</h5></div></div>
     </div>

     <div class="card-premium mt-4">
        <h5 class="page-title mb-3"><i class="fas fa-book-reader"></i> Petunjuk Penggunaan</h5>
        <div class="accordion accordion-flush" id="accPetunjuk">
          
          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button bg-light text-danger" type="button" data-bs-toggle="collapse" data-bs-target="#c1">⚠️ LANGKAH 1: SETTING PROFIL (WAJIB)</button></h2>
            <div id="c1" class="accordion-collapse collapse show" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Sebelum menggunakan menu lain, Anda <strong>wajib</strong> mengisi Profil. Klik tombol <b>Edit Profil</b>. Isi Nama, NIP, Nama Sekolah, Alamat, Tempat Cetak Laporan (Misal: Kerinci), dan URL Logo. Data profil ini akan otomatis diintegrasikan sebagai Kop Surat dan Tanda Tangan pada setiap cetakan Laporan PDF Anda.
              </div>
            </div>
          </div>
          
          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#c2"><i class="fas fa-users me-2"></i> Manajemen Data Siswa</button></h2>
            <div id="c2" class="accordion-collapse collapse" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Gunakan menu ini untuk memasukkan nama-nama siswa Anda. Anda bisa mem-<i>paste</i> langsung daftar nama dari Excel ke kotak <b>Input Masal</b> (satu nama per baris), ketik nama kelasnya, lalu klik Simpan.
              </div>
            </div>
          </div>

          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#c3"><i class="fas fa-calendar-check me-2"></i> Mengisi Absensi Harian</button></h2>
            <div id="c3" class="accordion-collapse collapse" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Pilih Kelas, lalu klik <b>Buka Absen</b>. Tandai siswa yang Hadir (H), Sakit (S), Izin (I), atau Alpa (A). Klik <b>Simpan & Email</b>. Anda juga dapat mencetak rekapitulasi harian dan persentase kehadiran bulanan di bagian bawah menu Absen.
              </div>
            </div>
          </div>

          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#c4"><i class="fas fa-star me-2"></i> Penilaian & Leger</button></h2>
            <div id="c4" class="accordion-collapse collapse" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Pilih Kelas, isi Jenis Nilai (Misal: UH1, UTS, Tugas 1), dan materi. Klik <b>Buka Form Nilai</b> dan ketik angka penilaiannya. Sistem akan secara otomatis menyesuaikan kolom di <b>Buku Leger</b> berapapun jumlah tugas/ulangan yang Anda berikan, serta otomatis menghitung rata-ratanya.
              </div>
            </div>
          </div>

          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#c5"><i class="fas fa-book me-2"></i> Jurnal Agenda Mengajar</button></h2>
            <div id="c5" class="accordion-collapse collapse" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Catat aktivitas mengajar Anda setiap selesai masuk kelas. Isi Tanggal, Jam, Kelas, Status Anda, dan Materi yang diajarkan. Jurnal ini dapat dicetak secara otomatis dalam format Kertas Landscape/Mendatar.
              </div>
            </div>
          </div>

          <div class="accordion-item">
            <h2 class="accordion-header"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#c6"><i class="fas fa-user-tie me-2"></i> Catatan Guru Wali</button></h2>
            <div id="c6" class="accordion-collapse collapse" data-bs-parent="#accPetunjuk">
              <div class="accordion-body small">
                Khusus jika Anda bertugas sebagai Wali Kelas. Simpan dulu data <b>Siswa Binaan</b> (beserta nama orang tua dan No HP). Setelah itu, Anda bisa mencatat riwayat Bimbingan (Masalah & Solusi) per siswa secara mendetail untuk dicetak sebagai laporan akhir semester.
              </div>
            </div>
          </div>

        </div>
     </div>

  </div>

  <div id="v-siswa" class="view-sec hidden">
     <h4 class="page-title">Manajemen Data Siswa</h4>
     <div class="row g-3 mb-4">
        <div class="col-md-6">
           <div class="card-premium h-100">
              <h6><i class="fas fa-keyboard text-primary"></i> Input Masal</h6>
              <textarea id="bulk-siswa" class="form-control form-control-sm mb-2" rows="2" placeholder="Satu nama per baris"></textarea>
              <div class="input-group input-group-sm">
                 <input type="text" id="bulk-kelas" class="form-control" placeholder="Kelas">
                 <button onclick="simpanMasalSiswa()" class="btn btn-primary">Simpan</button>
              </div>
           </div>
        </div>
     </div>
     <div class="card-premium">
        <div class="input-group mb-3">
           <select id="s-filter" class="form-select cls-select"><option value="">Pilih Kelas</option></select>
           <button onclick="loadSiswa()" class="btn btn-dark">Tampil</button>
        </div>
        <div class="table-responsive"><table class="table table-sm table-hover" id="tbl-siswa-view"><thead><tr><th>Nama</th><th>Kelas</th></tr></thead><tbody id="tbl-siswa"></tbody></table></div>
        <button onclick="exportOfficialPDF('tbl-siswa-view', 'Data_Siswa_Aktif')" class="btn btn-danger btn-sm w-100 mt-2">Cetak PDF Siswa</button>
     </div>
  </div>

  <div id="v-absen" class="view-sec hidden">
     <h4 class="page-title">Absensi Siswa</h4>
     <div class="card-premium">
        <div class="input-group mb-3">
           <select id="a-kls" class="form-select cls-select"></select>
           <button onclick="loadAbsenSiswa()" class="btn btn-primary">Buka Absen</button>
        </div>
        <div class="table-responsive"><table class="table text-center"><thead class="table-dark"><tr><th>Nama</th><th>H</th><th>S</th><th>I</th><th>A</th></tr></thead><tbody id="tbl-absen"></tbody></table></div>
        <button onclick="saveAbsen()" class="btn btn-warning w-100 fw-bold">SIMPAN & EMAIL</button>
     </div>
     <div class="card-premium">
        <h6>Rekapitulasi Absensi</h6>
        <div class="row g-2 mb-2">
           <div class="col-12"><select id="r-kls" class="form-select cls-select form-select-sm"></select></div>
           <div class="col-4"><button onclick="loadRekap()" class="btn btn-info btn-sm w-100 text-white">Lihat Rekap</button></div>
           <div class="col-4"><button onclick="exportOfficialPDF('tbl-rekap-view', 'Laporan_Absensi_Harian')" class="btn btn-danger btn-sm w-100">Cetak Harian</button></div>
           <div class="col-4"><button onclick="exportOfficialPDF('tbl-persen-view', 'Rekapitulasi_Kehadiran')" class="btn btn-dark btn-sm w-100">Cetak Rekap (%)</button></div>
        </div>
        <div class="table-responsive mb-2 small mt-3"><table class="table table-bordered" id="tbl-rekap-view"><thead><tr><th>Tgl</th><th>Kelas</th><th>Nama</th><th>Stts</th></tr></thead><tbody></tbody></table></div>
        <div class="table-responsive mb-2 small"><table class="table table-bordered" id="tbl-persen-view"><thead><tr><th>Nama</th><th>H</th><th>S</th><th>I</th><th>A</th><th>%</th></tr></thead><tbody></tbody></table></div>
     </div>
  </div>

  <div id="v-nilai" class="view-sec hidden">
     <h4 class="page-title">Penilaian</h4>
     <div class="card-premium">
        <div class="row g-2 mb-3">
           <div class="col-4"><select id="n-kls" class="form-select cls-select"></select></div>
           <div class="col-4"><input id="n-jns" type="text" class="form-control" placeholder="Jenis (UH1/DLL)"></div>
           <div class="col-4"><input id="n-ket" type="text" class="form-control" placeholder="Materi"></div>
        </div>
        <button onclick="loadNilaiSiswa()" class="btn btn-dark w-100 mb-2">Buka Form Nilai</button>
        <div id="tbl-nilai"></div>
        <button onclick="saveNilai()" class="btn btn-success w-100 mt-2">SIMPAN & EMAIL</button>
     </div>
     <div class="card-premium">
        <h6>Leger & Riwayat Nilai</h6>
        <select id="lv-kls" class="form-select cls-select mb-2" onchange="loadLeger()"></select>
        <div class="row g-2 mb-3">
           <div class="col-6"><button onclick="exportOfficialPDF('tbl-leger-view', 'Leger_Nilai_Siswa', 'l')" class="btn btn-danger btn-sm w-100">Cetak Leger Resmi</button></div>
           <div class="col-6"><button onclick="cetakRiwayatNilai()" class="btn btn-primary btn-sm w-100">Cetak Riwayat Nilai</button></div>
        </div>
        <div class="table-responsive"><table class="table table-sm table-bordered small" id="tbl-leger-view"><thead></thead><tbody></tbody></table></div>
        <div id="riwayat-container" class="hidden"><table id="tbl-riwayat-view"><thead><tr><th>Tgl</th><th>Jenis</th><th>Nama</th><th>Nilai</th><th>Ket</th></tr></thead><tbody></tbody></table></div>
     </div>
  </div>

  <div id="v-agenda" class="view-sec hidden">
     <h4 class="page-title">Agenda Mengajar</h4>
     <div class="card-premium">
        <div class="row g-2 mb-2">
           <div class="col-6"><label class="small fw-bold">Tanggal</label><input type="date" id="ag-tgl" class="form-control form-control-sm"></div>
           <div class="col-6"><label class="small fw-bold">Jam Ke</label><input type="text" id="ag-jam" class="form-control form-control-sm" placeholder="1-2"></div>
           <div class="col-6"><label class="small fw-bold">Kelas</label><select id="ag-kls" class="form-select form-select-sm cls-select"></select></div>
           <div class="col-6"><label class="small fw-bold">Status</label><select id="ag-stat" class="form-select form-select-sm"><option>Hadir</option><option>Izin</option><option>Tugas</option></select></div>
        </div>
        <textarea id="ag-mat" class="form-control form-control-sm mb-2" placeholder="Materi Pembelajaran"></textarea>
        <div class="row g-2 mb-3">
           <div class="col-6"><input type="text" id="ag-rpp" class="form-control form-control-sm" placeholder="Link RPP"></div>
           <div class="col-6"><input type="text" id="ag-absen" class="form-control form-control-sm" placeholder="Siswa Absen"></div>
           <div class="col-12"><input type="text" id="ag-ket" class="form-control form-control-sm" placeholder="Keterangan Tambahan"></div>
        </div>
        <button onclick="saveAgenda()" class="btn btn-primary w-100 fw-bold">SIMPAN AGENDA</button>
     </div>
     <div class="card-premium">
        <div class="d-flex justify-content-between mb-2"><h6>Jurnal Agenda</h6><button onclick="loadAgenda()" class="btn btn-sm btn-outline-dark">Refresh</button></div>
        <div class="table-responsive mb-2"><table class="table table-sm table-bordered small" id="tbl-agenda-view"><thead><tr><th>Tgl</th><th>Jam</th><th>Kelas</th><th>Materi</th><th>RPP</th><th>Stts</th><th>Absen</th><th>Ket</th></tr></thead><tbody></tbody></table></div>
        <button onclick="exportOfficialPDF('tbl-agenda-view', 'Jurnal_Agenda_Mengajar', 'l')" class="btn btn-danger btn-sm w-100">Cetak Agenda (Landscape)</button>
     </div>
  </div>

  <div id="v-wali" class="view-sec hidden">
     <h4 class="page-title">Bimbingan Wali</h4>
     <div class="card-premium">
        <h6><i class="fas fa-user-plus text-success"></i> Input Siswa Binaan</h6>
        <div class="row g-2 mb-3">
           <div class="col-8"><input type="text" id="wb-nama" class="form-control form-control-sm" placeholder="Nama Siswa"></div>
           <div class="col-4"><input type="text" id="wb-kelas" class="form-control form-control-sm" placeholder="Kelas"></div>
           <div class="col-6"><input type="text" id="wb-ortu" class="form-control form-control-sm" placeholder="Nama Ortu"></div>
           <div class="col-6"><input type="text" id="wb-hp" class="form-control form-control-sm" placeholder="No HP/WA"></div>
           <div class="col-12"><button onclick="saveSiswaWali()" class="btn btn-success btn-sm w-100">Simpan Siswa Binaan</button></div>
        </div>
        <hr>
        <h6><i class="fas fa-comment-dots text-warning"></i> Form Bimbingan</h6>
        <select id="wk-nama" class="form-select form-select-sm mb-2"></select>
        <select id="wk-jenis" class="form-select form-select-sm mb-2"><option>Kedisiplinan</option><option>Akademik</option><option>Sosial</option><option>Home Visit</option></select>
        <textarea id="wk-masalah" class="form-control form-control-sm mb-2" placeholder="Masalah"></textarea>
        <textarea id="wk-solusi" class="form-control form-control-sm mb-2" placeholder="Solusi"></textarea>
        <button onclick="saveBimbingan()" class="btn btn-warning w-100 fw-bold">SIMPAN BIMBINGAN</button>
     </div>
     <div class="card-premium">
        <div class="table-responsive mb-2"><table class="table table-sm table-bordered small" id="tbl-bk-view"><thead><tr><th>Tgl</th><th>Nama</th><th>Kelas</th><th>Masalah</th><th>Solusi</th><th>Jenis</th></tr></thead><tbody></tbody></table></div>
        <button onclick="exportOfficialPDF('tbl-bk-view', 'Laporan_Bimbingan_Wali', 'l')" class="btn btn-danger btn-sm w-100">Cetak Laporan BK</button>
     </div>
  </div>

</div>

<div class="modal fade" id="modalProfil" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header bg-dark text-white"><h5 class="modal-title">Edit Profil & Instansi</h5><button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button></div>
      <div class="modal-body p-4"><form id="formProfil"><div class="row g-3">
         <div class="col-md-6"><label class="small fw-bold">Nama Guru</label><input type="text" name="NamaGuru" class="form-control"></div>
         <div class="col-md-6"><label class="small fw-bold">NIP Guru</label><input type="text" name="NipGuru" class="form-control"></div>
         <div class="col-md-6"><label class="small fw-bold">Email (Gmail)</label><input type="email" name="EmailGuru" class="form-control"></div>
         <div class="col-md-6"><label class="small fw-bold">Mata Pelajaran</label><input type="text" name="Mapel" class="form-control"></div>
         <hr>
         <div class="col-md-4"><label class="small fw-bold">Kepala Sekolah</label><input type="text" name="NamaKepsek" class="form-control"></div>
         <div class="col-md-4"><label class="small fw-bold">NIP Kepsek</label><input type="text" name="NipKepsek" class="form-control"></div>
         <div class="col-md-4"><label class="small fw-bold text-danger">Tempat Cetak TTD</label><input type="text" name="TempatCetak" class="form-control" placeholder="Contoh: Kerinci"></div>
         <div class="col-md-6"><label class="small fw-bold">Instansi</label><input type="text" name="Sekolah" class="form-control"></div>
         <div class="col-md-6"><label class="small fw-bold">Pemerintah</label><input type="text" name="Pemerintah" class="form-control"></div>
         <div class="col-12"><label class="small fw-bold">Alamat Instansi</label><input type="text" name="Alamat" class="form-control"></div>
         <hr>
         <div class="col-6"><label class="small fw-bold">Logo Daerah (URL)</label><input type="text" name="LogoDaerah" class="form-control"></div>
         <div class="col-6"><label class="small fw-bold">Logo Sekolah (URL)</label><input type="text" name="LogoSekolah" class="form-control"></div>
      </div></form></div>
      <div class="modal-footer"><button onclick="updateProfil()" class="btn btn-primary w-100">UPDATE DATA</button></div>
    </div>
  </div>
</div>

<script>
const { jsPDF } = window.jspdf;

window.onload = function() { loadProfileHeader(); loadClassDropdowns(); loadAgenda(); loadDashboardStats(); document.getElementById('ag-tgl').valueAsDate = new Date(); };

function showLoading(msg = 'Sedang memproses...') {
  Swal.fire({ title: msg, allowOutsideClick: false, didOpen: () => { Swal.showLoading(); } });
}

function nav(id, el) {
  document.querySelectorAll('.view-sec').forEach(d => d.classList.add('hidden'));
  document.getElementById('v-'+id).classList.remove('hidden');
  if(el) { document.querySelectorAll('.btn-nav').forEach(b => b.classList.remove('active')); el.classList.add('active'); }
  if(id === 'wali') loadWali();
  if(id === 'home') loadDashboardStats(); 
}

function triggerNav(id) { const btns = document.querySelectorAll('.btn-nav'); const map = {'siswa':1, 'absen':2, 'nilai':3, 'agenda':4, 'wali':5}; nav(id, btns[map[id]]); }

function loadDashboardStats() {
  google.script.run.withSuccessHandler(res => {
     document.getElementById('st-rombel').innerText = res.rombel;
     document.getElementById('st-siswa').innerText = res.siswa;
     document.getElementById('st-binaan').innerText = res.binaan;
     document.getElementById('st-mapel').innerText = res.mapel;
  }).getDashboardStats();
}

function loadProfileHeader() {
  google.script.run.withSuccessHandler(p => { document.getElementById('h-sekolah').innerText = p.Sekolah; document.getElementById('h-guru').innerText = p.NamaGuru; }).getProfileData();
}

function openProfile() {
  showLoading('Mengambil data profil...');
  google.script.run.withSuccessHandler(p => { 
    Swal.close();
    const f = document.getElementById('formProfil'); 
    for (let k in p) if (f.elements[k]) f.elements[k].value = p[k]; 
    new bootstrap.Modal(document.getElementById('modalProfil')).show(); 
  }).getProfileData();
}

function updateProfil() {
  const f = document.getElementById('formProfil'); const fd = new FormData(f); const obj = {}; fd.forEach((v, k) => obj[k] = v);
  showLoading('Memperbarui profil...');
  google.script.run.withSuccessHandler(m => { Swal.fire('Ok', m, 'success'); loadProfileHeader(); loadDashboardStats(); bootstrap.Modal.getInstance(document.getElementById('modalProfil')).hide(); }).saveProfileData(obj);
}

function loadClassDropdowns() {
  google.script.run.withSuccessHandler(list => { let opts = '<option value="">Pilih Kelas</option>'; list.forEach(c => opts += `<option value="${c}">${c}</option>`); document.querySelectorAll('.cls-select').forEach(el => el.innerHTML = opts); }).getKelasList();
}

function loadSiswa() {
  const k = document.getElementById('s-filter').value;
  showLoading('Memuat data siswa...');
  google.script.run.withSuccessHandler(d => { Swal.close(); let h = ''; d.forEach(n => h += `<tr><td>${n}</td><td>${k}</td></tr>`); document.getElementById('tbl-siswa').innerHTML = h; }).getSiswaByKelas(k);
}

function simpanMasalSiswa() {
  const n = document.getElementById('bulk-siswa').value, k = document.getElementById('bulk-kelas').value;
  if(!n || !k) return Swal.fire('Error','Lengkapi data','error');
  showLoading('Menyimpan data...');
  google.script.run.withSuccessHandler(m => { Swal.fire('Ok', m, 'success'); document.getElementById('bulk-siswa').value = ''; loadClassDropdowns(); loadDashboardStats(); }).saveBulkSiswa(n, k);
}

function loadAbsenSiswa() { 
  const k = document.getElementById('a-kls').value; 
  if(!k) return Swal.fire('Info','Pilih kelas dulu','info');
  showLoading('Membuka form absen...');
  google.script.run.withSuccessHandler(d => { 
    Swal.close();
    let h = ''; d.forEach((n,i) => h += `<tr><td class="text-start small">${n}<input type="hidden" class="ab-nm" value="${n}"></td><td><input type="radio" name="r${i}" value="H" checked></td><td><input type="radio" name="r${i}" value="S"></td><td><input type="radio" name="r${i}" value="I"></td><td><input type="radio" name="r${i}" value="A"></td></tr>`); 
    document.getElementById('tbl-absen').innerHTML = h; 
  }).getSiswaByKelas(k); 
}

function saveAbsen() { 
  const k = document.getElementById('a-kls').value; 
  let d = []; 
  document.querySelectorAll('#tbl-absen tr').forEach(tr => { 
    let n = tr.querySelector('.ab-nm'); 
    if(n) d.push({nama: n.value, status: tr.querySelector('input:checked').value}); 
  }); 
  if(d.length === 0) return Swal.fire('Error','Data kosong','error');
  showLoading('Menyimpan & Mengirim Email...');
  google.script.run.withSuccessHandler(m => Swal.fire('Sukses', m, 'success')).simpanAbsensiServer(k,d); 
}

function loadRekap() { 
  const k = document.getElementById('r-kls').value, b = new Date().getMonth()+1, th = new Date().getFullYear(); 
  if(!k) return Swal.fire('Info','Pilih kelas dulu','info');
  showLoading('Mengambil rekap...');
  google.script.run.withSuccessHandler(d => { 
    let h = ''; d.forEach(r => h += `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td><td>${r[3]}</td></tr>`); 
    document.querySelector('#tbl-rekap-view tbody').innerHTML = h; 
  }).getRekapAbsensi(b, th, k); 
  google.script.run.withSuccessHandler(d => { 
    Swal.close();
    let h = ''; d.forEach(r => h += `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td><td>${r[3]}</td><td>${r[4]}</td><td><b>${r[5]}</b></td></tr>`); 
    document.querySelector('#tbl-persen-view tbody').innerHTML = h; 
  }).getRekapPersentase(b, th, k); 
}

function loadNilaiSiswa() { 
  const k = document.getElementById('n-kls').value; 
  if(!k) return Swal.fire('Info','Pilih kelas dulu','info');
  showLoading('Membuka form nilai...');
  google.script.run.withSuccessHandler(d => { 
    Swal.close();
    let h = '<table class="table table-sm">'; 
    d.forEach(n => h += `<tr><td>${n}<input type="hidden" class="nl-nm" value="${n}"></td><td><input type="number" class="form-control nl-val"></td></tr>`); 
    h += '</table>'; document.getElementById('tbl-nilai').innerHTML = h; 
  }).getSiswaByKelas(k); 
}

function saveNilai() { 
  const k = document.getElementById('n-kls').value, j = document.getElementById('n-jns').value, ket = document.getElementById('n-ket').value; 
  let d = []; 
  document.querySelectorAll('.nl-nm').forEach((n,i) => { 
    let v = document.querySelectorAll('.nl-val')[i].value; 
    if(v) d.push({nama: n.value, nilai: v}); 
  }); 
  if(d.length === 0) return Swal.fire('Error','Data nilai kosong','error');
  showLoading('Menyimpan & Mengirim Email...');
  google.script.run.withSuccessHandler(m => Swal.fire('Sukses', m, 'success')).simpanNilaiServer(j,k,ket,d); 
}

function loadLeger() { 
  const k = document.getElementById('lv-kls').value; 
  showLoading('Memuat leger dinamis...');
  google.script.run.withSuccessHandler(res => { 
    Swal.close();
    
    let theadHtml = `<tr><th>Nama</th>`;
    res.headers.forEach(h => theadHtml += `<th>${h}</th>`);
    theadHtml += `<th>Jml</th><th>Rata</th></tr>`;
    document.querySelector('#tbl-leger-view thead').innerHTML = theadHtml;
    
    let tbodyHtml = ''; 
    res.data.forEach(r => { 
      tbodyHtml += `<tr>`;
      r.forEach(cell => tbodyHtml += `<td>${cell}</td>`);
      tbodyHtml += `</tr>`;
    }); 
    document.querySelector('#tbl-leger-view tbody').innerHTML = tbodyHtml; 
  }).getLegerData(k); 
}

function cetakRiwayatNilai() {
  const k = document.getElementById('lv-kls').value;
  if(!k) return Swal.fire('Error','Pilih kelas dulu','error');
  showLoading('Menyiapkan riwayat...');
  google.script.run.withSuccessHandler(d => {
    Swal.close();
    let h = '';
    d.forEach(r => h += `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td><td>${r[3]}</td><td>${r[4]}</td></tr>`);
    document.querySelector('#tbl-riwayat-view tbody').innerHTML = h;
    setTimeout(() => { exportOfficialPDF('tbl-riwayat-view', 'Riwayat_Nilai_Siswa_' + k, 'p'); }, 300);
  }).getRiwayatNilai(k);
}

function saveAgenda() {
  const ids = ['ag-tgl','ag-jam','ag-kls','ag-mat','ag-rpp','ag-stat','ag-absen','ag-ket'];
  const vals = ids.map(id => document.getElementById(id).value);
  showLoading('Menyimpan agenda...');
  google.script.run.withSuccessHandler(m => { loadAgenda(); Swal.fire('Sukses', m, 'success'); }).tambahAgenda(vals);
}

function loadAgenda() {
  google.script.run.withSuccessHandler(d => { let h = ''; d.forEach(r => h += `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td><td>${r[3]}</td><td>${r[4]}</td><td>${r[5]}</td><td>${r[6]}</td><td>${r[7]}</td></tr>`); document.querySelector('#tbl-agenda-view tbody').innerHTML = h; }).getAgenda();
}

function loadWali() { 
  google.script.run.withSuccessHandler(d => { 
    let op = ''; d.forEach(r => op += `<option value="${r[1]}">${r[1]}</option>`); 
    document.getElementById('wk-nama').innerHTML = op; 
  }).getSiswaBinaan(); 
  google.script.run.withSuccessHandler(d => { 
    let h = ''; d.forEach(r => h += `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td><td>${r[3]}</td><td>${r[4]}</td><td>${r[5]}</td></tr>`); 
    document.querySelector('#tbl-bk-view tbody').innerHTML = h; 
  }).getBimbingan(); 
}

function saveSiswaWali() {
  const n = document.getElementById('wb-nama').value, k = document.getElementById('wb-kelas').value, o = document.getElementById('wb-ortu').value, h = document.getElementById('wb-hp').value;
  if(!n || !k) return Swal.fire('Error','Lengkapi Nama & Kelas','error');
  showLoading('Menyimpan siswa binaan...');
  google.script.run.withSuccessHandler(m => { Swal.fire('Ok', m, 'success'); loadWali(); loadDashboardStats(); }).simpanSiswaBinaanLengkap(n,k,o,h);
}

function saveBimbingan() { 
  const n = document.getElementById('wk-nama').value, m = document.getElementById('wk-masalah').value, s = document.getElementById('wk-solusi').value, j = document.getElementById('wk-jenis').value; 
  if(!n) return Swal.fire('Error','Pilih siswa binaan','error');
  showLoading('Menyimpan bimbingan...');
  google.script.run.withSuccessHandler(m => { loadWali(); Swal.fire('Sukses', m, 'success'); }).simpanBimbinganWaliFix(n,m,s,j); 
}

function exportOfficialPDF(tableId, filename, orient = 'p') {
  google.script.run.withSuccessHandler(p => {
    const doc = new jsPDF({ orientation: orient, unit: 'mm', format: 'a4' });
    const pageWidth = doc.internal.pageSize.width;
    
    if(p.LogoDaerah) try { doc.addImage(p.LogoDaerah, 'PNG', 15, 10, 18, 18); } catch(e){}
    if(p.LogoSekolah) try { doc.addImage(p.LogoSekolah, 'PNG', pageWidth - 33, 10, 18, 18); } catch(e){}
    
    doc.setFontSize(11); doc.setFont("helvetica", "bold");
    doc.text(p.Pemerintah.toUpperCase(), pageWidth/2, 14, {align:"center"});
    doc.text("DINAS PENDIDIKAN", pageWidth/2, 19, {align:"center"});
    doc.setFontSize(13);
    doc.text(p.Sekolah.toUpperCase(), pageWidth/2, 25, {align:"center"});
    doc.setFontSize(8); doc.setFont("helvetica", "normal");
    doc.text(p.Alamat, pageWidth/2, 30, {align:"center"});
    doc.line(15, 32, pageWidth-15, 32); doc.line(15, 32.5, pageWidth-15, 32.5);

    doc.setFontSize(11); doc.setFont("helvetica", "bold");
    doc.text(filename.replace(/_/g," ").toUpperCase(), pageWidth/2, 42, {align:"center"});
    
    doc.setFontSize(9); doc.setFont("helvetica", "normal");
    doc.text(`Guru Mata Pelajaran : ${p.NamaGuru}`, 15, 48);
    doc.text(`Mata Pelajaran : ${p.Mapel}`, 15, 53);
    
    doc.autoTable({
      html: '#' + tableId,
      startY: 58,
      theme: 'grid',
      styles: { fontSize: 7 },
      headStyles: { fillColor: [50, 50, 50] }
    });

    let finalY = doc.lastAutoTable.finalY + 10;
    
    if (finalY > doc.internal.pageSize.height - 45) { 
        doc.addPage(); 
        finalY = 20; 
    }

    doc.setFontSize(9);
    doc.text("Mengetahui,", 15, finalY + 10);
    doc.text("Kepala Sekolah,", 15, finalY + 15);
    doc.text(p.NamaKepsek, 15, finalY + 35);
    doc.text("NIP. " + p.NipKepsek, 15, finalY + 39);

    let tempatTtd = p.TempatCetak || "Kerinci";
    doc.text(tempatTtd + ", " + new Date().toLocaleDateString('id-ID'), pageWidth-65, finalY + 10);
    doc.text("Guru Mata Pelajaran,", pageWidth-65, finalY + 15);
    doc.text(p.NamaGuru, pageWidth-65, finalY + 35);
    doc.text("NIP. " + p.NipGuru, pageWidth-65, finalY + 39);

    doc.save(filename + ".pdf");
  }).getProfileData();
}
</script>
</body>
</html>