// Deklarasi ekstraksi React Hooks di baris paling atas const { useState, useEffect, useMemo } = React; const API_URL = "api.php"; const INITIAL_CLASSES = [ { id: 1, nama: 'Kelas 1 MI', fase: 'Fase A' }, { id: 2, nama: 'Kelas 2 MI', fase: 'Fase A' }, { id: 3, nama: 'Kelas 3 MI', fase: 'Fase B' }, { id: 4, nama: 'Kelas 4 MI', fase: 'Fase B' }, { id: 5, nama: 'Kelas 5 MI', fase: 'Fase C' }, { id: 6, nama: 'Kelas 6 MI', fase: 'Fase C' }, ]; function App() { const [theme, setTheme] = useState('light'); const [isSidebarOpen, setIsSidebarOpen] = useState(true); const [isLoggedIn, setIsLoggedIn] = useState(false); const [classes] = useState(INITIAL_CLASSES); const [babList, setBabList] = useState([]); const [subBabList, setSubBabList] = useState([]); const [materiList, setMateriList] = useState([]); const [loading, setLoading] = useState(true); const [adminLogs, setAdminLogs] = useState([ { waktu: '2026-06-28 09:00', aksi: 'Sistem Akidah Akhlak MI Kurikulum Berbasis Cinta (KBC) siap di cPanel.', user: 'Sistem' } ]); const [currentView, setCurrentView] = useState('home'); const [selectedClass, setSelectedClass] = useState(null); const [selectedBab, setSelectedBab] = useState(null); const [selectedSubBab, setSelectedSubBab] = useState(null); const [selectedMateri, setSelectedMateri] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [adminActiveTab, setAdminActiveTab] = useState('materi'); const [editingBabId, setEditingBabId] = useState(null); const [editingBabName, setEditingBabName] = useState(''); const [editingBabNomor, setEditingBabNomor] = useState(1); const [selectedAdminClassId, setSelectedAdminClassId] = useState(1); const [editingSubBabId, setEditingSubBabId] = useState(null); const [editingSubBabName, setEditingSubBabName] = useState(''); const [editingSubBabNomor, setEditingSubBabNomor] = useState(1); const [selectedAdminBabId, setSelectedAdminBabId] = useState(1); const [formMode, setFormMode] = useState('add'); const [materiForm, setMateriForm] = useState({ id: null, class_id: 1, bab_id: 1, sub_bab_id: 1, judul: '', konten: '', gambar: '', pdf_nama: '', video_url: '', youtube_url: '', penulis: '' }); const [showLoginModal, setShowLoginModal] = useState(false); const [loginForm, setLoginForm] = useState({ username: '', password: '' }); const [loginError, setLoginError] = useState(''); const [toast, setToast] = useState({ show: false, message: '', type: 'success' }); const [isPreviewFormMode, setIsPreviewFormMode] = useState(false); const loadDatabaseFromMySQL = async () => { setLoading(true); try { const response = await fetch(`${API_URL}?action=get_data`); const data = await response.json(); if (data.status === 'success') { setBabList(data.babList || []); setSubBabList(data.subBabList || []); setMateriList(data.materiList || []); } else { showToast('Database MySQL kosong, menggunakan data demo KBC.', 'info'); loadOfflineData(); } } catch (error) { loadOfflineData(); } finally { setLoading(false); } }; const loadOfflineData = () => { setBabList([ { id: 1, kelas_id: 1, nomor: 1, nama: "Bab 1: Aku Cinta Dua Kalimat Syahadat" }, { id: 2, kelas_id: 1, nomor: 2, nama: "Bab 2: Mengenal Allah Melalui Ar-Rahman dan Ar-Rahim" }, { id: 3, kelas_id: 1, nomor: 3, nama: "Bab 3: Adab Mandi dan Berpakaian Bersih" }, { id: 4, kelas_id: 1, nomor: 4, nama: "Bab 4: Menghormati Orang Tua dan Guru" }, { id: 5, kelas_id: 1, nomor: 5, nama: "Bab 5: Kisah Keteladanan Nabi Muhammad SAW" }, { id: 6, kelas_id: 1, nomor: 6, nama: "Bab 6: Kalimat Tayyibah Basmalah dan Hamdalah" }, { id: 7, kelas_id: 1, nomor: 7, nama: "Bab 7: Asmaul Husna: Al-Ahad dan Al-Khaliq" }, { id: 8, kelas_id: 1, nomor: 8, nama: "Bab 8: Berterima Kasih dan Rendah Hati" }, { id: 9, kelas_id: 1, nomor: 9, nama: "Bab 9: Adab Belajar dan Bermain" }, { id: 10, kelas_id: 1, nomor: 10, nama: "Bab 10: Kisah Keteladanan Nabi Ismail AS" } ]); setSubBabList([ { id: 1, bab_id: 1, nomor: 1, nama: "Sub Bab 1: Tujuan Pembelajaran & Refleksi Mulia" }, { id: 2, bab_id: 1, nomor: 2, nama: "Sub Bab 2: Kajian Materi & Dalil Al-Qur'an/Hadis" }, { id: 3, bab_id: 1, nomor: 3, nama: "Sub Bab 3: Implementasi Kurikulum Berbasis Cinta (KBC)" }, { id: 4, bab_id: 1, nomor: 4, nama: "Sub Bab 4: Kisah Inspiratif Pembawa Hikmah" }, { id: 5, bab_id: 1, nomor: 5, nama: "Sub Bab 5: Rangkuman Intisari Pembelajaran" }, { id: 6, bab_id: 1, nomor: 6, nama: "Sub Bab 6: Asesmen Sumatif & Evaluasi Mandiri" } ]); setMateriList([ { id: 1, sub_bab_id: 1, judul: "Mari Mengenal Dua Kalimat Syahadat", konten: `

Assalamu'alaikum Warahmatullahi Wabarakatuh.
Anak-anakku yang hebat, cerdas, dan shalih-shalihah, selamat datang di Kurikulum Berbasis Cinta (KBC)!

Pada bab pertama ini, kita akan bersama-sama menanamkan rasa cinta kita kepada Allah dan Rasul-Nya melalui pondasi utama keimanan kita, yaitu Dua Kalimat Syahadat (Syahadatain).

أَشْهَدُ أَنْ لَا إِلَهَ إِلَّا اللهُ وَأَشْهَدُ أَنَّ مُحَمَّدًا رَسُولُ اللهِ

"Aku bersaksi bahwa tiada Tuhan selain Allah, dan aku bersaksi bahwa Nabi Muhammad adalah utusan Allah."

`, media: { gambar: "https://images.unsplash.com/photo-1564507592333-c60657eea523?auto=format&fit=crop&w=800&q=80", pdf_nama: "syahadatain_kurikulum_kbc_k1.pdf", video_url: "https://www.w3schools.com/html/mov_bbb.mp4", youtube_url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, penulis: "Ustadzah Aisyah Rahma, S.Pd", diupdate_pada: "2026-06-28 08:30" } ]); }; const showToast = (message, type = 'success') => { setToast({ show: true, message, type }); setTimeout(() => { setToast({ show: false, message: '', type: 'success' }); }, 4000); }; const addLog = (aksi, user = isLoggedIn ? 'Admin' : 'Tamu') => { const waktu = new Date().toISOString().replace('T', ' ').substring(0, 16); setAdminLogs(prev => [{ waktu, aksi, user }, ...prev]); }; const filteredBab = useMemo(() => { if (!selectedClass) return []; return babList.filter(b => Number(b.kelas_id) === selectedClass.id); }, [selectedClass, babList]); const filteredSubBab = useMemo(() => { if (!selectedBab) return []; return subBabList.filter(sb => Number(sb.bab_id) === selectedBab.id); }, [selectedBab, subBabList]); const formSubBabList = useMemo(() => { return subBabList.filter(sb => Number(sb.bab_id) === Number(materiForm.bab_id)); }, [materiForm.bab_id, subBabList]); const formBabList = useMemo(() => { return babList.filter(b => Number(b.kelas_id) === Number(materiForm.class_id)); }, [materiForm.class_id, babList]); const searchResults = useMemo(() => { if (!searchQuery.trim()) return []; const query = searchQuery.toLowerCase(); return materiList.map(materi => { const sub = subBabList.find(s => Number(s.id) === Number(materi.sub_bab_id)); const bab = sub ? babList.find(b => Number(b.id) === Number(sub.bab_id)) : null; const klis = bab ? classes.find(c => Number(c.id) === Number(bab.kelas_id)) : null; return { materi, sub, bab, kelas: klis, matchScore: ( (materi.judul.toLowerCase().includes(query) ? 3 : 0) + (materi.konten.toLowerCase().includes(query) ? 1 : 0) + (sub?.nama.toLowerCase().includes(query) ? 2 : 0) + (bab?.nama.toLowerCase().includes(query) ? 2 : 0) ) }; }).filter(res => res.matchScore > 0); }, [searchQuery, materiList, subBabList, babList, classes]); const handleLogin = async (e) => { e.preventDefault(); try { const response = await fetch(`${API_URL}?action=login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(loginForm) }); const data = await response.json(); if (data.status === 'success') { setIsLoggedIn(true); setShowLoginModal(false); setLoginForm({ username: '', password: '' }); setLoginError(''); showToast('Login berhasil sebagai Admin!', 'success'); addLog('Login admin berhasil terautentikasi.', data.user.nama_lengkap); } else { setLoginError(data.message); } } catch (err) { if (loginForm.username === 'admin' && loginForm.password === 'akidahmi123') { setIsLoggedIn(true); setShowLoginModal(false); setLoginForm({ username: '', password: '' }); showToast('Login berhasil (Mode Offline)!', 'success'); } else { setLoginError('Koneksi database cPanel offline. Gunakan kredensial default.'); } } }; const handleLogout = () => { setIsLoggedIn(false); setCurrentView('home'); showToast('Logout berhasil.', 'info'); }; const navigateToMateri = (subBabId) => { const foundSub = subBabList.find(sb => Number(sb.id) === Number(subBabId)); if (!foundSub) return; const foundBab = babList.find(b => Number(b.id) === Number(foundSub.bab_id)); const foundClass = classes.find(c => Number(c.id) === Number(foundBab.kelas_id)); const foundMateri = materiList.find(m => Number(m.sub_bab_id) === Number(subBabId)); setSelectedClass(foundClass); setSelectedBab(foundBab); setSelectedSubBab(foundSub); setSelectedMateri(foundMateri || null); setCurrentView('materi-baca'); }; const handleDeleteMateri = async (id) => { if (confirm('Apakah Anda yakin ingin menghapus materi ini dari database?')) { try { const response = await fetch(`${API_URL}?action=delete_materi&id=${id}`); const data = await response.json(); if (data.status === 'success') { showToast('Materi berhasil dihapus!', 'success'); loadDatabaseFromMySQL(); } } catch (err) { showToast('Koneksi server gagal.', 'error'); } } }; const handleSaveMateri = async (e) => { e.preventDefault(); const payload = { id: formMode === 'add' ? null : materiForm.id, sub_bab_id: Number(materiForm.sub_bab_id), judul: materiForm.judul, konten: materiForm.konten, penulis: materiForm.penulis || 'Guru Pengampu', media: { gambar: materiForm.gambar || '', pdf_nama: materiForm.pdf_nama || '', video_url: materiForm.video_url || '', youtube_url: materiForm.youtube_url || '' } }; try { const response = await fetch(`${API_URL}?action=save_materi`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); if (data.status === 'success') { showToast('Materi berhasil disimpan!', 'success'); await loadDatabaseFromMySQL(); navigateToMateri(materiForm.sub_bab_id); } } catch (err) { showToast('Gagal terhubung ke database. Data tidak tersimpan.', 'error'); } }; const handleSaveBab = async (e) => { e.preventDefault(); if (!editingBabName.trim()) return; const payload = { id: editingBabId, kelas_id: Number(selectedAdminClassId), nomor: Number(editingBabNomor), nama: `Bab ${editingBabNomor}: ${editingBabName.replace(/^Bab \d+:\s*/i, '')}` }; try { const response = await fetch(`${API_URL}?action=save_bab`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); if (data.status === 'success') { showToast('Bab berhasil disimpan!', 'success'); setEditingBabId(null); setEditingBabName(''); loadDatabaseFromMySQL(); } } catch (err) { showToast('Gagal koneksi server.', 'error'); } }; const handleDeleteBab = async (id) => { if (confirm('Hapus Bab ini dari database?')) { try { await fetch(`${API_URL}?action=delete_bab&id=${id}`); showToast('Bab berhasil dihapus!', 'success'); loadDatabaseFromMySQL(); } catch (err) { showToast('Gagal menghapus.', 'error'); } } }; const handleSaveSubBab = async (e) => { e.preventDefault(); if (!editingSubBabName.trim()) return; const payload = { id: editingSubBabId, bab_id: Number(selectedAdminBabId), nomor: Number(editingSubBabNomor), nama: `Sub Bab ${editingSubBabNomor}: ${editingSubBabName.replace(/^Sub Bab \d+:\s*/i, '')}` }; try { const response = await fetch(`${API_URL}?action=save_sub_bab`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); if (data.status === 'success') { showToast('Sub-Bab berhasil disimpan!', 'success'); setEditingSubBabId(null); setEditingSubBabName(''); loadDatabaseFromMySQL(); } } catch (err) { showToast('Gagal koneksi server.', 'error'); } }; const handleDeleteSubBab = async (id) => { if (confirm('Hapus Sub-Bab ini?')) { try { await fetch(`${API_URL}?action=delete_sub_bab&id=${id}`); showToast('Sub-Bab berhasil dihapus!', 'success'); loadDatabaseFromMySQL(); } catch (err) { showToast('Gagal menghapus.', 'error'); } } }; const openMateriForm = (mode, targetMateri = null) => { if (mode === 'add') { setFormMode('add'); setMateriForm({ id: null, class_id: selectedClass ? selectedClass.id : 1, bab_id: selectedBab ? selectedBab.id : 1, sub_bab_id: selectedSubBab ? selectedSubBab.id : 1, judul: '', konten: '', gambar: '', pdf_nama: '', video_url: '', youtube_url: '', penulis: 'Pendidik KBC' }); } else { setFormMode('edit'); setMateriForm({ id: targetMateri.id, class_id: selectedClass ? selectedClass.id : 1, bab_id: selectedBab ? selectedBab.id : 1, sub_bab_id: targetMateri.sub_bab_id, judul: targetMateri.judul, konten: targetMateri.konten, gambar: targetMateri.media?.gambar || '', pdf_nama: targetMateri.media?.pdf_nama || '', video_url: targetMateri.media?.video_url || '', youtube_url: targetMateri.media?.youtube_url || '', penulis: targetMateri.penulis }); } setIsPreviewFormMode(false); setCurrentView('admin-materi-form'); }; const handleBackup = () => { const databaseJSON = JSON.stringify({ classes, babList, subBabList, materiList }, null, 2); const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(databaseJSON); const linkElement = document.createElement('a'); linkElement.setAttribute('href', dataUri); linkElement.setAttribute('download', 'backup_akidah_kbc_mi.json'); linkElement.click(); showToast('Backup JSON berhasil diunduh!', 'success'); }; const handleImport = (e) => { const fileReader = new FileReader(); if (e.target.files.length > 0) { fileReader.readAsText(e.target.files[0], "UTF-8"); fileReader.onload = (event) => { try { const parsed = JSON.parse(event.target.result); if (parsed.materiList && parsed.babList && parsed.subBabList) { setBabList(parsed.babList); setSubBabList(parsed.subBabList); setMateriList(parsed.materiList); showToast('Data materi Kurikulum KBC sukses di-import!', 'success'); } } catch (err) { showToast('Gagal memproses berkas JSON.', 'error'); } }; } }; return (
{/* ========================================== HEADER NAVBAR (PREMIUM STYLE) ========================================== */}
{ setCurrentView('home'); setSelectedClass(null); }}>
00

Akidah Akhlak MI

Kurikulum Berbasis Cinta (KBC)
{isLoggedIn && ( )} {isLoggedIn ? ( ) : ( )}
{/* Loading State Overlay */} {loading && (
Mengkoneksikan & memuat data dari database MySQL cPanel...
)}
{/* ========================================== SIDEBAR NAVIGATION (PREMIUM DESIGN) ========================================== */} {isSidebarOpen && ( )} {/* ========================================== MAIN CONTENT WINDOW ========================================== */}
{currentView === 'home' && (
🕌
Kurikulum Berbasis Cinta (KBC)

Portal Belajar Akidah Akhlak

Membangun akhlak mulia dan akidah Islamiah berbasis kecintaan tulus kepada Allah SWT, sesama manusia, dan alam semesta.

{/* INTEGRASI KBC HIGHLIGHT */}

Fokus Utama: Kurikulum Berbasis Cinta (KBC)

Kurikulum di Madrasah Ibtidaiyah menekankan pembelajaran bermakna berlandaskan cinta kasih untuk menghasilkan generasi muslim yang tulus, berakhlak mulia melalui pendekatan Kurikulum Berbasis Cinta (KBC), toleran, beradab, serta memiliki empati tinggi. Setiap sub-bab dilengkapi aksi nyata berbasis empati dan cinta kasih yang kontekstual.

)} {currentView === 'kelas-detail' && selectedClass && (

Alur Pembelajaran {selectedClass.nama}

{isLoggedIn && ( )}
{babList.filter(b => Number(b.kelas_id) === selectedClass.id).map((bab) => (
{`Bab ${bab.nomor}`}

{bab.nama}

{subBabList.filter(s => Number(s.bab_id) === bab.id).map(sub => ( ))}
))}
)} {currentView === 'materi-baca' && selectedSubBab && (
{selectedClass?.nama} ➔ {selectedBab?.nama.split(': ')[0]}

{selectedSubBab.nama}

{isLoggedIn && (
{selectedMateri && ( )}
)}
{selectedMateri ? (

Ditulis oleh: {selectedMateri.penulis} | Terakhir diupdate: {selectedMateri.diupdate_pada}

{selectedMateri.media?.gambar && ( Cover )}
{/* Lampiran Media */} {(selectedMateri.media?.pdf_nama || selectedMateri.media?.youtube_url) && (

📚 Sumber Belajar Tambahan

{selectedMateri.media.pdf_nama && (
{selectedMateri.media.pdf_nama}
)} {selectedMateri.media.youtube_url && (
Video Referensi Pembelajaran
{selectedMateri.media.youtube_url}
)}
)}
) : (

Materi belum diisi oleh guru pengampu.

{isLoggedIn && ( )}
)}
)} {/* ======================================================== VIEW 5: ADMIN DASHBOARD (DENGAN TIGA TAB KELOLA) ======================================================== */} {currentView === 'admin-dashboard' && isLoggedIn && (

Dashboard Pengelolaan Kurikulum Merdeka (KBC)

Ubah materi, bab, dan sub-bab secara instan ke database cPanel.

{/* Tabs */}
{/* TAB CONTENT: KELOLA MATERI */} {adminActiveTab === 'materi' && (

Daftar Modul Terbit

{materiList.map(m => (

{m.judul}

Penulis: {m.penulis}

))}
)} {/* TAB CONTENT: KELOLA BAB */} {adminActiveTab === 'bab' && (

{editingBabId ? 'Ubah Bab' : 'Tambah Bab'}

setEditingBabNomor(e.target.value)} className="w-full p-2 border rounded-xl text-xs bg-transparent" required />
setEditingBabName(e.target.value)} className="w-full p-2 border rounded-xl text-xs bg-transparent" required />

Daftar Bab Kelas Terpilih

{babList.filter(b => Number(b.kelas_id) === Number(selectedAdminClassId)).map(b => (
{b.nama}
))}
)} {/* TAB CONTENT: KELOLA SUB-BAB */} {adminActiveTab === 'sub_bab' && (

{editingSubBabId ? 'Ubah Sub-Bab' : 'Tambah Sub-Bab'}

setEditingSubBabNomor(e.target.value)} className="w-full p-2 border rounded-xl text-xs bg-transparent" required />
setEditingSubBabName(e.target.value)} className="w-full p-2 border rounded-xl text-xs bg-transparent" required />

Daftar Sub-Bab

{subBabList.filter(s => Number(s.bab_id) === Number(selectedAdminBabId)).map(s => (
{s.nama}
))}
)}
)} {/* ======================================================== VIEW 6: EDITOR FORM (TAMBAH & EDIT MATERI) ======================================================== */} {currentView === 'admin-materi-form' && isLoggedIn && (

{formMode === 'add' ? 'Tambah Modul Materi Baru' : 'Ubah Modul Materi'}

setMateriForm({...materiForm, judul: e.target.value})} className="w-full p-2.5 border rounded-xl text-xs bg-transparent" required />
setMateriForm({...materiForm, penulis: e.target.value})} className="w-full p-2.5 border rounded-xl text-xs bg-transparent" required />