import React from 'react';
import { useGame } from '../context/GameContext';
import { GamePhase } from '../types';
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell } from 'recharts';
import { Trophy, Zap, Users } from 'lucide-react';
export const SpectatorView: React.FC = () => {
const { gameState, questions, teams, players, buzzQueue } = useGame();
const currentQ = questions[gameState.currentQuestionIndex];
// Helper to get formatted leaderboard data
const leaderboardData = [...teams].sort((a, b) => b.score - a.score);
const COLORS = ['#F59E0B', '#3B82F6', '#10B981', '#EC4899', '#8B5CF6'];
// Helper for YouTube ID extraction
const getYoutubeId = (url: string) => {
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
const match = url.match(regExp);
return (match && match[2].length === 11) ? match[2] : null;
};
const renderContent = () => {
switch (gameState.phase) {
case GamePhase.LOBBY:
return (
JOIN THE QUIZ
Scan to Join
{players.filter(p => p.isApproved).map(p => (
{p.name}
))}
);
case GamePhase.COUNTDOWN:
return (
{gameState.countdownValue}
);
case GamePhase.QUESTION_DISPLAY:
case GamePhase.BUZZER_OPEN:
case GamePhase.ADJUDICATION:
return (
{currentQ?.category || 'General'}
{currentQ?.points} PTS
{currentQ?.text}
{/* Media Display */}
{currentQ?.mediaUrl && (
{currentQ.mediaType === 'video' ? (
) : (

)}
)}
{/* Buzzer Status for Audience */}
{buzzQueue.map((buzz, idx) => {
const player = players.find(p => p.id === buzz.playerId);
let bg = 'bg-slate-700';
if (buzz.status === 'CORRECT') bg = 'bg-green-600';
if (buzz.status === 'WRONG') bg = 'bg-red-600';
if (buzz.status === 'PENDING' && idx === 0) bg = 'bg-yellow-500 animate-pulse';
return (
#{idx + 1}
{player?.name}
);
})}
);
case GamePhase.ANSWER_REVEAL:
return (
The answer is...
{currentQ?.answer}
);
case GamePhase.LEADERBOARD:
return (
LEADERBOARD
{leaderboardData.map((entry, index) => (
|
))}
);
case GamePhase.FINAL_STATS:
const sortedTeams = [...teams].sort((a,b) => b.score - a.score);
const winningTeam = sortedTeams[0];
const otherTeams = sortedTeams.slice(1);
// Top 5 Players
const topPlayers = [...players].sort((a,b) => b.score - a.score).slice(0, 5);
// Fastest Buzzer Calculation
let fastestPlayer = null;
let fastestTime = Infinity;
players.forEach(p => {
if (p.stats.bestReactionTime && p.stats.bestReactionTime < fastestTime) {
fastestTime = p.stats.bestReactionTime;
fastestPlayer = p;
}
});
return (
Game Over
{/* 1. Grand Champion Section */}
Grand Champion
{winningTeam?.name || 'No Winner'}
{winningTeam?.score || 0} PTS
{/* 2. Remaining Teams Leaderboard */}
Team Standings
{otherTeams.length > 0 ? (
otherTeams.map((team, idx) => (
#{idx + 2}
{team.name}
{team.score}
))
) : (
No other teams participated.
)}
{/* 3. Player Accolades */}
{/* Fastest Buzzer Card */}
Fastest Finger
{fastestPlayer?.name || '-'}
{fastestPlayer && fastestTime !== Infinity ? (fastestTime / 1000).toFixed(2) : '-'}s
{/* Top 5 Players Table */}
Top 5 Players
| Rank |
Player |
Score |
Acc |
{topPlayers.map((p, i) => (
| #{i + 1} |
{p.name} |
{p.score} |
{p.stats.correctAnswers}/{p.stats.totalBuzzes}
|
))}
);
default:
return null;
}
};
return (
{/* Ambient Background Elements */}
{renderContent()}
);
};