// MULTIPLIER — main app shell const { useState, useEffect, useCallback } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "theme": "space", "soundOn": true, "musicOn": false, "defaultDifficulty": "auto" }/*EDITMODE-END*/; const App = () => { const t = window.MP_I18N.t; const [profile, setProfile] = useState(() => window.MP_DATA.loadProfile()); const [screen, setScreen] = useState('home'); // home | ranking | profile | game | resultado | diploma const [game, setGame] = useState(null); const [result, setResult] = useState(null); const [share, setShare] = useState(false); const [tweaks, setTweaks] = useState(TWEAK_DEFAULTS); // Load language preference useEffect(() => { if (profile?.lang) window.MP_I18N.setLang(profile.lang); window.MP_SOUND.setEnabled(tweaks.soundOn); }, [profile?.lang, tweaks.soundOn]); // Tweaks integration useEffect(() => { const onMsg = (e) => { if (e.data?.type === '__activate_edit_mode') { window.dispatchEvent(new CustomEvent('mp-tweaks-show')); } else if (e.data?.type === '__deactivate_edit_mode') { window.dispatchEvent(new CustomEvent('mp-tweaks-hide')); } }; window.addEventListener('message', onMsg); window.parent.postMessage({ type: '__edit_mode_available' }, '*'); return () => window.removeEventListener('message', onMsg); }, []); // Service worker useEffect(() => { if ('serviceWorker' in navigator) { navigator.serviceWorker.register('./sw.js').catch(() => {}); } }, []); // Onboarding if (!profile || !profile.firstName) { return (
{ const p = { ...window.MP_DATA.emptyProfile(), ...data }; window.MP_DATA.saveProfile(p); setProfile(p); // Register on backend (fire and forget) window.MP_API.register({ first_name: p.firstName, last_initial: p.lastInitial, school_code: p.schoolCode, school_name: p.schoolName, grade: p.grade }); }} />
); } const updateProfile = (p) => { window.MP_DATA.saveProfile(p); setProfile({ ...p }); }; const playMode = (id) => { setGame(id); setScreen('game'); }; const finishGame = (gameResult) => { const isBestTA = gameResult.mode === 'time_attack' && gameResult.score > (profile.bestTimeAttack || 0); const isBestES = gameResult.mode === 'escalera' && gameResult.score > (profile.bestEscalera || 0); const { profile: newProfile, newBadges, newMascots } = window.MP_DATA.applyResult(profile, gameResult); window.MP_DATA.saveProfile(newProfile); setProfile(newProfile); // Submit to server window.MP_API.submitScore({ first_name: newProfile.firstName, last_initial: newProfile.lastInitial, school_code: newProfile.schoolCode, school_name: newProfile.schoolName, grade: newProfile.grade, mode: gameResult.mode, score: gameResult.score, correct: gameResult.correct, total: gameResult.total }); setResult({ ...gameResult, isBest: isBestTA || isBestES, newBadges, newMascots }); setScreen('resultado'); if (newBadges.length || newMascots.length) { setTimeout(() => window.MP_SOUND.unlock(), 800); } }; const goHome = () => { setScreen('home'); setGame(null); setResult(null); }; // Game router const renderGame = () => { const props = { profile, onFinish: finishGame, onQuit: goHome }; switch (game) { case 'time_attack': return ; case 'memorama': return ; case 'escalera': return ; case 'mision': return ; case 'tabla': return ; case 'tf': return ; case 'blank': return ; default: return null; } }; return (
{screen === 'home' && ( playMode('mision')} /> )} {screen === 'ranking' && } {screen === 'profile' && ( { localStorage.removeItem('mp_profile'); setProfile(null); }} onDiploma={() => setScreen('diploma')} /> )} {screen === 'game' && renderGame()} {screen === 'resultado' && result && ( { setScreen('game'); setResult(null); }} onHome={goHome} onShare={() => setShare(true)} onDiploma={() => setScreen('diploma')} /> )} {screen === 'diploma' && ( setScreen(result ? 'resultado' : 'profile')} /> )} {share && setShare(false)} />} {/* Bottom navigation */} {(screen === 'home' || screen === 'ranking' || screen === 'profile') && ( )}
); }; ReactDOM.createRoot(document.getElementById('root')).render();