// App.jsx
const { useState: useAppState, useEffect: useAppEffect, useCallback: useAppCallback } = React;
// ── Theme toggle helper ───────────────────────────────────────────────────────
function getStoredTheme() {
return localStorage.getItem('mona26_theme') || 'dark';
}
function applyTheme(t) {
document.documentElement.setAttribute('data-theme', t);
localStorage.setItem('mona26_theme', t);
}
// ── App ───────────────────────────────────────────────────────────────────────
function App() {
const [view, setView] = useAppState('loading');
const [user, setUser] = useAppState(null);
const [stickers, setStickers] = useAppState({});
const [selectedCountry, setSelectedCountry] = useAppState(null);
const [mobileOpen, setMobileOpen] = useAppState(false);
const [theme, setTheme] = useAppState(getStoredTheme);
// Apply theme on mount and change
useAppEffect(() => { applyTheme(theme); }, [theme]);
function toggleTheme() {
setTheme(t => { const n = t==='dark'?'light':'dark'; applyTheme(n); return n; });
}
useAppEffect(() => {
DB.getCurrentUser().then(u => {
if (u) { setUser(u); DB.getStickers().then(s => setStickers(s)); setView('dashboard'); }
else setView('auth');
});
}, []);
function handleLogin(u) {
setUser(u);
DB.getStickers().then(s => setStickers(s));
setView('dashboard');
}
async function handleLogout() {
await DB.logout();
setUser(null); setStickers({}); setView('auth');
}
function navigate(v, country) {
setView(v);
if (country) setSelectedCountry(country);
setMobileOpen(false);
}
const handleUpdateSticker = useAppCallback((id, qty) => {
setStickers(prev => ({ ...prev, [id]: qty }));
DB.updateSticker(id, qty);
}, []);
if (view === 'loading') return (
{/* ── Sidebar ─────────────────────────────────────────── */}
{/* ── Mobile top bar ────────────────────────────────── */}
{view==='dashboard'?'Resumen':view==='album'?'Álbum':view==='country'?'Láminas':view==='trades'?'Intercambios':''}
{/* Mobile overlay */}
{mobileOpen &&
setMobileOpen(false)} />}
{/* ── Main content ──────────────────────────────────── */}
{view === 'dashboard' && }
{view === 'album' && navigate('country', c)} />}
{view === 'country' && selectedCountry && (
setView('album')}
/>
)}
{view === 'trades' && }
);
}
// ── Sidebar Progress Widget ───────────────────────────────────────────────────
function SidebarProgress({ stickers }) {
const { ALL_STICKERS } = ALBUM_DATA;
const owned = ALL_STICKERS.filter(s => (stickers[s.id]||0) >= 1).length;
const pct = Math.round(owned / ALL_STICKERS.length * 100);
return (
Progreso
{pct}%
{owned} / {ALL_STICKERS.length}
);
}
const sCSS = {
sidebar: { width:240, background:'var(--surface2)', borderRight:'1px solid var(--border)', display:'flex', flexDirection:'column', position:'fixed', top:0, left:0, height:'100vh', zIndex:100, padding:'20px 0', transition:'transform .3s', overflowY:'auto' },
brand: { display:'flex', alignItems:'center', gap:10, padding:'0 16px 16px', borderBottom:'1px solid var(--border)', marginBottom:12 },
themeBtn: { marginLeft:'auto', background:'none', border:'none', fontSize:18, cursor:'pointer', padding:'4px 6px', borderRadius:8 },
userChip: { display:'flex', alignItems:'center', gap:10, background:'var(--surface)', borderRadius:10, padding:'10px 12px', margin:'0 16px 4px' },
avatar: { width:32, height:32, borderRadius:'50%', background:'var(--green)', color:'#fff', display:'flex', alignItems:'center', justifyContent:'center', fontWeight:800, fontSize:14, flexShrink:0 },
navBtn: { display:'flex', alignItems:'center', gap:12, width:'100%', padding:'10px 12px', background:'none', border:'none', borderRadius:10, color:'var(--text-muted)', fontSize:14, cursor:'pointer', marginBottom:2, fontWeight:500 },
navActive: { background:'var(--green-bg)', color:'var(--green)', fontWeight:700 },
logoutBtn: { padding:'9px 12px', background:'none', border:'none', borderRadius:8, color:'var(--text-dimmer)', fontSize:13, cursor:'pointer', textAlign:'left', marginBottom:8 },
topBar: { display:'none', position:'fixed', top:0, left:0, right:0, height:52, background:'var(--surface2)', borderBottom:'1px solid var(--border)', zIndex:99, alignItems:'center', justifyContent:'space-between', padding:'0 16px' },
menuBtn: { background:'none', border:'none', color:'var(--text)', fontSize:20, cursor:'pointer', width:36 },
overlay: { position:'fixed', inset:0, background:'rgba(0,0,0,.55)', zIndex:99 },
main: { marginLeft:240, flex:1, minHeight:'100vh', background:'var(--bg)' },
};
ReactDOM.createRoot(document.getElementById('root')).render(
);