Penilaian Siswa

 

Panduan dan Kalkulasi Penilaian Siswa

Sebagai guru, menyusun sistem penilaian yang komprehensif sangat penting untuk mengukur pemahaman siswa secara menyeluruh (kognitif, afektif, dan psikomotorik). Berikut adalah rancangan bobot dan formula perhitungan nilai akhir siswa yang menggabungkan nilai harian, nilai bulanan, catatan/sikap, dan projek.

1. Menentukan Bobot Penilaian (Contoh Persentase)

Anda dapat menyesuaikan bobot ini sesuai dengan kebijakan sekolah atau Kurikulum yang Anda gunakan (misalnya Kurikulum Merdeka).

Komponen PenilaianBobot (%)Keterangan

Nilai Harian

30%

Ulangan harian, kuis, tugas rumah, keaktifan kelas.

Nilai Bulanan

25%

Ujian tengah semester / asesmen sumatif bulanan.

Catatan (Sikap/Keaktifan)

10%

Jurnal guru, kedisiplinan, catatan perilaku, kehadiran.

Projek

35%

Tugas berbasis projek, portofolio, produk akhir.

Total

100%


2. Formula Penghitungan Nilai Akhir (NA)

$$\text{Nilai Akhir (NA)} = (NH \times 0.30) + (NB \times 0.25) + (NC \times 0.10) + (NP \times 0.35)$$

Di mana:

  • $NH$ = Rata-rata Nilai Harian

  • $NB$ = Nilai Bulanan (Sumatif)

  • $NC$ = Nilai Catatan / Sikap (dikonversi ke skala 0-100)

  • $NP$ = Nilai Projek

3. Contoh Simulasi Perhitungan untuk Satu Siswa (Nama: Budi)

  • Nilai Harian (NH): Rata-rata dari 4 tugas/kuis = $85$

  • Nilai Bulanan (NB): Ujian bulan lalu = $80$

  • Catatan/Sikap (NC): Berdasarkan catatan guru, sikap Budi sangat baik, disiplin, dan aktif (diberi skor konversi $90$)

  • Projek (NP): Projek sains/materi semester ini mendapat nilai $88$

Proses Perhitungan:

  1. $\text{Komponen Harian} = 85 \times 0.30 = 25.5$

  2. $\text{Komponen Bulanan} = 80 \times 0.25 = 20.0$

  3. $\text{Komponen Catatan} = 90 \times 0.10 = 9.0$

  4. $\text{Komponen Projek} = 88 \times 0.35 = 30.8$

$$\text{Nilai Akhir} = 25.5 + 20.0 + 9.0 + 30.8 = \mathbf{85.3}$$

Maka, Nilai Akhir Budi pada rapor adalah 85.3.

4. Tips Mengelola Catatan & Penilaian Harian

  • Rubrik Projek: Pastikan komponen projek dinilai menggunakan rubrik yang jelas (misalnya: kreativitas, kerja sama tim, ketepatan waktu, dan hasil akhir).

  • Konversi Catatan: Catatan harian yang bersifat kualitatif (misalnya: "Sangat Aktif", "Cukup", "Kurang") dapat Anda ubah menjadi angka kuantitatif untuk memudahkan rumus Excel (contoh: Sangat Baik = 90, Baik = 80, Cukup = 70).

code

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Portal Nilai Informatika</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
    <!-- SheetJS for Excel file parsing support -->
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
    <style>
        body { font-family: 'Plus Jakarta Sans', sans-serif; }
        .fade-in { animation: fadeIn 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(8px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .tech-gradient {
            background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%);
        }
        .card-glass {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(12px);
        }
    </style>
</head>
<body class="bg-slate-900 text-slate-100 min-h-screen flex flex-col selection:bg-cyan-500 selection:text-white">

    <header class="tech-gradient border-b border-slate-800 text-white sticky top-0 z-40 shadow-xl">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 py-4 flex flex-col sm:flex-row justify-between items-center gap-4">
            <div class="flex items-center space-x-3.5">
                <div class="bg-gradient-to-br from-cyan-500 to-indigo-600 p-3 rounded-2xl shadow-lg shadow-cyan-500/20 text-white">
                    <i class="fa-solid fa-code text-2xl"></i>
                </div>
                <div>
                    <div class="flex items-center gap-2">
                        <h1 class="text-xl font-extrabold tracking-tight bg-gradient-to-r from-cyan-400 via-sky-300 to-indigo-300 bg-clip-text text-transparent">Portal Nilai Informatika</h1>
                        <span class="px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider bg-cyan-500/20 text-cyan-400 rounded-full border border-cyan-500/30">v2.8 Pro</span>
                    </div>
                    <p class="text-xs text-slate-400 font-medium">Sistem Evaluasi & Manajemen Nilai Kompetensi Keahlian</p>
                </div>
            </div>
            
            <div class="flex items-center gap-3">
                <!-- Quick Portal Switcher Bar -->
                <div class="flex bg-slate-900/90 p-1.5 rounded-2xl border border-slate-700/80 shadow-inner">
                    <button onclick="switchPortal('teacher')" id="navBtnTeacher" class="px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white">
                        <i class="fa-solid fa-terminal text-cyan-400"></i> Portal Guru
                    </button>
                    <button onclick="switchPortal('student')" id="navBtnStudent" class="px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white">
                        <i class="fa-solid fa-laptop-code text-sky-400"></i> Portal Siswa
                    </button>
                    <button onclick="backToSelector()" id="navBtnSelector" class="px-3 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-1.5 text-slate-400 hover:text-white" title="Pilih Akses">
                        <i class="fa-solid fa-shield-halved text-indigo-400"></i>
                    </button>
                </div>

                <div id="roleIndicator" class="hidden sm:flex items-center bg-slate-800/90 px-4 py-2 rounded-xl text-xs font-semibold border border-slate-700/80 text-slate-300 shadow-inner">
                    <span id="currentRoleText" class="flex items-center gap-2">
                        <i class="fa-solid fa-shield-halved text-cyan-400"></i> Pilih Portal
                    </span>
                </div>
            </div>
        </div>
    </header>

    <main class="flex-grow max-w-7xl w-full mx-auto px-4 sm:px-6 py-8">
        
        <!-- Streamlined Modal / Custom Alert Notification Container -->
        <div id="customModal" class="fixed inset-0 bg-slate-950/80 backdrop-blur-md z-50 hidden flex items-center justify-center p-4">
            <div class="bg-slate-900 border border-slate-800 rounded-3xl max-w-md w-full p-6 sm:p-8 shadow-2xl fade-in text-slate-100">
                <div id="modalIcon" class="w-14 h-14 rounded-2xl bg-cyan-500/10 text-cyan-400 flex items-center justify-center text-2xl mb-5 border border-cyan-500/20 shadow-lg shadow-cyan-500/10">
                    <i class="fa-solid fa-circle-info"></i>
                </div>
                <h3 id="modalTitle" class="text-xl font-bold text-white mb-2">Informasi Sistem</h3>
                <p id="modalMessage" class="text-sm text-slate-400 mb-8 leading-relaxed">Pesan sistem...</p>
                <div class="flex justify-end gap-3">
                    <button id="modalCancelBtn" onclick="closeModal(false)" class="hidden px-5 py-2.5 text-sm font-semibold text-slate-300 bg-slate-800 hover:bg-slate-700 rounded-xl transition-all border border-slate-700">Batal</button>
                    <button onclick="closeModal(true)" class="px-6 py-2.5 text-sm font-semibold text-slate-950 bg-gradient-to-r from-cyan-400 to-sky-400 hover:from-cyan-300 hover:to-sky-300 rounded-xl transition-all shadow-lg shadow-cyan-500/25">Mengerti</button>
                </div>
            </div>
        </div>

        <!-- Role Selection Screen -->
        <div id="viewRoleSelector" class="max-w-3xl mx-auto my-12 text-center fade-in">
            <div class="bg-slate-800/60 border border-slate-700/60 p-8 sm:p-12 rounded-3xl shadow-2xl backdrop-blur-xl relative overflow-hidden">
                <div class="absolute -right-20 -top-20 w-60 h-60 bg-cyan-500/10 rounded-full blur-3xl pointer-events-none"></div>
                <div class="absolute -left-20 -bottom-20 w-60 h-60 bg-indigo-500/10 rounded-full blur-3xl pointer-events-none"></div>

                <span class="px-3.5 py-1.5 bg-cyan-500/10 text-cyan-400 font-bold text-xs uppercase tracking-widest rounded-full border border-cyan-500/20">Akses Terautentikasi</span>
                <h2 class="text-3xl sm:text-4xl font-extrabold text-white mt-4 mb-3 tracking-tight">Pilih Portal Masuk</h2>
                <p class="text-slate-400 mb-10 max-w-md mx-auto text-sm leading-relaxed">Silakan pilih akses sesuai peran Anda di departemen Informatika untuk mengelola atau memantau progres nilai.</p>
                
                <div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
                    <!-- Teacher Portal Card -->
                    <button onclick="promptTeacherPassword()" class="group text-left p-6 sm:p-7 rounded-2xl border border-slate-700/80 hover:border-cyan-500 bg-slate-900/60 hover:bg-slate-900 transition-all duration-300 flex flex-col justify-between shadow-xl relative overflow-hidden">
                        <div class="absolute top-0 right-0 w-32 h-32 bg-cyan-500/5 rounded-full blur-2xl group-hover:bg-cyan-500/10 transition-colors"></div>
                        <div>
                            <div class="w-14 h-14 rounded-2xl bg-cyan-500/10 text-cyan-400 flex items-center justify-center text-2xl mb-5 group-hover:scale-110 group-hover:bg-cyan-500 group-hover:text-slate-950 transition-all duration-300 border border-cyan-500/20">
                                <i class="fa-solid fa-terminal"></i>
                            </div>
                            <h3 class="text-lg font-bold text-white mb-1.5 group-hover:text-cyan-400 transition-colors">Portal Guru / Pengajar</h3>
                            <p class="text-xs text-slate-400 leading-relaxed">Kelola bobot penilaian kode, nilai harian, sumatif modul, portofolio, catatan lab, serta impor Excel REKAP_NILAI. (Memerlukan Sandi)</p>
                        </div>
                        <div class="mt-8 flex items-center text-xs font-bold text-cyan-400 group-hover:translate-x-1.5 transition-transform">
                            Masuk Dashboard Guru <i class="fa-solid fa-arrow-right ml-2"></i>
                        </div>
                    </button>

                    <!-- Student Portal Card -->
                    <button onclick="switchPortal('student')" class="group text-left p-6 sm:p-7 rounded-2xl border border-slate-700/80 hover:border-sky-400 bg-slate-900/60 hover:bg-slate-900 transition-all duration-300 flex flex-col justify-between shadow-xl relative overflow-hidden">
                        <div class="absolute top-0 right-0 w-32 h-32 bg-sky-500/5 rounded-full blur-2xl group-hover:bg-sky-500/10 transition-colors"></div>
                        <div>
                            <div class="w-14 h-14 rounded-2xl bg-sky-500/10 text-sky-400 flex items-center justify-center text-2xl mb-5 group-hover:scale-110 group-hover:bg-sky-400 group-hover:text-slate-950 transition-all duration-300 border border-sky-500/20">
                                <i class="fa-solid fa-laptop-code"></i>
                            </div>
                            <h3 class="text-lg font-bold text-white mb-1.5 group-hover:text-sky-400 transition-colors">Portal Siswa / Praktikan</h3>
                            <p class="text-xs text-slate-400 leading-relaxed">Pantau transkrip nilai akhir praktikum, rincian komponen tugas, dan catatan pembimbing. (Tanpa Kata Sandi)</p>
                        </div>
                        <div class="mt-8 flex items-center text-xs font-bold text-sky-400 group-hover:translate-x-1.5 transition-transform">
                            Masuk Dashboard Siswa <i class="fa-solid fa-arrow-right ml-2"></i>
                        </div>
                    </button>
                </div>
            </div>
        </div>

        <div id="viewTeacherPortal" class="hidden fade-in space-y-6">
            <div class="bg-slate-800/80 border border-slate-700/80 p-6 rounded-3xl shadow-xl backdrop-blur-md flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
                <div>
                    <button onclick="backToSelector()" class="text-xs font-semibold text-slate-400 hover:text-cyan-400 mb-2 flex items-center gap-1.5 transition-colors">
                        <i class="fa-solid fa-arrow-left"></i> Kembali ke Pilih Portal
                    </button>
                    <h2 class="text-2xl font-extrabold text-white">Dashboard Manajemen Nilai Informatika</h2>
                    <p class="text-sm text-slate-400">Atur bobot rumus nilai, jenjang, kelas, jurusan IT, kontak siswa, & rekapitulasi nilai praktikum.</p>
                </div>
                
                <div class="flex flex-wrap items-center gap-3">
                    <!-- Excel Importer Input Button -->
                    <label class="px-4 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs rounded-xl shadow-lg shadow-emerald-600/20 transition-all flex items-center gap-2 cursor-pointer">
                        <i class="fa-solid fa-file-excel"></i> Impor Rekap Excel
                        <input type="file" id="excelFileInput" accept=".xlsx, .xls, .csv" class="hidden" onchange="handleExcelImport(event)">
                    </label>

                    <button onclick="saveAllTeacherData()" class="px-5 py-2.5 bg-gradient-to-r from-cyan-500 to-sky-500 hover:from-cyan-400 hover:to-sky-400 text-slate-950 font-bold text-sm rounded-xl shadow-lg shadow-cyan-500/20 transition-all flex items-center gap-2">
                        <i class="fa-solid fa-cloud-arrow-up"></i> Simpan Data ke Server
                    </button>
                </div>
            </div>

            <!-- Configuration Box: Weights -->
            <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
                <div class="bg-slate-800/80 border border-slate-700/80 p-6 rounded-3xl shadow-xl lg:col-span-1 space-y-4 backdrop-blur-md">
                    <h3 class="font-bold text-white flex items-center gap-2">
                        <i class="fa-solid fa-sliders text-cyan-400"></i> Konfigurasi Bobot Nilai (%)
                    </h3>
                    <p class="text-xs text-slate-400">Total akumulasi bobot komponen evaluasi harus bernilai tepat 100%.</p>
                    
                    <div class="space-y-3.5 pt-2">
                        <div>
                            <label class="block text-xs font-semibold text-slate-300 mb-1">Nilai Harian / Tugas (NH)</label>
                            <input type="number" id="weightNH" value="30" onchange="validateWeights()" class="w-full px-3.5 py-2.5 bg-slate-900 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                        </div>
                        <div>
                            <label class="block text-xs font-semibold text-slate-300 mb-1">Nilai Bulanan / Sumatif (NB)</label>
                            <input type="number" id="weightNB" value="25" onchange="validateWeights()" class="w-full px-3.5 py-2.5 bg-slate-900 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                        </div>
                        <div>
                            <label class="block text-xs font-semibold text-slate-300 mb-1">Catatan / Sikap Lab (NC)</label>
                            <input type="number" id="weightNC" value="10" onchange="validateWeights()" class="w-full px-3.5 py-2.5 bg-slate-900 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                        </div>
                        <div>
                            <label class="block text-xs font-semibold text-slate-300 mb-1">Projek / Coding Portofolio (NP)</label>
                            <input type="number" id="weightNP" value="35" onchange="validateWeights()" class="w-full px-3.5 py-2.5 bg-slate-900 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                        </div>
                        <div class="pt-3 border-t border-slate-700/80 flex justify-between items-center text-sm font-bold">
                            <span class="text-slate-300">Total Akumulasi:</span>
                            <span id="weightTotalDisplay" class="text-cyan-400">100%</span>
                        </div>
                    </div>
                </div>

                <!-- Student Grades Input Table container -->
                <div class="bg-slate-800/80 border border-slate-700/80 p-6 rounded-3xl shadow-xl lg:col-span-2 space-y-4 backdrop-blur-md">
                    <div class="flex justify-between items-center flex-wrap gap-4">
                        <div>
                            <h3 class="font-bold text-white flex items-center gap-2">
                                <i class="fa-solid fa-database text-cyan-400"></i> Rekapitulasi Data Siswa & Nilai Praktikum
                            </h3>
                            <p class="text-xs text-slate-400">Kelola dan update data nilai siswa secara real-time.</p>
                        </div>
                        <button onclick="openAddStudentModal()" class="px-4 py-2 bg-cyan-500/10 hover:bg-cyan-500/20 text-cyan-400 border border-cyan-500/30 font-bold text-xs rounded-xl transition-colors flex items-center gap-1.5 shadow-sm">
                            <i class="fa-solid fa-user-plus"></i> Tambah Siswa Baru
                        </button>
                    </div>

                    <div class="overflow-x-auto">
                        <table class="w-full text-left border-collapse">
                            <thead>
                                <tr class="border-b border-slate-700 text-xs font-bold text-slate-400 uppercase tracking-wider">
                                    <th class="py-3 px-3">Siswa & Kontak</th>
                                    <th class="py-3 px-3">Jenjang, Kelas & Jurusan</th>
                                    <th class="py-3 px-2 text-center">NH (30%)</th>
                                    <th class="py-3 px-2 text-center">NB (25%)</th>
                                    <th class="py-3 px-2 text-center">NC (10%)</th>
                                    <th class="py-3 px-2 text-center">NP (35%)</th>
                                    <th class="py-3 px-2 text-center">NA</th>
                                    <th class="py-3 px-3 text-right">Aksi</th>
                                </tr>
                            </thead>
                            <tbody id="teacherTableBody" class="divide-y divide-slate-700/60 text-sm">
                                <!-- Dynamic rows populated via JS -->
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <div id="viewStudentPortal" class="hidden fade-in space-y-6">
            <div class="bg-slate-800/80 border border-slate-700/80 p-6 rounded-3xl shadow-xl backdrop-blur-md flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
                <div>
                    <button onclick="backToSelector()" class="text-xs font-semibold text-slate-400 hover:text-sky-400 mb-2 flex items-center gap-1.5 transition-colors">
                        <i class="fa-solid fa-arrow-left"></i> Kembali ke Pilih Portal
                    </button>
                    <h2 class="text-2xl font-extrabold text-white">Transkrip Portal Nilai Siswa</h2>
                    <p class="text-sm text-slate-400">Pilih nama Anda untuk melihat rekap nilai akhir, rincian komponen, dan evaluasi lab.</p>
                </div>
                
                <div class="w-full sm:w-auto">
                    <label class="block text-xs font-semibold text-slate-300 mb-1">Pilih Identitas Siswa:</label>
                    <select id="studentSelectorDropdown" onchange="renderStudentDashboard()" class="w-full sm:w-72 px-3.5 py-2.5 border border-slate-700 rounded-xl text-sm font-semibold bg-slate-900 text-slate-100 focus:ring-2 focus:ring-sky-400 focus:outline-none">
                        <!-- Populated dynamically -->
                    </select>
                </div>
            </div>

            <!-- Student Detailed Report Card -->
            <div id="studentReportCard" class="grid grid-cols-1 md:grid-cols-3 gap-6">
                <!-- Summary Card -->
                <div class="bg-gradient-to-br from-cyan-600 via-sky-600 to-indigo-700 text-white p-6 rounded-3xl shadow-2xl flex flex-col justify-between relative overflow-hidden">
                    <div class="absolute -right-10 -bottom-10 w-40 h-40 bg-white/10 rounded-full blur-xl pointer-events-none"></div>
                    <div>
                        <span class="px-3 py-1 bg-white/20 text-white font-bold text-xs rounded-full uppercase tracking-wider backdrop-blur-md">Hasil Akhir Rapor IT</span>
                        <h3 id="srStudentName" class="text-2xl font-extrabold mt-4 mb-1">Nama Siswa</h3>
                        <p id="srStudentLevelClassMajor" class="text-xs text-sky-100 mb-2 font-medium">Jenjang, Kelas, Jurusan & Telepon</p>
                    </div>
                    <div class="my-6 text-center bg-slate-950/20 backdrop-blur-md py-6 rounded-2xl border border-white/15 shadow-inner">
                        <span class="text-xs uppercase tracking-widest text-sky-200 font-semibold block mb-1">Nilai Akhir (NA)</span>
                        <span id="srFinalScore" class="text-6xl font-black tracking-tight text-white">0.0</span>
                    </div>
                    <div class="text-xs text-sky-100 flex justify-between items-center bg-slate-950/20 px-4 py-2.5 rounded-xl border border-white/10">
                        <span>Predikat: <strong id="srGradePredicate" class="text-white font-extrabold text-sm ml-1">A</strong></span>
                        <span id="srStatusPass" class="px-2.5 py-1 bg-emerald-500/80 rounded-lg text-[10px] font-bold text-white shadow">Tuntas</span>
                    </div>
                </div>

                <!-- Breakdown Components -->
                <div class="bg-slate-800/80 border border-slate-700/80 p-6 rounded-3xl shadow-xl md:col-span-2 space-y-4 backdrop-blur-md">
                    <h3 class="font-bold text-white flex items-center gap-2">
                        <i class="fa-solid fa-chart-pie text-sky-400"></i> Rincian Formula & Komponen Nilai
                    </h3>
                    <p class="text-xs text-slate-400">Komposisi perhitungan nilai akhir berdasarkan standar laboratorium informatika.</p>

                    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 pt-2">
                        <div class="p-4 rounded-2xl bg-slate-900 border border-slate-700/80 flex justify-between items-center shadow-inner">
                            <div>
                                <span class="text-xs font-semibold text-slate-400 block mb-0.5">Nilai Harian (NH)</span>
                                <span id="srValNH" class="text-xl font-bold text-white">0</span>
                                <span class="text-[10px] text-slate-500 block">Bobot 30%</span>
                            </div>
                            <div class="text-right">
                                <span class="text-xs text-slate-500 block">Kontribusi</span>
                                <span id="srContribNH" class="text-sm font-bold text-cyan-400">0</span>
                            </div>
                        </div>

                        <div class="p-4 rounded-2xl bg-slate-900 border border-slate-700/80 flex justify-between items-center shadow-inner">
                            <div>
                                <span class="text-xs font-semibold text-slate-400 block mb-0.5">Nilai Bulanan (NB)</span>
                                <span id="srValNB" class="text-xl font-bold text-white">0</span>
                                <span class="text-[10px] text-slate-500 block">Bobot 25%</span>
                            </div>
                            <div class="text-right">
                                <span class="text-xs text-slate-500 block">Kontribusi</span>
                                <span id="srContribNB" class="text-sm font-bold text-cyan-400">0</span>
                            </div>
                        </div>

                        <div class="p-4 rounded-2xl bg-slate-900 border border-slate-700/80 flex justify-between items-center shadow-inner">
                            <div>
                                <span class="text-xs font-semibold text-slate-400 block mb-0.5">Catatan / Sikap Lab (NC)</span>
                                <span id="srValNC" class="text-xl font-bold text-white">0</span>
                                <span class="text-[10px] text-slate-500 block">Bobot 10%</span>
                            </div>
                            <div class="text-right">
                                <span class="text-xs text-slate-500 block">Kontribusi</span>
                                <span id="srContribNC" class="text-sm font-bold text-cyan-400">0</span>
                            </div>
                        </div>

                        <div class="p-4 rounded-2xl bg-slate-900 border border-slate-700/80 flex justify-between items-center shadow-inner">
                            <div>
                                <span class="text-xs font-semibold text-slate-400 block mb-0.5">Projek & Portofolio (NP)</span>
                                <span id="srValNP" class="text-xl font-bold text-white">0</span>
                                <span class="text-[10px] text-slate-500 block">Bobot 35%</span>
                            </div>
                            <div class="text-right">
                                <span class="text-xs text-slate-500 block">Kontribusi</span>
                                <span id="srContribNP" class="text-sm font-bold text-cyan-400">0</span>
                            </div>
                        </div>
                    </div>

                    <!-- Teacher Note / Journal Note -->
                    <div class="mt-4 p-4 rounded-2xl bg-cyan-950/40 border border-cyan-500/30">
                        <h4 class="text-xs font-bold text-cyan-400 uppercase tracking-wider mb-1.5 flex items-center gap-2">
                            <i class="fa-solid fa-terminal text-cyan-400"></i> Catatan Pembimbing & Evaluasi Kode
                        </h4>
                        <p id="srTeacherNote" class="text-sm text-slate-300 italic">"Menunjukkan pemahaman algoritma dan logika pemrograman yang sangat baik."</p>
                    </div>
                </div>
            </div>
        </div>

    </main>

    <!-- Add/Edit Student Modal -->
    <div id="studentModal" class="fixed inset-0 bg-slate-950/80 backdrop-blur-md z-50 hidden flex items-center justify-center p-4">
        <div class="bg-slate-900 border border-slate-800 rounded-3xl max-w-lg w-full p-6 sm:p-8 shadow-2xl fade-in text-slate-100 max-h-[90vh] overflow-y-auto">
            <h3 id="studentModalTitle" class="text-xl font-bold text-white mb-5 flex items-center gap-2.5">
                <i class="fa-solid fa-user-pen text-cyan-400"></i> Tambah Siswa Baru
            </h3>
            <input type="hidden" id="editStudentId">
            
            <div class="space-y-4">
                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Nama Lengkap Siswa</label>
                        <input type="text" id="inputStudentName" placeholder="Contoh: Budi Santoso" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                    </div>
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Jenjang Pendidikan</label>
                        <select id="inputStudentLevel" onchange="updateModalMajorOptions()" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                            <option value="SMP">SMP</option>
                            <option value="SMK" selected>SMK</option>
                        </select>
                    </div>
                </div>

                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Kelas</label>
                        <select id="inputStudentGradeClass" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                            <!-- Populated dynamically based on level -->
                        </select>
                    </div>
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Jurusan / Konsentrasi Keahlian</label>
                        <select id="inputStudentMajor" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                            <!-- Populated dynamically based on level -->
                        </select>
                    </div>
                </div>

                <div>
                    <label class="block text-xs font-semibold text-slate-300 mb-1">Nomor Telepon / WhatsApp</label>
                    <input type="text" id="inputStudentPhone" placeholder="Contoh: 081234567890" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                </div>
                <div class="grid grid-cols-2 gap-4">
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Nilai Harian (0-100)</label>
                        <input type="number" id="inputNH" value="85" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                    </div>
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Nilai Bulanan (0-100)</label>
                        <input type="number" id="inputNB" value="80" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                    </div>
                </div>
                <div class="grid grid-cols-2 gap-4">
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Catatan/Sikap (0-100)</label>
                        <input type="number" id="inputNC" value="90" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                    </div>
                    <div>
                        <label class="block text-xs font-semibold text-slate-300 mb-1">Nilai Projek (0-100)</label>
                        <input type="number" id="inputNP" value="88" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none">
                    </div>
                </div>
                <div>
                    <label class="block text-xs font-semibold text-slate-300 mb-1">Catatan Khusus Pembimbing Lab</label>
                    <textarea id="inputNote" rows="2" class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none" placeholder="Tulis catatan perkembangan siswa..."></textarea>
                </div>
            </div>

            <div class="flex justify-end gap-3 mt-6">
                <button onclick="closeStudentModal()" class="px-5 py-2.5 text-sm font-semibold text-slate-300 bg-slate-800 hover:bg-slate-700 rounded-xl transition-all border border-slate-700">Batal</button>
                <button onclick="saveStudentData()" class="px-6 py-2.5 text-sm font-semibold text-slate-950 bg-gradient-to-r from-cyan-400 to-sky-400 hover:from-cyan-300 hover:to-sky-300 rounded-xl transition-all shadow-lg shadow-cyan-500/20">Simpan Siswa</button>
            </div>
        </div>
    </div>

    <!-- Teacher Password Authentication Modal -->
    <div id="teacherPasswordModal" class="fixed inset-0 bg-slate-950/80 backdrop-blur-md z-50 hidden flex items-center justify-center p-4">
        <div class="bg-slate-900 border border-slate-800 rounded-3xl max-w-sm w-full p-6 sm:p-8 shadow-2xl fade-in text-slate-100">
            <div class="w-14 h-14 rounded-2xl bg-cyan-500/10 text-cyan-400 flex items-center justify-center text-2xl mb-5 border border-cyan-500/20 shadow-lg shadow-cyan-500/10">
                <i class="fa-solid fa-lock"></i>
            </div>
            <h3 class="text-xl font-bold text-white mb-2">Autentikasi Guru</h3>
            <p class="text-xs text-slate-400 mb-6 leading-relaxed">Silakan masukkan kode sandi pengajar (<code class="text-cyan-400 font-bold">suryogarage</code>) untuk masuk ke Portal Guru.</p>
            
            <div class="space-y-4">
                <div>
                    <label class="block text-xs font-semibold text-slate-300 mb-1">Kata Sandi Pengajar</label>
                    <input type="password" id="inputTeacherPassword" placeholder="Masukkan sandi..." class="w-full px-3.5 py-2.5 bg-slate-950 border border-slate-700 rounded-xl text-sm text-slate-100 focus:ring-2 focus:ring-cyan-500 focus:outline-none" onkeydown="if(event.key==='Enter') verifyTeacherPassword()">
                </div>
                <div id="passwordErrorMsg" class="text-xs text-rose-400 hidden font-semibold">Kata sandi salah. Silakan coba lagi.</div>
            </div>

            <div class="flex justify-end gap-3 mt-6">
                <button onclick="closeTeacherPasswordModal()" class="px-4 py-2.5 text-xs font-semibold text-slate-300 bg-slate-800 hover:bg-slate-700 rounded-xl transition-all border border-slate-700">Batal</button>
                <button onclick="verifyTeacherPassword()" class="px-5 py-2.5 text-xs font-semibold text-slate-950 bg-gradient-to-r from-cyan-400 to-sky-400 hover:from-cyan-300 hover:to-sky-300 rounded-xl transition-all shadow-lg shadow-cyan-500/20">Masuk</button>
            </div>
        </div>
    </div>

    <footer class="bg-slate-950 border-t border-slate-800/80 py-6 text-center text-xs text-slate-500 mt-auto">
        <p>&copy; 2026 Portal Nilai Informatika &mdash; Professional IT Grading & Assessment System.</p>
    </footer>

    <script type="module">
        import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js";
        import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js";
        import { getFirestore, doc, setDoc, getDoc, collection, getDocs, onSnapshot } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js";

        // Environment variables setup
        const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-grade-app';
        const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : null;

        let db = null;
        let auth = null;
        let userId = 'offline-user';
        let isCloudActive = false;

        // Default In-Memory / State Data populated from image list
        window.appState = {
            weights: { nh: 30, nb: 25, nc: 10, np: 35 },
            students: [
                { id: 'img_1', name: 'ARIE SISW', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000001', nh: 65.5, nb: 70, nc: 80, np: 75, note: 'Perlu bimbingan ekstra pada tugas praktik dasar.' },
                { id: 'img_2', name: 'AUDY TYA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000002', nh: 78, nb: 80, nc: 85, np: 80, note: 'Keaktifan dan pemahaman materi cukup baik.' },
                { id: 'img_3', name: 'Aura Nabi', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000003', nh: 61, nb: 65, nc: 75, np: 70, note: 'Tingkatkan latihan mandiri di rumah.' },
                { id: 'img_4', name: 'AZHRIEL F', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000004', nh: 74.5, nb: 75, nc: 80, np: 78, note: 'Progres stabil dalam pengerjaan tugas.' },
                { id: 'img_5', name: 'CHAIRIL G', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000005', nh: 77.5, nb: 78, nc: 82, np: 80, note: 'Pemahaman logika dasar sudah baik.' },
                { id: 'img_6', name: 'JAHIRA PU', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000006', nh: 0, nb: 50, nc: 60, np: 50, note: 'Perlu konfirmasi kehadiran dan pengumpulan tugas susulan.' },
                { id: 'img_7', name: 'MOHAMM', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000007', nh: 83.5, nb: 85, nc: 88, np: 85, note: 'Sangat teliti dalam menyelesaikan asesmen.' },
                { id: 'img_8', name: 'MUHAMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000008', nh: 80, nb: 80, nc: 85, np: 82, note: 'Konsisten menyelesaikan latihan harian.' },
                { id: 'img_9', name: 'MUHAMM', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000009', nh: 56, nb: 60, nc: 70, np: 65, note: 'Perlu perhatian khusus pada materi praktikum.' },
                { id: 'img_10', name: 'MUHAMM', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000010', nh: 81.5, nb: 82, nc: 85, np: 84, note: 'Menunjukkan keaktifan dalam diskusi kelompok.' },
                { id: 'img_11', name: 'MUHAMM', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000011', nh: 54, nb: 60, nc: 65, np: 60, note: 'Perlu peningkatan kedisiplinan dan pengumpulan tugas.' },
                { id: 'img_12', name: 'Revi Rizky', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000012', nh: 83.5, nb: 85, nc: 90, np: 86, note: 'Sikap dan hasil kerja lab memuaskan.' },
                { id: 'img_13', name: 'SAIF AMAI', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000013', nh: 63.25, nb: 68, nc: 75, np: 70, note: 'Perlu bimbingan lanjutan pada latihan soal.' },
                { id: 'img_14', name: 'SASKIA FA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000014', nh: 82, nb: 83, nc: 88, np: 85, note: 'Ketelitian tugas praktik sangat baik.' },
                { id: 'img_15', name: 'ZAHRA RIN', level: 'SMK', gradeClass: 'Kelas 10', major: 'AK', phone: '081200000015', nh: 75.5, nb: 78, nc: 82, np: 80, note: 'Performa stabil sepanjang semester.' },
                { id: 'img_16', name: 'AQIL FATT', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000016', nh: 79.5, nb: 80, nc: 85, np: 82, note: 'Pemahaman materi audio video baik.' },
                { id: 'img_17', name: 'DIMAS JOI', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000017', nh: 83.5, nb: 85, nc: 88, np: 86, note: 'Keterampilan praktik lab sangat baik.' },
                { id: 'img_18', name: 'EGA ERNE', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000018', nh: 83, nb: 84, nc: 86, np: 85, note: 'Konsisten menyelesaikan tugas tepat waktu.' },
                { id: 'img_19', name: 'FAKHRY TR', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000019', nh: 85, nb: 86, nc: 90, np: 88, note: 'Sangat antusias dalam praktikum hardware/software.' },
                { id: 'img_20', name: 'HAMZAH A', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000020', nh: 73.5, nb: 75, nc: 80, np: 78, note: 'Cukup baik, pertahankan motivasi belajar.' },
                { id: 'img_21', name: 'MUHAMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000021', nh: 81.5, nb: 82, nc: 85, np: 84, note: 'Aktif bertanya saat materi praktik.' },
                { id: 'img_22', name: 'MUHAMAMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000022', nh: 53.5, nb: 60, nc: 65, np: 60, note: 'Perlu pendampingan khusus remedial.' },
                { id: 'img_23', name: 'MUHAMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000023', nh: 75.5, nb: 78, nc: 82, np: 80, note: 'Peningkatan nilai terlihat konsisten.' },
                { id: 'img_24', name: 'RADITYA A', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000024', nh: 85, nb: 85, nc: 90, np: 88, note: 'Hasil kerja portofolio sangat rapi.' },
                { id: 'img_25', name: 'RAFFI ABIY', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000025', nh: 62.5, nb: 65, nc: 75, np: 70, note: 'Perlu peningkatan fokus dalam sesi teori.' },
                { id: 'img_26', name: 'RIFQI SYAI', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000026', nh: 76.5, nb: 78, nc: 82, np: 80, note: 'Disiplin dan kehadiran lab sangat baik.' },
                { id: 'img_27', name: 'RINALDI', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000027', nh: 77, nb: 78, nc: 82, np: 80, note: 'Kerjasama tim dalam kelompok baik.' },
                { id: 'img_28', name: 'RIZKY MAU', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000028', nh: 82, nb: 83, nc: 87, np: 85, note: 'Pemahaman teknis memuaskan.' },
                { id: 'img_29', name: 'VICKO AL-', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000029', nh: 73, nb: 75, nc: 80, np: 78, note: 'Tingkatkan ketelitian saat uji kompetensi.' },
                { id: 'img_30', name: 'ZHIDANE H', level: 'SMK', gradeClass: 'Kelas 10', major: 'AV', phone: '081200000030', nh: 82, nb: 84, nc: 88, np: 85, note: 'Menunjukkan kemampuan analisis yang baik.' },
                { id: 'img_31', name: 'ADITYA PU', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000031', nh: 68.5, nb: 70, nc: 78, np: 74, note: 'Cukup aktif dalam manajemen perkantoran digital.' },
                { id: 'img_32', name: 'AHMAD R', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000032', nh: 68, nb: 70, nc: 78, np: 74, note: 'Perlu latihan lebih sering pada aplikasi perkantoran.' },
                { id: 'img_33', name: 'ANDIRA M', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000033', nh: 83, nb: 85, nc: 90, np: 87, note: 'Kerapian administrasi dan tugas sangat baik.' },
                { id: 'img_34', name: 'ARRAHMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000034', nh: 92.5, nb: 94, nc: 96, np: 94, note: 'Prestasi sangat menonjol di kelas.' },
                { id: 'img_35', name: 'CLARISA P', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000035', nh: 82.5, nb: 85, nc: 88, np: 86, note: 'Ketepatan pengumpulan tugas sangat baik.' },
                { id: 'img_36', name: 'FADILLAH', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000036', nh: 85, nb: 86, nc: 90, np: 88, note: 'Sangat responsif terhadap materi instruktur.' },
                { id: 'img_37', name: 'HILMI ARI', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000037', nh: 79, nb: 80, nc: 85, np: 82, note: 'Keaktifan kelas memuaskan.' },
                { id: 'img_38', name: 'KESYA SEL', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000038', nh: 81, nb: 82, nc: 86, np: 84, note: 'Konsisten menjaga kualitas tugas.' },
                { id: 'img_39', name: 'MUHAMA', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000039', nh: 83, nb: 84, nc: 88, np: 86, note: 'Kerjasama kelompok sangat baik.' },
                { id: 'img_40', name: 'MUHAMAF', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000040', nh: 64, nb: 68, nc: 75, np: 70, note: 'Perlu peningkatan fokus pengerjaan tugas.' },
                { id: 'img_41', name: 'Muhammad', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000041', nh: 84, nb: 85, nc: 90, np: 87, note: 'Hasil kerja praktik sangat rapi.' },
                { id: 'img_42', name: 'MURNI CA', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000042', nh: 83, nb: 84, nc: 88, np: 86, note: 'Ketelitian administrasi perkantoran baik.' },
                { id: 'img_43', name: 'NAZARYAN', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000043', nh: 85, nb: 86, nc: 90, np: 88, note: 'Sangat aktif berdiskusi.' },
                { id: 'img_44', name: 'NURKHOLI', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000044', nh: 85, nb: 86, nc: 90, np: 88, note: 'Disiplin dan dedikasi belajar tinggi.' },
                { id: 'img_45', name: 'QATRUNN', level: 'SMK', gradeClass: 'Kelas 10', major: 'MP', phone: '081200000045', nh: 80.5, nb: 82, nc: 85, np: 83, note: 'Pemahaman modul perkantoran memuaskan.' },
                { id: 'img_46', name: 'Ahmad Ok', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000046', nh: 83, nb: 84, nc: 88, np: 86, note: 'Praktik bengkel dan kelistrikan baik.' },
                { id: 'img_47', name: 'Angga Juli', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000047', nh: 85, nb: 86, nc: 90, np: 88, note: 'Sangat terampil dalam praktik otomotif dasar.' },
                { id: 'img_48', name: 'Bintang W', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000048', nh: 85, nb: 86, nc: 90, np: 88, note: 'Disiplin bengkel sangat tinggi.' },
                { id: 'img_49', name: 'DASWA N', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000049', nh: 83, nb: 84, nc: 88, np: 86, note: 'Kerjasama tim mekanik sangat baik.' },
                { id: 'img_50', name: 'DUSTIN GI', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000050', nh: 85, nb: 86, nc: 90, np: 88, note: 'Pemahaman komponen mesin sangat teliti.' },
                { id: 'img_51', name: 'FAUJAN SA', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000051', nh: 77, nb: 79, nc: 83, np: 80, note: 'Cukup aktif dalam latihan praktikum.' },
                { id: 'img_52', name: 'HILMI PUT', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000052', nh: 79, nb: 80, nc: 85, np: 82, note: 'Konsisten mengikuti instruksi keselamatan kerja.' },
                { id: 'img_53', name: 'HISAM A', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000053', nh: 78, nb: 80, nc: 84, np: 81, note: 'Ketepatan waktu kumpul laporan baik.' },
                { id: 'img_54', name: 'MOHAMN', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000054', nh: 85, nb: 86, nc: 90, np: 88, note: 'Keterampilan motorik dan analisis mesin bagus.' },
                { id: 'img_55', name: 'Muhamad', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000055', nh: 80, nb: 81, nc: 85, np: 83, note: 'Keaktifan dan antusiasme tinggi.' },
                { id: 'img_56', name: 'MUHAMM', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000056', nh: 79, nb: 80, nc: 85, np: 82, note: 'Pemahaman materi dasar mesin baik.' },
                { id: 'img_57', name: 'NAUVAL D', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000057', nh: 85, nb: 86, nc: 90, np: 88, note: 'Sangat cekatan dalam pembongkaran komponen.' },
                { id: 'img_58', name: 'RIZKI RAM', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000058', nh: 85, nb: 86, nc: 90, np: 88, note: 'Hasil kerja praktik mesin memuaskan.' },
                { id: 'img_59', name: 'SUSENO A', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000059', nh: 83, nb: 84, nc: 88, np: 86, note: 'Disiplin dan kepatuhan SOP sangat baik.' },
                { id: 'img_60', name: 'SYAHID M', level: 'SMK', gradeClass: 'Kelas 10', major: 'TKR', phone: '081200000060', nh: 85, nb: 86, nc: 90, np: 88, note: 'Prestasi dan kinerja praktik konsisten.' }
            ]
        };

        // Initialize Firebase if config exists
        if (firebaseConfig) {
            try {
                const app = initializeApp(firebaseConfig);
                db = getFirestore(app);
                auth = getAuth(app);
                
                const token = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null;
                if (token) {
                    signInWithCustomToken(auth, token).then(() => {
                        userId = auth.currentUser?.uid || crypto.randomUUID();
                        isCloudActive = true;
                        initCloudSync();
                    }).catch(() => {
                        signInAnonymously(auth).then(() => {
                            userId = auth.currentUser?.uid || crypto.randomUUID();
                            isCloudActive = true;
                            initCloudSync();
                        });
                    });
                } else {
                    signInAnonymously(auth).then(() => {
                        userId = auth.currentUser?.uid || crypto.randomUUID();
                        isCloudActive = true;
                        initCloudSync();
                    });
                }
            } catch (e) {
                console.log("Running in offline mode.");
            }
        }

        function initCloudSync() {
            if (!db || !userId) return;
            const docRef = doc(db, 'artifacts', appId, 'public', 'data', 'informatika_grading_config');
            onSnapshot(docRef, (docSnap) => {
                if (docSnap.exists()) {
                    const data = docSnap.data();
                    if (data && data.weights && data.students) {
                        window.appState.weights = data.weights;
                        window.appState.students = data.students;
                        refreshUIViews();
                    }
                }
            }, (err) => { console.error(err); });
        }

        window.saveAllTeacherData = async function() {
            const wNh = parseFloat(document.getElementById('weightNH').value) || 0;
            const wNb = parseFloat(document.getElementById('weightNB').value) || 0;
            const wNc = parseFloat(document.getElementById('weightNC').value) || 0;
            const wNp = parseFloat(document.getElementById('weightNP').value) || 0;

            if ((wNh + wNb + wNc + wNp) !== 100) {
                showModal("Peringatan Bobot", "Total bobot seluruh komponen wajib persis 100% sebelum disimpan.", "warning");
                return;
            }

            window.appState.weights = { nh: wNh, nb: wNb, nc: wNc, np: wNp };

            if (isCloudActive && db) {
                try {
                    const docRef = doc(db, 'artifacts', appId, 'public', 'data', 'informatika_grading_config');
                    await setDoc(docRef, window.appState);
                    showModal("Berhasil Disimpan", "Data bobot dan nilai siswa berhasil disinkronkan ke server cloud.", "success");
                } catch (e) {
                    showModal("Penyimpanan Lokal", "Data berhasil diperbarui di memori lokal peramban.", "success");
                }
            } else {
                showModal("Penyimpanan Lokal", "Data berhasil diperbarui secara lokal.", "success");
            }
            refreshUIViews();
        };

        // Excel File Importer Handler using SheetJS
        window.handleExcelImport = function(event) {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function(e) {
                try {
                    const data = new Uint8Array(e.target.result);
                    const workbook = XLSX.read(data, { type: 'array' });
                    
                    // Take the first worksheet
                    const firstSheetName = workbook.SheetNames[0];
                    const worksheet = workbook.Sheets[firstSheetName];
                    
                    // Convert sheet to JSON rows
                    const rows = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
                    
                    if (!rows || rows.length === 0) {
                        showModal("Gagal Impor", "File Excel kosong atau format tabel tidak dikenali.", "warning");
                        return;
                    }

                    let importedCount = 0;
                    rows.forEach((row, idx) => {
                        // Flexible key matching for columns like Nama, Nilai Harian, NH, NB, etc.
                        const name = row['Nama'] || row['Nama Siswa'] || row['NAMA'] || row['nama'] || row['Student Name'] || '';
                        if (!name) return;

                        const level = row['Jenjang'] || row['Level'] || row['JENJANG'] || 'SMK';
                        const gradeClass = row['Kelas'] || row['Grade'] || row['KELAS'] || 'Kelas 10';
                        const major = row['Jurusan'] || row['Major'] || row['JURUSAN'] || 'PPLG';
                        const phone = row['Telepon'] || row['HP'] || row['No HP'] || row['WhatsApp'] || '081200000000';

                        const nh = parseFloat(row['NH'] || row['Nilai Harian'] || row['Harian'] || 80) || 80;
                        const nb = parseFloat(row['NB'] || row['Nilai Bulanan'] || row['Bulanan'] || row['Sumatif'] || 80) || 80;
                        const nc = parseFloat(row['NC'] || row['Catatan'] || row['Sikap'] || 85) || 85;
                        const np = parseFloat(row['NP'] || row['Nilai Projek'] || row['Projek'] || 85) || 85;
                        const note = row['Catatan Guru'] || row['Keterangan'] || 'Diimpor dari berkas REKAP_NILAI Excel.';

                        const newStudent = {
                            id: 'imp_' + Date.now() + '_' + idx,
                            name: String(name).trim(),
                            level: String(level).trim(),
                            gradeClass: String(gradeClass).trim(),
                            major: String(major).trim(),
                            phone: String(phone).trim(),
                            nh, nb, nc, np,
                            note: String(note).trim()
                        };

                        window.appState.students.push(newStudent);
                        importedCount++;
                    });

                    populateTeacherTable();
                    showModal("Berhasil Impor Excel", `Berhasil memuat ${importedCount} data siswa dari file ${file.name}.`, "success");
                } catch (err) {
                    console.error(err);
                    showModal("Kesalahan Berkas", "Terjadi kesalahan saat memproses file Excel. Pastikan format tabel benar.", "warning");
                }
                // Reset file input
                event.target.value = '';
            };
            reader.readAsArrayBuffer(file);
        };

        // Teacher Password Verification Handlers
        window.promptTeacherPassword = function() {
            document.getElementById('inputTeacherPassword').value = '';
            document.getElementById('passwordErrorMsg').classList.add('hidden');
            document.getElementById('teacherPasswordModal').classList.remove('hidden');
            setTimeout(() => {
                document.getElementById('inputTeacherPassword').focus();
            }, 100);
        };

        window.closeTeacherPasswordModal = function() {
            document.getElementById('teacherPasswordModal').classList.add('hidden');
        };

        window.verifyTeacherPassword = function() {
            const pwd = document.getElementById('inputTeacherPassword').value;
            if (pwd === 'suryogarage') {
                closeTeacherPasswordModal();
                switchPortal('teacher');
            } else {
                document.getElementById('passwordErrorMsg').classList.remove('hidden');
            }
        };

        // UI View Switcher Functions
        window.switchPortal = function(role) {
            document.getElementById('viewRoleSelector').classList.add('hidden');
            const roleText = document.getElementById('currentRoleText');
            
            // Update Navigation Pill Active Styles
            const btnT = document.getElementById('navBtnTeacher');
            const btnS = document.getElementById('navBtnStudent');
            const btnSel = document.getElementById('navBtnSelector');

            btnT.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white";
            btnS.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white";
            btnSel.className = "px-3 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-1.5 text-slate-400 hover:text-white";

            if (role === 'teacher') {
                document.getElementById('viewTeacherPortal').classList.remove('hidden');
                document.getElementById('viewStudentPortal').classList.add('hidden');
                roleText.innerHTML = `<i class="fa-solid fa-terminal text-cyan-400"></i> Portal Guru (Mode Edit)`;
                btnT.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 bg-cyan-500 text-slate-950 shadow-lg shadow-cyan-500/20";
                populateTeacherTable();
                validateWeights();
            } else if (role === 'student') {
                document.getElementById('viewTeacherPortal').classList.add('hidden');
                document.getElementById('viewStudentPortal').classList.remove('hidden');
                roleText.innerHTML = `<i class="fa-solid fa-laptop-code text-sky-400"></i> Portal Siswa (Mode Lihat)`;
                btnS.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 bg-sky-400 text-slate-950 shadow-lg shadow-sky-400/20";
                populateStudentDropdown();
                renderStudentDashboard();
            }
        };

        window.backToSelector = function() {
            document.getElementById('viewRoleSelector').classList.remove('hidden');
            document.getElementById('viewTeacherPortal').classList.add('hidden');
            document.getElementById('viewStudentPortal').classList.add('hidden');
            document.getElementById('currentRoleText').innerHTML = `<i class="fa-solid fa-shield-halved text-cyan-400"></i> Pilih Portal`;
            
            const btnT = document.getElementById('navBtnTeacher');
            const btnS = document.getElementById('navBtnStudent');
            const btnSel = document.getElementById('navBtnSelector');
            btnT.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white";
            btnS.className = "px-3.5 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-2 text-slate-400 hover:text-white";
            btnSel.className = "px-3 py-1.5 rounded-xl text-xs font-bold transition-all flex items-center gap-1.5 bg-slate-800 text-white shadow";
        };

        window.validateWeights = function() {
            const w1 = parseFloat(document.getElementById('weightNH').value) || 0;
            const w2 = parseFloat(document.getElementById('weightNB').value) || 0;
            const w3 = parseFloat(document.getElementById('weightNC').value) || 0;
            const w4 = parseFloat(document.getElementById('weightNP').value) || 0;
            const total = w1 + w2 + w3 + w4;

            const disp = document.getElementById('weightTotalDisplay');
            disp.innerText = total + '%';
            if (total === 100) {
                disp.className = "text-cyan-400 font-bold";
            } else {
                disp.className = "text-rose-400 font-bold";
            }
        };

        // Formula Calculation Helper
        window.calculateFinalScore = function(s, w) {
            const nh = parseFloat(s.nh) || 0;
            const nb = parseFloat(s.nb) || 0;
            const nc = parseFloat(s.nc) || 0;
            const np = parseFloat(s.np) || 0;

            const totalWeight = w.nh + w.nb + w.nc + w.np;
            if (totalWeight === 0) return 0;

            const final = (nh * (w.nh / 100)) + (nb * (w.nb / 100)) + (nc * (w.nc / 100)) + (np * (w.np / 100));
            return Math.round(final * 100) / 100;
        };

        window.populateTeacherTable = function() {
            const tbody = document.getElementById('teacherTableBody');
            tbody.innerHTML = '';
            const w = window.appState.weights;

            document.getElementById('weightNH').value = w.nh;
            document.getElementById('weightNB').value = w.nb;
            document.getElementById('weightNC').value = w.nc;
            document.getElementById('weightNP').value = w.np;
            validateWeights();

            window.appState.students.forEach((s, index) => {
                const final = calculateFinalScore(s, w);
                const isRemedial = final < 75;
                const finalScoreClass = isRemedial ? 'text-rose-400 font-extrabold bg-rose-950/40 px-2 py-0.5 rounded-lg border border-rose-500/30 inline-block' : 'text-cyan-400 font-extrabold';
                
                const tr = document.createElement('tr');
                tr.className = "hover:bg-slate-800/50 transition-colors";
                tr.innerHTML = `
                    <td class="py-3 px-3">
                        <div class="font-bold text-white">${s.name}</div>
                        <div class="text-xs text-slate-400 flex items-center gap-1.5 mt-0.5 font-medium">
                            <i class="fa-solid fa-phone text-[10px] text-cyan-400"></i> ${s.phone || '-'}
                        </div>
                    </td>
                    <td class="py-3 px-3">
                        <div class="flex items-center gap-1.5 mb-1">
                            <span class="px-2 py-0.5 bg-slate-900 text-slate-300 border border-slate-700 text-[10px] font-bold rounded">${s.level || 'SMK'}</span>
                            <span class="text-xs font-semibold text-slate-300">${s.gradeClass || 'Kelas 10'}</span>
                        </div>
                        <span class="px-2.5 py-1 bg-cyan-950/60 border border-cyan-500/30 text-cyan-300 text-xs font-bold rounded-lg inline-block">
                            ${s.major || 'PPLG'}
                        </span>
                    </td>
                    <td class="py-3 px-2 text-center font-medium">${s.nh}</td>
                    <td class="py-3 px-2 text-center font-medium">${s.nb}</td>
                    <td class="py-3 px-2 text-center font-medium">${s.nc}</td>
                    <td class="py-3 px-2 text-center font-medium">${s.np}</td>
                    <td class="py-3 px-2 text-center"><span class="${finalScoreClass}">${final}</span></td>
                    <td class="py-3 px-3 text-right space-x-1.5">
                        <button onclick="editStudent('${s.id}')" class="p-2 bg-slate-800 hover:bg-cyan-500/20 text-slate-300 hover:text-cyan-400 rounded-xl transition-colors border border-slate-700" title="Edit Siswa">
                            <i class="fa-solid fa-pen-to-square"></i>
                        </button>
                        <button onclick="deleteStudent('${s.id}')" class="p-2 bg-slate-800 hover:bg-rose-500/20 text-slate-300 hover:text-rose-400 rounded-xl transition-colors border border-slate-700" title="Hapus Siswa">
                            <i class="fa-solid fa-trash"></i>
                        </button>
                    </td>
                `;
                tbody.appendChild(tr);
            });
        };

        window.populateStudentDropdown = function() {
            const dropdown = document.getElementById('studentSelectorDropdown');
            dropdown.innerHTML = '';
            window.appState.students.forEach(s => {
                const opt = document.createElement('option');
                opt.value = s.id;
                opt.innerText = `${s.name} (${s.level || 'SMK'} - ${s.gradeClass || ''} - ${s.major || 'IT'})`;
                dropdown.appendChild(opt);
            });
        };

        window.renderStudentDashboard = function() {
            const dropdown = document.getElementById('studentSelectorDropdown');
            if (!dropdown || dropdown.options.length === 0) return;
            const selectedId = dropdown.value;
            const s = window.appState.students.find(item => item.id === selectedId) || window.appState.students[0];
            if (!s) return;

            const w = window.appState.weights;
            const final = calculateFinalScore(s, w);

            document.getElementById('srStudentName').innerText = s.name;
            document.getElementById('srStudentLevelClassMajor').innerHTML = `<i class="fa-solid fa-school"></i> ${s.level || 'SMK'} &bull; ${s.gradeClass || 'Kelas 10'} &bull; <i class="fa-solid fa-code"></i> ${s.major || '-'} &bull; <i class="fa-solid fa-phone"></i> ${s.phone || '-'}`;
            document.getElementById('srFinalScore').innerText = final.toFixed(1);

            document.getElementById('srValNH').innerText = s.nh;
            document.getElementById('srContribNH').innerText = ((s.nh * (w.nh / 100))).toFixed(1);

            document.getElementById('srValNB').innerText = s.nb;
            document.getElementById('srContribNB').innerText = ((s.nb * (w.nb / 100))).toFixed(1);

            document.getElementById('srValNC').innerText = s.nc;
            document.getElementById('srContribNC').innerText = ((s.nc * (w.nc / 100))).toFixed(1);

            document.getElementById('srValNP').innerText = s.np;
            document.getElementById('srContribNP').innerText = ((s.np * (w.np / 100))).toFixed(1);

            document.getElementById('srTeacherNote').innerText = `"${s.note || 'Belum ada catatan khusus dari pembimbing lab.'}"`;

            // Predicate & Status
            let predicate = 'A';
            if (final < 70) predicate = 'C';
            else if (final < 80) predicate = 'B';
            else if (final < 90) predicate = 'A-';
            else predicate = 'A+';

            document.getElementById('srGradePredicate').innerText = predicate;
            const passBadge = document.getElementById('srStatusPass');
            if (final >= 75) {
                passBadge.innerText = 'Tuntas / Kompeten';
                passBadge.className = 'px-2.5 py-1 bg-emerald-500 rounded-lg text-[10px] font-bold text-white shadow';
            } else {
                passBadge.innerText = 'Remidi / Perbaikan';
                passBadge.className = 'px-3 py-1 bg-rose-600 animate-pulse rounded-lg text-[11px] font-extrabold text-white shadow-lg border border-rose-400';
            }
        };

        window.refreshUIViews = function() {
            if (!document.getElementById('viewTeacherPortal').classList.contains('hidden')) {
                populateTeacherTable();
            }
            if (!document.getElementById('viewStudentPortal').classList.contains('hidden')) {
                populateStudentDropdown();
                renderStudentDashboard();
            }
        };

        window.updateModalMajorOptions = function(selectedMajor = 'PPLG', selectedGradeClass = 'Kelas 10') {
            const level = document.getElementById('inputStudentLevel').value;
            const majorSelect = document.getElementById('inputStudentMajor');
            const gradeClassSelect = document.getElementById('inputStudentGradeClass');

            // Grade classes based on level
            gradeClassSelect.innerHTML = '';
            if (level === 'SMP') {
                ['Kelas 7', 'Kelas 8', 'Kelas 9'].forEach(cls => {
                    const opt = document.createElement('option');
                    opt.value = cls;
                    opt.innerText = cls;
                    if (cls === selectedGradeClass) opt.selected = true;
                    gradeClassSelect.appendChild(opt);
                });
            } else {
                ['Kelas 10', 'Kelas 11', 'Kelas 12'].forEach(cls => {
                    const opt = document.createElement('option');
                    opt.value = cls;
                    opt.innerText = cls;
                    if (cls === selectedGradeClass) opt.selected = true;
                    gradeClassSelect.appendChild(opt);
                });
            }

            // Majors based on level
            majorSelect.innerHTML = '';
            if (level === 'SMP') {
                const opt = document.createElement('option');
                opt.value = 'Informatika Dasar';
                opt.innerText = 'Informatika Dasar (SMP)';
                majorSelect.appendChild(opt);
            } else {
                const majors = [
                    { code: 'PPLG', name: 'PPLG (Pengembangan Perangkat Lunak & GIM)' },
                    { code: 'TJKT', name: 'TJKT (Teknik Jaringan Komputer & Telekomunikasi)' },
                    { code: 'MPLB', name: 'MPLB (Manajemen Perkantoran & Layanan Bisnis)' },
                    { code: 'AKL', name: 'AKL (Akuntansi & Keuangan Lembaga)' },
                    { code: 'TKR', name: 'TKR (Teknik Kendaraan Ringan)' },
                    { code: 'TAV', name: 'TAV (Teknik Audio Video)' },
                    { code: 'DKV', name: 'DKV (Desain Komunikasi Visual)' },
                    { code: 'ANIMASI', name: 'Animasi & Multimedia' }
                ];
                majors.forEach(m => {
                    const opt = document.createElement('option');
                    opt.value = m.code;
                    opt.innerText = m.name;
                    if (m.code === selectedMajor) opt.selected = true;
                    majorSelect.appendChild(opt);
                });
            }
        };

        // Modal Form Handlers for Teacher adding/editing students
        window.openAddStudentModal = function() {
            document.getElementById('studentModalTitle').innerHTML = '<i class="fa-solid fa-user-plus text-cyan-400"></i> Tambah Siswa Baru';
            document.getElementById('editStudentId').value = '';
            document.getElementById('inputStudentName').value = '';
            document.getElementById('inputStudentLevel').value = 'SMK';
            updateModalMajorOptions('PPLG', 'Kelas 10');
            document.getElementById('inputStudentPhone').value = '';
            document.getElementById('inputNH').value = '80';
            document.getElementById('inputNB').value = '80';
            document.getElementById('inputNC').value = '85';
            document.getElementById('inputNP').value = '85';
            document.getElementById('inputNote').value = 'Menunjukkan perkembangan logika pemrograman yang positif.';
            document.getElementById('studentModal').classList.remove('hidden');
        };

        window.editStudent = function(id) {
            const s = window.appState.students.find(item => item.id === id);
            if (!s) return;
            document.getElementById('studentModalTitle').innerHTML = '<i class="fa-solid fa-user-pen text-cyan-400"></i> Edit Nilai Siswa';
            document.getElementById('editStudentId').value = s.id;
            document.getElementById('inputStudentName').value = s.name;
            document.getElementById('inputStudentLevel').value = s.level || 'SMK';
            updateModalMajorOptions(s.major || 'PPLG', s.gradeClass || 'Kelas 10');
            document.getElementById('inputStudentPhone').value = s.phone || '';
            document.getElementById('inputNH').value = s.nh;
            document.getElementById('inputNB').value = s.nb;
            document.getElementById('inputNC').value = s.nc;
            document.getElementById('inputNP').value = s.np;
            document.getElementById('inputNote').value = s.note || '';
            document.getElementById('studentModal').classList.remove('hidden');
        };

        window.closeStudentModal = function() {
            document.getElementById('studentModal').classList.add('hidden');
        };

        window.saveStudentData = function() {
            const id = document.getElementById('editStudentId').value;
            const name = document.getElementById('inputStudentName').value.trim();
            const level = document.getElementById('inputStudentLevel').value;
            const gradeClass = document.getElementById('inputStudentGradeClass').value;
            const major = document.getElementById('inputStudentMajor').value;
            const phone = document.getElementById('inputStudentPhone').value.trim();
            const nh = parseFloat(document.getElementById('inputNH').value) || 0;
            const nb = parseFloat(document.getElementById('inputNB').value) || 0;
            const nc = parseFloat(document.getElementById('inputNC').value) || 0;
            const np = parseFloat(document.getElementById('inputNP').value) || 0;
            const note = document.getElementById('inputNote').value.trim();

            if (!name) {
                showModal("Validasi Gagal", "Nama siswa wajib diisi.", "warning");
                return;
            }

            if (id) {
                const s = window.appState.students.find(item => item.id === id);
                if (s) {
                    s.name = name;
                    s.level = level;
                    s.gradeClass = gradeClass;
                    s.major = major;
                    s.phone = phone;
                    s.nh = nh; s.nb = nb; s.nc = nc; s.np = np; s.note = note;
                }
            } else {
                const newStudent = {
                    id: 's_' + Date.now(),
                    name, level, gradeClass, major, phone, nh, nb, nc, np, note
                };
                window.appState.students.push(newStudent);
            }

            closeStudentModal();
            populateTeacherTable();
            showModal("Berhasil", "Data siswa berhasil diperbarui.", "success");
        };

        window.deleteStudent = function(id) {
            window.appState.students = window.appState.students.filter(item => item.id !== id);
            populateTeacherTable();
            showModal("Berhasil", "Siswa telah dihapus dari daftar.", "success");
        };

        // Custom Modal helper
        window.showModal = function(title, message, type = 'info') {
            document.getElementById('modalTitle').innerText = title;
            document.getElementById('modalMessage').innerText = message;
            const iconDiv = document.getElementById('modalIcon');
            if (type === 'success') {
                iconDiv.className = 'w-14 h-14 rounded-2xl bg-emerald-500/10 text-emerald-400 flex items-center justify-center text-2xl mb-5 border border-emerald-500/20 shadow-lg shadow-emerald-500/10';
                iconDiv.innerHTML = '<i class="fa-solid fa-circle-check"></i>';
            } else if (type === 'warning') {
                iconDiv.className = 'w-14 h-14 rounded-2xl bg-amber-500/10 text-amber-400 flex items-center justify-center text-2xl mb-5 border border-amber-500/20 shadow-lg shadow-amber-500/10';
                iconDiv.innerHTML = '<i class="fa-solid fa-triangle-exclamation"></i>';
            } else {
                iconDiv.className = 'w-14 h-14 rounded-2xl bg-cyan-500/10 text-cyan-400 flex items-center justify-center text-2xl mb-5 border border-cyan-500/20 shadow-lg shadow-cyan-500/10';
                iconDiv.innerHTML = '<i class="fa-solid fa-circle-info"></i>';
            }
            document.getElementById('customModal').classList.remove('hidden');
        };

        window.closeModal = function(val) {
            document.getElementById('customModal').classList.add('hidden');
        };
    </script>
</body>
</html>

suryogarage

Post a Comment

0 Comments