import React, { useState, useEffect, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { BookOpen, GraduationCap, ChevronLeft, Timer, Trophy, CheckCircle2, XCircle, RotateCcw, Calculator, Atom, Microscope, History, Globe2, Lock, Upload, User, LogOut, FileSpreadsheet, Plus, Trash2, Library, AlertCircle, Sparkles, Rocket, Star, Gamepad2, PartyPopper, Ghost, Lightbulb, LayoutDashboard, Target, Medal, Flame, ArrowRight } from 'lucide-react'; // Muat pustaka XLSX untuk parsing Excel const loadXLSX = () => { return new Promise((resolve) => { if (window.XLSX) return resolve(window.XLSX); const script = document.createElement('script'); script.src = "https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"; script.onload = () => resolve(window.XLSX); document.head.appendChild(script); }); }; const iconMap = { Matematika: , Sains: , Biologi: , Sejarah: , Ekonomi: , English: , Default: }; const INITIAL_DATA = { SD: { label: "Sekolah Dasar", tagline: "Dunia Bermain & Belajar", color: "from-orange-400 to-yellow-400", mascot: "🤖", bg: "bg-orange-50", grades: { "Kelas 1": { subjects: [] }, "Kelas 2": { subjects: [] }, "Kelas 3": { subjects: [] }, "Kelas 4": { subjects: [] }, "Kelas 5": { subjects: [] }, "Kelas 6": { subjects: [ { id: "mat-6", name: "Matematika", icon: 'Matematika', questions: [ { q: "Berapakah hasil dari 25 + 17?", o: ["32", "42", "52", "40"], c: 1 }, { q: "Bangun datar yang memiliki 3 sisi disebut...", o: ["Persegi", "Segitiga", "Lingkaran", "Trapesium"], c: 1 } ] } ] }, } }, SMP: { label: "Sekolah Menengah", tagline: "Eksplorasi Pengetahuan", color: "from-blue-500 to-cyan-400", mascot: "🚀", bg: "bg-blue-50", grades: { "Kelas 7": { subjects: [] }, "Kelas 8": { subjects: [] }, "Kelas 9": { subjects: [ { id: "bio-9", name: "Biologi", icon: 'Biologi', questions: [ { q: "Alat pernapasan pada ikan adalah...", o: ["Paru-paru", "Trakea", "Insang", "Kulit"], c: 2 } ] } ] }, } }, SMA: { label: "Sekolah Menengah Atas", tagline: "Persiapan Masa Depan", color: "from-indigo-600 to-purple-500", mascot: "🧠", bg: "bg-purple-50", grades: { "Kelas 10": { subjects: [] }, "Kelas 11": { subjects: [] }, "Kelas 12": { subjects: [ { id: "fis-12", name: "Fisika", icon: 'Sains', questions: [ { q: "Apa satuan SI untuk gaya?", o: ["Joule", "Watt", "Newton", "Pascal"], c: 2 } ] } ] }, } } }; export default function App() { const [view, setView] = useState('login'); const [userRole, setUserRole] = useState(null); const [quizData, setQuizData] = useState(INITIAL_DATA); const [levelKey, setLevelKey] = useState(null); const [gradeKey, setGradeKey] = useState(null); const [subject, setSubject] = useState(null); const [currentIdx, setCurrentIdx] = useState(0); const [score, setScore] = useState(0); const [timeLeft, setTimeLeft] = useState(20); const [selectedOption, setSelectedOption] = useState(null); const [feedback, setFeedback] = useState(null); const [userAnswers, setUserAnswers] = useState([]); const [adminPass, setAdminPass] = useState(''); const [isXlsxLoaded, setIsXlsxLoaded] = useState(false); const [toast, setToast] = useState(null); // Simulated student stats const [stats, setStats] = useState({ points: 1250, streak: 5, completed: 12, rank: "Bintang Pelajar" }); useEffect(() => { loadXLSX().then(() => setIsXlsxLoaded(true)); }, []); useEffect(() => { if (view !== 'quiz' || feedback) return; if (timeLeft === 0) { processAnswer(null); return; } const timer = setInterval(() => setTimeLeft(prev => prev - 1), 1000); return () => clearInterval(timer); }, [timeLeft, view, feedback]); const processAnswer = (idx) => { const isCorrect = idx === subject.questions[currentIdx].c; setFeedback(isCorrect ? 'correct' : 'wrong'); setTimeout(() => { if (isCorrect) { setScore(s => s + 1); setStats(prev => ({ ...prev, points: prev.points + 50 })); } setUserAnswers(prev => [...prev, { q: subject.questions[currentIdx].q, selected: idx, correct: subject.questions[currentIdx].c, isCorrect }]); if (currentIdx + 1 < subject.questions.length) { setCurrentIdx(i => i + 1); setSelectedOption(null); setTimeLeft(20); setFeedback(null); } else { setView('result'); setFeedback(null); setStats(prev => ({ ...prev, completed: prev.completed + 1 })); } }, 1500); }; const handleExcelUpload = (e) => { const file = e.target.files[0]; if (!file || !window.XLSX) return; const reader = new FileReader(); reader.onload = (evt) => { try { const bstr = evt.target.result; const wb = window.XLSX.read(bstr, { type: 'binary' }); const ws = wb.Sheets[wb.SheetNames[0]]; const rawData = window.XLSX.utils.sheet_to_json(ws); const newData = JSON.parse(JSON.stringify(quizData)); let count = 0; rawData.forEach(row => { const findKey = (name) => { const key = Object.keys(row).find(k => k.toLowerCase().trim() === name.toLowerCase()); return row[key]; }; const Jenjang = findKey('Jenjang'); const Kelas = findKey('Kelas'); const Mapel = findKey('Mapel'); const Pertanyaan = findKey('Pertanyaan'); const A = findKey('A'); const B = findKey('B'); const C = findKey('C'); const D = findKey('D'); const Kunci = findKey('Kunci'); if (!Jenjang || !Kelas || !Mapel || !Pertanyaan) return; const normalizedLevel = String(Jenjang).toUpperCase().trim(); if (newData[normalizedLevel]) { const currentGrades = newData[normalizedLevel].grades; const kelasStr = String(Kelas).trim(); const targetGrade = kelasStr.startsWith('Kelas') ? kelasStr : `Kelas ${kelasStr}`; if (!currentGrades[targetGrade]) { currentGrades[targetGrade] = { subjects: [] }; } let subj = currentGrades[targetGrade].subjects.find(s => s.name === Mapel); if (!subj) { subj = { id: Math.random().toString(36).substr(2, 9), name: Mapel, icon: 'Default', questions: [] }; currentGrades[targetGrade].subjects.push(subj); } subj.questions.push({ q: Pertanyaan, o: [A, B, C, D], c: isNaN(parseInt(Kunci)) ? 0 : parseInt(Kunci) }); count++; } }); if (count > 0) { setQuizData(newData); setToast({ type: 'success', message: `Berhasil! ${count} soal ditambahkan.` }); } } catch (err) { setToast({ type: 'error', message: "Error membaca file." }); } e.target.value = null; }; reader.readAsBinaryString(file); }; const renderToast = () => ( {toast && ( {toast.type === 'success' ? : } {toast.message} )} ); const renderLogin = () => (

EduPintar

Pintu Masa Depanmu

setAdminPass(e.target.value)} className="w-full px-6 py-4 bg-gray-50 rounded-2xl border-2 border-transparent focus:border-indigo-400 outline-none text-center font-bold mb-3"/>
); const renderDashboard = () => (
{/* Top Bar Dashboard */}

Selamat Datang, Sobat Pintar!

{stats.rank}

{stats.points}
{stats.streak} Hari
{userRole === 'admin' && ( )}
{/* Sidebar Stats & Info */}

Misi Belajar

{stats.completed}

Kuis Selesai

85%

Rata-rata Skor

"Pendidikan adalah senjata paling mematikan di dunia."

— Nelson Mandela

{/* Main Content: Level Selection */}

Jelajahi Tingkatan

{Object.entries(quizData).map(([key, data], idx) => ( { setLevelKey(key); setView('grades'); }} className={`group bg-white p-8 rounded-[3rem] shadow-2xl transition-all text-left relative overflow-hidden border-b-[12px] border-black/5 flex flex-col`} >
{data.mascot}

{key}

{data.tagline}

PILIH
))}
{/* Daily Challenge Promo */}
Tantangan Harian

Siap Untuk Menjadi Juara Minggu Ini?

Selesaikan 3 kuis hari ini untuk mendapatkan lencana khusus!

); const renderGradeSelect = () => (

Pilih Kelas

{quizData[levelKey].label}

{Object.keys(quizData[levelKey].grades).map((grade, idx) => ( { setGradeKey(grade); setView('subjects'); }} className="p-10 bg-white rounded-[3rem] shadow-xl border-b-[8px] border-slate-100 hover:border-indigo-400 transition-all group"> {grade.split(' ')[1]}

{grade.split(' ')[0]}

))}
); const renderSubjectSelect = () => { const subjects = quizData[levelKey].grades[gradeKey].subjects; return (

Mata Pelajaran

{levelKey} • {gradeKey}

{subjects.length > 0 ? (
{subjects.map((subj, idx) => ( { setSubject(subj); setView('quiz'); setCurrentIdx(0); setScore(0); setTimeLeft(20); setUserAnswers([]); setSelectedOption(null); }} className="flex items-center gap-6 p-8 bg-white rounded-[3rem] shadow-xl border-b-[8px] border-slate-50 group">
{iconMap[subj.name] || iconMap.Default}

{subj.name}

{subj.questions.length} LEVEL

))}
) : (

Belum Ada Soal Disini!

)}
); }; const renderQuiz = () => { const q = subject.questions[currentIdx]; const progress = ((currentIdx + 1) / subject.questions.length) * 100; return (
{feedback && ( {feedback === 'correct' ? '🌟' : '💢'}

{feedback === 'correct' ? 'KEREN!' : 'COBA LAGI'}

)}
{timeLeft}s

{subject.name}

{currentIdx + 1} / {subject.questions.length}

{quizData[levelKey].mascot}

{q.q}

{q.o.map((opt, idx) => ( ))}
); }; const renderResult = () => { const percent = Math.round((score / subject.questions.length) * 100); return (
🎉

LUAR BIASA!

Poin Kamu Bertambah!

+{score * 50}

Poin Baru

{percent}%

Akurasi

); }; const renderAdmin = () => (

Ruang Guru

Sistem Pengelolaan Soal

Unggah Berkas

DAFTAR SOAL TERUNGGAH
{Object.entries(quizData).map(([lvl, lvlData]) => Object.entries(lvlData.grades).map(([grd, grdData]) => grdData.subjects.map(subj => (
{lvlData.mascot}

{lvl} - {grd}

{subj.name}

)) ) )}
); return (
{renderToast()} {!isXlsxLoaded && (

Memuat EduPintar...

)}
{view === 'login' &&
{renderLogin()}
} {view === 'home' &&
{renderDashboard()}
} {view === 'grades' &&
{renderGradeSelect()}
} {view === 'subjects' &&
{renderSubjectSelect()}
} {view === 'quiz' &&
{renderQuiz()}
} {view === 'result' &&
{renderResult()}
} {view === 'admin' &&
{renderAdmin()}
}
{/* Decorative BG */}
); }