Files
encoach_ui_odoo19/src/exams/Writing.tsx
Tiago Ribeiro 61d1bbbe13 ENCOA-268
2024-12-12 16:14:54 +00:00

128 lines
4.5 KiB
TypeScript

import { renderExercise } from "@/components/Exercises";
import ModuleTitle from "@/components/Medium/ModuleTitle";
import { renderSolution } from "@/components/Solutions";
import { Exercise, UserSolution, WritingExam } from "@/interfaces/exam";
import useExamStore, { usePersistentExamStore } from "@/stores/exam";
import { countExercises } from "@/utils/moduleUtils";
import PartDivider from "./Navigation/SectionDivider";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ExamProps } from "./types";
import useExamTimer from "@/hooks/useExamTimer";
import useExamNavigation from "./Navigation/useExamNavigation";
import SectionNavbar from "./Navigation/SectionNavbar";
import ProgressButtons from "./components/ProgressButtons";
import PracticeModal from "@/components/PracticeModal";
const Writing: React.FC<ExamProps<WritingExam>> = ({ exam, showSolutions = false, preview = false }) => {
const updateTimers = useExamTimer(exam.module, preview || showSolutions);
const userSolutionRef = useRef<(() => UserSolution) | null>(null);
const [solutionWasUpdated, setSolutionWasUpdated] = useState(false);
const examState = useExamStore((state) => state);
const persistentExamState = usePersistentExamStore((state) => state);
const {
exerciseIndex, flags, setBgColor,
setUserSolutions, setTimeIsUp, userSolutions,
dispatch, navigation, timeSpentCurrentModule
} = !preview ? examState : persistentExamState;
const timer = useRef(exam.minTimer - timeSpentCurrentModule / 60);
const hasPractice = useMemo(() => exam.exercises.some(e => e.isPractice), [exam.exercises])
const { finalizeModule, timeIsUp } = flags;
const { nextDisabled } = navigation;
useEffect(() => {
if (finalizeModule || timeIsUp) {
updateTimers();
if (timeIsUp) {
setTimeIsUp(false);
}
dispatch({ type: "FINALIZE_MODULE", payload: { updateTimers: false } })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [finalizeModule, timeIsUp])
const {
nextExercise, previousExercise,
showPartDivider, setShowPartDivider,
seenParts, setSeenParts,
} = useExamNavigation({ exam, module: "writing", showSolutions, preview });
const registerSolution = useCallback((updateSolution: () => UserSolution) => {
userSolutionRef.current = updateSolution;
setSolutionWasUpdated(true);
}, []);
useEffect(() => {
if (solutionWasUpdated && userSolutionRef.current) {
const solution = userSolutionRef.current();
setUserSolutions([...userSolutions.filter((x) => x.exercise !== solution.exercise), { ...solution, module: "writing", exam: exam.id }]);
setSolutionWasUpdated(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [solutionWasUpdated])
const currentExercise = useMemo<Exercise>(() => {
const exercise = exam.exercises[exerciseIndex];
return {
...exercise,
userSolutions: userSolutions.find((x) => x.exercise === exercise.id)?.solutions || [],
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [exerciseIndex]);
const handlePartDividerClick = () => {
setShowPartDivider(false);
setBgColor("bg-white");
setSeenParts((prev) => new Set(prev).add(exerciseIndex));
}
const progressButtons = useMemo(() =>
// Do not remove the ()=> in handle next
<ProgressButtons handlePrevious={previousExercise} handleNext={() => nextExercise()} nextDisabled={nextDisabled} />
, [nextExercise, previousExercise, nextDisabled]);
return (
<>
{(showPartDivider) ?
<PartDivider
module="writing"
sectionLabel="Task"
defaultTitle="Writing exam"
section={exam.exercises[exerciseIndex]}
sectionIndex={exerciseIndex}
onNext={handlePartDividerClick}
/> : (
<div className="flex flex-col h-full w-full gap-8 items-center">
<PracticeModal open={hasPractice} />
{exam.exercises.length > 1 && <SectionNavbar
module="writing"
sectionLabel="Part"
seenParts={seenParts}
setShowPartDivider={setShowPartDivider}
setSeenParts={setSeenParts}
preview={preview}
/>}
<ModuleTitle
minTimer={timer.current}
exerciseIndex={exerciseIndex + 1}
module="writing"
totalExercises={countExercises(exam.exercises)}
disableTimer={showSolutions || preview}
preview={preview}
/>
{!showPartDivider && !showSolutions && renderExercise(currentExercise, exam.id, registerSolution, preview, progressButtons, progressButtons)}
{showSolutions && renderSolution(currentExercise, progressButtons, progressButtons)}
</div>
)
}
</>
);
}
export default Writing;