feat: multiple choice question must all be correct before next question (#432)
This commit is contained in:
+4
-2
@@ -25,6 +25,7 @@
|
|||||||
nextStatusId: number;
|
nextStatusId: number;
|
||||||
total: number;
|
total: number;
|
||||||
}) => {};
|
}) => {};
|
||||||
|
export let isSaving = false;
|
||||||
|
|
||||||
const SELECTABLE_STATUS = [
|
const SELECTABLE_STATUS = [
|
||||||
{
|
{
|
||||||
@@ -128,7 +129,7 @@
|
|||||||
'course.navItem.submissions.grading_modal.questions_tried'
|
'course.navItem.submissions.grading_modal.questions_tried'
|
||||||
)} ${answerPoints} `
|
)} ${answerPoints} `
|
||||||
};
|
};
|
||||||
data.questionAnswerByPoint[id] = `${points / answerPoints}`;
|
data.questionAnswerByPoint[id] = `${Math.ceil(points / answerPoints)}`;
|
||||||
} else if (aiResponses.length) {
|
} else if (aiResponses.length) {
|
||||||
const graded = aiResponses.find((res) => res.id === id);
|
const graded = aiResponses.find((res) => res.id === id);
|
||||||
|
|
||||||
@@ -335,8 +336,9 @@
|
|||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleSave(data);
|
handleSave(data);
|
||||||
onClose();
|
// onClose();
|
||||||
}}
|
}}
|
||||||
|
isLoading={isSaving}
|
||||||
label={$t('course.navItem.submissions.grading_modal.submit_grades')}
|
label={$t('course.navItem.submissions.grading_modal.submit_grades')}
|
||||||
variant={VARIANTS.CONTAINED}
|
variant={VARIANTS.CONTAINED}
|
||||||
className="py-3 px-8 w-full"
|
className="py-3 px-8 w-full"
|
||||||
|
|||||||
+19
-8
@@ -5,6 +5,12 @@ export const isAnswerCorrect = (options, answer) => {
|
|||||||
return options.some((option) => option.is_correct && option.value === answer);
|
return options.some((option) => option.is_correct && option.value === answer);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
GRADING RULES
|
||||||
|
Textarea = no validation
|
||||||
|
Single = only one should be correct
|
||||||
|
Multiple = all should be correct
|
||||||
|
*/
|
||||||
export function wasCorrectAnswerSelected(currentQuestion, answers, isFinished) {
|
export function wasCorrectAnswerSelected(currentQuestion, answers, isFinished) {
|
||||||
if (currentQuestion.question_type.id === QUESTION_TYPE.TEXTAREA) {
|
if (currentQuestion.question_type.id === QUESTION_TYPE.TEXTAREA) {
|
||||||
return true;
|
return true;
|
||||||
@@ -13,15 +19,20 @@ export function wasCorrectAnswerSelected(currentQuestion, answers, isFinished) {
|
|||||||
const answer = answers[currentQuestion.name];
|
const answer = answers[currentQuestion.name];
|
||||||
|
|
||||||
const formattedAnswers = typeof answer === 'string' ? [answer] : answer;
|
const formattedAnswers = typeof answer === 'string' ? [answer] : answer;
|
||||||
const isCorrect =
|
|
||||||
formattedAnswers &&
|
|
||||||
formattedAnswers.some((answer) => {
|
|
||||||
if (isAnswerCorrect(currentQuestion.options, answer)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
let isCorrect = false;
|
||||||
});
|
|
||||||
|
if (currentQuestion.question_type.id === QUESTION_TYPE.CHECKBOX) {
|
||||||
|
// Every correct answer should be in the selected answer
|
||||||
|
isCorrect = currentQuestion.options
|
||||||
|
.filter((o) => o.is_correct)
|
||||||
|
.every((option) => formattedAnswers?.includes(option.value));
|
||||||
|
} else if (currentQuestion.question_type.id === QUESTION_TYPE.RADIO) {
|
||||||
|
// At least one correct answer should be selected
|
||||||
|
isCorrect = formattedAnswers?.some((answer) =>
|
||||||
|
isAnswerCorrect(currentQuestion.options, answer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isCorrect && !isFinished) {
|
if (isCorrect && !isFinished) {
|
||||||
toggleConfetti();
|
toggleConfetti();
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
let openExercise = false;
|
let openExercise = false;
|
||||||
let isGradeWithAI = false;
|
let isGradeWithAI = false;
|
||||||
let fetching = false;
|
let fetching = false;
|
||||||
|
let isSaving = false;
|
||||||
|
|
||||||
const submissionStatus: { [key: number]: string } = {
|
const submissionStatus: { [key: number]: string } = {
|
||||||
1: $t('course.navItem.submissions.submission_status.submitted'),
|
1: $t('course.navItem.submissions.submission_status.submitted'),
|
||||||
@@ -243,30 +244,40 @@
|
|||||||
questionAnswers: any;
|
questionAnswers: any;
|
||||||
feedback: any;
|
feedback: any;
|
||||||
}) {
|
}) {
|
||||||
|
isSaving = true;
|
||||||
const { questionAnswerByPoint, questionAnswers, feedback } = submission;
|
const { questionAnswerByPoint, questionAnswers, feedback } = submission;
|
||||||
|
|
||||||
let totalPoints = 0;
|
let totalPoints = 0;
|
||||||
|
|
||||||
const updates = Object.keys(questionAnswerByPoint).map((questionId) => {
|
for (const questionId in questionAnswerByPoint) {
|
||||||
const questionAnswer = questionAnswers.find(
|
if (Object.prototype.hasOwnProperty.call(questionAnswerByPoint, questionId)) {
|
||||||
(answer: { question_id: string }) => answer.question_id == questionId
|
const questionAnswer = questionAnswers.find(
|
||||||
);
|
(answer: { question_id: string }) => answer.question_id == questionId
|
||||||
const point = questionAnswerByPoint[questionId];
|
);
|
||||||
|
const point = questionAnswerByPoint[questionId];
|
||||||
|
|
||||||
totalPoints += parseInt(point, 10);
|
totalPoints += parseInt(point, 10);
|
||||||
|
|
||||||
return updateQuestionAnswer({ point }, { id: questionAnswer?.id });
|
const qaResponse = await updateQuestionAnswer({ point }, { id: questionAnswer?.id });
|
||||||
});
|
|
||||||
|
|
||||||
updateSubmission({
|
if (qaResponse.error) {
|
||||||
|
console.error('Error saving', qaResponse.error);
|
||||||
|
snackbar.error(`snackbar.something`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateSubmission({
|
||||||
id: submissionId,
|
id: submissionId,
|
||||||
total: totalPoints,
|
total: totalPoints,
|
||||||
feedback: feedback
|
feedback: feedback
|
||||||
}).then((res) => console.log('Updated submission', res));
|
});
|
||||||
|
|
||||||
snackbar.success('snackbar.submissions.success.grading');
|
snackbar.success('snackbar.submissions.success.grading');
|
||||||
|
|
||||||
await Promise.all(updates);
|
isSaving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function firstRender(courseId: string) {
|
async function firstRender(courseId: string) {
|
||||||
@@ -354,6 +365,7 @@
|
|||||||
{updateStatus}
|
{updateStatus}
|
||||||
deleteSubmission={handleDeleteSubmission}
|
deleteSubmission={handleDeleteSubmission}
|
||||||
bind:isGradeWithAI
|
bind:isGradeWithAI
|
||||||
|
{isSaving}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CourseContainer bind:courseId={data.courseId}>
|
<CourseContainer bind:courseId={data.courseId}>
|
||||||
|
|||||||
Reference in New Issue
Block a user