diff --git a/components/organisation/courses/ModuleDetail.tsx b/components/organisation/courses/ModuleDetail.tsx index 7b16fb6..8a05588 100644 --- a/components/organisation/courses/ModuleDetail.tsx +++ b/components/organisation/courses/ModuleDetail.tsx @@ -78,12 +78,22 @@ export default function ModuleDetail({ moduleId }: Props) {

{q.question_text}

{q.options?.map((opt) => (
- + {q.question_type === "multiple_choice" && ( + + )} + {q.question_type === "true_false" && ( + + )}
))} diff --git a/components/organisation/courses/ModuleForm.tsx b/components/organisation/courses/ModuleForm.tsx index ef7b55c..713c827 100644 --- a/components/organisation/courses/ModuleForm.tsx +++ b/components/organisation/courses/ModuleForm.tsx @@ -10,6 +10,12 @@ interface Props { moduleId?: string; } +interface Question { + question_text: string; + question_type: "multiple_choice" | "true_false"; + options: { option_text: string; is_correct: boolean }[]; +} + export default function ModuleForm({ mode, courseId, moduleId }: Props) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); @@ -19,6 +25,8 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) { const [moduleType, setModuleType] = useState("pdf"); + const [questions, setQuestions] = useState([]); + useEffect(() => { async function fetchModuleDetails() { try { @@ -58,7 +66,48 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) { fd.append("name", name); fd.append("description", description); fd.append("type", moduleType); - if (uploadFile) { + if (moduleType === "quiz") { + if (questions.length === 0) { + alert("Please add at least one question."); + return; + } + for (let i = 0; i < questions.length; i++) { + const q = questions[i]; + if (!q.question_text.trim()) { + alert(`Question ${i + 1} is empty. Please enter question text.`); + return; + } + if (q.question_type === "multiple_choice") { + if (q.options.length === 0) { + alert(`Question ${i + 1} must have at least one option.`); + return; + } + if (q.options.some((opt) => !opt.option_text.trim())) { + alert(`All options for question ${i + 1} must have text.`); + return; + } + if (!q.options.some((opt) => opt.is_correct)) { + alert( + `Please mark at least one correct answer for question ${i + 1}.` + ); + return; + } + } else if (q.question_type === "true_false") { + const correctCount = q.options.filter( + (opt) => opt.is_correct + ).length; + if (correctCount !== 1) { + alert( + `Please mark the correct answer for question ${ + i + 1 + } as either True or False.` + ); + return; + } + } + } + fd.append("questions", JSON.stringify(questions)); + } else if (uploadFile) { fd.append("file", uploadFile); } try { @@ -104,7 +153,45 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) { fd.append("moduleId", moduleId || ""); fd.append("name", name); fd.append("description", description); - if (uploadFile) { + if (moduleType === "quiz" && questions.length > 0) { + for (let i = 0; i < questions.length; i++) { + const q = questions[i]; + if (!q.question_text.trim()) { + alert(`Question ${i + 1} is empty. Please enter question text.`); + return; + } + if (q.question_type === "multiple_choice") { + if (q.options.length === 0) { + alert(`Question ${i + 1} must have at least one option.`); + return; + } + if (q.options.some((opt) => !opt.option_text.trim())) { + alert(`All options for question ${i + 1} must have text.`); + return; + } + if (!q.options.some((opt) => opt.is_correct)) { + alert( + `Please mark at least one correct answer for question ${i + 1}.` + ); + return; + } + } else if (q.question_type === "true_false") { + const correctCount = q.options.filter( + (opt) => opt.is_correct + ).length; + if (correctCount !== 1) { + alert( + `Please mark the correct answer for question ${ + i + 1 + } as either True or False.` + ); + return; + } + } + } + fd.append("type", moduleType); + fd.append("questions", JSON.stringify(questions)); + } else if (uploadFile) { fd.append("type", moduleType); fd.append("file", uploadFile); } @@ -162,23 +249,170 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) { -
- {" "} - setUploadFile(e.target.files?.[0] || null)} - required={mode === "create"} - className=" + {moduleType === "quiz" ? ( +
+

Quiz Questions

+ {questions.map((q, qi) => ( +
+ { + const qs = [...questions]; + qs[qi].question_text = e.target.value; + setQuestions(qs); + }} + className="w-full mb-2 p-2 border rounded" + /> + + {q.question_type === "true_false" ? ( +
+ {["True", "False"].map((label) => ( + + ))} +
+ ) : ( + <> + {q.options.map((opt, oi) => ( +
+ { + const qs = [...questions]; + qs[qi].options[oi].option_text = e.target.value; + setQuestions(qs); + }} + className="flex-1 p-2 border rounded" + /> + + +
+ ))} + + + )} +
+ +
+ ))} + +
+ ) : ( +
+ {" "} + setUploadFile(e.target.files?.[0] || null)} + required={mode === "create"} + className=" block w-full mt-1 p-3 text-gray-600 bg-white @@ -197,8 +431,9 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) { file:font-semibold hover:file:bg-purple-700 " - /> -
+ /> +
+ )}
{mode === "edit" && (