diff --git a/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityid]/CoursePlayerWrapper.tsx b/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/CoursePlayerWrapper.tsx similarity index 89% rename from app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityid]/CoursePlayerWrapper.tsx rename to app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/CoursePlayerWrapper.tsx index a0104c6..972391f 100644 --- a/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityid]/CoursePlayerWrapper.tsx +++ b/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/CoursePlayerWrapper.tsx @@ -7,7 +7,7 @@ import { Loader2 } from "lucide-react"; // slow loading const VideoPlayerModule = lazy(() => import("./VideoPlayerModule")); const PDFViewerModule = lazy(() => import("./PDFViewModule")); -// quiz view is inline btw +const QuizView = lazy(() => import("./QuizView")); interface CoursePlayerWrapperProps { activity: { type: string; @@ -95,16 +95,15 @@ export default function CoursePlayerWrapper({ activity, onComplete, submitting } ); case "quiz": - // can import and use the exisiting quiz view - const quizConfig = content as QuizBlockConfig; - if (!quizConfig.quizQuestions?.length) { - return ( -
-

No quiz questions have been added to this block yet.

-
- ); - } - return
Quiz renderer — wire in QuizView component here.
; + return ( + }> + + + ); case "storyline": return (
diff --git a/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityid]/PDFViewModule.tsx b/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/PDFViewModule.tsx similarity index 100% rename from app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityid]/PDFViewModule.tsx rename to app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/PDFViewModule.tsx diff --git a/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/QuizView.tsx b/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/QuizView.tsx new file mode 100644 index 0000000..864404d --- /dev/null +++ b/app/StudentPortal/courses/[id]/modules/[moduleId]/activities/[activityId]/activities/[activityId]/QuizView.tsx @@ -0,0 +1,92 @@ +"use client"; + +import React, { useState } from "react"; +import { CheckCircle, Loader2 } from "lucide-react"; +import { QuizBlockConfig } from "@/app/lib/course.types"; + +interface QuizViewProps { + config: QuizBlockConfig; + onComplete: (points?: number) => void; + submitting: boolean; +} + +export default function QuizView({ config, onComplete, submitting }: QuizViewProps) { + const [answers, setAnswers] = useState>({}); + const [submitted, setSubmitted] = useState(false); + + const questions = config.quizQuestions || []; + + const handleSubmit = () => { + setSubmitted(true); + const correct = questions.filter((q, i) => + answers[i]?.trim().toLowerCase() === q.answer?.trim().toLowerCase() + ).length; + + const accuracy = questions.length > 0 ? (correct / questions.length) * 100 : 0; + // accuracy is used by completeActivity via handleComplete's overridePoints mapping + // handleComplete in page.tsx: accuracy = overridePoints ? Math.round((overridePoints / 30) * 100) : 100 + // So we pass points equivalent to accuracy out of 30. + // Wait, the page.tsx expects overridePoints out of 30 if we want to influence accuracy. + // If we pass 10 here, page.tsx will calculate accuracy as (10/30)*100 = 33%. + // So we should pass the accuracy percentage scaled to 30. + const accuracyScaledTo30 = Math.round((accuracy / 100) * 30); + onComplete(accuracyScaledTo30); + }; + + const allAnswered = questions.every((_, i) => answers[i]?.trim()); + + if (questions.length === 0) { + return ( +
+

No quiz questions have been added to this block yet.

+
+ ); + } + + return ( +
+ {questions.map((q, i) => ( +
+

{i + 1}. {q.question}

+ {q.options && q.options.length > 0 ? ( +
+ {q.options.map((opt: string, oi: number) => ( + + ))} +
+ ) : ( +