Documentation Index
Fetch the complete documentation index at: https://mintlify.com/0xchriswilder/journey/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The QuizSection component provides an interactive quiz experience with multiple-choice questions, instant feedback, explanations, and score tracking.
Location: src/components/lesson/QuizSection.tsx
Features
- Multiple-choice question interface
- Instant answer validation with visual feedback
- Detailed explanations for correct/incorrect answers
- Progress tracking (current question / total)
- Score calculation with pass/fail determination
- Quiz reset/retry functionality
- Animated transitions and feedback
Props
The quiz configuration object containing questions and settings.interface Quiz {
title: string;
description: string;
questions: QuizQuestion[];
passingScore: number; // percentage (e.g., 70)
}
onComplete
(score: number, passed: boolean) => void
required
Callback function invoked when the quiz is completed.Parameters:
score - Final score as percentage (0-100)
passed - Whether score meets or exceeds passingScore
Quiz Data Structure
Quiz Interface
interface Quiz {
title: string; // Quiz title
description: string; // Quiz description/instructions
questions: QuizQuestion[]; // Array of questions
passingScore: number; // Minimum percentage to pass (e.g., 70)
}
QuizQuestion Interface
interface QuizQuestion {
id: number | string; // Unique question identifier
question: string; // Question text
options: string[]; // Answer choices (4 options)
correctAnswer: number; // Index of correct option (0-3)
explanation: string; // Explanation shown after answering
category?: string; // Optional question category
}
Usage Example
Basic Usage
import { QuizSection } from '@/components/lesson/QuizSection';
function LessonPage() {
const quiz = {
title: "Understanding FHE",
description: "Test your knowledge of Fully Homomorphic Encryption basics.",
passingScore: 70,
questions: [
{
id: 1,
question: "What does FHE stand for?",
options: [
"Fast Hash Encryption",
"Fully Homomorphic Encryption",
"Federated Hash Exchange",
"Forward Hash Encoding"
],
correctAnswer: 1,
explanation: "FHE stands for Fully Homomorphic Encryption, which allows computation on encrypted data."
},
// ... more questions
]
};
const handleQuizComplete = (score: number, passed: boolean) => {
console.log(`Quiz completed! Score: ${score}%, Passed: ${passed}`);
if (passed) {
// Mark lesson as complete, unlock next lesson, etc.
}
};
return (
<div>
<h1>Lesson Content</h1>
{/* ... lesson content ... */}
<QuizSection quiz={quiz} onComplete={handleQuizComplete} />
</div>
);
}
With Progress Tracking
import { QuizSection } from '@/components/lesson/QuizSection';
import { useBootcampStore } from '@/state/bootcampStore';
function LessonWithQuiz({ weekId, lessonId, quiz }) {
const { setQuizScore, completeLesson } = useBootcampStore();
const handleQuizComplete = (score: number, passed: boolean) => {
// Save quiz score
setQuizScore(weekId, lessonId, score, passed);
// Mark lesson as complete if passed
if (passed) {
completeLesson(weekId, lessonId);
}
};
return <QuizSection quiz={quiz} onComplete={handleQuizComplete} />;
}
Component States
1. Question State (Active Quiz)
When: User is answering questions
Display:
- Quiz title and progress badge (e.g., “2/5”)
- Current question text
- Answer options (A, B, C, D)
- Explanation (after answering)
- Next/Finish button (after answering)
2. Completion State (Passed)
When: Quiz finished with passing score
Display:
- Green checkmark icon
- “Quiz Passed!” message
- Score display (e.g., “85% (4/5 correct)”)
- Passing score requirement
- “Retake Quiz” button
3. Completion State (Failed)
When: Quiz finished with failing score
Display:
- Red X icon
- “Quiz Not Passed” message
- Score display
- Passing score requirement
- “Try Again” button
Internal State Management
const [currentQuestion, setCurrentQuestion] = useState(0);
const [selectedAnswer, setSelectedAnswer] = useState<number | null>(null);
const [showExplanation, setShowExplanation] = useState(false);
const [correctCount, setCorrectCount] = useState(0);
const [finished, setFinished] = useState(false);
const [answers, setAnswers] = useState<(number | null)[]>(...);
State Variables
currentQuestion - Index of current question (0-based)
selectedAnswer - Index of selected answer option
showExplanation - Whether to show explanation
correctCount - Number of correct answers
finished - Whether quiz is complete
answers - Array tracking all user answers
User Interaction Flow
1. Answer Selection
const handleSelectAnswer = (answerIndex: number) => {
if (showExplanation) return; // Prevent changing answer
setSelectedAnswer(answerIndex);
setShowExplanation(true);
// Track answer
const newAnswers = [...answers];
newAnswers[currentQuestion] = answerIndex;
setAnswers(newAnswers);
// Update score if correct
if (answerIndex === question.correctAnswer) {
setCorrectCount((c) => c + 1);
}
};
2. Navigation to Next Question
const handleNext = () => {
if (currentQuestion < totalQuestions - 1) {
// Move to next question
setCurrentQuestion((c) => c + 1);
setSelectedAnswer(null);
setShowExplanation(false);
} else {
// Finish quiz
const finalScore = Math.round((correctCount / totalQuestions) * 100);
setFinished(true);
onComplete(finalScore, finalScore >= quiz.passingScore);
}
};
3. Quiz Reset
const handleReset = () => {
setCurrentQuestion(0);
setSelectedAnswer(null);
setShowExplanation(false);
setCorrectCount(0);
setFinished(false);
setAnswers(new Array(totalQuestions).fill(null));
};
Visual Feedback
Answer Option Styling
Before Answering:
- Default: Outlined buttons
- Selected: Primary color border and background
After Answering:
- Correct answer: Green border and background
- Incorrect selection: Red border and background
- Other options: Dimmed opacity
if (showExplanation) {
if (i === question.correctAnswer) {
className += ' border-green-500 bg-green-500/10 text-green-700';
} else if (i === selectedAnswer && !isCorrect) {
className += ' border-red-500 bg-red-500/10 text-red-700';
} else {
className += ' opacity-50';
}
}
Explanation Panel
Correct Answer:
- Green background with green border
- Green checkmark icon
- “Correct!” heading
Incorrect Answer:
- Red background with red border
- Red X icon
- “Incorrect” heading
Score Calculation
const score = Math.round((correctCount / totalQuestions) * 100);
const passed = score >= quiz.passingScore;
Example:
- Total questions: 5
- Correct answers: 4
- Score: (4/5) × 100 = 80%
- Passing score: 70%
- Result: Passed
Animations
Uses Framer Motion for:
- Explanation panel fade-in
- Smooth state transitions
<AnimatePresence>
{showExplanation && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
>
{/* Explanation content */}
</motion.div>
)}
</AnimatePresence>
Accessibility
- Answer options labeled A, B, C, D for easy reference
- Disabled state prevents answer changes after selection
- Clear visual feedback for correct/incorrect answers
- Keyboard-accessible button controls
Best Practices
Quiz Design
- Include 3-5 questions per quiz
- Set passing score to 70-80%
- Provide clear, educational explanations
- Use 4 answer options per question
Integration
// ✅ Good: Key prop for re-initialization
<QuizSection
key={`${weekId}-${lessonId}`}
quiz={quiz}
onComplete={handleComplete}
/>
// ❌ Bad: Missing key may cause state persistence
<QuizSection quiz={quiz} onComplete={handleComplete} />
- LessonView - Main lesson page that integrates QuizSection
Card - UI wrapper component
Badge - Progress and status indicators
Button - Interactive controls
See Also