Mistakes are the best way to master complex logic.
+
+ {isCorrect ? "Great job!" : "Keep going!"}
+
+
+ {isCorrect
+ ? "You're on the right track."
+ : "Mistakes are the best way to master complex logic."}
+
@@ -76,7 +88,8 @@ function FeedbackPage() {
let boxClass = "feedback-option-box";
if (option === correctAnswer) boxClass += " correct-box";
- if (userAnswer === option && option !== correctAnswer) boxClass += " wrong-box";
+ if (userAnswer === option && option !== correctAnswer)
+ boxClass += " wrong-box";
return (
@@ -94,20 +107,27 @@ function FeedbackPage() {
AI Explanation
-
LUCID MENTOR ANALYSIS
+
+ LUCID MENTOR ANALYSIS
+
{isCorrect
- ? "Great job. Your answer matches the expected reasoning. This concept works because the underlying condition is already organized in a way that supports efficient searching."
- : "Think of this like finding a name in a sorted phone book. Because the data is ordered, you can repeatedly eliminate half of the remaining items. That is why the more efficient approach depends on sorted input."}
+ ? "Great job. Your answer matches the expected reasoning."
+ : "Think of this like searching in a sorted structure. Efficient algorithms eliminate large portions quickly, which is why ordering matters."}
-
@@ -115,16 +135,15 @@ function FeedbackPage() {
Pro Tip
- Efficient searching often depends on structure. Ordered data creates
- stronger algorithmic shortcuts.
+ Efficient searching depends on structure. Ordered data allows
+ faster algorithms.
Confused?
- Our interactive visualizer can show how the algorithm narrows the
- search space.
+ Use visual explanations to better understand how the algorithm works.
diff --git a/src/pages/GenerateQuizPage.jsx b/src/pages/GenerateQuizPage.jsx
index 35b79a6..d74cdbf 100644
--- a/src/pages/GenerateQuizPage.jsx
+++ b/src/pages/GenerateQuizPage.jsx
@@ -1,86 +1,87 @@
-//DUMMY version to test frontend design and screens
import { useState } from "react";
import { useNavigate } from "react-router-dom";
function GenerateQuizPage() {
const navigate = useNavigate();
+
const [topic, setTopic] = useState("");
- const [uploadedFile, setUploadedFile] = useState(null);
- const [uploadedContent, setUploadedContent] = useState("");
const [numQuestions, setNumQuestions] = useState(10);
const [difficulty, setDifficulty] = useState("medium");
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
+ const [errors, setErrors] = useState({});
- const handleFileUpload = async (e) => {
- const file = e.target.files[0];
- if (!file) return;
+ const API_URL = "http://localhost:5000/api/quiz/generate";
- setUploadedFile(file);
- setError("");
+ const validateForm = () => {
+ const newErrors = {};
- try {
- const fileContent = await file.text();
- setUploadedContent(fileContent);
- } catch (err) {
- setError("Failed to read file. Please try another document.");
- setUploadedFile(null);
- setUploadedContent("");
+ if (!topic.trim()) {
+ newErrors.topic = "Topic or study material is required.";
+ } else if (topic.trim().length < 3) {
+ newErrors.topic = "Please enter at least 3 characters.";
+ } else if (topic.trim().length > 200) {
+ newErrors.topic = "Please keep the topic under 200 characters.";
+ }
+
+ if (!numQuestions || numQuestions < 1 || numQuestions > 20) {
+ newErrors.numQuestions = "Number of questions must be between 1 and 20.";
}
- };
- const handleRemoveFile = () => {
- setUploadedFile(null);
- setUploadedContent("");
+ if (!difficulty) {
+ newErrors.difficulty = "Please select a difficulty level.";
+ }
+
+ return newErrors;
};
const handleGenerate = async (e) => {
e.preventDefault();
- if (!topic.trim() && !uploadedContent.trim()) {
- setError("Please enter a topic or upload a document.");
+ const validationErrors = validateForm();
+ if (Object.keys(validationErrors).length > 0) {
+ setErrors(validationErrors);
return;
}
try {
setLoading(true);
setError("");
+ setErrors({});
- // Use uploaded content if available, otherwise use topic
- const inputData = uploadedContent.trim() ? { text: uploadedContent } : { topic };
-
- // Call backend API to generate quiz
- const response = await fetch("http://localhost:5000/api/quiz/generate", {
+ const response = await fetch(API_URL, {
method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(inputData),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ topic: topic.trim(),
+ }),
});
+ const data = await response.json();
+
if (!response.ok) {
- const errorData = await response.json();
- throw new Error(errorData.details || "Failed to generate quiz");
+ throw new Error(data.error || "Failed to generate quiz.");
}
- const data = await response.json();
- const questions = data.questions;
-
- // Format questions for the quiz page (convert options array to object with A, B, C, D)
- const formattedQuestions = questions.map((q) => ({
- question: q.question,
- options: [q.options.A, q.options.B, q.options.C, q.options.D],
- correctAnswer: q.answer,
- }));
-
- setTimeout(() => {
- navigate("/quiz", {
- state: {
- topic: uploadedFile ? uploadedFile.name : topic,
- questions: formattedQuestions,
- },
- });
- }, 600);
+ const questions = data.questions || [];
+
+ if (!Array.isArray(questions) || questions.length === 0) {
+ throw new Error("No quiz questions were returned from the server.");
+ }
+
+ navigate("/quiz", {
+ state: {
+ topic,
+ quizId: data.quizId,
+ questions,
+ numQuestions,
+ difficulty,
+ },
+ });
} catch (err) {
- setError(err.message || "Failed to generate quiz. Please try again.");
+ setError(err.message || "Failed to generate quiz.");
} finally {
setLoading(false);
}
@@ -131,48 +132,34 @@ function GenerateQuizPage() {
type="text"
placeholder="e.g., Data Structures"
value={topic}
- onChange={(e) => setTopic(e.target.value)}
+ onChange={(e) => {
+ setTopic(e.target.value);
+ setErrors((prev) => ({ ...prev, topic: "" }));
+ }}
/>
+ {errors.topic &&