import clsx from "clsx"; import SectionRenderer from "./SectionRenderer"; import Checkbox from "../Low/Checkbox"; import Input from "../Low/Input"; import Select from "../Low/Select"; import { capitalize } from "lodash"; import { AccessType, ACCESSTYPE, Difficulty } from "@/interfaces/exam"; import { useCallback, useEffect, useState } from "react"; import { toast } from "react-toastify"; import { ModuleState, SectionState } from "@/stores/examEditor/types"; import { Module } from "@/interfaces"; import useExamEditorStore from "@/stores/examEditor"; import WritingSettings from "./SettingsEditor/writing"; import ReadingSettings from "./SettingsEditor/reading"; import LevelSettings from "./SettingsEditor/level"; import ListeningSettings from "./SettingsEditor/listening"; import SpeakingSettings from "./SettingsEditor/speaking"; import ImportOrStartFromScratch from "./ImportExam/ImportOrFromScratch"; import { defaultSectionSettings } from "@/stores/examEditor/defaults"; import Button from "../Low/Button"; import ResetModule from "./Standalone/ResetModule"; import ListeningInstructions from "./Standalone/ListeningInstructions"; import { EntityWithRoles } from "@/interfaces/entity"; const DIFFICULTIES: Difficulty[] = ["A1", "A2", "B1", "B2", "C1", "C2"]; const ExamEditor: React.FC<{ levelParts?: number; entitiesAllowEditPrivacy: EntityWithRoles[]; }> = ({ levelParts = 0, entitiesAllowEditPrivacy = [] }) => { const { currentModule, dispatch } = useExamEditorStore(); const { sections, minTimer, expandedSections, examLabel, access, difficulty, sectionLabels, importModule, } = useExamEditorStore((state) => state.modules[currentModule]); const [numberOfLevelParts, setNumberOfLevelParts] = useState( levelParts !== 0 ? levelParts : 1 ); const [isResetModuleOpen, setIsResetModuleOpen] = useState(false); // For exam edits useEffect(() => { if (levelParts !== 0) { setNumberOfLevelParts(levelParts); dispatch({ type: "UPDATE_MODULE", payload: { updates: { sectionLabels: Array.from({ length: levelParts }).map((_, i) => ({ id: i + 1, label: `Part ${i + 1}`, })), }, module: "level", }, }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [levelParts]); useEffect(() => { const currentSections = sections; const currentLabels = sectionLabels; let updatedSections: SectionState[]; let updatedLabels: any; if ( (currentModule === "level" && currentSections.length !== currentLabels.length) || numberOfLevelParts !== currentSections.length ) { const newSections = [...currentSections]; const newLabels = [...currentLabels]; for (let i = currentLabels.length; i < numberOfLevelParts; i++) { if (currentSections.length !== numberOfLevelParts) newSections.push(defaultSectionSettings(currentModule, i + 1)); newLabels.push({ id: i + 1, label: `Part ${i + 1}`, }); } updatedSections = newSections; updatedLabels = newLabels; } else if (numberOfLevelParts < currentSections.length) { updatedSections = currentSections.slice(0, numberOfLevelParts); updatedLabels = currentLabels.slice(0, numberOfLevelParts); } else { return; } const updatedExpandedSections = expandedSections.filter((sectionId) => updatedSections.some((section) => section.sectionId === sectionId) ); dispatch({ type: "UPDATE_MODULE", payload: { updates: { sections: updatedSections, sectionLabels: updatedLabels, expandedSections: updatedExpandedSections, }, }, }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [numberOfLevelParts]); const sectionIds = sections.map((section) => section.sectionId); const updateModule = useCallback( (updates: Partial) => { dispatch({ type: "UPDATE_MODULE", payload: { updates } }); }, [dispatch] ); const toggleSection = (sectionId: number) => { if (expandedSections.length === 1 && sectionIds.includes(sectionId)) { toast.error("Include at least one section!"); return; } dispatch({ type: "TOGGLE_SECTION", payload: { sectionId } }); }; const ModuleSettings: Record = { reading: ReadingSettings, writing: WritingSettings, speaking: SpeakingSettings, listening: ListeningSettings, level: LevelSettings, }; const Settings = ModuleSettings[currentModule]; const showImport = importModule && ["reading", "listening", "level"].includes(currentModule); const updateLevelParts = (parts: number) => { setNumberOfLevelParts(parts); }; return ( <> {showImport ? ( ) : ( <> {isResetModuleOpen && ( )}
updateModule({ minTimer: parseInt(e) < 15 ? 15 : parseInt(e), }) } value={minTimer} className="max-w-[300px]" />
setNumberOfLevelParts(parseInt(v))} value={numberOfLevelParts} />
)}
updateModule({ examLabel: text })} roundness="xl" value={examLabel} required />
{currentModule === "listening" && }
)} ); }; export default ExamEditor;