/* =========================================================================
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;