Loading module details...
;
}
- const finalUrl = `http://localhost:4000${data.file_url}`;
- return (
-
-
{data.title}
-
{data.description}
+ if (!enrolled) {
+ return (
+
+ You must be enrolled in the course to view this module.
+
+ );
+ }
- {data.module_type === "video" && data.file_url && (
-
- )}
+ if (
+ data.module_type !== "video" &&
+ data.module_type !== "pdf" &&
+ data.module_type !== "slide" &&
+ data.module_type !== "quiz"
+ ) {
+ return (
+
+ No preview available for this module type: {data.module_type}.
+
+ );
+ }
- {["pdf", "slide"].includes(data.module_type) && data.file_url && (
-
- )}
+ if (data.module_type !== "quiz") {
+ const finalUrl = `http://localhost:4000${data.file_url}`;
+ return (
+
+
+ {moduleStatus === "not_started" && !courseCompleted && (
+
+ )}
- {data.module_type === "quiz" && data.quiz && (
-
-
{data.quiz.title}
- {data.quiz.questions.map((q) => (
-
- ))}
+ {moduleStatus === "in_progress" && !courseCompleted && (
+
+ )}
+
+ {moduleStatus === "completed" && !courseCompleted && (
+
+ )}
- )}
+
{data.title}
+
{data.description}
+
+ {data.module_type === "video" && data.file_url && (
+
+ )}
+
+ {["pdf", "slide"].includes(data.module_type) && data.file_url && (
+
+ )}
+
+ );
+ }
+
+ const { quiz } = data;
+
+ const handleChange = (qId: number, optId: number, multiple: boolean) => {
+ setAnswers((ans) => {
+ if (multiple) {
+ const prev = Array.isArray(ans[qId]) ? (ans[qId] as number[]) : [];
+ if (prev.includes(optId)) {
+ return { ...ans, [qId]: prev.filter((x) => x !== optId) };
+ } else {
+ return { ...ans, [qId]: [...prev, optId] };
+ }
+ } else {
+ return { ...ans, [qId]: optId };
+ }
+ });
+ };
- {!["video", "pdf", "slide", "quiz"].includes(data.module_type) && (
-
No preview available for this module.
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (isAdmin || courseCompleted) {
+ return;
+ }
+
+ const missing = quiz!.questions
+ .filter((q) => q.question_type === "multiple_choice")
+ .filter((q) => {
+ const sel = answers[q.id];
+ return !Array.isArray(sel) || sel.length === 0;
+ });
+
+ if (missing.length > 0) {
+ alert(
+ "Please select at least one option for:\n" +
+ missing.map((q) => `• ${q.question_text}`).join("\n")
+ );
+ return;
+ }
+
+ const payload = {
+ quizId: quiz?.id,
+ answers: Object.entries(answers).map(([qId, sel]) => ({
+ questionId: Number(qId),
+
+ selectedOptionIds: Array.isArray(sel) ? sel : [sel],
+ })),
+ };
+ try {
+ const res = await fetch("/api/courses/submit-and-grade-quiz", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+ if (!res.ok) throw new Error("Submit failed");
+ const data = await res.json();
+ setResults(data.results);
+ } catch (err) {
+ console.error(err);
+ alert("Failed to submit quiz.");
+ }
+ };
+
+ const handleRetake = () => {
+ setResults(null);
+ setAnswers({});
+ };
+
+ if (data.module_type === "quiz" && results) {
+ return (
+
+
{data.title} — Results
+ {results.map((r) => (
+
+
Question {r.questionId}
+
+ Your answers:
+ {r.selectedOptions.map((o) => o.text).join(", ")}
+
+
+ Correct:
+ {r.correctOptions.map((o) => o.text).join(", ")}
+
+
+ {r.isCorrect ? (
+ Correct
+ ) : (
+ Incorrect
+ )}
+
+
+ ))}
+ {!courseCompleted && (
+
+ )}
+
+ );
+ }
+
+ return (
+
+ {quiz?.questions.map((q) => (
+
+
{q.question_text}
+ {q.options.map((opt) => (
+
+ ))}
+
+ ))}
+
+
);
}
diff --git a/components/organisation/courses/ModuleForm.tsx b/components/organisation/courses/ModuleForm.tsx
index 713c827..b40c097 100644
--- a/components/organisation/courses/ModuleForm.tsx
+++ b/components/organisation/courses/ModuleForm.tsx
@@ -20,7 +20,6 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) {
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [uploadFile, setUploadFile] = useState
(null);
- const [deleteMode, setDeleteMode] = useState(false);
const router = useRouter();
const [moduleType, setModuleType] =
useState("pdf");
@@ -126,28 +125,6 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) {
console.error(err);
alert("Could not create module. Please try again.");
}
- } else if (deleteMode) {
- if (!confirm("Are you sure you want to delete this module?")) return;
-
- try {
- const response = await fetch("/api/courses/delete-module", {
- method: "DELETE",
- credentials: "include",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ moduleId }),
- });
-
- if (!response.ok) {
- throw new Error("Failed to delete module");
- }
-
- router.push(`/courses`);
- } catch (error) {
- console.error("Error deleting module:", error);
- alert("Failed to delete module. Please try again.");
- }
} else {
const fd = new FormData();
fd.append("moduleId", moduleId || "");
@@ -214,6 +191,32 @@ export default function ModuleForm({ mode, courseId, moduleId }: Props) {
}
};
+ const handleDelete = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (!confirm("Are you sure you want to delete this module?")) return;
+
+ try {
+ const response = await fetch("/api/courses/delete-module", {
+ method: "DELETE",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ moduleId }),
+ });
+
+ if (!response.ok) {
+ throw new Error("Failed to delete module");
+ }
+
+ router.push(`/courses`);
+ } catch (error) {
+ console.error("Error deleting module:", error);
+ alert("Failed to delete module. Please try again.");
+ }
+ };
+
return (