Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from 'react'; | |
| import { Link } from 'react-router-dom'; | |
| import { createPageUrl } from '@/utils'; | |
| import { motion, AnimatePresence } from 'framer-motion'; | |
| import { Brain, CheckCircle2, XCircle, ArrowLeft, Trophy, RotateCcw, Sparkles, Target } from 'lucide-react'; | |
| import { Button } from '@/components/ui/button'; | |
| import { Progress } from '@/components/ui/progress'; | |
| import confetti from 'canvas-confetti'; | |
| const questions = [ | |
| { | |
| id: 1, | |
| question: "In YOLO (You Only Look Once), what makes it faster than traditional object detection methods?", | |
| options: [ | |
| "It uses smaller images", | |
| "It processes the entire image in a single pass instead of multiple regions", | |
| "It only detects one object at a time", | |
| "It uses black and white images" | |
| ], | |
| correct: 1, | |
| topic: "Object Detection" | |
| }, | |
| { | |
| id: 2, | |
| question: "What does a confidence score of 95% mean in object detection?", | |
| options: [ | |
| "The object is 95% visible in the image", | |
| "The AI is 95% certain about its prediction", | |
| "95% of the object is inside the bounding box", | |
| "The detection took 95% of the processing time" | |
| ], | |
| correct: 1, | |
| topic: "Object Detection" | |
| }, | |
| { | |
| id: 3, | |
| question: "How many keypoints does a standard pose estimation model typically track on the human body?", | |
| options: [ | |
| "7 keypoints", | |
| "10 keypoints", | |
| "17 keypoints", | |
| "25 keypoints" | |
| ], | |
| correct: 2, | |
| topic: "Pose Estimation" | |
| }, | |
| { | |
| id: 4, | |
| question: "What are 'skeleton lines' in pose estimation?", | |
| options: [ | |
| "Lines that show bones in an X-ray", | |
| "Connections between keypoints showing body structure", | |
| "Errors in the detection algorithm", | |
| "Grid lines dividing the image" | |
| ], | |
| correct: 1, | |
| topic: "Pose Estimation" | |
| }, | |
| { | |
| id: 5, | |
| question: "Which of these is NOT one of the 7 basic emotions in FER (Facial Emotion Recognition)?", | |
| options: [ | |
| "Fear", | |
| "Disgust", | |
| "Confused", | |
| "Surprise" | |
| ], | |
| correct: 2, | |
| topic: "Emotion Recognition" | |
| }, | |
| { | |
| id: 6, | |
| question: "Why do facial emotion recognition models use 48×48 pixel images?", | |
| options: [ | |
| "Larger images don't work with AI", | |
| "Smaller size allows faster processing while retaining key facial features", | |
| "48×48 is the size of human faces", | |
| "It's the only size cameras can capture" | |
| ], | |
| correct: 1, | |
| topic: "Emotion Recognition" | |
| }, | |
| { | |
| id: 7, | |
| question: "Which technology would be BEST for analyzing a dancer's movements in real-time?", | |
| options: [ | |
| "Object Detection", | |
| "Emotion Recognition", | |
| "Pose Estimation", | |
| "Voice Recognition" | |
| ], | |
| correct: 2, | |
| topic: "Pose Estimation" | |
| }, | |
| { | |
| id: 8, | |
| question: "In object detection, what happens during 'non-max suppression'?", | |
| options: [ | |
| "The AI stops detecting objects", | |
| "Duplicate or overlapping bounding boxes are removed", | |
| "The confidence threshold is lowered", | |
| "The image brightness is reduced" | |
| ], | |
| correct: 1, | |
| topic: "Object Detection" | |
| }, | |
| { | |
| id: 9, | |
| question: "Why is consent important before using emotion recognition technology on someone?", | |
| options: [ | |
| "It makes the AI more accurate", | |
| "People have a right to privacy and to know when they're being analyzed", | |
| "It's required by all cameras", | |
| "Consent improves the lighting in photos" | |
| ], | |
| correct: 1, | |
| topic: "Emotion Recognition" | |
| }, | |
| { | |
| id: 10, | |
| question: "What is the main advantage of using grayscale images in emotion recognition instead of color?", | |
| options: [ | |
| "Grayscale images look more professional", | |
| "Color doesn't exist in emotions", | |
| "It reduces processing complexity and focuses on facial structure rather than skin tone", | |
| "Grayscale cameras are cheaper" | |
| ], | |
| correct: 2, | |
| topic: "Emotion Recognition" | |
| }, | |
| { | |
| id: 11, | |
| question: "If pose estimation detects 2 people in a video, how many total keypoints might it track?", | |
| options: [ | |
| "17 keypoints total", | |
| "34 keypoints (17 per person)", | |
| "25 keypoints total", | |
| "10 keypoints total" | |
| ], | |
| correct: 1, | |
| topic: "Pose Estimation" | |
| }, | |
| { | |
| id: 12, | |
| question: "What is a potential bias concern with emotion recognition AI?", | |
| options: [ | |
| "It works too slowly", | |
| "It might perform differently across different cultures, ages, or demographics", | |
| "It can only detect happy emotions", | |
| "It requires too much computer power" | |
| ], | |
| correct: 1, | |
| topic: "Emotion Recognition" | |
| } | |
| ]; | |
| // 60-minute TTL logic (same as Lessons.js) | |
| const COMPLETED_KEY = 'completedChapters_v1'; | |
| const TTL_MS = 60 * 60 * 1000; | |
| function checkLessonsCompleted() { | |
| try { | |
| const raw = localStorage.getItem(COMPLETED_KEY); | |
| if (!raw) return false; | |
| const parsed = JSON.parse(raw); | |
| const savedAt = parsed?.savedAt; | |
| const value = parsed?.value; | |
| if (!Array.isArray(value) || typeof savedAt !== 'number') return false; | |
| if (Date.now() - savedAt > TTL_MS) { | |
| localStorage.removeItem(COMPLETED_KEY); | |
| return false; | |
| } | |
| return value.length === 3; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| export default function Quiz() { | |
| const [started, setStarted] = useState(false); | |
| const [currentQuestion, setCurrentQuestion] = useState(0); | |
| const [selectedAnswer, setSelectedAnswer] = useState(null); | |
| const [showResult, setShowResult] = useState(false); | |
| const [score, setScore] = useState(0); | |
| const [answers, setAnswers] = useState([]); | |
| const [finished, setFinished] = useState(false); | |
| const [allLessonsCompleted, setAllLessonsCompleted] = useState(checkLessonsCompleted); | |
| // Trigger confetti when finished with perfect score | |
| useEffect(() => { | |
| if (finished && score === questions.length) { | |
| triggerConfetti(); | |
| } | |
| }, [finished, score]); | |
| const triggerConfetti = () => { | |
| const duration = 5 * 1000; | |
| const animationEnd = Date.now() + duration; | |
| const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; | |
| const random = (min, max) => Math.random() * (max - min) + min; | |
| const interval = setInterval(function() { | |
| const timeLeft = animationEnd - Date.now(); | |
| if (timeLeft <= 0) { | |
| return clearInterval(interval); | |
| } | |
| const particleCount = 50 * (timeLeft / duration); | |
| // Since particles fall down, start a bit higher than random | |
| confetti({ | |
| ...defaults, | |
| particleCount, | |
| origin: { x: random(0.1, 0.3), y: Math.random() - 0.2 } | |
| }); | |
| confetti({ | |
| ...defaults, | |
| particleCount, | |
| origin: { x: random(0.7, 0.9), y: Math.random() - 0.2 } | |
| }); | |
| }, 250); | |
| }; | |
| const handleStart = () => { | |
| setStarted(true); | |
| setCurrentQuestion(0); | |
| setScore(0); | |
| setAnswers([]); | |
| setFinished(false); | |
| }; | |
| const handleAnswer = (index) => { | |
| if (showResult) return; | |
| setSelectedAnswer(index); | |
| setShowResult(true); | |
| const isCorrect = index === questions[currentQuestion].correct; | |
| if (isCorrect) { | |
| setScore(score + 1); | |
| } | |
| setAnswers([...answers, { questionId: currentQuestion, selected: index, correct: isCorrect }]); | |
| }; | |
| const handleNext = () => { | |
| if (currentQuestion < questions.length - 1) { | |
| setCurrentQuestion(currentQuestion + 1); | |
| setSelectedAnswer(null); | |
| setShowResult(false); | |
| } else { | |
| setFinished(true); | |
| } | |
| }; | |
| const getScoreMessage = () => { | |
| const percentage = (score / questions.length) * 100; | |
| if (percentage === 100) return { emoji: "🏆", message: "PERFECT SCORE! You're an AI Vision Master!" }; | |
| if (percentage >= 80) return { emoji: "🌟", message: "Amazing! You really know your AI stuff!" }; | |
| if (percentage >= 60) return { emoji: "👍", message: "Good job! Keep learning and you'll be an expert!" }; | |
| if (percentage >= 40) return { emoji: "📚", message: "Nice try! Review the lessons and try again!" }; | |
| return { emoji: "💪", message: "Don't give up! Go through the lessons and come back stronger!" }; | |
| }; | |
| // Start Screen | |
| if (!started) { | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 pt-24 pb-12 px-6"> | |
| <div className="fixed inset-0 overflow-hidden pointer-events-none"> | |
| <div className="absolute top-20 left-10 w-72 h-72 bg-yellow-500/20 rounded-full blur-3xl animate-pulse" /> | |
| <div className="absolute bottom-20 right-10 w-96 h-96 bg-orange-500/20 rounded-full blur-3xl animate-pulse" /> | |
| </div> | |
| <div className="max-w-2xl mx-auto relative text-center"> | |
| <Link to={createPageUrl('Home')}> | |
| <Button className="text-white/70 hover:text-white mb-8 bg-transparent border-0 hover:bg-white/5"> | |
| <ArrowLeft className="w-4 h-4 mr-2" /> | |
| Back to Home | |
| </Button> | |
| </Link> | |
| <motion.div | |
| initial={{ scale: 0 }} | |
| animate={{ scale: 1 }} | |
| transition={{ type: "spring" }} | |
| className="w-32 h-32 mx-auto rounded-3xl bg-gradient-to-br from-yellow-500 to-orange-500 flex items-center justify-center shadow-2xl shadow-yellow-500/30 mb-8" | |
| > | |
| <Target className="w-16 h-16 text-white" /> | |
| </motion.div> | |
| <motion.h1 | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| className="text-4xl md:text-5xl font-black text-white mb-4" | |
| > | |
| AI Vision Quiz | |
| </motion.h1> | |
| <motion.p | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.1 }} | |
| className="text-xl text-white/70 mb-8" | |
| > | |
| Test your knowledge with {questions.length} questions about Object Detection, Pose Estimation, and Emotion Recognition! | |
| </motion.p> | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.2 }} | |
| className="bg-white/5 backdrop-blur-xl rounded-3xl p-8 border border-white/10 mb-8" | |
| > | |
| <div className="grid grid-cols-3 gap-4 text-center"> | |
| <div> | |
| <div className="text-3xl font-bold text-cyan-400">{questions.length}</div> | |
| <div className="text-white/60">Questions</div> | |
| </div> | |
| <div> | |
| <div className="text-3xl font-bold text-purple-400">3</div> | |
| <div className="text-white/60">Topics</div> | |
| </div> | |
| <div> | |
| <div className="text-3xl font-bold text-emerald-400">∞</div> | |
| <div className="text-white/60">Retries</div> | |
| </div> | |
| </div> | |
| </motion.div> | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.3 }} | |
| > | |
| {allLessonsCompleted ? ( | |
| <Button | |
| onClick={handleStart} | |
| size="lg" | |
| className="text-xl px-12 py-8 bg-gradient-to-r from-yellow-500 to-orange-500 hover:from-yellow-600 hover:to-orange-600 rounded-2xl shadow-2xl shadow-orange-500/30 text-white font-bold border-0 transition-all hover:scale-105" | |
| > | |
| <Sparkles className="w-6 h-6 mr-2" /> | |
| Start Quiz | |
| </Button> | |
| ) : ( | |
| <div> | |
| <Button | |
| disabled | |
| size="lg" | |
| className="text-xl px-12 py-8 bg-slate-700 text-slate-400 rounded-2xl font-bold border-0 cursor-not-allowed opacity-60 mb-4" | |
| > | |
| 🔒 Quiz Locked | |
| </Button> | |
| <p className="text-white/60">Complete all 3 lessons to unlock the quiz!</p> | |
| <Link to={createPageUrl('Lessons')} className="inline-block mt-4"> | |
| <Button className="bg-blue-600 hover:bg-blue-700 text-white border-0 rounded-xl px-6 py-3"> | |
| Go to Lessons | |
| </Button> | |
| </Link> | |
| </div> | |
| )} | |
| </motion.div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // Results Screen | |
| if (finished) { | |
| const { emoji, message } = getScoreMessage(); | |
| const percentage = Math.round((score / questions.length) * 100); | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 pt-24 pb-12 px-6"> | |
| <div className="fixed inset-0 overflow-hidden pointer-events-none"> | |
| <div className="absolute top-20 left-10 w-72 h-72 bg-yellow-500/20 rounded-full blur-3xl animate-pulse" /> | |
| <div className="absolute bottom-20 right-10 w-96 h-96 bg-orange-500/20 rounded-full blur-3xl animate-pulse" /> | |
| </div> | |
| <div className="max-w-2xl mx-auto relative"> | |
| <motion.div | |
| initial={{ scale: 0 }} | |
| animate={{ scale: 1 }} | |
| transition={{ type: "spring" }} | |
| className="text-center" | |
| > | |
| <div className="text-8xl mb-6">{emoji}</div> | |
| <h1 className="text-4xl md:text-5xl font-black text-white mb-4"> | |
| Quiz Complete! | |
| </h1> | |
| <div className="bg-white/5 backdrop-blur-xl rounded-3xl p-8 border border-white/10 mb-8"> | |
| <div className="text-6xl font-black text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-orange-400 mb-2"> | |
| {score}/{questions.length} | |
| </div> | |
| <div className="text-xl text-white/70 mb-6"> | |
| {percentage}% Correct | |
| </div> | |
| <Progress value={percentage} className="h-4 bg-white/10" /> | |
| <p className="text-white/80 mt-6 text-lg">{message}</p> | |
| </div> | |
| {/* Answer Summary */} | |
| <div className="bg-white/5 backdrop-blur-xl rounded-3xl p-6 border border-white/10 mb-8"> | |
| <h3 className="text-lg font-bold text-white mb-4">Your Answers</h3> | |
| <div className="grid grid-cols-5 gap-2"> | |
| {answers.map((answer, i) => ( | |
| <motion.div | |
| key={i} | |
| initial={{ scale: 0 }} | |
| animate={{ scale: 1 }} | |
| transition={{ delay: i * 0.05 }} | |
| className={`w-12 h-12 rounded-xl flex items-center justify-center font-bold text-white ${ | |
| answer.correct | |
| ? 'bg-gradient-to-br from-emerald-500 to-teal-500' | |
| : 'bg-gradient-to-br from-red-500 to-rose-500' | |
| }`} | |
| > | |
| {i + 1} | |
| </motion.div> | |
| ))} | |
| </div> | |
| </div> | |
| <div className="flex flex-col sm:flex-row gap-4 justify-center mb-12"> | |
| <Button | |
| onClick={handleStart} | |
| size="lg" | |
| className="bg-gradient-to-r from-yellow-500 to-orange-500 hover:from-yellow-600 hover:to-orange-600 rounded-xl text-white font-bold border-0 px-8 py-6 text-lg shadow-xl shadow-orange-500/25 transition-all hover:scale-105" | |
| > | |
| <RotateCcw className="w-5 h-5 mr-2" /> | |
| Try Again | |
| </Button> | |
| <Link to={createPageUrl('Lessons')}> | |
| <Button | |
| size="lg" | |
| className="border-2 border-white/30 text-white bg-white/5 hover:bg-white/10 rounded-xl w-full px-8 py-6 text-lg font-bold transition-all" | |
| > | |
| Review Lessons | |
| </Button> | |
| </Link> | |
| </div> | |
| {/* Test It Yourself Section */} | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ delay: 0.3 }} | |
| className="bg-gradient-to-br from-blue-500/10 to-purple-500/10 rounded-3xl p-10 border border-blue-500/20" | |
| > | |
| <div className="text-center mb-6"> | |
| <div className="text-5xl mb-4">🚀</div> | |
| <h2 className="text-3xl font-black text-white mb-3">Ready to Test It Yourself?</h2> | |
| <p className="text-white/70 text-lg mb-8"> | |
| Now that you've mastered the concepts, try building your own AI vision projects! | |
| </p> | |
| </div> | |
| <div className="grid md:grid-cols-3 gap-4 mb-8"> | |
| <div className="bg-white/5 rounded-2xl p-6 border border-white/10"> | |
| <div className="text-3xl mb-3">👁️</div> | |
| <h3 className="text-white font-bold mb-2">Object Detection</h3> | |
| <p className="text-white/60 text-sm">Build your own detector</p> | |
| </div> | |
| <div className="bg-white/5 rounded-2xl p-6 border border-white/10"> | |
| <div className="text-3xl mb-3">🏃</div> | |
| <h3 className="text-white font-bold mb-2">Pose Tracking</h3> | |
| <p className="text-white/60 text-sm">Create motion games</p> | |
| </div> | |
| <div className="bg-white/5 rounded-2xl p-6 border border-white/10"> | |
| <div className="text-3xl mb-3">😊</div> | |
| <h3 className="text-white font-bold mb-2">Emotion AI</h3> | |
| <p className="text-white/60 text-sm">Analyze expressions</p> | |
| </div> | |
| </div> | |
| <Button | |
| size="lg" | |
| onClick={() => { | |
| window.location.href = "/Lab-Selection.html"; | |
| }} | |
| className="w-full bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 hover:from-blue-600 hover:via-purple-600 hover:to-pink-600 text-white font-bold text-xl py-8 rounded-2xl border-0 shadow-2xl transition-all hover:scale-105" | |
| > | |
| <Sparkles className="w-6 h-6 mr-3" /> | |
| Launch AI Playground | |
| </Button> | |
| </motion.div> | |
| </motion.div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // Quiz Question Screen | |
| const question = questions[currentQuestion]; | |
| return ( | |
| <div className="min-h-screen bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900 pt-24 pb-12 px-6"> | |
| <div className="fixed inset-0 overflow-hidden pointer-events-none"> | |
| <div className="absolute top-20 left-10 w-72 h-72 bg-yellow-500/20 rounded-full blur-3xl animate-pulse" /> | |
| <div className="absolute bottom-20 right-10 w-96 h-96 bg-orange-500/20 rounded-full blur-3xl animate-pulse" /> | |
| </div> | |
| <div className="max-w-2xl mx-auto relative"> | |
| {/* Progress */} | |
| <div className="mb-8"> | |
| <div className="flex items-center justify-between text-white/60 mb-2"> | |
| <span>Question {currentQuestion + 1} of {questions.length}</span> | |
| <span className="px-3 py-1 rounded-full bg-white/10 text-sm">{question.topic}</span> | |
| </div> | |
| <Progress | |
| value={((currentQuestion + 1) / questions.length) * 100} | |
| className="h-2 bg-white/10" | |
| /> | |
| </div> | |
| {/* Question */} | |
| <AnimatePresence mode="wait"> | |
| <motion.div | |
| key={currentQuestion} | |
| initial={{ opacity: 0, x: 50 }} | |
| animate={{ opacity: 1, x: 0 }} | |
| exit={{ opacity: 0, x: -50 }} | |
| > | |
| <div className="bg-white/5 backdrop-blur-xl rounded-3xl p-8 border border-white/10 mb-6"> | |
| <div className="flex items-start gap-4 mb-6"> | |
| <div className="w-12 h-12 rounded-xl bg-gradient-to-br from-yellow-500 to-orange-500 flex items-center justify-center flex-shrink-0"> | |
| <Brain className="w-6 h-6 text-white" /> | |
| </div> | |
| <h2 className="text-2xl font-bold text-white leading-relaxed"> | |
| {question.question} | |
| </h2> | |
| </div> | |
| {/* Options */} | |
| <div className="space-y-3"> | |
| {question.options.map((option, index) => { | |
| const isSelected = selectedAnswer === index; | |
| const isCorrect = index === question.correct; | |
| const showCorrect = showResult && isCorrect; | |
| const showWrong = showResult && isSelected && !isCorrect; | |
| return ( | |
| <motion.button | |
| key={index} | |
| onClick={() => handleAnswer(index)} | |
| disabled={showResult} | |
| className={`w-full p-4 rounded-2xl text-left transition-all border-2 ${ | |
| showCorrect | |
| ? 'bg-emerald-500/20 border-emerald-500 text-white' | |
| : showWrong | |
| ? 'bg-red-500/20 border-red-500 text-white' | |
| : isSelected | |
| ? 'bg-white/20 border-white/40 text-white' | |
| : 'bg-white/5 border-white/10 text-white/80 hover:bg-white/10 hover:border-white/20' | |
| }`} | |
| whileHover={!showResult ? { scale: 1.02 } : {}} | |
| whileTap={!showResult ? { scale: 0.98 } : {}} | |
| > | |
| <div className="flex items-center gap-4"> | |
| <div className={`w-10 h-10 rounded-xl flex items-center justify-center font-bold ${ | |
| showCorrect | |
| ? 'bg-emerald-500 text-white' | |
| : showWrong | |
| ? 'bg-red-500 text-white' | |
| : 'bg-white/10 text-white/60' | |
| }`}> | |
| {showCorrect ? ( | |
| <CheckCircle2 className="w-5 h-5" /> | |
| ) : showWrong ? ( | |
| <XCircle className="w-5 h-5" /> | |
| ) : ( | |
| String.fromCharCode(65 + index) | |
| )} | |
| </div> | |
| <span className="text-lg">{option}</span> | |
| </div> | |
| </motion.button> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* Feedback */} | |
| <AnimatePresence> | |
| {showResult && ( | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| exit={{ opacity: 0, y: -20 }} | |
| className={`rounded-2xl p-6 mb-6 ${ | |
| selectedAnswer === question.correct | |
| ? 'bg-gradient-to-br from-emerald-500/20 to-teal-500/20 border border-emerald-500/30' | |
| : 'bg-gradient-to-br from-red-500/20 to-rose-500/20 border border-red-500/30' | |
| }`} | |
| > | |
| <div className="flex items-center gap-3"> | |
| {selectedAnswer === question.correct ? ( | |
| <> | |
| <CheckCircle2 className="w-8 h-8 text-emerald-400" /> | |
| <div> | |
| <h3 className="text-xl font-bold text-white">Correct! 🎉</h3> | |
| <p className="text-white/70">Great job! You got this one right.</p> | |
| </div> | |
| </> | |
| ) : ( | |
| <> | |
| <XCircle className="w-8 h-8 text-red-400" /> | |
| <div> | |
| <h3 className="text-xl font-bold text-white">Not quite! 🤔</h3> | |
| <p className="text-white/70"> | |
| The correct answer was: {question.options[question.correct]} | |
| </p> | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| {/* Next Button */} | |
| {showResult && ( | |
| <motion.div | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| className="text-center" | |
| > | |
| <Button | |
| onClick={handleNext} | |
| size="lg" | |
| className="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 rounded-2xl px-12 py-6 text-lg font-bold text-white border-0 shadow-xl shadow-purple-500/30 transition-all hover:scale-105" | |
| > | |
| {currentQuestion < questions.length - 1 ? 'Next Question →' : '✨ See Results'} | |
| </Button> | |
| </motion.div> | |
| )} | |
| </motion.div> | |
| </AnimatePresence> | |
| </div> | |
| </div> | |
| ); | |
| } | |