chore: simplify grading for self paced course (#326)
* updated the grading flow for self paced course * updated some logic and translations * fix bug with newsfeed not opening for students and fix more bugs * remove console * add blog template route * add doc page --------- Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
import TextareaQuestion from '$lib/components/Question/TextareaQuestion/index.svelte';
|
||||
import { QUESTION_TYPE } from '$lib/components/Question/constants';
|
||||
import { getPropsForQuestion } from './functions';
|
||||
import { course } from '$lib/components/Course/store';
|
||||
import { COURSE_TYPE } from '$lib/utils/types';
|
||||
|
||||
export let questions = [];
|
||||
export let questionnaireMetaData = {};
|
||||
@@ -37,6 +39,7 @@
|
||||
handleGrade={handleGrade(currentQuestion.id)}
|
||||
{disableGrading}
|
||||
disabled={true}
|
||||
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
|
||||
/>
|
||||
{:else if QUESTION_TYPE.CHECKBOX === currentQuestion.question_type.id}
|
||||
<CheckboxQuestion
|
||||
@@ -57,6 +60,7 @@
|
||||
handleGrade={handleGrade(currentQuestion.id)}
|
||||
{disableGrading}
|
||||
disabled={true}
|
||||
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
|
||||
/>
|
||||
{:else if QUESTION_TYPE.TEXTAREA === currentQuestion.question_type.id}
|
||||
<TextareaQuestion
|
||||
@@ -77,6 +81,7 @@
|
||||
handleGrade={handleGrade(currentQuestion.id)}
|
||||
{disableGrading}
|
||||
disabled={true}
|
||||
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
+19
-114
@@ -17,11 +17,7 @@
|
||||
import { getPropsForQuestion, filterOutDeleted, wasCorrectAnswerSelected } from './functions';
|
||||
import { formatAnswers, getGroupMemberId } from '$lib/components/Course/function';
|
||||
import { submitExercise } from '$lib/utils/services/courses';
|
||||
import {
|
||||
fetchSubmission,
|
||||
updateQuestionAnswer,
|
||||
updateSubmission
|
||||
} from '$lib/utils/services/submissions';
|
||||
import { fetchSubmission } from '$lib/utils/services/submissions';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { currentOrg } from '$lib/utils/store/org';
|
||||
import {
|
||||
@@ -30,9 +26,8 @@
|
||||
} from '$lib/utils/services/notification/notification';
|
||||
import { lesson } from '../store/lessons';
|
||||
import { browser } from '$app/environment';
|
||||
import { useCompletion } from 'ai/svelte';
|
||||
import { COURSE_TYPE } from '$lib/utils/types';
|
||||
import GradingLoader from './GradingLoader.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
|
||||
export let preview: boolean = false;
|
||||
export let exerciseId = '';
|
||||
@@ -44,10 +39,7 @@
|
||||
let hasSubmission = false;
|
||||
let isLoadingAutoSavedData = false;
|
||||
let alreadyCheckedAutoSavedData = false;
|
||||
let gradedComment = true;
|
||||
let isLoading = false;
|
||||
let submissionResponse;
|
||||
let submissionId;
|
||||
|
||||
function handleStart() {
|
||||
$questionnaireMetaData.currentQuestionIndex += 1;
|
||||
@@ -88,89 +80,7 @@
|
||||
});
|
||||
};
|
||||
|
||||
const { input, handleSubmit, completion } = useCompletion({
|
||||
api: '/api/completion/gradingprompt',
|
||||
onFinish: async () => {
|
||||
try {
|
||||
const responseData = $completion.replace('```json', '').replace('```', '');
|
||||
|
||||
let aiResponses = [];
|
||||
try {
|
||||
// Parse the modified response data as JSON
|
||||
aiResponses = JSON.parse(responseData);
|
||||
} catch (error) {
|
||||
console.error('Error parsing AI response', error);
|
||||
}
|
||||
|
||||
$questionnaire.questions.forEach((question) => {
|
||||
const { id, points, question_type_id } = question;
|
||||
let questionAnswer = submissionResponse?.res?.data.find(
|
||||
(answer) => answer.question_id === id
|
||||
);
|
||||
|
||||
console.log('this is the question answer', questionAnswer);
|
||||
if (question_type_id !== QUESTION_TYPE.TEXTAREA) {
|
||||
const answer = $questionnaireMetaData.answers[question.name];
|
||||
let score = points / answer.length;
|
||||
$questionnaireMetaData.grades = {
|
||||
...$questionnaireMetaData.grades,
|
||||
[id]: score
|
||||
};
|
||||
updateQuestionAnswer({ point: score }, { id: questionAnswer?.id });
|
||||
} else if (aiResponses.length) {
|
||||
const graded = aiResponses.find((res) => res.id === id);
|
||||
|
||||
$questionnaireMetaData.grades = {
|
||||
...$questionnaireMetaData.grades,
|
||||
[id]: graded.score
|
||||
};
|
||||
updateQuestionAnswer({ point: graded.score }, { id: questionAnswer?.id });
|
||||
}
|
||||
});
|
||||
|
||||
$questionnaireMetaData.finalTotalGrade = Object.values(
|
||||
$questionnaireMetaData.grades
|
||||
).reduce((acc, answer): number => {
|
||||
return acc + answer;
|
||||
}, 0);
|
||||
|
||||
updateSubmission({
|
||||
id: submissionId,
|
||||
status_id: STATUS.GRADED,
|
||||
total: $questionnaireMetaData.finalTotalGrade
|
||||
});
|
||||
|
||||
$questionnaireMetaData.status = STATUS.GRADED;
|
||||
console.log('grade', $questionnaireMetaData.finalTotalGrade);
|
||||
} catch (error) {
|
||||
console.error('Error', error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function automaticGrading(answers, questions) {
|
||||
const paragraphAiInput = questions
|
||||
.filter((q) => q.question_type_id === QUESTION_TYPE.TEXTAREA)
|
||||
.map((q) => {
|
||||
const answer = answers?.answers[q.name]; // { open_answer: '' }
|
||||
return {
|
||||
id: q.id,
|
||||
question: q.title,
|
||||
answer: answer,
|
||||
point: q.points
|
||||
};
|
||||
});
|
||||
$input = JSON.stringify(paragraphAiInput);
|
||||
handleSubmit({ preventDefault: () => {} });
|
||||
}
|
||||
|
||||
async function onSubmit(id, value) {
|
||||
if ($course.type === COURSE_TYPE.SELF_PACED) {
|
||||
isLoading = true;
|
||||
}
|
||||
|
||||
const { answers } = $questionnaireMetaData;
|
||||
const { questions } = $questionnaire;
|
||||
const prevAnswer = answers[id] || [];
|
||||
@@ -220,11 +130,6 @@
|
||||
);
|
||||
if (response) {
|
||||
submissionResponse = response;
|
||||
submissionId = submissionResponse.submission[0]?.id;
|
||||
}
|
||||
|
||||
if ($course.type === COURSE_TYPE.SELF_PACED) {
|
||||
automaticGrading($questionnaireMetaData, $questionnaire.questions);
|
||||
}
|
||||
|
||||
notifyEducator();
|
||||
@@ -316,10 +221,6 @@
|
||||
alreadyCheckedAutoSavedData = true;
|
||||
}
|
||||
|
||||
const toggleComments = () => {
|
||||
gradedComment = !gradedComment;
|
||||
};
|
||||
|
||||
$: browser && !alreadyCheckedAutoSavedData && getAutoSavedData();
|
||||
|
||||
// Reactive code
|
||||
@@ -406,42 +307,46 @@
|
||||
</div>
|
||||
</RoleBasedSecurity>
|
||||
{:else if $questionnaireMetaData.isFinished}
|
||||
{#if isLoading}
|
||||
<GradingLoader />
|
||||
{:else if !isLoading && !isLoadingAutoSavedData}
|
||||
{#if !isLoadingAutoSavedData}
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-col lg:flex-row items-start lg:items-center lg:space-x-4 w-full">
|
||||
<h2 class="text-xl font-normal">{$questionnaire.title}</h2>
|
||||
|
||||
{#if STATUS.GRADED === $questionnaireMetaData.status}
|
||||
<span
|
||||
class="status-text bg-green-700 text-white py-1 px-2 text-center"
|
||||
title="Status: Pending Review"
|
||||
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_graded')}
|
||||
>
|
||||
Graded
|
||||
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.graded')}
|
||||
</span>
|
||||
{:else if $course.type === COURSE_TYPE.SELF_PACED}
|
||||
<span
|
||||
class="status-text bg-green-700 text-white py-1 px-2 text-center"
|
||||
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_submitted')}
|
||||
>
|
||||
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.submitted')}
|
||||
</span>
|
||||
{:else}
|
||||
<span
|
||||
class="status-text bg-yellow-600 text-white py-1 px-2 text-center"
|
||||
title="Status: Pending Review"
|
||||
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_pending')}
|
||||
>
|
||||
Pending
|
||||
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.pending')}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if STATUS.GRADED === $questionnaireMetaData.status}
|
||||
{#if STATUS.GRADED === $questionnaireMetaData.status && $course.type !== COURSE_TYPE.SELF_PACED}
|
||||
<span
|
||||
class="p-6 border-2 border-gray-300 bg-[#F5F8FE] rounded-full h-10 w-10 flex items-center justify-center text-[#2751DA] text-sm font-semibold"
|
||||
title="Status: Pending Review"
|
||||
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_graded')}
|
||||
>
|
||||
{$questionnaireMetaData.finalTotalGrade}/{$questionnaireMetaData.totalPossibleGrade}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if $questionnaireMetaData.status === STATUS.GRADED && $questionnaireMetaData.comment}
|
||||
<div
|
||||
class="flex items-center justify-between bg-primary-700 p-4 text-white font-semibold rounded-sm mt-3"
|
||||
>
|
||||
{#if $questionnaireMetaData.status === STATUS.GRADED && $questionnaireMetaData.comment && $course.type !== COURSE_TYPE.SELF_PACED}
|
||||
<div class="flex items-center justify-between bg-primary-700 p-4 text-white rounded-sm mt-3">
|
||||
<span> {$questionnaireMetaData.comment}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user