ENCOA-233: Added the option for certain exercises to not count towards scores
This commit is contained in:
@@ -11,6 +11,7 @@ import MCDropdown from "./MCDropdown";
|
||||
const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
id,
|
||||
type,
|
||||
isPractice = false,
|
||||
prompt,
|
||||
solutions,
|
||||
text,
|
||||
@@ -40,6 +41,11 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
const shuffleMaps = shuffles.find((x) => x.exerciseID == id)?.shuffles;
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, disableProgressButtons])
|
||||
|
||||
const excludeWordMCType = (x: any) => {
|
||||
return typeof x === "string" ? x : (x as { letter: string; word: string });
|
||||
};
|
||||
@@ -169,7 +175,7 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
<Button
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps })}
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice })}
|
||||
className="max-w-[200px] w-full"
|
||||
disabled={exam && exam.module === "level" && partIndex === 0 && questionIndex === 0}>
|
||||
Previous Page
|
||||
@@ -178,7 +184,7 @@ const FillBlanks: React.FC<FillBlanksExercise & CommonProps> = ({
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() => {
|
||||
onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice });
|
||||
}}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next Page
|
||||
|
||||
@@ -24,6 +24,7 @@ export default function InteractiveSpeaking({
|
||||
userSolutions,
|
||||
onNext,
|
||||
onBack,
|
||||
isPractice = false,
|
||||
preview = false
|
||||
}: InteractiveSpeakingExercise & CommonProps) {
|
||||
const [recordingDuration, setRecordingDuration] = useState(0);
|
||||
@@ -54,6 +55,7 @@ export default function InteractiveSpeaking({
|
||||
solutions: [...answers.filter((x) => x.questionIndex !== questionIndex), answer],
|
||||
score: { correct: 100, total: 100, missing: 0 },
|
||||
type,
|
||||
isPractice
|
||||
});
|
||||
};
|
||||
|
||||
@@ -76,6 +78,7 @@ export default function InteractiveSpeaking({
|
||||
solutions: [...answers.filter((x) => x.questionIndex !== questionIndex), answer],
|
||||
score: { correct: 100, total: 100, missing: 0 },
|
||||
type,
|
||||
isPractice
|
||||
});
|
||||
};
|
||||
|
||||
@@ -146,6 +149,7 @@ export default function InteractiveSpeaking({
|
||||
module: "speaking",
|
||||
exam: examID,
|
||||
type,
|
||||
isPractice
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ export default function MatchSentences({
|
||||
userSolutions,
|
||||
onNext,
|
||||
onBack,
|
||||
isPractice = false,
|
||||
disableProgressButtons = false
|
||||
}: MatchSentencesExercise & CommonProps) {
|
||||
const [answers, setAnswers] = useState<{ question: string; option: string }[]>(userSolutions);
|
||||
@@ -81,7 +82,7 @@ export default function MatchSentences({
|
||||
const setCurrentSolution = useExamStore((state) => state.setCurrentSolution);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, setAnswers]);
|
||||
|
||||
@@ -105,12 +106,12 @@ export default function MatchSentences({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, disableProgressButtons])
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
@@ -119,14 +120,14 @@ export default function MatchSentences({
|
||||
<Button
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] w-full">
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next
|
||||
</Button>
|
||||
|
||||
@@ -78,6 +78,7 @@ export default function MultipleChoice({
|
||||
type,
|
||||
questions,
|
||||
userSolutions,
|
||||
isPractice = false,
|
||||
onNext,
|
||||
onBack,
|
||||
disableProgressButtons = false
|
||||
@@ -93,7 +94,7 @@ export default function MultipleChoice({
|
||||
const scrollToTop = () => Array.from(document.getElementsByTagName("body")).forEach((body) => body.scrollTo(0, 0));
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
@@ -102,7 +103,7 @@ export default function MultipleChoice({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, setAnswers]);
|
||||
|
||||
@@ -140,13 +141,13 @@ export default function MultipleChoice({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, disableProgressButtons])
|
||||
|
||||
const next = () => {
|
||||
if (questionIndex + 1 >= questions.length - 1) {
|
||||
onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
onNext({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice });
|
||||
} else {
|
||||
setQuestionIndex(questionIndex + 2);
|
||||
}
|
||||
@@ -155,7 +156,7 @@ export default function MultipleChoice({
|
||||
|
||||
const back = () => {
|
||||
if (questionIndex === 0) {
|
||||
onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps });
|
||||
onBack({ exercise: id, solutions: answers, score: calculateScore(), type, shuffleMaps: shuffleMaps, isPractice });
|
||||
} else {
|
||||
if (exam?.module === "level" && typeof exam.parts[0].intro !== "undefined" && questionIndex === 0) return;
|
||||
setQuestionIndex(questionIndex - 2);
|
||||
|
||||
@@ -14,7 +14,7 @@ const ReactMediaRecorder = dynamic(() => import("react-media-recorder").then((mo
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
export default function Speaking({ id, title, text, video_url, type, prompts, suffix, userSolutions, onNext, onBack, preview = false }: SpeakingExercise & CommonProps) {
|
||||
export default function Speaking({ id, title, text, video_url, type, prompts, suffix, userSolutions, isPractice = false, onNext, onBack, preview = false }: SpeakingExercise & CommonProps) {
|
||||
const [recordingDuration, setRecordingDuration] = useState(0);
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [mediaBlob, setMediaBlob] = useState<string>();
|
||||
@@ -81,7 +81,7 @@ export default function Speaking({ id, title, text, video_url, type, prompts, su
|
||||
exercise: id,
|
||||
solutions: mediaBlob ? [{ id, solution: mediaBlob }] : [],
|
||||
score: { correct: 0, total: 100, missing: 0 },
|
||||
type,
|
||||
type, isPractice
|
||||
});
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function Speaking({ id, title, text, video_url, type, prompts, su
|
||||
exercise: id,
|
||||
solutions: mediaBlob ? [{ id, solution: mediaBlob }] : [],
|
||||
score: { correct: 0, total: 100, missing: 0 },
|
||||
type,
|
||||
type, isPractice
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export default function TrueFalse({
|
||||
prompt,
|
||||
questions,
|
||||
userSolutions,
|
||||
isPractice = false,
|
||||
onNext,
|
||||
onBack,
|
||||
disableProgressButtons = false
|
||||
@@ -21,7 +22,7 @@ export default function TrueFalse({
|
||||
const setCurrentSolution = useExamStore((state) => state.setCurrentSolution);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
@@ -40,7 +41,7 @@ export default function TrueFalse({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, setAnswers]);
|
||||
|
||||
@@ -55,7 +56,7 @@ export default function TrueFalse({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, disableProgressButtons])
|
||||
|
||||
@@ -64,14 +65,14 @@ export default function TrueFalse({
|
||||
<Button
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] w-full">
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next
|
||||
</Button>
|
||||
|
||||
@@ -53,6 +53,7 @@ export default function WriteBlanks({
|
||||
maxWords,
|
||||
solutions,
|
||||
userSolutions,
|
||||
isPractice = false,
|
||||
text,
|
||||
onNext,
|
||||
onBack,
|
||||
@@ -63,7 +64,7 @@ export default function WriteBlanks({
|
||||
const { hasExamEnded, setCurrentSolution } = useExamStore((state) => state);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (hasExamEnded) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
@@ -82,12 +83,12 @@ export default function WriteBlanks({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
setCurrentSolution({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, setAnswers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type });
|
||||
if (disableProgressButtons) onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [answers, disableProgressButtons])
|
||||
|
||||
@@ -112,14 +113,14 @@ export default function WriteBlanks({
|
||||
<Button
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onBack({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] w-full">
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="purple"
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type })}
|
||||
onClick={() => onNext({ exercise: id, solutions: answers, score: calculateScore(), type, isPractice })}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Next
|
||||
</Button>
|
||||
|
||||
@@ -16,6 +16,7 @@ export default function Writing({
|
||||
wordCounter,
|
||||
attachment,
|
||||
userSolutions,
|
||||
isPractice = false,
|
||||
onNext,
|
||||
onBack,
|
||||
enableNavigation = false
|
||||
@@ -66,7 +67,7 @@ export default function Writing({
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded)
|
||||
onNext({exercise: id, solutions: [{id, solution: inputText}], score: {correct: 100, total: 100, missing: 0}, type, module: "writing"});
|
||||
onNext({ exercise: id, solutions: [{ id, solution: inputText }], score: { correct: 100, total: 100, missing: 0 }, type, module: "writing", isPractice });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
@@ -91,7 +92,7 @@ export default function Writing({
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
onBack({exercise: id, solutions: [{id, solution: inputText}], score: {correct: 100, total: 100, missing: 0}, type})
|
||||
onBack({ exercise: id, solutions: [{ id, solution: inputText }], score: { correct: 100, total: 100, missing: 0 }, type, isPractice })
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Back
|
||||
@@ -105,7 +106,7 @@ export default function Writing({
|
||||
solutions: [{ id, solution: inputText.replaceAll(/\s{2,}/g, " ") }],
|
||||
score: { correct: 100, total: 100, missing: 0 },
|
||||
type,
|
||||
module: "writing",
|
||||
module: "writing", isPractice
|
||||
})
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
@@ -177,7 +178,7 @@ export default function Writing({
|
||||
color="purple"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
onBack({exercise: id, solutions: [{id, solution: inputText}], score: {correct: 100, total: 100, missing: 0}, type})
|
||||
onBack({ exercise: id, solutions: [{ id, solution: inputText }], score: { correct: 100, total: 100, missing: 0 }, type, isPractice })
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
Back
|
||||
@@ -191,7 +192,7 @@ export default function Writing({
|
||||
solutions: [{ id, solution: inputText.replaceAll(/\s{2,}/g, " ") }],
|
||||
score: { correct: 100, total: 100, missing: 0 },
|
||||
type,
|
||||
module: "writing",
|
||||
module: "writing", isPractice
|
||||
})
|
||||
}
|
||||
className="max-w-[200px] self-end w-full">
|
||||
|
||||
@@ -54,7 +54,7 @@ const aggregateScoresByModule = (stats: Stat[]): {module: Module; total: number;
|
||||
},
|
||||
};
|
||||
|
||||
stats.forEach((x) => {
|
||||
stats.filter(x => !x.isPractice).forEach((x) => {
|
||||
scores[x.module!] = {
|
||||
total: scores[x.module!].total + x.score.total,
|
||||
correct: scores[x.module!].correct + x.score.correct,
|
||||
|
||||
@@ -88,6 +88,7 @@ export interface UserSolution {
|
||||
exercise: string;
|
||||
isDisabled?: boolean;
|
||||
shuffleMaps?: ShuffleMap[];
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface WritingExam extends ExamBase {
|
||||
@@ -162,6 +163,7 @@ export interface WritingExercise extends Section {
|
||||
evaluation?: WritingEvaluation;
|
||||
}[];
|
||||
topic?: string;
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface AIDetectionAttributes {
|
||||
@@ -196,6 +198,7 @@ export interface SpeakingExercise extends Section {
|
||||
evaluation?: SpeakingEvaluation;
|
||||
}[];
|
||||
topic?: string;
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface InteractiveSpeakingExercise extends Section {
|
||||
@@ -215,6 +218,7 @@ export interface InteractiveSpeakingExercise extends Section {
|
||||
first_topic?: string;
|
||||
second_topic?: string;
|
||||
variant?: "initial" | "final";
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface FillBlanksMCOption {
|
||||
@@ -243,6 +247,7 @@ export interface FillBlanksExercise {
|
||||
solution: string; // *EXAMPLE: "preserve"
|
||||
}[];
|
||||
variant?: string;
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface TrueFalseExercise {
|
||||
@@ -251,6 +256,7 @@ export interface TrueFalseExercise {
|
||||
prompt: string; // *EXAMPLE: "Select the appropriate option."
|
||||
questions: TrueFalseQuestion[];
|
||||
userSolutions: { id: string; solution: "true" | "false" | "not_given" }[];
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface TrueFalseQuestion {
|
||||
@@ -274,6 +280,7 @@ export interface WriteBlanksExercise {
|
||||
solution: string;
|
||||
}[];
|
||||
variant?: string;
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface MatchSentencesExercise {
|
||||
@@ -285,6 +292,7 @@ export interface MatchSentencesExercise {
|
||||
allowRepetition: boolean;
|
||||
options: MatchSentenceExerciseOption[];
|
||||
variant?: string;
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface MatchSentenceExerciseSentence {
|
||||
@@ -309,6 +317,7 @@ export interface MultipleChoiceExercise {
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface MultipleChoiceQuestion {
|
||||
|
||||
@@ -142,6 +142,7 @@ export interface Stat {
|
||||
path: string;
|
||||
version: string;
|
||||
};
|
||||
isPractice?: boolean
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
|
||||
@@ -11,7 +11,6 @@ import Reading from "@/exams/Reading";
|
||||
import Selection from "@/exams/Selection";
|
||||
import Speaking from "@/exams/Speaking";
|
||||
import Writing from "@/exams/Writing";
|
||||
import useUser from "@/hooks/useUser";
|
||||
import { Exam, LevelExam, UserSolution, Variant } from "@/interfaces/exam";
|
||||
import { Stat, User } from "@/interfaces/user";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
@@ -21,12 +20,7 @@ import axios from "axios";
|
||||
import { useRouter } from "next/router";
|
||||
import { toast, ToastContainer } from "react-toastify";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import useSessions from "@/hooks/useSessions";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import clsx from "clsx";
|
||||
import useGradingSystem from "@/hooks/useGrading";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { mapBy } from "@/utils";
|
||||
|
||||
interface Props {
|
||||
page: "exams" | "exercises";
|
||||
@@ -214,7 +208,6 @@ export default function ExamPage({ page, user, destination = "/exam", hideSideba
|
||||
}, [setModuleIndex, showSolutions]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(selectedModules)
|
||||
if (selectedModules.length > 0 && exams.length > 0 && moduleIndex < selectedModules.length) {
|
||||
const nextExam = exams[moduleIndex];
|
||||
|
||||
@@ -264,6 +257,7 @@ export default function ExamPage({ page, user, destination = "/exam", hideSideba
|
||||
isDisabled: solution.isDisabled,
|
||||
shuffleMaps: solution.shuffleMaps,
|
||||
...(assignment ? { assignment: assignment.id } : {}),
|
||||
isPractice: solution.isPractice
|
||||
}));
|
||||
|
||||
axios
|
||||
@@ -422,7 +416,7 @@ export default function ExamPage({ page, user, destination = "/exam", hideSideba
|
||||
},
|
||||
};
|
||||
|
||||
userSolutions.forEach((x) => {
|
||||
userSolutions.filter(x => !x.isPractice).forEach((x) => {
|
||||
const examModule =
|
||||
x.module || (x.type === "writing" ? "writing" : x.type === "speaking" || x.type === "interactiveSpeaking" ? "speaking" : undefined);
|
||||
|
||||
|
||||
@@ -43,12 +43,10 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
|
||||
|
||||
const entities = await getEntitiesWithRoles(checkAccess(user, ["admin", "developer"]) ? undefined : entityIDs)
|
||||
const users = await (checkAccess(user, ["admin", "developer"]) ? getUsers() : getEntitiesUsers(mapBy(entities, 'id')))
|
||||
const groups = await (checkAccess(user, ["admin", "developer"]) ? getGroups() : getGroupsByEntities(mapBy(entities, 'id')))
|
||||
const assignments = await (checkAccess(user, ["admin", "developer"]) ? getAssignments() : getEntitiesAssignments(mapBy(entities, 'id')))
|
||||
const gradingSystems = await Promise.all(entityIDs.map(getGradingSystemByEntity))
|
||||
|
||||
return {
|
||||
props: serialize({user, users, assignments, entities, gradingSystems}),
|
||||
props: serialize({ user, users, assignments, entities }),
|
||||
};
|
||||
}, sessionOptions);
|
||||
|
||||
@@ -58,13 +56,12 @@ interface Props {
|
||||
user: User;
|
||||
users: User[];
|
||||
assignments: Assignment[];
|
||||
gradingSystems: Grading[]
|
||||
entities: EntityWithRoles[]
|
||||
}
|
||||
|
||||
const MAX_TRAINING_EXAMS = 10;
|
||||
|
||||
export default function History({user, users, assignments, entities, gradingSystems}: Props) {
|
||||
export default function History({ user, users, assignments, entities }: Props) {
|
||||
const router = useRouter();
|
||||
const [statsUserId, setStatsUserId, training, setTraining] = useRecordStore((state) => [
|
||||
state.selectedUser,
|
||||
|
||||
Reference in New Issue
Block a user