'use client' import React, { useState, useEffect } from 'react' import { useRouter, useParams } from 'next/navigation' import { Users, Trophy, Clock, Play, Pause, Square, UserMinus, RefreshCw, Settings, Monitor, AlertCircle } from 'lucide-react' interface Participant { name: string score: number completed: boolean submitted_at?: string joined_at: string } interface ExamInfo { title: string status: 'waiting' | 'active' | 'completed' duration_minutes: number participants_count: number max_participants: number problem_title: string languages: string[] created_at: string host_name: string } export default function HostPanel() { const params = useParams() const router = useRouter() const examCode = params.examCode as string const [examInfo, setExamInfo] = useState(null) const [participants, setParticipants] = useState([]) const [leaderboard, setLeaderboard] = useState([]) const [timeRemaining, setTimeRemaining] = useState(0) const [loading, setLoading] = useState(true) const [error, setError] = useState('') useEffect(() => { if (examCode) { fetchExamInfo() fetchParticipants() fetchLeaderboard() // Auto-refresh every 5 seconds const interval = setInterval(() => { fetchParticipants() fetchLeaderboard() }, 5000) return () => clearInterval(interval) } }, [examCode]) const fetchExamInfo = async () => { try { const response = await fetch(`http://127.0.0.1:5000/api/exam/info/${examCode}`) const data = await response.json() if (data.success) { setExamInfo(data.exam_info) if (data.exam_info.status === 'active') { startTimer(data.exam_info.duration_minutes * 60) } } else { setError('Failed to load exam information') } } catch (error) { setError('Network error') } finally { setLoading(false) } } const fetchParticipants = async () => { try { const response = await fetch(`http://127.0.0.1:5000/api/exam/participants/${examCode}`) const data = await response.json() if (data.success) { setParticipants(data.participants) } } catch (error) { console.error('Failed to fetch participants') } } const fetchLeaderboard = async () => { try { const response = await fetch(`http://127.0.0.1:5000/api/exam/leaderboard/${examCode}`) const data = await response.json() if (data.success) { setLeaderboard(data.leaderboard) } } catch (error) { console.error('Failed to fetch leaderboard') } } const startExam = async () => { try { const response = await fetch('http://127.0.0.1:5000/api/exam/start-exam', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exam_code: examCode }) }) const data = await response.json() if (data.success) { setExamInfo(prev => prev ? { ...prev, status: 'active' } : null) startTimer(examInfo?.duration_minutes ? examInfo.duration_minutes * 60 : 1800) alert('✅ Exam started! Participants can now begin coding.') } else { alert(`❌ Failed to start exam: ${data.error}`) } } catch (error) { alert('❌ Network error occurred') } } const stopExam = async () => { try { const response = await fetch('http://127.0.0.1:5000/api/exam/stop-exam', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exam_code: examCode }) }) const data = await response.json() if (data.success) { setExamInfo(prev => prev ? { ...prev, status: 'completed' } : null) setTimeRemaining(0) alert('🛑 Exam stopped successfully!') } else { alert(`❌ Failed to stop exam: ${data.error}`) } } catch (error) { alert('❌ Network error occurred') } } const removeParticipant = async (participantName: string) => { if (!confirm(`Are you sure you want to remove "${participantName}" from the exam?`)) { return } try { const response = await fetch('http://127.0.0.1:5000/api/exam/remove-participant', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exam_code: examCode, participant_name: participantName }) }) const data = await response.json() if (data.success) { alert(`✅ Removed "${participantName}" from the exam`) fetchParticipants() fetchLeaderboard() } else { alert(`❌ Failed to remove participant: ${data.error}`) } } catch (error) { alert('❌ Network error occurred') } } const startTimer = (seconds: number) => { setTimeRemaining(seconds) const timer = setInterval(() => { setTimeRemaining(prev => { if (prev <= 1) { clearInterval(timer) alert('⏰ Time is up! Exam has ended.') setExamInfo(prev => prev ? { ...prev, status: 'completed' } : null) return 0 } return prev - 1 }) }, 1000) } const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60) const secs = seconds % 60 return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` } const getStatusColor = (status: string) => { switch (status) { case 'waiting': return 'bg-yellow-600' case 'active': return 'bg-green-600' case 'completed': return 'bg-red-600' default: return 'bg-gray-600' } } if (loading) { return (

Loading host panel...

) } if (error || !examInfo) { return (

Error

{error || 'Exam not found'}

) } return (
{/* Header */}

Host Panel

Managing exam: {examCode}

{examInfo.status.toUpperCase()}
{timeRemaining > 0 && (
{formatTime(timeRemaining)}
)}
{/* Main Content */}
{/* Exam Info Cards */}

Participants

{examInfo.participants_count}/{examInfo.max_participants}

Duration

{examInfo.duration_minutes}m

Completed

{leaderboard.filter(p => p.completed).length}

Problem

{examInfo.problem_title}

{/* Control Panel */}

Exam Controls

{examInfo.status === 'waiting' && ( )} {examInfo.status === 'active' && ( <> )}
{/* Participants List */}

Participants ({participants.length})

{participants.map((participant, index) => ( ))}
Name Joined At Status Score Actions
{participant.name} {new Date(participant.joined_at).toLocaleTimeString()} {participant.completed ? 'Completed' : 'In Progress'} {participant.completed ? ( {participant.score}% ) : ( - )}
{participants.length === 0 && (
No participants have joined yet.
)}
{/* Leaderboard Sidebar */}

Live Leaderboard

{leaderboard.map((participant, index) => (
#{index + 1} {participant.name}
{participant.submitted_at && (

Submitted: {new Date(participant.submitted_at).toLocaleTimeString()}

)}
{participant.score}%
{participant.completed ? 'Completed' : 'In Progress'}
))}
{leaderboard.length === 0 && (
No submissions yet.
)}
) }