/* ========================================================================= CISCO ARENA — Chrome components (Header, Sidebar, Footer, ScreenNav) ========================================================================= */ const { useState, useEffect, useMemo, useRef } = React; function Header({ theme, phaseLabel, phaseKey, me, team, sessionCode, proctorName }) { const themeLabel = theme.label.toUpperCase(); return ( <> Skip to content
A
{themeLabel}
{phaseKey === "join" ? "CHECK-IN · SEASON 04" : `${phaseLabel.toUpperCase()} · SEASON 04 · ROUND 03`}
{phaseLabel}
{me.name} · {team.short} {me.name.split(" ").map(n=>n[0]).join("").slice(0,2)}
); } function Sidebar({ theme, leaderboard, me, streak, score, prevScore, timerSec, totalSec, urgent, powerupsSpent, onPowerup, layoutCompact, screen, draftStatus, draftTeams, draftUndrafted, isCaptain, isMyTurn, connected, tdActive }) { // Filter out proctors const activePlayers = leaderboard.filter(p => !p.is_proctor && p.role !== 'proctor'); // Build team groups sorted by team total score DESC const teamGroups = useMemo(() => { const groups = theme.teams.map(t => { const members = activePlayers .filter(p => p.tid === t.id) .sort((a, b) => (b.score || 0) - (a.score || 0)); const total = members.reduce((s, p) => s + (p.score || 0), 0); return { ...t, members, total }; }).sort((a, b) => b.total - a.total); const unassigned = activePlayers.filter(p => !p.tid).sort((a, b) => (b.score || 0) - (a.score || 0)); if (unassigned.length > 0) groups.push({ id: '__none__', short: '—', name: 'Sin equipo', color: 'var(--ink-muted)', emoji: '❓', members: unassigned, total: 0 }); return groups; }, [theme, activePlayers]); const sorted = [...activePlayers].sort((a,b) => b.score - a.score); const myRank = sorted.findIndex(p => p.id === me.id) + 1; const showTimer = (screen === "quiz" || screen === "triage") && !tdActive; const isLobby = screen === "lobby"; const draftActive = !!(draftStatus && draftStatus.active); const [draftNow, setDraftNow] = useState(Date.now()); const timerDisplay = useMemo(() => { const s = Math.max(0, Math.floor(timerSec)); return `${String(Math.floor(s/60)).padStart(2,"0")}:${String(s%60).padStart(2,"0")}`; }, [timerSec]); const timerPct = Math.max(0, Math.min(100, (timerSec / totalSec) * 100)); useEffect(() => { if (!draftActive) return; const t = setInterval(() => setDraftNow(Date.now()), 100); return () => clearInterval(t); }, [draftActive]); // ── Lobby / Draft: roster view ── if (isLobby) { if (draftActive) { const getTeamTheme = (teamId) => theme.teams.find(t => t.id === teamId) || {}; const getTeamName = (teamId) => getTeamTheme(teamId).name || teamId || "Unassigned"; const getCurrentCaptainInfo = () => { if (!draftStatus || !draftStatus.active) return null; const order = draftStatus.captain_order || []; const idx = draftStatus.current_pick_index || 0; const round = draftStatus.round || 1; const n = order.length; if (n === 0) return null; const captainIdx = round % 2 === 1 ? (idx % n) : ((n - 1) - (idx % n)); const email = order[captainIdx]; for (const [teamId, teamData] of Object.entries(draftTeams || {})) { const captain = teamData.captain || (teamData.members || []).find(m => m.isCaptain); if (captain && captain.email === email) { const themeTeam = theme.teams.find(t => t.id === teamId); return { ...captain, teamId, teamName: themeTeam?.name || teamId, teamColor: themeTeam?.color || 'var(--accent)' }; } } return { email, teamId: '', teamName: '', teamColor: 'var(--accent)' }; }; const currentCaptain = getCurrentCaptainInfo(); const draftCountdown = draftStatus?.pick_deadline ? Math.max(0, draftStatus.pick_deadline - (draftNow / 1000)) : 0; const draftTotal = draftStatus?.pick_duration || 15; const draftPct = draftTotal > 0 ? Math.max(0, Math.min(100, (draftCountdown / draftTotal) * 100)) : 0; const draftTimerColor = draftPct > 60 ? "var(--success)" : (draftPct > 30 ? "var(--warning)" : "var(--danger)"); const assignedTeam = me?.tid ? getTeamName(me.tid) : ""; const maxManual = draftStatus?.max_manual_rounds || 2; const modeLabel = (draftStatus?.round || 1) > maxManual ? "Auto" : "Manual"; return ( ); } const unassigned = leaderboard.filter(p => !p.tid); return ( ); } // ── Game mode: timer + score + leaderboard + powerups ── return ( ); } function Footer({ theme, sessionCode, proctorName, region }) { const displaySession = sessionCode || "CA-7842-KR"; const displayProctor = proctorName || "J. Medina"; const displayRegion = region || "LATAM-S"; return ( <>
{theme.label} / Powered by Cisco Arena
Session: {displaySession} / Proctor: {displayProctor} / Region: {displayRegion}
Cisco · v4.2
); } function ScreenNav({ screen, onPick }) { const items = [ { k: "join", label: "01", ariaLabel: "Go to Join screen" }, { k: "lobby", label: "02", ariaLabel: "Go to Lobby screen" }, { k: "quiz", label: "03", ariaLabel: "Go to Quiz screen" }, { k: "triage", label: "04", ariaLabel: "Go to Triage screen" }, { k: "wrap", label: "05", ariaLabel: "Go to Wrap-up screen" }, ]; return ( ); } window.Header = Header; window.Sidebar = Sidebar; window.Footer = Footer; window.ScreenNav = ScreenNav;