import React, { useState, useEffect } from 'react';
class SoundManager {
constructor() {
this.ctx = null;
}
init() {
if (!this.ctx) {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
}
}
playCorrect() {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
const now = this.ctx.currentTime;
osc.type = 'sine';
osc.frequency.setValueAtTime(523.25, now); // C5
osc.frequency.setValueAtTime(659.25, now + 0.1); // E5
osc.frequency.setValueAtTime(783.99, now + 0.2); // G5
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(0.25, now + 0.05);
gain.gain.linearRampToValueAtTime(0, now + 0.35);
osc.start(now);
osc.stop(now + 0.35);
}
playWrong() {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
const now = this.ctx.currentTime;
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(150, now);
osc.frequency.linearRampToValueAtTime(95, now + 0.25);
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(0.3, now + 0.05);
gain.gain.linearRampToValueAtTime(0, now + 0.3);
osc.start(now);
osc.stop(now + 0.3);
}
playLevelUp() {
this.init();
if (!this.ctx) return;
const now = this.ctx.currentTime;
const notes = [523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];
notes.forEach((freq, idx) => {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'triangle';
osc.frequency.setValueAtTime(freq, now + idx * 0.08);
gain.gain.setValueAtTime(0, now + idx * 0.08);
gain.gain.linearRampToValueAtTime(0.2, now + idx * 0.08 + 0.02);
gain.gain.linearRampToValueAtTime(0, now + idx * 0.08 + 0.12);
osc.start(now + idx * 0.08);
osc.stop(now + idx * 0.08 + 0.15);
});
}
}
const sounds = new SoundManager();
const subjectsList = [
{ id: 'PAI', name: 'Pendidikan Agama', icon: '🕌', color: 'border-emerald-500 text-emerald-700' },
{ id: 'Pancasila', name: 'Pendidikan Pancasila', icon: '🦅', color: 'border-red-500 text-red-600' },
{ id: 'BIndo', name: 'Bahasa Indonesia', icon: '🇮🇩', color: 'border-rose-500 text-rose-600' },
{ id: 'Matematika', name: 'Matematika', icon: '🧮', color: 'border-blue-500 text-blue-600' },
{ id: 'IPA', name: 'IPA', icon: '🔬', color: 'border-teal-500 text-teal-600' },
{ id: 'IPS', name: 'IPS', icon: '🌍', color: 'border-amber-600 text-amber-700' },
{ id: 'BInggris', name: 'Bahasa Inggris', icon: '🇬🇧', color: 'border-indigo-500 text-indigo-600' },
{ id: 'PJOK', name: 'PJOK', icon: '⚽', color: 'border-green-500 text-green-600' },
{ id: 'Informatika', name: 'Informatika', icon: '💻', color: 'border-cyan-500 text-cyan-600' },
{ id: 'SeniBudaya', name: 'Seni Budaya', icon: '🎨', color: 'border-fuchsia-500 text-fuchsia-600' },
{ id: 'BSunda', name: 'Bahasa Sunda', icon: '🥥', color: 'border-orange-500 text-orange-600' },
{ id: 'Jepang', name: 'Jepang', icon: '🇯🇵', color: 'border-pink-500 text-pink-600' },
{ id: 'Arab', name: 'Arab', icon: '🗣️', color: 'border-emerald-600 text-emerald-800' },
{ id: 'Nahwu', name: 'Nahwu', icon: '📖', color: 'border-violet-500 text-violet-600' },
{ id: 'Shorof', name: 'Shorof', icon: '✍️', color: 'border-purple-500 text-purple-600' },
{ id: 'Fiqh', name: 'Fiqh', icon: '⚖️', color: 'border-sky-500 text-sky-600' },
{ id: 'Tauhid', name: 'Tauhid', icon: '☝️', color: 'border-yellow-600 text-yellow-700' }
];
const fallbackDatabase = {
getChallenges: (subject, material) => {
return {
quiz: [
{
question: `Pertanyaan dasar mengenai ${material} pada mata pelajaran ${subject}?`,
options: ["Pilihan Jawaban A", "Pilihan Jawaban B", "Pilihan Jawaban C", "Pilihan Jawaban D"],
correctAnswer: "Pilihan Jawaban A",
explanation: `Ini adalah penjelasan dasar materi ${material} untuk mata pelajaran ${subject}.`
},
{
question: `Manakah definisi yang paling tepat mengenai aspek krusial dari ${material}?`,
options: ["Konsep Pertama", "Konsep Kedua", "Konsep Ketiga", "Konsep Keempat"],
correctAnswer: "Konsep Pertama",
explanation: `Penjelasan mengenai struktur penting pada pembelajaran ${material}.`
}
],
classification: {
title: `Klasifikasi Istilah ${material}`,
categories: [
{ id: 'cat1', name: 'Kategori Esensial', desc: 'Aspek inti materi ini.', color: 'bg-emerald-500' },
{ id: 'cat2', name: 'Kategori Pendukung', desc: 'Aspek pelengkap materi.', color: 'bg-orange-500' }
],
items: [
{ char: 'Istilah Kunci A', category: 'cat1', hint: 'Termasuk dalam pilar utama bahasan.' },
{ char: 'Istilah Kunci B', category: 'cat2', hint: 'Merupakan elemen pendukung tambahan.' }
]
},
arrange: [
{
name: `Urutan Definisi ${material}`,
correctOrder: ["Belajar", "Dengan", "Gembira", "Pasti", "Bisa"],
translation: "Slogan motivasi belajar untuk menguasai materi secara mendalam."
}
]
};
}
};
export default function App() {
const [users, setUsers] = useState(() => {
const saved = localStorage.getItem('edu_multimapel_users');
if (saved) return JSON.parse(saved);
// Seed default simulated accounts for instant testing
const defaultUsers = [
{
username: "Budi Pratama",
phone: "081234567890",
joinedAt: new Date(Date.now() - 30 * 60 * 60 * 1000).toISOString(), // Joined 30 hours ago (Trial Expired!)
trialExpiresAt: new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString(),
isPremium: false,
paymentStatus: "none"
},
{
username: "Aisyah Zahra",
phone: "087778626570",
joinedAt: new Date().toISOString(), // Joined now (Active 1 Day Trial)
trialExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
isPremium: false,
paymentStatus: "none"
}
];
localStorage.setItem('edu_multimapel_users', JSON.stringify(defaultUsers));
return defaultUsers;
});
const [currentUser, setCurrentUser] = useState(() => {
const savedSession = sessionStorage.getItem('edu_multimapel_session');
return savedSession ? JSON.parse(savedSession) : null;
});
const [isAdmin, setIsAdmin] = useState(() => {
return sessionStorage.getItem('edu_multimapel_is_admin') === 'true';
});
// Auth Forms State
const [authMode, setAuthMode] = useState('login'); // login, register, admin_login
const [loginPhone, setLoginPhone] = useState('');
const [loginPassword, setLoginPassword] = useState('');
const [regName, setRegName] = useState('');
const [regPhone, setRegPhone] = useState('');
const [regPassword] = useState('mbr123'); // Fixed member standard password
const [adminUser, setAdminUser] = useState('');
const [adminPass, setAdminPass] = useState('');
// Custom Modal/Alert State (Instead of browser alerts)
const [customAlert, setCustomAlert] = useState(null); // { type: 'success'|'error', text: 'string' }
// Navigation, Curriculums & Setup Selection State
const [setup, setSetup] = useState({
phase: 'Fase A', // Fase A to Fase F
subject: 'PAI',
material: '' // Hand-filled manually (Kolom materi diisi manual)
});
const [isSetupComplete, setIsSetupComplete] = useState(false);
const [activeTab, setActiveTab] = useState('menu'); // menu, quiz, classification, arrange, library
const [apiLoading, setApiLoading] = useState(false);
// Gamification Metrics
const [score, setScore] = useState(0);
const [streak, setStreak] = useState(0);
const [level, setLevel] = useState(1);
const [showConfetti, setShowConfetti] = useState(false);
const [gameFeedback, setGameFeedback] = useState(null); // { isCorrect: bool, text: string }
// Game Core Data State (Loaded dynamically via Gemini API or fallback)
const [challenges, setChallenges] = useState(null);
const [quizIndex, setQuizIndex] = useState(0);
const [currentClassifyItem, setCurrentClassifyItem] = useState(null);
const [arrangeIndex, setArrangeIndex] = useState(0);
const [scrambledWords, setScrambledWords] = useState([]);
const [userSelectionWords, setUserSelectionWords] = useState([]);
useEffect(() => {
localStorage.setItem('edu_multimapel_users', JSON.stringify(users));
}, [users]);
// Handle active session sync
useEffect(() => {
if (currentUser) {
const liveUser = users.find(u => u.phone === currentUser.phone);
if (liveUser) {
sessionStorage.setItem('edu_multimapel_session', JSON.stringify(liveUser));
}
}
}, [users, currentUser]);
const getSubscriptionStatus = (user) => {
if (!user) return { status: 'none', timeLeft: 0 };
if (user.isPremium) {
return { status: 'premium', timeLeft: 99999 };
}
const timeLeftMs = new Date(user.trialExpiresAt) - new Date();
const hoursLeft = Math.max(0, Math.ceil(timeLeftMs / (1000 * 60 * 60)));
return hoursLeft > 0 ? { status: 'trial', hoursLeft } : { status: 'expired_trial', hoursLeft: 0 };
};
const currentStatus = getSubscriptionStatus(currentUser);
const isAksesBlocked = currentUser && currentStatus.status === 'expired_trial';
const triggerAlert = (type, text) => {
setCustomAlert({ type, text });
setTimeout(() => setCustomAlert(null), 5000);
};
const handleRegister = (e) => {
e.preventDefault();
if (!regName.trim() || !regPhone.trim()) {
triggerAlert('error', 'Harap lengkapi semua kolom pendaftaran.');
return;
}
const cleanPhone = regPhone.replace(/\D/g, '');
if (users.some(u => u.phone === cleanPhone)) {
triggerAlert('error', 'Nomor HP WhatsApp ini telah terdaftar.');
return;
}
if (regPassword !== 'mbr123') {
triggerAlert('error', 'Password standar wajib menggunakan: mbr123');
return;
}
const newUser = {
username: regName.trim(),
phone: cleanPhone,
joinedAt: new Date().toISOString(),
trialExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 1 Day Free Trial
isPremium: false,
paymentStatus: 'none'
};
setUsers([...users, newUser]);
triggerAlert('success', 'Pendaftaran Berhasil! Silakan masuk dengan nomor HP Anda.');
setAuthMode('login');
setLoginPhone(cleanPhone);
};
const handleLogin = (e) => {
e.preventDefault();
const cleanPhone = loginPhone.replace(/\D/g, '');
const user = users.find(u => u.phone === cleanPhone);
if (!user) {
triggerAlert('error', 'Akun tidak terdaftar. Silakan lakukan pendaftaran baru.');
return;
}
if (loginPassword !== 'mbr123') {
triggerAlert('error', 'Kata sandi salah! Gunakan password standar member: mbr123');
return;
}
setCurrentUser(user);
sessionStorage.setItem('edu_multimapel_session', JSON.stringify(user));
setIsAdmin(false);
sessionStorage.removeItem('edu_multimapel_is_admin');
if (setup.material) {
setIsSetupComplete(true);
}
};
const handleAdminLogin = (e) => {
e.preventDefault();
if (adminUser === 'admin' && adminPass === 'admin123') {
setIsAdmin(true);
sessionStorage.setItem('edu_multimapel_is_admin', 'true');
setCurrentUser(null);
sessionStorage.removeItem('edu_multimapel_session');
triggerAlert('success', 'Berhasil masuk sebagai Administrator!');
} else {
triggerAlert('error', 'Username atau password admin tidak valid.');
}
};
const handleLogout = () => {
setCurrentUser(null);
setIsAdmin(false);
sessionStorage.clear();
setIsSetupComplete(false);
setActiveTab('menu');
};
const initiatePayment = () => {
if (!currentUser) return;
const updated = users.map(u => {
if (u.phone === currentUser.phone) {
return { ...u, paymentStatus: 'pending' };
}
return u;
});
setUsers(updated);
const updatedUserObj = updated.find(u => u.phone === currentUser.phone);
setCurrentUser(updatedUserObj);
const message = `Halo Admin Game Edukasi, saya ingin aktivasi akses premium seumur hidup (Lifetime) untuk akun:
- Nama: ${currentUser.username}
- No. HP WA: ${currentUser.phone}
- Tagihan: Rp 10.000 (Akses Selamanya)
Mohon segera disetujui aktivasinya. Terima kasih!`;
const waUrl = `https://wa.me/6287778626570?text=${encodeURIComponent(message)}`;
window.open(waUrl, '_blank');
};
// Admin Actions
const approveUserPayment = (phone) => {
const updated = users.map(u => {
if (u.phone === phone) {
return { ...u, isPremium: true, paymentStatus: 'approved' };
}
return u;
});
setUsers(updated);
sounds.playLevelUp();
triggerAlert('success', 'Aktivasi premium seumur hidup sukses!');
};
const simulateExpiry = (phone) => {
const updated = users.map(u => {
if (u.phone === phone) {
return {
...u,
isPremium: false,
paymentStatus: 'none',
trialExpiresAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString() // Expired 2 days ago
};
}
return u;
});
setUsers(updated);
triggerAlert('success', 'Simulasi kedaluwarsa uji coba berhasil diset!');
};
const deleteUser = (phone) => {
setUsers(users.filter(u => u.phone !== phone));
triggerAlert('success', 'Data member berhasil dihapus.');
};
const generateAIGameChallenges = async (e) => {
e.preventDefault();
if (!setup.phase || !setup.subject || !setup.material.trim()) {
triggerAlert('error', 'Lengkapi seluruh pilihan fase, mapel, dan kolom materi terlebih dahulu.');
return;
}
setApiLoading(true);
const subjectLabel = subjectsList.find(s => s.id === setup.subject)?.name || setup.subject;
// AI Generation Prompt
const systemPrompt = `Kamu adalah pakar kurikulum Merdeka dan game desainer edukasi anak sekolah dasar hingga menengah di Indonesia.
Buat satu set tantangan interaktif menarik dalam bahasa Indonesia untuk siswa tingkat ${setup.phase}, mata pelajaran ${subjectLabel}, fokus pada topik spesifik: "${setup.material}".
Hasilkan JSON terstruktur rapi sesuai dengan schema yang ditentukan tanpa teks pengantar di luar JSON.`;
const userQuery = `Buatkan konten tantangan dengan format JSON tepat seperti schema ini:
{
"quiz": [
{
"question": "Pertanyaan kuis yang menantang dan edukatif",
"options": ["Opsi A", "Opsi B", "Opsi C", "Opsi D"],
"correctAnswer": "Opsi A (harus persis sama dengan salah satu nilai di array options)",
"explanation": "Penjelasan ilmiah/akademis yang ringkas dan mudah dipahami"
}
],
"classification": {
"title": "Judul Klasifikasi Materi",
"categories": [
{"id": "cat1", "name": "Nama Kategori 1", "desc": "Deskripsi singkat Kategori 1"},
{"id": "cat2", "name": "Nama Kategori 2", "desc": "Deskripsi singkat Kategori 2"}
],
"items": [
{"char": "Nama benda/konsep/contoh", "category": "cat1", "hint": "Petunjuk mengapa masuk kategori ini"}
]
},
"arrange": [
{
"name": "Nama tantangan susun kalimat/urutan proses",
"correctOrder": ["Kata1", "Kata2", "Kata3", "Kata4"],
"translation": "Kalimat utuh atau arti penting dari konsep tersebut"
}
]
}
Sediakan minimal 3 pertanyaan quiz, 4-6 items untuk klasifikasi (dengan 2-3 kategori), dan minimal 2 tantangan arrange.`;
try {
const apiKey = ""; // Canvas provides API key at runtime if set to empty string
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent?key=${apiKey}`;
const payload = {
contents: [{ parts: [{ text: userQuery }] }],
generationConfig: {
responseMimeType: "application/json"
},
systemInstruction: {
parts: [{ text: systemPrompt }]
}
};
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const result = await response.json();
const generatedText = result.candidates?.[0]?.content?.parts?.[0]?.text;
if (generatedText) {
const parsedChallenges = JSON.parse(generatedText);
setChallenges(parsedChallenges);
setIsSetupComplete(true);
setActiveTab('menu');
setQuizIndex(0);
setArrangeIndex(0);
setCurrentClassifyItem(null);
sounds.playLevelUp();
triggerAlert('success', 'Tantangan game belajar telah siap diluncurkan!');
} else {
throw new Error("No text returned from Gemini");
}
} catch (err) {
console.warn("Gemini API Error, using highly smart local fallback database...", err);
// Fallback content loading
const fallbackData = fallbackDatabase.getChallenges(subjectLabel, setup.material);
setChallenges(fallbackData);
setIsSetupComplete(true);
setActiveTab('menu');
setQuizIndex(0);
setArrangeIndex(0);
setCurrentClassifyItem(null);
triggerAlert('success', 'Tantangan belajar siap (mode offline)!');
} finally {
setApiLoading(false);
}
};
// Game 2 (Classification Sorter) initializer
useEffect(() => {
if (activeTab === 'classification' && challenges?.classification && !currentClassifyItem) {
getNewClassificationItem();
}
}, [activeTab, challenges, currentClassifyItem]);
const getNewClassificationItem = () => {
if (!challenges?.classification?.items?.length) return;
const items = challenges.classification.items;
const random = items[Math.floor(Math.random() * items.length)];
setCurrentClassifyItem(random);
};
// Game 3 (Word / Equation Arranger) initializer
useEffect(() => {
if (activeTab === 'arrange' && challenges?.arrange?.length) {
const activeObj = challenges.arrange[arrangeIndex % challenges.arrange.length];
const original = [...activeObj.correctOrder];
let shuffled = [];
do {
shuffled = [...original].sort(() => Math.random() - 0.5);
} while (shuffled.join(' ') === original.join(' ') && original.length > 1);
setScrambledWords(shuffled);
setUserSelectionWords([]);
}
}, [arrangeIndex, activeTab, challenges]);
const handleQuizAnswer = (option) => {
sounds.init();
const currentQ = challenges.quiz[quizIndex % challenges.quiz.length];
const isCorrect = option === currentQ.correctAnswer;
if (isCorrect) {
sounds.playCorrect();
setScore(prev => prev + 25);
setStreak(prev => prev + 1);
setGameFeedback({ isCorrect: true, text: `Maa Syaa Allah, Jawabanmu Benar! ${currentQ.explanation}` });
if (streak + 1 >= 3) {
setLevel(prev => prev + 1);
setShowConfetti(true);
setTimeout(() => setShowConfetti(false), 3000);
}
} else {
sounds.playWrong();
setStreak(0);
setGameFeedback({ isCorrect: false, text: `Ups! Jawaban yang benar adalah: "${currentQ.correctAnswer}". ${currentQ.explanation}` });
}
};
const handleClassifyAnswer = (catId) => {
sounds.init();
const isCorrect = currentClassifyItem.category === catId;
const correctCategoryObj = challenges.classification.categories.find(c => c.id === currentClassifyItem.category);
if (isCorrect) {
sounds.playCorrect();
setScore(prev => prev + 20);
setStreak(prev => prev + 1);
setGameFeedback({ isCorrect: true, text: `Hebat! "${currentClassifyItem.char}" berasosiasi tepat ke "${correctCategoryObj.name}". ${currentClassifyItem.hint || ''}` });
if (streak + 1 >= 3) {
setLevel(prev => prev + 1);
setShowConfetti(true);
setTimeout(() => setShowConfetti(false), 3000);
}
} else {
sounds.playWrong();
setStreak(0);
setGameFeedback({ isCorrect: false, text: `Belum tepat. "${currentClassifyItem.char}" seharusnya berada pada kategori "${correctCategoryObj.name}".` });
}
};
const selectWordTile = (word) => {
setUserSelectionWords([...userSelectionWords, word]);
setScrambledWords(scrambledWords.filter(w => w !== word));
};
const deselectWordTile = (word) => {
setScrambledWords([...scrambledWords, word]);
setUserSelectionWords(userSelectionWords.filter(w => w !== word));
};
const verifyArrangement = () => {
sounds.init();
const activeObj = challenges.arrange[arrangeIndex % challenges.arrange.length];
const isCorrect = userSelectionWords.join(' ') === activeObj.correctOrder.join(' ');
if (isCorrect) {
sounds.playCorrect();
setScore(prev => prev + 30);
setStreak(prev => prev + 1);
setGameFeedback({ isCorrect: true, text: `Luar Biasa! Susunanmu Sempurna! Clue: ${activeObj.translation}` });
if (streak + 1 >= 3) {
setLevel(prev => prev + 1);
setShowConfetti(true);
setTimeout(() => setShowConfetti(false), 3000);
}
} else {
sounds.playWrong();
setStreak(0);
setGameFeedback({ isCorrect: false, text: 'Rangkaian elemen belum tepat. Perhatikan kaidah logika atau tata bahasanya!' });
}
};
return (
{/* HEADER BAR */}
{ sounds.init(); setActiveTab('menu'); setGameFeedback(null); }}
className="flex items-center gap-3 hover:opacity-90 active:scale-95 transition-transform"
>
🧠
Game Edukasi Pintar Multi-Mapel AI
Pengembang Aplikasi: eep.edu_daily
{currentUser && (
<>
👤 {currentUser.username}
{currentStatus.status === 'trial' && (
⏱️ Trial: {currentStatus.hoursLeft} Jam Lagi
)}
{currentStatus.status === 'premium' && (
👑 Premium Selamanya
)}
⭐ {score} Pts
Keluar
>
)}
{isAdmin && (
<>
⚙️ PANEL KONTROL ADMIN
Keluar Admin
>
)}
{/* CUSTOM ALERT COMPONENT */}
{customAlert && (
{customAlert.type === 'success' ? '✅' : '⚠️'}
{customAlert.text}
)}
{/* CONFETTI SELEBRASI LEVEL UP */}
{showConfetti && (
🎉
MAA SYAA ALLAH! LEVEL UP!
LEVEL SEKARANG: LEVEL {level}
)}
{/* MAIN CONTENT AREA */}
{/* VIEW 1: AUTH GATE (LOGIN / REGISTER MEMBER & ADMIN) */}
{!currentUser && !isAdmin && (
{/* Logo and Greeting */}
🧠
Aplikasi Game Edukasi
Bermain Sambil Belajar Seluruh Mapel dengan Nilai Islami
{/* Auth Tab Selectors */}
setAuthMode('login')}
className={`flex-1 py-3 text-center rounded-2xl font-bold text-sm transition-all duration-200 ${authMode === 'login' ? 'bg-emerald-600 text-white shadow-md' : 'text-slate-600 hover:bg-slate-100'}`}
>
Masuk Member
setAuthMode('register')}
className={`flex-1 py-3 text-center rounded-2xl font-bold text-sm transition-all duration-200 ${authMode === 'register' ? 'bg-orange-500 text-white shadow-md' : 'text-slate-600 hover:bg-slate-100'}`}
>
Daftar Baru
setAuthMode('admin_login')}
className={`flex-1 py-3 text-center rounded-2xl font-bold text-sm transition-all duration-200 ${authMode === 'admin_login' ? 'bg-slate-800 text-white shadow-md' : 'text-slate-500 hover:bg-slate-100'}`}
>
Admin
{/* Tab Form Containers */}
{/* MODE: MEMBER LOGIN */}
{authMode === 'login' && (
)}
{/* MODE: REGISTER MEMBER */}
{authMode === 'register' && (
)}
{/* MODE: ADMIN LOGIN */}
{authMode === 'admin_login' && (
)}
)}
{/* VIEW 2: LOGGED IN MEMBER / TRIAL EXPIRED / KUNCI AKSES */}
{currentUser && isAksesBlocked && (
🔒
Masa Akses Aplikasi Habis!
Assalamu'alaikum, {currentUser.username} . Masa uji coba gratis 1 hari Anda telah berakhir. Untuk terus menikmati tantangan game edukasi semua mata pelajaran, silakan lakukan aktivasi paket premium selamanya.
{/* Lifetime Access Ticket Card */}
LIFETIME ACCESS
PROMO BELAJAR PINTAR
Akses Premium Selamanya
Membuka seluruh game kuis, klasifikasi sorter, dan perangkai kata untuk 17 mata pelajaran.
Bayar 1x Gratis Selamanya
{currentUser.paymentStatus === 'pending' && (
🔄 Menunggu Persetujuan Aktivasi Admin
Kami mendeteksi konfirmasi pembayaran Anda. Silakan hubungi admin WhatsApp 087778626570 untuk proses verifikasi kilat.
)}
Konfirmasi Aktivasi Via WhatsApp 🟢
Setelah konfirmasi transfer sukses, admin akan segera menyetujui akun Anda.
)}
{/* VIEW 3: SETUP SELECTIONS (FASE, SUBJECT, MANUAL MATERI) */}
{currentUser && !isAksesBlocked && !isSetupComplete && (
🎯
Set Up Tantangan Belajarmu
Pilih kurikulum dan mapelmu, lalu ketik materi belajarmu hari ini.
{/* Loading Screen */}
{apiLoading ? (
Merancang Tantangan Game Belajar Anda...
Menggunakan kecerdasan buatan Gemini AI untuk merangkai kuis, klasifikasi, dan puzzle dari materi yang kamu masukkan.
) : (
)}
)}
{/* VIEW 4: ACTIVE GAME PLAYBOARD */}
{currentUser && !isAksesBlocked && isSetupComplete && challenges && (
{/* Active Curriculum, Subject, and Material Info Bar */}
Kurikulum & Materi Aktif
{setup.phase}
•
{subjectsList.find(s => s.id === setup.subject)?.icon} {subjectsList.find(s => s.id === setup.subject)?.name}
•
{setup.material}
setIsSetupComplete(false)}
className="bg-orange-500 hover:bg-orange-600 text-white text-[10px] font-bold px-3 py-1.5 rounded-lg transition"
>
Ganti Materi / Mapel
{/* TAB NAVIGATION */}
{activeTab !== 'menu' && (
{ setGameFeedback(null); setActiveTab('menu'); }}
className="bg-slate-800 hover:bg-slate-900 text-white font-bold py-2 px-4 rounded-xl text-xs transition"
>
🏠 Kembali ke Menu Game
)}
{/* TAB 4.1: CHOOSE GAME MENU */}
{activeTab === 'menu' && (
{/* Greeting Card */}
🚀
Siap Mengalahkan Tantangan, {currentUser.username}?
Ayo selesaikan 3 game interaktif di bawah ini untuk menguasai topik "{setup.material}" secara menyeluruh!
🧠 Level {level}
🔥 {streak} Streak
⭐ {score} Pts
{/* 3 Games Selection Cards */}
{/* Game 1: Quiz */}
🔍
Detektif Cerdas (Quiz)
Uji pengetahuan faktual dan logika analisismu dari materi terkait.
{ sounds.init(); setActiveTab('quiz'); }}
className="w-full bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition-all shadow-md active:scale-95 border-b-4 border-emerald-800"
>
Mulai Kuis
{/* Game 2: Category Sorter */}
🧬
Klasifikasi Pintar
Pilah elemen dan istilah kunci materi ke dalam wadah klasifikasi yang tepat.
{ sounds.init(); setActiveTab('classification'); }}
className="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition-all shadow-md active:scale-95 border-b-4 border-indigo-800"
>
Mulai Sortir
{/* Game 3: Sentence/Process Arranger */}
🧩
Susun Elemen Belajar
Urutkan proses kejadian, alur definisi, atau rangkaian kata agar tersusun sempurna.
{ sounds.init(); setActiveTab('arrange'); }}
className="w-full bg-orange-500 hover:bg-orange-600 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition-all shadow-md active:scale-95 border-b-4 border-orange-700"
>
Mulai Menyusun
)}
{/* TAB 4.2: DETEKTIF CERDAS (QUIZ GAMEPLAY) */}
{activeTab === 'quiz' && challenges.quiz && challenges.quiz.length > 0 && (
Misi: Detektif Cerdas
Tantangan {quizIndex % challenges.quiz.length + 1} dari {challenges.quiz.length}
{/* Question Display Screen */}
{challenges.quiz[quizIndex % challenges.quiz.length].question}
{gameFeedback ? (
{gameFeedback.isCorrect ? '✅ Hebat!' : '❌ Terlewat!'}
{gameFeedback.text}
{
setGameFeedback(null);
setQuizIndex(prev => prev + 1);
}}
className="bg-slate-800 hover:bg-slate-900 text-white font-bold py-2 px-6 rounded-xl text-xs transition"
>
Lanjut Tantangan Berikutnya
) : (
{challenges.quiz[quizIndex % challenges.quiz.length].options.map((option, idx) => (
handleQuizAnswer(option)}
className="w-full bg-slate-50 hover:bg-emerald-50 border-2 border-slate-200 hover:border-emerald-400 rounded-xl p-4 font-bold text-slate-700 hover:text-emerald-950 text-left transition duration-200 active:scale-95 text-xs sm:text-sm"
>
{String.fromCharCode(65 + idx)}
{option}
))}
)}
)}
{/* TAB 4.3: KLASIFIKASI PINTAR GAMEPLAY */}
{activeTab === 'classification' && challenges.classification && currentClassifyItem && (
Misi: Klasifikasi Cerdas
Kelompokkan Istilah
{challenges.classification.title}
{currentClassifyItem.char}
Seret atau ketuk kategori yang sesuai di bawah untuk mengelompokkannya.
{gameFeedback ? (
{gameFeedback.isCorrect ? '✅ Betul Sekali!' : '💡 Pikirkan Lagi!'}
{gameFeedback.text}
{
setGameFeedback(null);
getNewClassificationItem();
}}
className="bg-slate-800 hover:bg-slate-900 text-white font-bold py-2 px-6 rounded-xl text-xs transition"
>
Dapatkan Item Lain
) : (
{challenges.classification.categories.map((cat) => (
handleClassifyAnswer(cat.id)}
className="border-2 border-slate-200 hover:border-indigo-500 hover:bg-indigo-50 bg-white rounded-2xl p-4 text-center transition active:scale-95 shadow-sm"
>
{cat.name}
{cat.desc}
))}
)}
)}
{/* TAB 4.4: SUSUN ELEMEN (ARRANGE GAMEPLAY) */}
{activeTab === 'arrange' && challenges.arrange && challenges.arrange.length > 0 && (
Misi: Urutkan Elemen
Susun Elemen Runtut
Topik Puzzle
{challenges.arrange[arrangeIndex % challenges.arrange.length].name}
Petunjuk: "{challenges.arrange[arrangeIndex % challenges.arrange.length].translation}"
{/* Target Drop Zone */}
{userSelectionWords.length === 0 && (
Ketuk potongan kata di bawah dengan urutan yang logis
)}
{userSelectionWords.map((word, idx) => (
deselectWordTile(word)}
className="bg-orange-400 hover:bg-orange-300 text-slate-950 font-bold text-xs sm:text-sm px-3.5 py-1.5 rounded-xl shadow-md border-b-4 border-orange-600 active:scale-95 transition-all"
>
{word}
))}
{/* Selection Word Pool */}
{!gameFeedback && (
{scrambledWords.map((word, idx) => (
selectWordTile(word)}
className="bg-white hover:bg-slate-100 text-slate-800 border-2 border-slate-200 font-bold text-xs sm:text-sm px-3.5 py-1.5 rounded-xl shadow-sm hover:shadow active:scale-95 transition-all"
>
{word}
))}
)}
{gameFeedback ? (
{gameFeedback.isCorrect ? '🎉 Alhamdulillah!' : '🔍 Urutkan Ulang!'}
{gameFeedback.text}
{
setGameFeedback(null);
setArrangeIndex(prev => prev + 1);
}}
className="bg-slate-800 hover:bg-slate-900 text-white font-bold py-2 px-6 rounded-xl text-xs transition"
>
Pertanyaan Berikutnya
) : (
Uji Kelayakan Rangkaian Elemen
)}
)}
)}
{/* VIEW 5: ADMINISTRATOR BACKEND CONTROL DASHBOARD */}
{isAdmin && (
⚙️ Panel Pengendali Admin (Sistem Billing & Member)
Lihat member terdaftar, setujui pembayaran premium seumur hidup, atau set kedaluwarsa uji coba untuk pengetesan.
Total Member: {users.length} Akun
{/* Members Data Table */}
Nama Lengkap
No. HP WA
Status & Sisa Akses
Status Bayar
Tindakan Admin
{users.map((m, idx) => {
const statusObj = getSubscriptionStatus(m);
return (
{m.username}
{m.phone}
{statusObj.status === 'premium' && 👑 Premium Selamanya }
{statusObj.status === 'trial' && ⏱️ Trial ({statusObj.hoursLeft} Jam) }
{statusObj.status === 'expired_trial' && ❌ Trial Habis (Terkunci) }
{m.paymentStatus === 'pending' && (
⏳ MENUNGGU WA (10.000)
)}
{m.paymentStatus === 'approved' && (
✓ SUKSES AKTIF
)}
{m.paymentStatus === 'none' && Belum Mengirim }
approveUserPayment(m.phone)}
disabled={m.isPremium}
className={`px-2 py-1 rounded text-[10px] font-bold ${m.isPremium ? 'bg-slate-100 text-slate-400 cursor-not-allowed' : 'bg-emerald-600 hover:bg-emerald-700 text-white'}`}
>
Setujui Premium
simulateExpiry(m.phone)}
className="bg-orange-500 hover:bg-orange-600 text-white px-2 py-1 rounded text-[10px] font-bold"
title="Set waktu trial ke lampau untuk mengunci akses member"
>
Simulasikan Kedaluwarsa
deleteUser(m.phone)}
className="bg-red-100 hover:bg-red-600 text-red-700 hover:text-white px-2 py-1 rounded text-[10px] font-bold transition"
>
Hapus
);
})}
{/* Simulation Instructions */}
💡 Cara Mencoba Penguncian Billing WhatsApp & Sistem Uji Coba:
1. Daftarkan akun baru di menu **Daftar Baru** (Password otomatis: `mbr123`). Anda akan masuk dalam masa trial gratis 1 hari.
2. Untuk memicu alur billing: Keluar akun, masuk ke **Admin** (User: `admin`, Pass: `admin123`).
3. Klik tombol **"Simulasikan Kedaluwarsa"** pada akun baru tersebut.
4. Kembali login sebagai member tadi. Akun Anda akan terkunci penuh dan menampilkan tiket pembayaran premium seumur hidup senilai **Rp 10.000**.
5. Member mengirim pesan pembayaran ke WA **087778626570**, lalu Anda (Admin) tinggal menekan tombol **"Setujui Premium"** di dashboard kontrol untuk membukanya selamanya!
)}
{/* FOOTER */}
);
}
0 comments:
Post a Comment