Add src/app/quiz/page.tsx
This commit is contained in:
381
src/app/quiz/page.tsx
Normal file
381
src/app/quiz/page.tsx
Normal file
@@ -0,0 +1,381 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { ArrowRight, CheckCircle, XCircle, RotateCcw } from "lucide-react";
|
||||
import NavbarStyleFullscreen from "@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
|
||||
|
||||
interface QuizQuestion {
|
||||
id: string;
|
||||
question: string;
|
||||
options: string[];
|
||||
correctAnswer: number;
|
||||
explanation: string;
|
||||
}
|
||||
|
||||
const quizzes: Record<string, { title: string; questions: QuizQuestion[] }> = {
|
||||
"password-security": {
|
||||
title: "Password Security Quiz", questions: [
|
||||
{
|
||||
id: "1", question: "What is the minimum recommended password length?", options: ["8 characters", "10 characters", "12 characters", "6 characters"],
|
||||
correctAnswer: 2,
|
||||
explanation: "Security experts recommend at least 12 characters for strong passwords to resist brute force attacks."},
|
||||
{
|
||||
id: "2", question: "Which of these is the strongest password?", options: [
|
||||
"Password123", "MyDog2024!", "X9#kL@mP2$wQ", "1234567890"],
|
||||
correctAnswer: 2,
|
||||
explanation: "Random combinations of letters, numbers, and special characters are strongest. Predictable patterns and personal information make passwords vulnerable."},
|
||||
{
|
||||
id: "3", question: "What does Two-Factor Authentication (2FA) add to your account security?", options: [
|
||||
"A longer password", "A second layer of verification", "Password encryption", "Automatic password changes"],
|
||||
correctAnswer: 1,
|
||||
explanation: "2FA requires a second verification method (like a code from your phone) after entering your password, significantly increasing security."},
|
||||
{
|
||||
id: "4", question: "Should you use the same password for multiple accounts?", options: [
|
||||
"Yes, it's easier to remember", "No, use unique passwords for each account", "Only for unimportant accounts", "Yes, with slight variations"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Using unique passwords for each account means if one is compromised, others remain secure. Use a password manager to help manage them."},
|
||||
{
|
||||
id: "5", question: "How often should you change your passwords?", options: [
|
||||
"Every day", "Every month", "Every year", "When compromised or every 90 days"],
|
||||
correctAnswer: 3,
|
||||
explanation: "Change passwords immediately if compromised. For regular maintenance, change every 90 days. More frequent changes can lead to weaker passwords."},
|
||||
],
|
||||
},
|
||||
"phishing-detection": {
|
||||
title: "Phishing Detection Quiz", questions: [
|
||||
{
|
||||
id: "1", question: "What is a red flag for phishing emails?", options: [
|
||||
"Professional formatting", "Request for personal information", "Official company logo", "Clear sender address"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Phishing emails often ask for passwords, social security numbers, or bank details. Legitimate companies never ask for sensitive info via email."},
|
||||
{
|
||||
id: "2", question: "How should you verify suspicious email links?", options: [
|
||||
"Click and see if it's legitimate", "Hover over the link to see the actual URL", "Ask friends if they received it", "Contact the company through the email"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Always hover over links to see their true destination before clicking. This reveals if the link actually goes where it claims to go."},
|
||||
{
|
||||
id: "3", question: "What common technique do phishers use?", options: [
|
||||
"Formal business language", "Creating urgency or fear", "Providing too much information", "Using official company names"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Phishing emails create artificial urgency (account locked, limited time) to make you act without thinking carefully."},
|
||||
{
|
||||
id: "4", question: "How can poor grammar indicate a phishing email?", options: [
|
||||
"It doesn't matter", "Legitimate companies always have typos", "Professional emails are carefully proofread", "Grammar is unrelated to security"],
|
||||
correctAnswer: 2,
|
||||
explanation: "Legitimate companies proofread communications carefully. Numerous errors, awkward phrasing, or grammatical mistakes are phishing warning signs."},
|
||||
{
|
||||
id: "5", question: "What should you do if you suspect a phishing email?", options: [
|
||||
"Reply asking them to stop", "Report it and don't click links", "Forward it to friends", "Click to check if it's real"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Report phishing emails to your email provider and the company being impersonated. Never click links or provide information."},
|
||||
],
|
||||
},
|
||||
"social-media-safety": {
|
||||
title: "Social Media Safety Quiz", questions: [
|
||||
{
|
||||
id: "1", question: "What personal information should you never post on social media?", options: [
|
||||
"Your hobbies", "Your exact location and home address", "Your favorite movies", "Your name"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Never share your home address, phone number, or location. This information can be used for stalking, theft, or identity theft."},
|
||||
{
|
||||
id: "2", question: "How often should you review your privacy settings?", options: [
|
||||
"Never", "Once a year", "Every few months", "Social media platforms never change them"],
|
||||
correctAnswer: 2,
|
||||
explanation: "Social media platforms frequently update privacy settings. Review yours every few months to ensure your information is protected."},
|
||||
{
|
||||
id: "3", question: "Is it safe to accept friend requests from strangers?", options: [
|
||||
"Yes, more friends is better", "No, they could be scammers or stalkers", "Only if they have a profile picture", "Yes, if they have mutual friends"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Strangers could be scammers, stalkers, or hackers. Always verify who you're connecting with before accepting requests."},
|
||||
{
|
||||
id: "4", question: "Before posting something, what should you think about?", options: [
|
||||
"How many likes it will get", "If your future employer might see it", "If your parents will be proud", "How quickly you can post it"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Employers, colleges, and others research social media profiles. Once posted, content is permanent and can affect your future."},
|
||||
{
|
||||
id: "5", question: "What is cyberbullying?", options: [
|
||||
"Making friends online", "Harassment, threats, or humiliation online", "Following your friends", "Commenting on posts"],
|
||||
correctAnswer: 1,
|
||||
explanation: "Cyberbullying includes harassment, threats, and humiliation online. If you experience it, report it and reach out to trusted adults."},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function QuizPage() {
|
||||
const [currentQuestion, setCurrentQuestion] = useState(0);
|
||||
const [score, setScore] = useState(0);
|
||||
const [selectedAnswer, setSelectedAnswer] = useState<number | null>(null);
|
||||
const [showResult, setShowResult] = useState(false);
|
||||
const [quizComplete, setQuizComplete] = useState(false);
|
||||
const [questions, setQuestions] = useState<QuizQuestion[]>([]);
|
||||
const [quizTitle, setQuizTitle] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
// Select a random quiz for demo
|
||||
const quizKeys = Object.keys(quizzes);
|
||||
const randomKey = quizKeys[Math.floor(Math.random() * quizKeys.length)];
|
||||
const quiz = quizzes[randomKey];
|
||||
setQuestions(quiz.questions);
|
||||
setQuizTitle(quiz.title);
|
||||
}, []);
|
||||
|
||||
if (questions.length === 0) return null;
|
||||
|
||||
const handleAnswerSelect = (answerIndex: number) => {
|
||||
if (!showResult) {
|
||||
setSelectedAnswer(answerIndex);
|
||||
setShowResult(true);
|
||||
|
||||
if (answerIndex === questions[currentQuestion].correctAnswer) {
|
||||
setScore(score + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleNextQuestion = () => {
|
||||
if (currentQuestion + 1 < questions.length) {
|
||||
setCurrentQuestion(currentQuestion + 1);
|
||||
setSelectedAnswer(null);
|
||||
setShowResult(false);
|
||||
} else {
|
||||
setQuizComplete(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRestartQuiz = () => {
|
||||
setCurrentQuestion(0);
|
||||
setScore(0);
|
||||
setSelectedAnswer(null);
|
||||
setShowResult(false);
|
||||
setQuizComplete(false);
|
||||
};
|
||||
|
||||
const percentage = Math.round((score / questions.length) * 100);
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="text-shift"
|
||||
defaultTextAnimation="entrance-slide"
|
||||
borderRadius="pill"
|
||||
contentWidth="compact"
|
||||
sizing="largeSmall"
|
||||
background="noise"
|
||||
cardStyle="outline"
|
||||
primaryButtonStyle="flat"
|
||||
secondaryButtonStyle="radial-glow"
|
||||
headingFontWeight="light"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleFullscreen
|
||||
brandName="CyberSafe"
|
||||
navItems={[
|
||||
{ name: "Home", id: "/" },
|
||||
{ name: "About", id: "#about" },
|
||||
{ name: "Resources", id: "#features" },
|
||||
{ name: "Learn", id: "#metrics" },
|
||||
{ name: "Quiz", id: "/quiz" },
|
||||
{ name: "Contact", id: "#contact" },
|
||||
]}
|
||||
bottomLeftText="Student Safety First"
|
||||
bottomRightText="cybersafe@education.org"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="quiz" data-section="quiz" className="min-h-screen py-20 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
{!quizComplete ? (
|
||||
<div className="space-y-8">
|
||||
{/* Header */}
|
||||
<div className="text-center space-y-2">
|
||||
<h1 className="text-4xl font-bold">{quizTitle}</h1>
|
||||
<p className="text-lg text-foreground/70">
|
||||
Question {currentQuestion + 1} of {questions.length}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="w-full bg-background-accent rounded-pill h-2">
|
||||
<div
|
||||
className="bg-primary-cta h-2 rounded-pill transition-all duration-300"
|
||||
style={{
|
||||
width: `${((currentQuestion + 1) / questions.length) * 100}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Question */}
|
||||
<div className="bg-card rounded-pill p-8 border border-background-accent">
|
||||
<h2 className="text-2xl font-semibold mb-6">
|
||||
{questions[currentQuestion].question}
|
||||
</h2>
|
||||
|
||||
{/* Options */}
|
||||
<div className="space-y-3">
|
||||
{questions[currentQuestion].options.map((option, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => handleAnswerSelect(index)}
|
||||
disabled={showResult}
|
||||
className={`w-full p-4 text-left rounded-pill border-2 transition-all ${
|
||||
selectedAnswer === index
|
||||
? index === questions[currentQuestion].correctAnswer
|
||||
? "border-green-500 bg-green-500/10"
|
||||
: "border-red-500 bg-red-500/10"
|
||||
: showResult &&
|
||||
index === questions[currentQuestion].correctAnswer
|
||||
? "border-green-500 bg-green-500/10"
|
||||
: "border-background-accent hover:border-primary-cta"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">{option}</span>
|
||||
{selectedAnswer === index && showResult && (
|
||||
index === questions[currentQuestion].correctAnswer ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-500" />
|
||||
) : (
|
||||
<XCircle className="w-5 h-5 text-red-500" />
|
||||
)
|
||||
)}
|
||||
{showResult &&
|
||||
index === questions[currentQuestion].correctAnswer &&
|
||||
selectedAnswer !== index && (
|
||||
<CheckCircle className="w-5 h-5 text-green-500" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Explanation */}
|
||||
{showResult && (
|
||||
<div className="mt-6 p-4 bg-background-accent rounded-pill border border-primary-cta/30">
|
||||
<p className="text-sm font-semibold text-primary-cta mb-2">Explanation:</p>
|
||||
<p className="text-foreground/80">
|
||||
{questions[currentQuestion].explanation}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Next Button */}
|
||||
{showResult && (
|
||||
<button
|
||||
onClick={handleNextQuestion}
|
||||
className="w-full py-3 px-6 bg-primary-cta text-background rounded-pill font-semibold flex items-center justify-center gap-2 hover:opacity-90 transition-opacity"
|
||||
>
|
||||
{currentQuestion + 1 === questions.length ? "See Results" : "Next Question"}
|
||||
<ArrowRight className="w-5 h-5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
/* Results Screen */
|
||||
<div className="space-y-8 text-center">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-4">Quiz Complete!</h1>
|
||||
<div className="w-32 h-32 mx-auto mb-6 rounded-full bg-primary-cta/10 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<p className="text-5xl font-bold text-primary-cta">{percentage}%</p>
|
||||
<p className="text-lg font-semibold text-foreground">
|
||||
{score}/{questions.length}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Result Message */}
|
||||
<div className="bg-card rounded-pill p-8 border border-background-accent">
|
||||
{percentage >= 80 ? (
|
||||
<div className="space-y-2">
|
||||
<p className="text-2xl font-bold text-green-600">Excellent!</p>
|
||||
<p className="text-foreground/80">
|
||||
You demonstrated strong cyber safety knowledge. Keep practicing to
|
||||
maintain your skills!
|
||||
</p>
|
||||
</div>
|
||||
) : percentage >= 60 ? (
|
||||
<div className="space-y-2">
|
||||
<p className="text-2xl font-bold text-yellow-600">Good Job!</p>
|
||||
<p className="text-foreground/80">
|
||||
You're on the right track! Review the explanations and try again to
|
||||
improve your score.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
<p className="text-2xl font-bold text-red-600">Keep Learning!</p>
|
||||
<p className="text-foreground/80">
|
||||
Take time to review the core modules and try the quiz again to
|
||||
strengthen your cyber safety knowledge.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex gap-4 justify-center">
|
||||
<button
|
||||
onClick={handleRestartQuiz}
|
||||
className="py-3 px-8 bg-secondary-cta text-foreground rounded-pill font-semibold flex items-center gap-2 hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<RotateCcw className="w-5 h-5" />
|
||||
Try Again
|
||||
</button>
|
||||
<a
|
||||
href="/#quiz"
|
||||
className="py-3 px-8 bg-primary-cta text-background rounded-pill font-semibold flex items-center gap-2 hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<ArrowRight className="w-5 h-5" />
|
||||
More Quizzes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBaseCard
|
||||
logoText="CyberSafe"
|
||||
columns={[
|
||||
{
|
||||
title: "Learning", items: [
|
||||
{ label: "Core Modules", href: "/#features" },
|
||||
{ label: "Threat Awareness", href: "/#metrics" },
|
||||
{ label: "Best Practices", href: "/#features" },
|
||||
{ label: "FAQ", href: "/#faq" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Resources", items: [
|
||||
{ label: "Blog", href: "#" },
|
||||
{ label: "Webinars", href: "#" },
|
||||
{ label: "Tools & Guides", href: "#" },
|
||||
{ label: "Community", href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Support", items: [
|
||||
{ label: "Contact Us", href: "/#contact" },
|
||||
{ label: "Report Issues", href: "#" },
|
||||
{ label: "Help Center", href: "#" },
|
||||
{ label: "Feedback", href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Organization", items: [
|
||||
{ label: "About Us", href: "/#about" },
|
||||
{ label: "Our Mission", href: "/#about" },
|
||||
{ label: "Partnerships", href: "#" },
|
||||
{ label: "Careers", href: "#" },
|
||||
],
|
||||
},
|
||||
]}
|
||||
copyrightText="© 2025 CyberSafe. Empowering students with cyber safety knowledge."
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user