// ============================================================================= // HUB — DASHBOARD HOME // ============================================================================= const { useState: hubUseState, useEffect: hubUseEffect } = React; const useState = hubUseState, useEffect = hubUseEffect; const { PROVIDERS:HP, RARITIES:HR, CARDS:HC, CHAMPIONS:HCH, COLLECTIONS:HCL } = window.GAME_DATA; function Hub({ state, actions }) { const ownedSet = state.collection; const packsLeft = state.packsToday; const totalCards = HC.length; const ownedCount = Object.keys(ownedSet).filter(k => k.indexOf('myth-') !== 0 && HC.find(c=>c.id===k)).length; const mythicsOwned = Object.keys(ownedSet).filter(k => window.GAME_DATA.MYTHIC_CARDS[k]).length; const champsDefeated = state.defeatedChamps.length; // Collection completion % const collProgress = HCL.map(coll => { const total = coll.total; const have = HC.filter(c => c.provider === coll.provider && ownedSet[c.id]).length; return { ...coll, have, pct: total ? Math.round(100*have/total) : 0, complete: have === total }; }); return (
{/* HERO ROW */}
◈ SLOT LEGENDS / EDICIÓN ARQUETIPOS · v1.0
COLECCIONA.
DESAFÍA.
DOMINA.
50 cartas arquetípicas. 5 colecciones por estudio. 5 campeones. Abre sobres cada día, completa las series y derrota a los maestros para obtener cartas MÍTICAS que ningún sobre te dará.
DAILY · SOBRES
{packsLeft}
de 2
hoy
{[...Array(2)].map((_, i) => (
))}
PRÓX. RECARGA
{/* KPI ROW */}
Cartas en colección
{ownedCount}/ {totalCards}
{Math.round(100*ownedCount/totalCards)}% completada
Colecciones completas
{collProgress.filter(c=>c.complete).length}/ 5
proveedores dominados
Campeones derrotados
{champsDefeated}/ 5
desafíos completados
Cartas míticas
{mythicsOwned}/ 5
solo vía desafío
{/* COLLECTIONS PREVIEW */}
02 / COLECCIONES
Progreso por proveedor
{collProgress.map(coll => { const p = HP[coll.provider]; return (
actions.go('collection')}>
{coll.complete ? '✓ COMPLETA' : `${coll.have}/${coll.total}`}
{p.name}
{p.tagline}
{coll.pct}% {coll.complete ? '◆ +1500 CRD reclamado' : `${coll.total - coll.have} restantes`}
); })}
{/* CHAMPIONS PREVIEW */}
03 / CAMPEONES
Maestros · Duelo de cartas
{HCH.map((champ, i) => { const defeated = state.defeatedChamps.includes(champ.id); const required = i; // each requires previous const locked = i > 0 && !state.defeatedChamps.includes(HCH[i-1].id); return ( !locked && !defeated && actions.battle(champ.id)} /> ); })}
); } function ChampionCard({ champion, defeated, locked, onClick }) { const c = champion; return (
BOSS · {String(c.difficulty).padStart(2,'0')}/05 {defeated ? '✓ CLEAR' : locked ? '◇ LOCK' : '◆ OPEN'}
[{c.sigil}]
{c.name}
{c.title}
"{c.quote}"
{[...Array(5)].map((_, j) => ( ))}
+{c.reward.credits.toLocaleString()} CRD · 1× MÍTICA
); } function NextReset({ resetAt, onReset }) { const [now, setNow] = useState(Date.now()); useEffect(() => { const id = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(id); }, []); if (!resetAt) return
recarga al recargar
; const remain = Math.max(0, resetAt - now); if (remain === 0) { return ; } const h = Math.floor(remain / 3.6e6); const m = Math.floor((remain % 3.6e6) / 6e4); const s = Math.floor((remain % 6e4) / 1000); return (
{String(h).padStart(2,'0')}:{String(m).padStart(2,'0')}:{String(s).padStart(2,'0')}
); } window.Hub = Hub;