'use client' import React, { useState, useEffect } from 'react' import { useParams, useRouter } from 'next/navigation' import { Users, Trophy, Clock, Play, Square, UserX, AlertTriangle, RefreshCw, Settings, BarChart, Eye, Trash2, Plus, Timer } from 'lucide-react' interface Participant { name: string joined_at: string score: number completed: boolean language?: string submission_time?: string rank?: number kicked?: boolean } interface ExamData { exam_info: { exam_code: string title: string status: string duration_minutes: number max_participants: number time_elapsed: number time_remaining: number start_time?: string end_time?: string } participants: { total: number completed: number working: number all_participants: Participant[] recent_joins: Participant[] } leaderboard: Participant[] statistics: { average_score: number highest_score: number lowest_score: number completion_rate: number } } export default function HostDashboard() { const params = useParams() const router = useRouter() const examCode = params.examCode as string const [examData, setExamData] = useState(null) const [loading, setLoading] = useState(true) const [activeTab, setActiveTab] = useState<'overview' | 'participants' | 'leaderboard' | 'settings'>('overview') const [selectedParticipant, setSelectedParticipant] = useState(null) const [showKickModal, setShowKickModal] = useState(false) const [refreshInterval, setRefreshInterval] = useState(3000) // 3 seconds useEffect(() => { if (!examCode) return fetchDashboardData() const interval = setInterval(fetchDashboardData, refreshInterval) return () => clearInterval(interval) }, [examCode, refreshInterval]) const fetchDashboardData = async () => { try { const response = await fetch(`http://127.0.0.1:5000/api/exam/host-dashboard/${examCode}`) const data = await response.json() if (data.success) { setExamData(data) } else { console.error('Failed to fetch dashboard data:', data.error) } } catch (error) { console.error('Error fetching dashboard data:', error) } finally { setLoading(false) } } 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) { alert('Exam started successfully!') fetchDashboardData() } else { alert(`Failed to start exam: ${data.error}`) } } catch (error) { alert('Failed to start exam') } } const endExam = async () => { if (!confirm('Are you sure you want to end the exam? This cannot be undone.')) return try { const response = await fetch('http://127.0.0.1:5000/api/exam/end-exam', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exam_code: examCode }) }) const data = await response.json() if (data.success) { alert('Exam ended successfully!') fetchDashboardData() } else { alert(`Failed to end exam: ${data.error}`) } } catch (error) { alert('Failed to end exam') } } const extendExam = async (minutes: number) => { try { const response = await fetch('http://127.0.0.1:5000/api/exam/extend-exam', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ exam_code: examCode, additional_minutes: minutes }) }) const data = await response.json() if (data.success) { alert(`Exam extended by ${minutes} minutes!`) fetchDashboardData() } else { alert(`Failed to extend exam: ${data.error}`) } } catch (error) { alert('Failed to extend exam') } } 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(`Participant "${participantName}" removed successfully!`) fetchDashboardData() setShowKickModal(false) setSelectedParticipant(null) } else { alert(`Failed to remove participant: ${data.error}`) } } catch (error) { alert('Failed to remove participant') } } 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-100 text-yellow-800' case 'active': return 'bg-green-100 text-green-800' case 'completed': return 'bg-gray-100 text-gray-800' default: return 'bg-gray-100 text-gray-800' } } if (loading) { return (

Loading host dashboard...

) } if (!examData) { return (

Exam Not Found

The exam code "{examCode}" is invalid or expired.

) } return (
{/* Header */}

{examData.exam_info.title}

CODE: {examData.exam_info.exam_code} {examData.exam_info.status.toUpperCase()} {examData.participants.total}/{examData.exam_info.max_participants} participants
{/* Timer */} {examData.exam_info.status === 'active' && examData.exam_info.time_remaining > 0 && (
{formatTime(examData.exam_info.time_remaining)}
)} {/* Control Buttons */} {examData.exam_info.status === 'waiting' && ( )} {examData.exam_info.status === 'active' && (
)}
{/* Tab Navigation */}
{[ { id: 'overview', label: 'Overview', icon: BarChart }, { id: 'participants', label: 'Participants', icon: Users }, { id: 'leaderboard', label: 'Leaderboard', icon: Trophy }, { id: 'settings', label: 'Settings', icon: Settings } ].map(tab => ( ))}
{/* Tab Content */} {activeTab === 'overview' && (
{/* Statistics Cards */}

Total Participants

{examData.participants.total}

Completed

{examData.participants.completed}

Still Working

{examData.participants.working}

Average Score

{Math.round(examData.statistics.average_score)}%

{/* Recent Activity */}

Recent Participants

{examData.participants.recent_joins.slice(0, 5).map((participant, index) => (
{participant.name.charAt(0).toUpperCase()}
{participant.name}
Joined {new Date(participant.joined_at).toLocaleTimeString()}
{participant.completed ? `${participant.score}% completed` : 'Working'}
))}
)} {activeTab === 'participants' && (

All Participants ({examData.participants.total})

Completion Rate: {Math.round(examData.statistics.completion_rate)}%
{examData.participants.all_participants.map((participant) => ( ))}
Participant Status Score Language Joined Actions
{participant.name.charAt(0).toUpperCase()}
{participant.name}
{participant.kicked ? 'Kicked' : participant.completed ? 'Completed' : 'Working'} {participant.completed ? `${participant.score}%` : '-'} {participant.language || '-'} {new Date(participant.joined_at).toLocaleString()}
)} {activeTab === 'leaderboard' && (

Live Leaderboard

{examData.leaderboard.map((participant, index) => { const rankColors = { 1: 'bg-gradient-to-r from-yellow-600 to-yellow-500 text-white', 2: 'bg-gradient-to-r from-gray-400 to-gray-500 text-white', 3: 'bg-gradient-to-r from-orange-600 to-orange-500 text-white' } return (
#{participant.rank}
{participant.name}
{participant.language && `${participant.language} • `} Submitted: {new Date(participant.submission_time!).toLocaleTimeString()}
{participant.score}%
) })}
)} {activeTab === 'settings' && (

Exam Controls

Auto-Refresh Settings

)}
{/* Kick Participant Modal */} {showKickModal && selectedParticipant && (

Remove Participant

Are you sure you want to remove "{selectedParticipant}" from the exam? This action cannot be undone.

)}
) }