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
);
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
"Pendidikan adalah senjata paling mematikan di dunia."
— Nelson Mandela
{/* Main Content: Level Selection */}
{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}
))}
{/* 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!
);
};
const renderAdmin = () => (
Ruang Guru
Sistem Pengelolaan Soal
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 && (
)}
{view === 'login' && {renderLogin()}
}
{view === 'home' && {renderDashboard()}
}
{view === 'grades' && {renderGradeSelect()}
}
{view === 'subjects' && {renderSubjectSelect()}
}
{view === 'quiz' && {renderQuiz()}
}
{view === 'result' && {renderResult()}
}
{view === 'admin' && {renderAdmin()}
}
{/* Decorative BG */}
);
}