Files
OpenLearnX/frontend/app/coding/page.tsx
T

1049 lines
56 KiB
TypeScript

'use client'
import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import { Play, Lock, Shield, AlertTriangle, Users, Trophy, Clock, Code, Zap, Sparkles, Star, Brain, CheckCircle, XCircle } from 'lucide-react'
type UserRole = 'selector' | 'host' | 'participant'
type ExamStatus = 'waiting' | 'active' | 'completed'
interface Participant {
name: string
score: number
completed: boolean
submitted_at?: string
}
export default function CodingExamPlatform() {
const [userRole, setUserRole] = useState<UserRole>('selector')
const [examId, setExamId] = useState('')
const [participantName, setParticipantName] = useState('')
const [examInfo, setExamInfo] = useState<any>(null)
const [systemChecked, setSystemChecked] = useState(false)
const [isSecureMode, setIsSecureMode] = useState(false)
const [leaderboard, setLeaderboard] = useState<Participant[]>([])
const [timeRemaining, setTimeRemaining] = useState(0)
// Coding states
const [code, setCode] = useState('')
const [output, setOutput] = useState('')
const [isExecuting, setIsExecuting] = useState(false)
const router = useRouter()
// System Requirements Check
const checkSystemRequirements = () => {
const checks = {
fullscreenSupported: document.fullscreenEnabled,
webGLSupported: !!document.createElement('canvas').getContext('webgl'),
localStorageSupported: typeof Storage !== 'undefined',
cookiesEnabled: navigator.cookieEnabled
}
const allPassed = Object.values(checks).every(check => check)
if (allPassed) {
setSystemChecked(true)
alert('System requirements check passed! ✅')
} else {
alert('System requirements not met. Please use a modern browser.')
}
return allPassed
}
const acceptSystemRequirements = () => {
if (checkSystemRequirements()) {
enableSecureMode()
}
}
const enableSecureMode = () => {
// Enter fullscreen
document.documentElement.requestFullscreen().then(() => {
setIsSecureMode(true)
disableBrowserFeatures()
detectVirtualEnvironment()
// Start exam timer if in active exam
if (examInfo?.status === 'active') {
startExamTimer()
}
}).catch(() => {
alert('Fullscreen mode is required for secure coding')
})
}
const disableBrowserFeatures = () => {
// Disable right-click, copy/paste, dev tools
const blockActions = (e: KeyboardEvent) => {
if (e.ctrlKey && ['c', 'v', 'x', 'a'].includes(e.key)) {
e.preventDefault()
alert('Copy/paste is disabled in exam mode')
}
if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && ['I', 'C'].includes(e.key))) {
e.preventDefault()
alert('Developer tools are disabled')
}
}
document.addEventListener('keydown', blockActions)
document.addEventListener('contextmenu', e => e.preventDefault())
document.addEventListener('selectstart', e => e.preventDefault())
}
const detectVirtualEnvironment = () => {
const canvas = document.createElement('canvas')
const gl = canvas.getContext('webgl')
if (gl) {
const renderer = gl.getParameter(gl.RENDERER)
if (renderer.includes('VMware') || renderer.includes('VirtualBox')) {
alert('Virtual environment detected. Exam will be terminated.')
window.location.href = '/'
}
}
}
// ✅ UPDATED CREATE EXAM WITH HOST PANEL REDIRECT
const createExam = async () => {
try {
const response = await fetch('http://127.0.0.1:5000/api/exam/create-exam', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'String Capitalizer Challenge',
problem_id: 'string-capitalizer',
duration_minutes: 30,
host_name: participantName,
max_participants: 50
})
})
const data = await response.json()
console.log('📦 Create exam response:', data)
if (data.success) {
// ✅ CORRECTED: Use exam_code, NOT exam_id
const participantCode = data.exam_code // This is the 6-character code
const databaseId = data.exam_id // This is the MongoDB ObjectId
setExamId(participantCode)
setExamInfo({ title: 'String Capitalizer Challenge', status: 'waiting' })
// Store host exam data
localStorage.setItem('host_exam', JSON.stringify({
exam_code: participantCode,
exam_id: databaseId,
host_name: participantName,
created_at: new Date().toISOString(),
exam_details: data.exam_details || {}
}))
alert(`✅ Exam Created Successfully!
📝 Exam Code: ${participantCode}
📋 Title: String Capitalizer Challenge
👤 Host: ${participantName}
⏱️ Duration: 30 minutes
🔗 Share this code with participants: ${participantCode}
Redirecting to Host Management Panel...`)
// ✅ REDIRECT TO HOST PANEL
setTimeout(() => {
router.push(`/coding/host/${participantCode}`)
}, 2000)
} else {
alert(`❌ Failed to create exam: ${data.error}`)
}
} catch (error) {
console.error('Create exam error:', error)
alert('❌ Failed to create exam - network error')
}
}
// ✅ CORRECTED JOIN FUNCTION WITH PROPER REDIRECT
const joinExam = async () => {
try {
console.log('🚀 Joining with:', { exam_code: examId, student_name: participantName })
const response = await fetch('http://127.0.0.1:5000/api/exam/join-exam', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
exam_code: examId, // ✅ Correct field name
student_name: participantName // ✅ Changed from 'name' to 'student_name'
})
})
const data = await response.json()
console.log('📦 Join response:', data)
if (data.success) {
setExamInfo(data.exam_info)
// Store exam session data for the exam interface
localStorage.setItem('exam_session', JSON.stringify({
exam_code: examId,
student_name: participantName,
exam_info: data.exam_info,
joined_at: new Date().toISOString()
}))
alert(`✅ Successfully joined: ${data.exam_info.title}!
👤 Joined as: ${participantName}
📊 Participants: ${data.exam_info.participants_count}/${data.exam_info.max_participants}
⏱️ Duration: ${data.exam_info.duration_minutes} minutes
Redirecting to exam interface...`)
// ✅ REDIRECT TO EXAM INTERFACE
setTimeout(() => {
router.push('/coding/exam')
}, 1500)
} else {
alert(`❌ Error: ${data.error}`)
}
} catch (error) {
console.error('Join error:', error)
alert('❌ Failed to join exam - network error')
}
}
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: examId })
})
const data = await response.json()
if (data.success) {
setExamInfo(prev => ({ ...prev, status: 'active' }))
alert('Exam started! Participants can now begin coding.')
startExamTimer()
}
} catch (error) {
alert('Failed to start exam')
}
}
const startExamTimer = () => {
const duration = 30 * 60 // 30 minutes in seconds
setTimeRemaining(duration)
const timer = setInterval(() => {
setTimeRemaining(prev => {
if (prev <= 1) {
clearInterval(timer)
alert('Time is up!')
return 0
}
return prev - 1
})
}, 1000)
}
const submitSolution = async () => {
setIsExecuting(true)
try {
const response = await fetch('http://127.0.0.1:5000/api/exam/submit-solution', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code })
})
const data = await response.json()
if (data.success) {
alert(`Solution submitted! Your score: ${data.score}%`)
fetchLeaderboard()
}
} catch (error) {
alert('Failed to submit solution')
} finally {
setIsExecuting(false)
}
}
const fetchLeaderboard = async () => {
try {
const response = await fetch(`http://127.0.0.1:5000/api/exam/leaderboard/${examId}`)
const data = await response.json()
setLeaderboard(data.leaderboard)
} catch (error) {
console.error('Failed to fetch leaderboard')
}
}
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')}`
}
// Role Selection Screen with Enhanced Animations
if (userRole === 'selector') {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:bg-gradient-to-br dark:from-[#1b3760] dark:via-[#24467d] dark:to-[#4a2f86] flex items-center justify-center relative overflow-hidden animate-fade-in">
{/* Animated Background Elements */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-1/4 left-1/4 w-32 h-32 bg-white rounded-full animate-float"></div>
<div className="absolute top-3/4 right-1/4 w-24 h-24 bg-white rounded-full animate-float animate-delay-500"></div>
<div className="absolute top-1/2 right-1/3 w-16 h-16 bg-white rounded-full animate-float animate-delay-1000"></div>
{/* Floating particles */}
<div className="absolute top-1/6 left-1/6 w-2 h-2 bg-white rounded-full animate-pulse opacity-60"></div>
<div className="absolute top-2/3 left-3/4 w-1 h-1 bg-white rounded-full animate-pulse animate-delay-300 opacity-40"></div>
<div className="absolute top-1/3 right-1/2 w-1.5 h-1.5 bg-white rounded-full animate-pulse animate-delay-700 opacity-50"></div>
</div>
{/* Floating sparkles */}
<div className="absolute top-1/4 right-1/3 animate-float animate-delay-200">
<Sparkles className="w-6 h-6 text-white opacity-60 animate-pulse" />
</div>
<div className="absolute bottom-1/4 left-1/4 animate-float animate-delay-800">
<Star className="w-4 h-4 text-white opacity-50 animate-spin-slow" />
</div>
<div className="bg-white/95 dark:bg-[#22314a]/95 backdrop-blur-sm rounded-2xl shadow-2xl p-10 max-w-lg w-full transform animate-scale-in hover:scale-105 transition-all duration-500 relative overflow-hidden group border border-gray-200 dark:border-blue-300/20">
{/* Card shine effect */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-white/20 to-transparent transition-transform duration-1000"></div>
<div className="relative z-10">
<div className="text-center mb-10">
<div className="flex justify-center mb-4 animate-bounce">
<Code className="h-16 w-16 text-blue-600 animate-pulse" />
</div>
<h1 className="text-3xl font-bold text-gray-800 dark:text-white mb-3 animate-slide-down">
OpenLearnX Coding Exam
</h1>
<p className="text-gray-600 dark:text-gray-300 animate-fade-in animate-delay-300">
Choose your role to get started
</p>
</div>
<div className="space-y-6">
<button
onClick={() => setUserRole('host')}
className="w-full bg-gradient-to-r from-blue-600 to-blue-700 dark:from-blue-700 dark:to-blue-800 hover:from-blue-700 hover:to-blue-800 dark:hover:from-blue-800 dark:hover:to-blue-900 text-white py-4 px-6 rounded-xl flex items-center justify-center space-x-3 transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.1s' }}
>
{/* Button background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center space-x-3">
<Users className="h-6 w-6 transition-transform duration-300 group-hover:rotate-12 group-hover:scale-110" />
<span className="text-lg font-semibold group-hover:tracking-wider transition-all duration-300">Host an Exam</span>
</div>
{/* Floating particles on hover */}
<div className="absolute -top-1 -right-1 opacity-0 group-hover:opacity-100 group-hover:animate-ping transition-all duration-300">
<div className="w-3 h-3 bg-white rounded-full"></div>
</div>
</button>
<button
onClick={() => setUserRole('participant')}
className="w-full bg-gradient-to-r from-green-600 to-green-700 dark:from-green-700 dark:to-green-800 hover:from-green-700 hover:to-green-800 dark:hover:from-green-800 dark:hover:to-green-900 text-white py-4 px-6 rounded-xl flex items-center justify-center space-x-3 transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.2s' }}
>
{/* Button background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-green-500 to-teal-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center space-x-3">
<Play className="h-6 w-6 transition-transform duration-300 group-hover:translate-x-1 group-hover:scale-110" />
<span className="text-lg font-semibold group-hover:tracking-wider transition-all duration-300">Join an Exam</span>
</div>
{/* Floating particles on hover */}
<div className="absolute -top-1 -right-1 opacity-0 group-hover:opacity-100 group-hover:animate-ping transition-all duration-300">
<div className="w-3 h-3 bg-white rounded-full"></div>
</div>
</button>
</div>
{/* Animated footer */}
<div className="mt-8 text-center animate-fade-in animate-delay-500">
<p className="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors duration-300">
Secure Real-time Professional
</p>
</div>
</div>
</div>
</div>
)
}
// Host Setup Screen with Enhanced UI
if (userRole === 'host' && !examId) {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:bg-gradient-to-br dark:from-[#1b3760] dark:via-[#24467d] dark:to-[#4a2f86] flex items-center justify-center relative overflow-hidden animate-fade-in">
{/* Enhanced background animations */}
<div className="absolute inset-0 opacity-5">
<div className="absolute top-0 left-0 w-96 h-96 bg-white rounded-full mix-blend-overlay animate-blob"></div>
<div className="absolute top-0 right-0 w-96 h-96 bg-white rounded-full mix-blend-overlay animate-blob animation-delay-2000"></div>
<div className="absolute -bottom-8 left-20 w-96 h-96 bg-white rounded-full mix-blend-overlay animate-blob animation-delay-4000"></div>
</div>
{/* Floating icons */}
<div className="absolute top-1/5 right-1/5 animate-float animate-delay-1000">
<Brain className="w-8 h-8 text-white opacity-30 animate-pulse" />
</div>
<div className="absolute bottom-1/5 left-1/5 animate-float animate-delay-2000">
<Zap className="w-6 h-6 text-white opacity-20 animate-bounce" />
</div>
<div className="bg-white/95 dark:bg-[#22314a]/95 backdrop-blur-lg rounded-3xl shadow-2xl p-12 max-w-xl w-full transform animate-scale-in hover:scale-105 transition-all duration-500 relative overflow-hidden group border border-gray-200 dark:border-blue-300/20">
{/* Enhanced shine effect */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-blue-200/30 to-transparent transition-transform duration-1000"></div>
<div className="relative z-10">
<div className="text-center mb-8">
<div className="flex justify-center mb-6 relative">
<div className="p-4 bg-blue-100 rounded-full animate-bounce">
<Users className="h-12 w-12 text-blue-600 animate-pulse" />
</div>
{/* Floating particles around icon */}
<div className="absolute -top-2 -right-2 w-3 h-3 bg-blue-400 rounded-full animate-ping"></div>
<div className="absolute -bottom-2 -left-2 w-2 h-2 bg-blue-300 rounded-full animate-ping animation-delay-500"></div>
</div>
<h1 className="text-4xl font-bold text-gray-800 dark:text-white mb-4 animate-slide-down">
Host Coding Exam
</h1>
<p className="text-gray-600 dark:text-gray-300 text-lg animate-fade-in animate-delay-300">
Create a secure coding environment for your participants
</p>
</div>
<div className="space-y-6">
<div className="relative animate-slide-up" style={{ animationDelay: '0.1s' }}>
<input
type="text"
placeholder="Enter your name"
value={participantName}
onChange={(e) => setParticipantName(e.target.value)}
className="w-full p-4 border-2 border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 rounded-xl text-lg text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 transition-all duration-300 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-800 focus:border-blue-500 dark:focus:border-blue-400 hover:border-blue-300 dark:hover:border-blue-500 hover:bg-white dark:hover:bg-gray-600 focus:bg-white dark:focus:bg-gray-700 group"
/>
{/* Input decoration */}
<div className="absolute right-4 top-1/2 transform -translate-y-1/2 opacity-0 group-focus-within:opacity-100 transition-opacity duration-300">
<CheckCircle className="w-5 h-5 text-green-500 animate-pulse" />
</div>
</div>
<button
onClick={createExam}
disabled={!participantName}
className="w-full bg-gradient-to-r from-blue-600 to-indigo-600 dark:from-blue-700 dark:to-indigo-700 hover:from-blue-700 hover:to-indigo-700 dark:hover:from-blue-800 dark:hover:to-indigo-800 disabled:from-gray-400 disabled:to-gray-500 text-white py-4 px-6 rounded-xl text-lg font-semibold transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 disabled:hover:scale-100 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.2s' }}
>
{/* Button animation background */}
<div className="absolute inset-0 bg-gradient-to-r from-purple-600 to-pink-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center justify-center space-x-3">
<span className="group-hover:tracking-wider transition-all duration-300">Create Exam</span>
<Sparkles className="w-5 h-5 group-hover:animate-spin transition-transform duration-300" />
</div>
{/* Ripple effect */}
<div className="absolute inset-0 opacity-0 group-hover:opacity-20 group-hover:animate-ping transition-all duration-300 bg-white rounded-xl"></div>
</button>
</div>
{/* Enhanced Debug Info */}
<div className="mt-8 p-6 bg-gradient-to-r from-gray-50 to-blue-50 dark:from-gray-700 dark:to-gray-800 rounded-xl text-sm text-gray-600 dark:text-gray-300 animate-fade-in border border-gray-200 dark:border-gray-600 hover:border-blue-300 dark:hover:border-blue-500 transition-colors duration-300" style={{ animationDelay: '0.3s' }}>
<div className="flex items-center space-x-2 mb-3">
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
<span className="font-semibold">System Status</span>
</div>
<div className="space-y-2">
<p className="flex items-center space-x-2">
<CheckCircle className="w-4 h-4 text-green-500" />
<span>Will create with host_name: "{participantName}"</span>
</p>
<p className="flex items-center space-x-2">
<CheckCircle className="w-4 h-4 text-green-500" />
<span>Will display exam_code (6 chars), not exam_id</span>
</p>
<p className="flex items-center space-x-2">
<Zap className="w-4 h-4 text-blue-500 animate-pulse" />
<span>After creation redirect to /coding/host/[examCode]</span>
</p>
</div>
</div>
</div>
</div>
</div>
)
}
// Join Exam Screen with Enhanced Animations
if (userRole === 'participant' && !examInfo) {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-green-50 to-blue-50 dark:bg-gradient-to-br dark:from-[#1b3760] dark:via-[#1f4f63] dark:to-[#274f80] flex items-center justify-center relative overflow-hidden animate-fade-in">
{/* Enhanced background effects */}
<div className="absolute inset-0 opacity-10">
<div className="absolute top-1/4 left-1/4 w-40 h-40 bg-white rounded-full animate-float hover:scale-150 transition-transform duration-500"></div>
<div className="absolute top-3/4 right-1/4 w-32 h-32 bg-white rounded-full animate-float animate-delay-500 hover:scale-125 transition-transform duration-500"></div>
<div className="absolute top-1/2 right-1/3 w-24 h-24 bg-white rounded-full animate-float animate-delay-1000 hover:scale-200 transition-transform duration-500"></div>
</div>
{/* Animated particles */}
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/6 left-1/6 w-3 h-3 bg-white rounded-full animate-pulse opacity-60 shadow-lg"></div>
<div className="absolute top-2/3 left-3/4 w-2 h-2 bg-white rounded-full animate-pulse animate-delay-300 opacity-40"></div>
<div className="absolute top-1/2 left-1/5 w-2.5 h-2.5 bg-white rounded-full animate-pulse animate-delay-700 opacity-50"></div>
</div>
<div className="bg-white/95 dark:bg-[#22314a]/95 backdrop-blur-lg rounded-3xl shadow-2xl p-12 max-w-xl w-full transform animate-scale-in hover:scale-105 transition-all duration-500 relative overflow-hidden group border border-gray-200 dark:border-blue-300/20">
{/* Enhanced card effects */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-green-200/30 to-transparent transition-transform duration-1000"></div>
<div className="relative z-10">
<div className="text-center mb-10">
<div className="flex justify-center mb-6 relative">
<div className="p-4 bg-green-100 rounded-full animate-bounce">
<Play className="h-12 w-12 text-green-600 animate-pulse" />
</div>
{/* Animated ring around icon */}
<div className="absolute inset-0 border-4 border-green-300 rounded-full animate-ping opacity-30"></div>
<div className="absolute inset-2 border-2 border-green-400 rounded-full animate-ping opacity-40 animation-delay-500"></div>
</div>
<h1 className="text-4xl font-bold text-gray-800 dark:text-white mb-4 animate-slide-down">
Join Coding Exam
</h1>
<p className="text-gray-600 dark:text-gray-300 text-lg animate-fade-in animate-delay-300">
Enter the exam code to participate in the coding challenge
</p>
</div>
<div className="space-y-6">
<div className="relative animate-slide-up" style={{ animationDelay: '0.1s' }}>
<input
type="text"
placeholder="Enter exam code (e.g., 3BPIBZ)"
value={examId}
onChange={(e) => setExamId(e.target.value.toUpperCase())}
className="w-full p-4 border-2 border-gray-200 dark:border-gray-600 rounded-xl text-center font-mono text-2xl tracking-widest uppercase text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 transition-all duration-300 focus:ring-4 focus:ring-green-200 dark:focus:ring-green-800 focus:border-green-500 dark:focus:border-green-400 hover:border-green-300 dark:hover:border-green-500 bg-gray-50 dark:bg-gray-700 hover:bg-white dark:hover:bg-gray-600 focus:bg-white dark:focus:bg-gray-700 relative group"
maxLength={6}
/>
{/* Input decorations */}
<div className="absolute inset-x-0 bottom-0 h-1 bg-gradient-to-r from-green-400 to-blue-400 transform scale-x-0 group-focus-within:scale-x-100 transition-transform duration-300 rounded-full"></div>
{examId.length === 6 && (
<div className="absolute right-4 top-1/2 transform -translate-y-1/2 animate-bounce">
<CheckCircle className="w-6 h-6 text-green-500 animate-pulse" />
</div>
)}
</div>
<div className="relative animate-slide-up" style={{ animationDelay: '0.2s' }}>
<input
type="text"
placeholder="Enter your name"
value={participantName}
onChange={(e) => setParticipantName(e.target.value)}
className="w-full p-4 border-2 border-gray-200 dark:border-gray-600 rounded-xl text-lg text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 transition-all duration-300 focus:ring-4 focus:ring-green-200 dark:focus:ring-green-800 focus:border-green-500 dark:focus:border-green-400 hover:border-green-300 dark:hover:border-green-500 bg-gray-50 dark:bg-gray-700 hover:bg-white dark:hover:bg-gray-600 focus:bg-white dark:focus:bg-gray-700 group"
/>
{/* Name validation indicator */}
{participantName.length > 2 && (
<div className="absolute right-4 top-1/2 transform -translate-y-1/2 animate-bounce">
<CheckCircle className="w-5 h-5 text-green-500 animate-pulse" />
</div>
)}
</div>
<button
onClick={joinExam}
disabled={!examId || !participantName}
className="w-full bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-700 hover:to-emerald-700 disabled:from-gray-400 disabled:to-gray-500 text-white py-4 px-6 rounded-xl text-lg font-semibold transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 disabled:hover:scale-100 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.3s' }}
>
{/* Enhanced button animations */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-600 to-purple-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center justify-center space-x-3">
<span className="group-hover:tracking-wider transition-all duration-300">Join Exam</span>
<div className="flex space-x-1">
<div className="w-1 h-1 bg-white rounded-full animate-bounce"></div>
<div className="w-1 h-1 bg-white rounded-full animate-bounce animation-delay-200"></div>
<div className="w-1 h-1 bg-white rounded-full animate-bounce animation-delay-400"></div>
</div>
</div>
{/* Button ripple effect */}
<div className="absolute inset-0 opacity-0 group-hover:opacity-20 group-hover:animate-ping transition-all duration-300 bg-white rounded-xl"></div>
</button>
{/* Enhanced Debug Info */}
<div className="text-sm text-gray-500 dark:text-gray-400 p-6 bg-gradient-to-r from-gray-50 to-green-50 dark:from-gray-700 dark:to-green-800 rounded-xl animate-fade-in border border-gray-200 dark:border-gray-600 hover:border-green-300 dark:hover:border-green-500 transition-colors duration-300" style={{ animationDelay: '0.4s' }}>
<div className="flex items-center space-x-2 mb-3">
<div className="w-2 h-2 bg-blue-500 rounded-full animate-pulse"></div>
<span className="font-semibold">Connection Status</span>
</div>
<div className="space-y-2">
<p className="flex items-center space-x-2">
<CheckCircle className="w-4 h-4 text-green-500" />
<span>Will send: exam_code="{examId}" student_name="{participantName}"</span>
</p>
<p className="flex items-center space-x-2">
<Zap className="w-4 h-4 text-blue-500 animate-pulse" />
<span>After join redirect to /coding/exam</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
// Enhanced System Requirements Check
if (!systemChecked) {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:bg-gradient-to-br dark:from-[#1b3760] dark:via-[#3f3b77] dark:to-[#4a2f86] text-gray-900 dark:text-white flex items-center justify-center relative overflow-hidden animate-fade-in">
{/* Animated warning elements */}
<div className="absolute inset-0 opacity-5">
<div className="absolute top-1/4 left-1/4 w-32 h-32 bg-red-500 rounded-full animate-pulse"></div>
<div className="absolute top-3/4 right-1/4 w-24 h-24 bg-yellow-500 rounded-full animate-pulse animate-delay-500"></div>
<div className="absolute top-1/2 right-1/3 w-16 h-16 bg-orange-500 rounded-full animate-pulse animate-delay-1000"></div>
</div>
{/* Floating warning icons */}
<div className="absolute top-1/5 right-1/5 animate-float animate-delay-1000">
<AlertTriangle className="w-8 h-8 text-red-400 opacity-60 animate-pulse" />
</div>
<div className="absolute bottom-1/5 left-1/5 animate-float animate-delay-2000">
<Shield className="w-6 h-6 text-yellow-400 opacity-40 animate-bounce" />
</div>
<div className="bg-white dark:bg-[#22314a]/95 backdrop-blur-lg rounded-3xl p-12 max-w-2xl w-full transform animate-scale-in hover:scale-105 transition-all duration-500 border border-red-500/30 dark:border-red-400/30 relative overflow-hidden group">
{/* Security-themed background */}
<div className="absolute inset-0 bg-gradient-to-r from-red-900/20 to-yellow-900/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative z-10">
<div className="text-center mb-8">
<div className="flex justify-center mb-6 relative">
<div className="p-4 bg-red-900/50 rounded-full animate-pulse">
<Shield className="h-16 w-16 text-red-400 animate-bounce" />
</div>
{/* Security rings */}
<div className="absolute inset-0 border-2 border-red-500 rounded-full animate-ping opacity-30"></div>
<div className="absolute inset-2 border border-yellow-500 rounded-full animate-ping opacity-40 animation-delay-500"></div>
</div>
<h1 className="text-4xl font-bold mb-6 animate-slide-down">
System Requirements Check
</h1>
<p className="text-xl text-gray-300 dark:text-gray-300 animate-fade-in animate-delay-300">
Preparing secure exam environment
</p>
</div>
<div className="space-y-6 mb-10">
<div className="flex items-center space-x-4 p-4 bg-gray-700/50 rounded-xl animate-slide-up hover:bg-gray-600/50 transition-colors duration-300" style={{ animationDelay: '0.1s' }}>
<Shield className="h-8 w-8 text-green-400 animate-pulse" />
<div className="flex-1">
<span className="text-lg font-medium">Fullscreen mode support</span>
<p className="text-sm text-gray-400 dark:text-gray-400">Required for secure examination</p>
</div>
<CheckCircle className="h-6 w-6 text-green-400 animate-bounce" />
</div>
<div className="flex items-center space-x-4 p-4 bg-gray-700/50 rounded-xl animate-slide-up hover:bg-gray-600/50 transition-colors duration-300" style={{ animationDelay: '0.2s' }}>
<Lock className="h-8 w-8 text-yellow-400 animate-bounce" />
<div className="flex-1">
<span className="text-lg font-medium">Copy/paste will be disabled</span>
<p className="text-sm text-gray-400 dark:text-gray-400">Prevents unauthorized assistance</p>
</div>
<XCircle className="h-6 w-6 text-yellow-400 animate-pulse" />
</div>
<div className="flex items-center space-x-4 p-4 bg-gray-700/50 rounded-xl animate-slide-up hover:bg-gray-600/50 transition-colors duration-300" style={{ animationDelay: '0.3s' }}>
<AlertTriangle className="h-8 w-8 text-red-400 animate-pulse" />
<div className="flex-1">
<span className="text-lg font-medium">Virtual environments will be detected</span>
<p className="text-sm text-gray-400 dark:text-gray-400">Ensures exam integrity</p>
</div>
<Shield className="h-6 w-6 text-red-400 animate-bounce" />
</div>
</div>
<button
onClick={acceptSystemRequirements}
className="w-full bg-gradient-to-r from-red-600 to-red-700 hover:from-red-700 hover:to-red-800 text-white py-4 px-6 rounded-xl text-lg font-semibold transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.4s' }}
>
{/* Button warning effect */}
<div className="absolute inset-0 bg-gradient-to-r from-orange-600 to-yellow-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center justify-center space-x-3">
<Lock className="h-6 w-6 group-hover:animate-bounce transition-transform duration-300" />
<span className="group-hover:tracking-wider transition-all duration-300">Accept & Enter Secure Mode</span>
<Shield className="h-6 w-6 group-hover:animate-pulse transition-transform duration-300" />
</div>
{/* Warning pulse effect */}
<div className="absolute inset-0 opacity-0 group-hover:opacity-20 group-hover:animate-ping transition-all duration-300 bg-white rounded-xl"></div>
</button>
{/* Security notice */}
<div className="mt-6 p-4 bg-yellow-900/30 border border-yellow-500/50 rounded-xl animate-fade-in animate-delay-500 dark:bg-yellow-900/30 dark:border-yellow-500/50">
<div className="flex items-center space-x-2 mb-2">
<AlertTriangle className="w-5 h-5 text-yellow-400 animate-pulse" />
<span className="font-semibold text-yellow-300">Security Notice</span>
</div>
<p className="text-sm text-yellow-200 dark:text-yellow-200">
This exam uses advanced security measures. Browser restrictions will be enforced during the examination period.
</p>
</div>
</div>
</div>
</div>
)
}
// Enhanced Main Exam Interface
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:bg-gradient-to-br dark:from-[#1b3760] dark:via-[#24467d] dark:to-[#4a2f86] text-gray-900 dark:text-white animate-fade-in relative overflow-hidden">
{/* Animated background elements */}
<div className="absolute inset-0 opacity-5">
<div className="absolute top-0 left-0 w-96 h-96 bg-blue-500 rounded-full mix-blend-overlay animate-blob"></div>
<div className="absolute top-0 right-0 w-96 h-96 bg-purple-500 rounded-full mix-blend-overlay animate-blob animation-delay-2000"></div>
<div className="absolute -bottom-8 left-20 w-96 h-96 bg-green-500 rounded-full mix-blend-overlay animate-blob animation-delay-4000"></div>
</div>
{/* Enhanced Security Status Bar */}
<div className="bg-gradient-to-r from-red-900 via-red-800 to-red-900 text-white p-4 flex items-center justify-between animate-slide-down shadow-2xl relative overflow-hidden">
{/* Security bar background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-red-600/20 to-transparent animate-pulse"></div>
<div className="flex items-center space-x-6 relative z-10">
<div className="flex items-center space-x-2 px-3 py-1 bg-red-800/50 rounded-full">
<Shield className="h-5 w-5 animate-pulse" />
<span className="text-sm font-bold tracking-wider">SECURE MODE ACTIVE</span>
</div>
<div className="flex items-center space-x-2 px-3 py-1 bg-red-700/50 rounded-full">
<Lock className="h-5 w-5 animate-bounce" />
<span className="text-sm font-medium">Copy/Paste Disabled</span>
</div>
<div className="flex items-center space-x-2 px-3 py-1 bg-red-600/50 rounded-full">
<AlertTriangle className="h-5 w-5 animate-pulse" />
<span className="text-sm font-medium">VM Detection Active</span>
</div>
</div>
<div className="flex items-center space-x-6 relative z-10">
{timeRemaining > 0 && (
<div className="flex items-center space-x-3 px-4 py-2 bg-gradient-to-r from-red-700 to-red-600 rounded-full shadow-lg">
<Clock className="h-5 w-5 animate-pulse" />
<span className="font-mono text-lg font-bold tracking-wider">{formatTime(timeRemaining)}</span>
{timeRemaining < 300 && ( // Last 5 minutes warning
<div className="w-2 h-2 bg-yellow-400 rounded-full animate-ping"></div>
)}
</div>
)}
<div className="px-4 py-2 bg-gradient-to-r from-gray-700 to-gray-600 rounded-full shadow-lg">
<span className="font-mono tracking-widest text-lg font-bold">Exam: {examId}</span>
</div>
</div>
</div>
<div className="flex h-screen">
{/* Enhanced Main Coding Area */}
<div className="flex-1 p-8 animate-slide-right relative">
{/* Problem Description with Enhanced Styling */}
<div className="bg-gradient-to-br from-gray-800 via-gray-800 to-gray-700 rounded-2xl p-8 mb-8 transform transition-all duration-300 hover:shadow-2xl hover:shadow-blue-500/20 hover:scale-105 relative overflow-hidden group">
{/* Card background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-900/20 to-purple-900/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative z-10">
<div className="flex items-center space-x-4 mb-6">
<div className="p-3 bg-blue-600/20 rounded-xl animate-pulse">
<Code className="h-8 w-8 text-blue-400" />
</div>
<h2 className="text-3xl font-bold animate-slide-up">Problem: String Capitalizer</h2>
<div className="flex-1 h-1 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full animate-pulse"></div>
</div>
<p className="mb-6 text-lg text-gray-300 dark:text-gray-300 animate-slide-up" style={{ animationDelay: '0.1s' }}>
Write a function that converts a string to uppercase.
</p>
<div className="bg-blue-950/35 p-6 rounded-xl transform transition-all duration-300 hover:bg-blue-900/40 animate-slide-up border border-blue-300/25 hover:border-blue-300/60" style={{ animationDelay: '0.2s' }}>
<pre className="text-green-400 font-mono text-lg">
{`def capitalize_string(text):
# Your code here
pass
# Test: capitalize_string("hello") should return "HELLO"`}
</pre>
</div>
</div>
{/* Hover shine effect */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-white/5 to-transparent transition-transform duration-1000"></div>
</div>
{/* Enhanced Code Editor */}
<div className="bg-gradient-to-br from-gray-800 via-gray-800 to-gray-700 rounded-2xl p-8 transform transition-all duration-300 hover:shadow-2xl hover:shadow-purple-500/20 relative overflow-hidden group">
{/* Editor background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-purple-900/20 to-green-900/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div className="relative z-10">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center space-x-4">
<div className="p-3 bg-purple-600/20 rounded-xl animate-pulse">
<Zap className="h-8 w-8 text-purple-400" />
</div>
<h3 className="text-2xl font-bold animate-slide-up">Code Editor</h3>
</div>
{/* Editor status indicators */}
<div className="flex items-center space-x-3">
<div className="flex items-center space-x-2 px-3 py-1 bg-green-900/30 rounded-full dark:bg-green-900/30">
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
<span className="text-sm text-green-300 dark:text-green-300">Ready</span>
</div>
<div className="text-sm text-gray-400 dark:text-gray-400 font-mono">
Lines: {code.split('\n').length} | Chars: {code.length}
</div>
</div>
</div>
<div className="relative">
<textarea
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="def capitalize_string(text):\n # Your code here\n pass"
className="w-full h-80 bg-blue-950/55 text-green-300 font-mono p-6 rounded-xl border-2 border-blue-300/25 resize-none transition-all duration-300 focus:border-green-400 focus:ring-4 focus:ring-green-500/20 hover:border-blue-300/50 animate-slide-up backdrop-blur-sm"
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
animationDelay: '0.1s',
lineHeight: '1.6',
fontSize: '16px'
}}
/>
{/* Editor enhancements */}
<div className="absolute top-4 right-4 flex space-x-2">
{code.length > 0 && (
<div className="px-2 py-1 bg-blue-900/50 rounded text-xs text-blue-300 animate-fade-in">
Modified
</div>
)}
</div>
{/* Line numbers overlay */}
<div className="absolute left-2 top-6 text-gray-500 dark:text-gray-600 font-mono text-sm select-none pointer-events-none">
{Array.from({ length: code.split('\n').length }, (_, i) => (
<div key={i} className="h-6 leading-6">
{i + 1}
</div>
))}
</div>
</div>
<div className="flex items-center justify-between mt-6">
<div className="flex space-x-4">
<button
onClick={submitSolution}
disabled={isExecuting}
className="bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-700 hover:to-emerald-700 disabled:from-gray-600 disabled:to-gray-700 px-8 py-3 rounded-xl flex items-center space-x-3 transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.2s' }}
>
{/* Button background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-600 to-purple-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center space-x-3">
{isExecuting ? (
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
) : (
<Play className="h-5 w-5 transition-transform duration-300 group-hover:translate-x-1" />
)}
<span className="text-lg font-semibold">
{isExecuting ? 'Submitting...' : 'Submit Solution'}
</span>
</div>
{/* Sparkle effect */}
<div className="absolute -top-1 -right-1 opacity-0 group-hover:opacity-100 group-hover:animate-ping transition-all duration-300">
<Sparkles className="w-4 h-4 text-white" />
</div>
</button>
{userRole === 'host' && examInfo?.status === 'waiting' && (
<button
onClick={startExam}
className="bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 px-8 py-3 rounded-xl text-lg font-semibold transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.3s' }}
>
{/* Button animation */}
<div className="absolute inset-0 bg-gradient-to-r from-purple-600 to-pink-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center space-x-2">
<span>Start Exam</span>
<Zap className="h-5 w-5 group-hover:animate-bounce" />
</div>
</button>
)}
</div>
{/* Code statistics */}
<div className="flex items-center space-x-4 text-sm text-gray-400 dark:text-gray-400">
<div className="flex items-center space-x-2">
<div className="w-2 h-2 bg-blue-400 dark:bg-blue-400 rounded-full animate-pulse"></div>
<span className="text-white dark:text-white">Python 3.9</span>
</div>
<div className="flex items-center space-x-2">
<CheckCircle className="w-4 h-4 text-green-400 dark:text-green-400" />
<span className="text-white dark:text-white">Syntax OK</span>
</div>
</div>
</div>
</div>
{/* Editor shine effect */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-white/5 to-transparent transition-transform duration-1000"></div>
</div>
</div>
{/* Enhanced Leaderboard Sidebar */}
<div className="w-96 bg-gradient-to-b from-gray-800 via-gray-800 to-gray-700 p-8 animate-slide-left relative overflow-hidden">
{/* Sidebar background animation */}
<div className="absolute inset-0 bg-gradient-to-b from-yellow-900/10 to-orange-900/10 opacity-50"></div>
<div className="relative z-10">
<div className="flex items-center space-x-4 mb-8 animate-slide-down">
<div className="p-3 bg-yellow-600/20 rounded-xl animate-bounce">
<Trophy className="h-8 w-8 text-yellow-400 animate-pulse" />
</div>
<h3 className="text-2xl font-bold dark:text-white">Leaderboard</h3>
<div className="flex-1 h-1 bg-gradient-to-r from-yellow-500 to-orange-500 rounded-full animate-pulse"></div>
</div>
{/* Leaderboard stats */}
<div className="mb-6 p-4 bg-blue-950/25 rounded-xl border border-blue-300/25 dark:border-blue-300/25">
<div className="flex justify-between items-center mb-2">
<span className="text-sm text-gray-400 dark:text-gray-400">Total Participants</span>
<span className="font-bold text-blue-400">{leaderboard.length}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-gray-400 dark:text-gray-400">Completed</span>
<span className="font-bold text-green-400">
{leaderboard.filter(p => p.completed).length}
</span>
</div>
</div>
<div className="space-y-3 max-h-96 overflow-y-auto custom-scrollbar">
{leaderboard.length > 0 ? leaderboard.map((participant, index) => (
<div
key={index}
className={`p-4 rounded-xl transform transition-all duration-300 hover:scale-105 hover:shadow-lg animate-slide-up relative overflow-hidden group cursor-pointer ${
index === 0 ? 'bg-gradient-to-r from-yellow-900/50 to-orange-900/50 border border-yellow-500/30' :
index === 1 ? 'bg-gradient-to-r from-gray-700/50 to-gray-600/50 border border-gray-400/30' :
index === 2 ? 'bg-gradient-to-r from-orange-900/50 to-red-900/50 border border-orange-500/30' :
'bg-gradient-to-r from-gray-700/50 to-gray-600/50 border border-gray-500/30'
}`}
style={{ animationDelay: `${0.1 * index}s` }}
>
{/* Rank indicator */}
<div className="absolute top-2 left-2">
{index < 3 ? (
<div className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold ${
index === 0 ? 'bg-yellow-500 text-black' :
index === 1 ? 'bg-gray-400 text-black' :
'bg-orange-500 text-white'
}`}>
{index + 1}
</div>
) : (
<div className="w-6 h-6 rounded-full bg-gray-600 flex items-center justify-center text-xs font-bold text-white">
{index + 1}
</div>
)}
</div>
{/* Participant info */}
<div className="ml-8">
<div className="flex justify-between items-start mb-2">
<span className="font-semibold text-lg group-hover:text-white transition-colors duration-300">
{participant.name}
</span>
<div className="flex items-center space-x-2">
<span className="font-bold text-xl animate-pulse">
{participant.score}%
</span>
{participant.completed && (
<CheckCircle className="w-5 h-5 text-green-400 animate-bounce" />
)}
</div>
</div>
{/* Progress bar */}
<div className="w-full bg-gray-600 rounded-full h-2 mb-2">
<div
className={`h-2 rounded-full transition-all duration-1000 ${
index === 0 ? 'bg-gradient-to-r from-yellow-400 to-orange-400' :
index === 1 ? 'bg-gradient-to-r from-gray-300 to-gray-400' :
index === 2 ? 'bg-gradient-to-r from-orange-400 to-red-400' :
'bg-gradient-to-r from-blue-400 to-purple-400'
}`}
style={{ width: `${participant.score}%` }}
></div>
</div>
{/* Submission time */}
{participant.submitted_at && (
<div className="text-xs text-gray-400 dark:text-gray-400">
Submitted: {new Date(participant.submitted_at).toLocaleTimeString()}
</div>
)}
</div>
{/* Hover effect */}
<div className="absolute inset-0 -translate-x-full group-hover:translate-x-full bg-gradient-to-r from-transparent via-white/5 to-transparent transition-transform duration-700"></div>
</div>
)) : (
<div className="text-center py-8 text-gray-400 dark:text-gray-400 animate-pulse">
<Users className="h-12 w-12 mx-auto mb-3 opacity-50" />
<p>No participants yet</p>
</div>
)}
</div>
<button
onClick={fetchLeaderboard}
className="w-full mt-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 px-6 py-3 rounded-xl text-lg font-semibold transform transition-all duration-300 hover:scale-105 hover:shadow-2xl active:scale-95 animate-slide-up group relative overflow-hidden"
style={{ animationDelay: '0.4s' }}
>
{/* Button background animation */}
<div className="absolute inset-0 bg-gradient-to-r from-purple-600 to-pink-600 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<div className="relative z-10 flex items-center justify-center space-x-2">
<span className="group-hover:tracking-wider transition-all duration-300">Refresh Leaderboard</span>
<div className="w-2 h-2 bg-white rounded-full animate-bounce group-hover:animate-ping"></div>
</div>
</button>
</div>
</div>
</div>
{/* Floating action button for help */}
<div className="fixed bottom-8 right-8 animate-bounce">
<button className="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 p-4 rounded-full shadow-2xl transform transition-all duration-300 hover:scale-110 group">
<AlertTriangle className="h-6 w-6 text-white group-hover:animate-spin" />
</button>
</div>
</div>
)
}