aki-008 commited on
Commit
aef0df4
·
1 Parent(s): a62d2e4

chore: time slider added

Browse files
Files changed (1) hide show
  1. Frontend/src/pages/quize.tsx +55 -30
Frontend/src/pages/quize.tsx CHANGED
@@ -6,13 +6,13 @@ import {
6
  Upload,
7
  X,
8
  Loader2,
 
9
  } from "lucide-react";
10
  import MCQQuizPage from "../components/quize/mcq";
11
  import API from "../api/api"; // Import your Axios instance
12
  import * as pdfjsLib from "pdfjs-dist";
13
 
14
  // Initialize PDF worker
15
- // In a Vite setup, pointing to a CDN is often the most stable way to avoid build config issues
16
  pdfjsLib.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.mjs`;
17
 
18
  const CodingQuizPage = ({ onBack }: any) => (
@@ -34,9 +34,12 @@ const ResumeGeneratedQuize: React.FC = () => {
34
  const [uploadedFile, setUploadedFile] = useState<string | null>(null);
35
  const [fileError, setFileError] = useState<string | null>(null);
36
  const [fileObject, setFileObject] = useState<File | null>(null);
37
- const [isProcessing, setIsProcessing] = useState(false); // Loading state
38
 
 
39
  const [customPrompt, setCustomPrompt] = useState("");
 
 
40
  const [quizData, setQuizData] = useState(null);
41
 
42
  const resumeInputRef = useRef<HTMLInputElement>(null);
@@ -98,8 +101,6 @@ const ResumeGeneratedQuize: React.FC = () => {
98
  };
99
 
100
  // ---------- GENERATE QUIZ ----------
101
- // --- START: Replace your existing generateQuiz function ---
102
-
103
  const generateQuiz = async () => {
104
  if (!fileObject || !quizType) return;
105
 
@@ -108,6 +109,7 @@ const ResumeGeneratedQuize: React.FC = () => {
108
 
109
  try {
110
  // 1. Extract text on the client side
 
111
  const extractedText = await extractTextFromPDF(fileObject);
112
 
113
  if (!extractedText.trim()) {
@@ -118,41 +120,33 @@ const ResumeGeneratedQuize: React.FC = () => {
118
 
119
  // 2. Prepare Payload matching Backend `Quiz_input` schema
120
  const payload = {
121
- // Ensure extractedText is cleaned up to prevent large string issues
122
  parsed_doc: extractedText.trim(),
123
- // Ensure user_prompt is always a valid string
124
  user_prompt:
125
  customPrompt.trim() || "Generate a quiz based on this content.",
126
  };
127
 
128
  // 3. Send to Backend
129
- // The URL is now correct: /api/v1/quiz/resume
130
  const response = await API.post("/quiz/resume", payload);
131
 
132
- // Success
133
  setQuizData(response.data);
134
  setShowQuiz(true);
135
  } catch (error: any) {
136
  console.error("Quiz Generation Error:", error);
137
-
138
- // Extract detailed error message from FastAPI response body
139
  let errorMessage = "Failed to generate quiz. Check login status.";
 
140
  if (error.response?.data?.detail) {
141
- // Check if the server returned a validation error list or a simple string
142
  if (typeof error.response.data.detail === "string") {
143
  errorMessage = error.response.data.detail;
144
  } else if (
145
  Array.isArray(error.response.data.detail) &&
146
  error.response.data.detail.length > 0
147
  ) {
148
- // Pydantic validation error format
149
  const firstError = error.response.data.detail[0];
150
  errorMessage = `Validation Error: Field '${firstError.loc.join(
151
  " -> "
152
  )}' ${firstError.msg}`;
153
  }
154
  } else if (error.code === "ERR_BAD_REQUEST") {
155
- // General network/Axios 400 error
156
  errorMessage = "Server rejected the data. Are you logged in?";
157
  }
158
 
@@ -162,12 +156,16 @@ const ResumeGeneratedQuize: React.FC = () => {
162
  }
163
  };
164
 
165
- // --- END: Replace your existing generateQuiz function ---
166
-
167
  // Load quiz UI
168
  if (showQuiz) {
169
  if (quizType === "mcq")
170
- return <MCQQuizPage data={quizData} onBack={() => setShowQuiz(false)} />;
 
 
 
 
 
 
171
  if (quizType === "coding")
172
  return (
173
  <CodingQuizPage data={quizData} onBack={() => setShowQuiz(false)} />
@@ -290,20 +288,47 @@ const ResumeGeneratedQuize: React.FC = () => {
290
  2. Configure & Generate
291
  </h3>
292
 
293
- <div className="bg-slate-900/60 rounded-2xl shadow-2xl p-6 border border-slate-800 mb-8">
294
- <label className="text-lg font-semibold block mb-3 text-gray-200">
295
- Custom Prompt/Instructions (Optional)
296
- </label>
297
- <textarea
298
- rows={4}
299
- value={customPrompt}
300
- onChange={(e) => setCustomPrompt(e.target.value)}
301
- placeholder="e.g., 'Focus on Python only'"
302
- className="w-full p-3 rounded-lg bg-black/40 border border-slate-700 text-gray-100 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 transition"
303
- ></textarea>
304
- <p className="text-gray-500 text-sm mt-2">
305
- This prompt influences the quiz generation.
306
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  </div>
308
  </div>
309
  </div>
 
6
  Upload,
7
  X,
8
  Loader2,
9
+ Clock,
10
  } from "lucide-react";
11
  import MCQQuizPage from "../components/quize/mcq";
12
  import API from "../api/api"; // Import your Axios instance
13
  import * as pdfjsLib from "pdfjs-dist";
14
 
15
  // Initialize PDF worker
 
16
  pdfjsLib.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.mjs`;
17
 
18
  const CodingQuizPage = ({ onBack }: any) => (
 
34
  const [uploadedFile, setUploadedFile] = useState<string | null>(null);
35
  const [fileError, setFileError] = useState<string | null>(null);
36
  const [fileObject, setFileObject] = useState<File | null>(null);
37
+ const [isProcessing, setIsProcessing] = useState(false);
38
 
39
+ // Configuration State
40
  const [customPrompt, setCustomPrompt] = useState("");
41
+ const [duration, setDuration] = useState(15); // Default 15 minutes
42
+
43
  const [quizData, setQuizData] = useState(null);
44
 
45
  const resumeInputRef = useRef<HTMLInputElement>(null);
 
101
  };
102
 
103
  // ---------- GENERATE QUIZ ----------
 
 
104
  const generateQuiz = async () => {
105
  if (!fileObject || !quizType) return;
106
 
 
109
 
110
  try {
111
  // 1. Extract text on the client side
112
+ console.log("Extracting text from PDF...");
113
  const extractedText = await extractTextFromPDF(fileObject);
114
 
115
  if (!extractedText.trim()) {
 
120
 
121
  // 2. Prepare Payload matching Backend `Quiz_input` schema
122
  const payload = {
 
123
  parsed_doc: extractedText.trim(),
 
124
  user_prompt:
125
  customPrompt.trim() || "Generate a quiz based on this content.",
126
  };
127
 
128
  // 3. Send to Backend
 
129
  const response = await API.post("/quiz/resume", payload);
130
 
 
131
  setQuizData(response.data);
132
  setShowQuiz(true);
133
  } catch (error: any) {
134
  console.error("Quiz Generation Error:", error);
 
 
135
  let errorMessage = "Failed to generate quiz. Check login status.";
136
+
137
  if (error.response?.data?.detail) {
 
138
  if (typeof error.response.data.detail === "string") {
139
  errorMessage = error.response.data.detail;
140
  } else if (
141
  Array.isArray(error.response.data.detail) &&
142
  error.response.data.detail.length > 0
143
  ) {
 
144
  const firstError = error.response.data.detail[0];
145
  errorMessage = `Validation Error: Field '${firstError.loc.join(
146
  " -> "
147
  )}' ${firstError.msg}`;
148
  }
149
  } else if (error.code === "ERR_BAD_REQUEST") {
 
150
  errorMessage = "Server rejected the data. Are you logged in?";
151
  }
152
 
 
156
  }
157
  };
158
 
 
 
159
  // Load quiz UI
160
  if (showQuiz) {
161
  if (quizType === "mcq")
162
+ return (
163
+ <MCQQuizPage
164
+ data={quizData}
165
+ onBack={() => setShowQuiz(false)}
166
+ totalTimeSeconds={duration * 60} // Pass user selected time
167
+ />
168
+ );
169
  if (quizType === "coding")
170
  return (
171
  <CodingQuizPage data={quizData} onBack={() => setShowQuiz(false)} />
 
288
  2. Configure & Generate
289
  </h3>
290
 
291
+ <div className="bg-slate-900/60 rounded-2xl shadow-2xl p-6 border border-slate-800 mb-8 space-y-6">
292
+ {/* Custom Prompt Input */}
293
+ <div>
294
+ <label className="text-lg font-semibold block mb-3 text-gray-200">
295
+ Custom Prompt/Instructions (Optional)
296
+ </label>
297
+ <textarea
298
+ rows={3}
299
+ value={customPrompt}
300
+ onChange={(e) => setCustomPrompt(e.target.value)}
301
+ placeholder="e.g., 'Focus on Python only'"
302
+ className="w-full p-3 rounded-lg bg-black/40 border border-slate-700 text-gray-100 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 transition"
303
+ ></textarea>
304
+ <p className="text-gray-500 text-sm mt-2">
305
+ This prompt influences the quiz generation.
306
+ </p>
307
+ </div>
308
+
309
+ {/* NEW: Duration Slider */}
310
+ <div>
311
+ <label className="text-lg font-semibold block mb-3 text-gray-200 flex items-center justify-between">
312
+ <span className="flex items-center gap-2">
313
+ <Clock className="w-5 h-5 text-blue-400" /> Quiz Duration
314
+ </span>
315
+ <span className="text-blue-400 font-bold">{duration} min</span>
316
+ </label>
317
+ <input
318
+ type="range"
319
+ min="1"
320
+ max="60"
321
+ step="5"
322
+ value={duration}
323
+ onChange={(e) => setDuration(parseInt(e.target.value))}
324
+ className="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer accent-blue-500"
325
+ />
326
+ <div className="flex justify-between text-xs text-gray-500 mt-2">
327
+ <span>5 min</span>
328
+ <span>30 min</span>
329
+ <span>60 min</span>
330
+ </div>
331
+ </div>
332
  </div>
333
  </div>
334
  </div>