feat: AI grading bug (#420)
* worked on the AI grading task * worked on the AI grading task * improved the ai grading function * improved the ai grading function * update types --------- Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
7e0443fc37
commit
594eb97caa
+70
-28
@@ -93,6 +93,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getMultipleAnswersGrade = (options, answer, points) => {
|
||||||
|
const correctOptions = options
|
||||||
|
.filter((option) => option.is_correct)
|
||||||
|
.map((option) => option.value);
|
||||||
|
|
||||||
|
const correctSelections = answer.answers.filter((answer) =>
|
||||||
|
correctOptions.includes(answer)
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const incorrectSelections = answer.answers.length - correctSelections;
|
||||||
|
|
||||||
|
const pointsEarned = (correctSelections / correctOptions.length) * points;
|
||||||
|
const deduction = (incorrectSelections * points) / correctOptions.length;
|
||||||
|
const finalPoints = Math.max(pointsEarned - deduction, 0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
finalPoints,
|
||||||
|
correctOptions,
|
||||||
|
correctSelections,
|
||||||
|
incorrectSelections
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
async function handleDeleteSubmission() {
|
async function handleDeleteSubmission() {
|
||||||
isDeleting = true;
|
isDeleting = true;
|
||||||
await deleteSubmission(data.id, status.id);
|
await deleteSubmission(data.id, status.id);
|
||||||
@@ -118,18 +141,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
data?.questions.forEach((question) => {
|
data?.questions.forEach((question) => {
|
||||||
const { id, points, question_type_id } = question;
|
const { id, points, question_type_id, options } = question;
|
||||||
|
if (question_type_id == QUESTION_TYPE.RADIO) {
|
||||||
if (question_type_id !== QUESTION_TYPE.TEXTAREA) {
|
|
||||||
const answer = data.questionAnswers.find((q) => q.question_id === id);
|
const answer = data.questionAnswers.find((q) => q.question_id === id);
|
||||||
|
|
||||||
const answerPoints = answer?.answers?.length ?? 0;
|
const answerPoints = answer?.answers?.length ?? 0;
|
||||||
|
|
||||||
reasons = {
|
reasons = {
|
||||||
...reasons,
|
...reasons,
|
||||||
[id]: `${$t(
|
[id]: `${$t('course.navItem.submissions.grading_modal.allocated')} ${$t(
|
||||||
'course.navItem.submissions.grading_modal.questions_tried'
|
'course.navItem.submissions.grading_modal.total_try'
|
||||||
)} ${answerPoints} `
|
)} ${answerPoints} `
|
||||||
};
|
};
|
||||||
data.questionAnswerByPoint[id] = `${Math.ceil(points / answerPoints)}`;
|
data.questionAnswerByPoint[id] = `${Math.ceil(points / answerPoints)}`;
|
||||||
|
} else if (question_type_id == QUESTION_TYPE.CHECKBOX) {
|
||||||
|
const answer = data.questionAnswers.find((q) => q.question_id === id);
|
||||||
|
|
||||||
|
const { finalPoints, correctOptions, correctSelections, incorrectSelections } =
|
||||||
|
getMultipleAnswersGrade(options, answer, points);
|
||||||
|
|
||||||
|
reasons = {
|
||||||
|
...reasons,
|
||||||
|
[id]: `${$t(
|
||||||
|
'course.navItem.submissions.grading_modal.allocated'
|
||||||
|
)} ${correctSelections} ${$t('course.navItem.submissions.grading_modal.out_of')} ${
|
||||||
|
correctOptions.length
|
||||||
|
} ${$t('course.navItem.submissions.grading_modal.options_correct')} ${$t(
|
||||||
|
'course.navItem.submissions.grading_modal.options_wrong'
|
||||||
|
)} ${incorrectSelections} `
|
||||||
|
};
|
||||||
|
|
||||||
|
data.questionAnswerByPoint[id] = `${finalPoints}`;
|
||||||
} else if (aiResponses.length) {
|
} else if (aiResponses.length) {
|
||||||
const graded = aiResponses.find((res) => res.id === id);
|
const graded = aiResponses.find((res) => res.id === id);
|
||||||
|
|
||||||
@@ -182,10 +224,10 @@
|
|||||||
headerClass="py-2"
|
headerClass="py-2"
|
||||||
labelClass="text-base font-semibold"
|
labelClass="text-base font-semibold"
|
||||||
>
|
>
|
||||||
<div class="w-full h-full mt-2">
|
<div class="mt-2 h-full w-full">
|
||||||
{#if openDeletePrompt}
|
{#if openDeletePrompt}
|
||||||
<div class="w-96 mx-auto p-3 border border-gray-300 rounded-md">
|
<div class="mx-auto w-96 rounded-md border border-gray-300 p-3">
|
||||||
<h1 class="dark:text-white text-lg">
|
<h1 class="text-lg dark:text-white">
|
||||||
{$t('delete_modal.content')}
|
{$t('delete_modal.content')}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -223,19 +265,19 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4 mt-2 w-2/5 sticky top-0">
|
<div class="sticky top-0 ml-4 mt-2 w-2/5">
|
||||||
<div class="border border-gray-300 rounded-md">
|
<div class="rounded-md border border-gray-300">
|
||||||
<div
|
<div
|
||||||
class="flex gap-1 justify-between items-center border-b border-t-0 border-l-0 border-r-0 border-gray-300 p-3"
|
class="flex items-center justify-between gap-1 border-b border-l-0 border-r-0 border-t-0 border-gray-300 p-3"
|
||||||
>
|
>
|
||||||
<p class="dark:text-white font-bold text-base">
|
<p class="text-base font-bold dark:text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.details')}
|
{$t('course.navItem.submissions.grading_modal.details')}
|
||||||
{#if data.isEarly}
|
{#if data.isEarly}
|
||||||
<span class="ml-2 text-sm badge rounded-sm px-2 bg-green-500 text-white">
|
<span class="badge ml-2 rounded-sm bg-green-500 px-2 text-sm text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.early')}</span
|
{$t('course.navItem.submissions.grading_modal.early')}</span
|
||||||
>
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="ml-2 badge text-sm rounded-sm px-2 bg-red-500 text-white">
|
<span class="badge ml-2 rounded-sm bg-red-500 px-2 text-sm text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.late')}
|
{$t('course.navItem.submissions.grading_modal.late')}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -253,13 +295,13 @@
|
|||||||
</OverflowMenu>
|
</OverflowMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center space-x-4 text-sm px-3 py-2">
|
<div class="flex items-center space-x-4 px-3 py-2 text-sm">
|
||||||
<p class="dark:text-white text-sm text-gray-500 font-semibold">
|
<p class="text-sm font-semibold text-gray-500 dark:text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.total_grade')}:
|
{$t('course.navItem.submissions.grading_modal.total_grade')}:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Tag
|
<Tag
|
||||||
class="dark:text-white font-semibold text-black bg-gray-100 dark:bg-neutral-700 rounded-md w-fit"
|
class="w-fit rounded-md bg-gray-100 font-semibold text-black dark:bg-neutral-700 dark:text-white"
|
||||||
>
|
>
|
||||||
{total}/{maxPoints}
|
{total}/{maxPoints}
|
||||||
</Tag>
|
</Tag>
|
||||||
@@ -271,20 +313,20 @@
|
|||||||
<p class="dark:text-white">Grading</p>
|
<p class="dark:text-white">Grading</p>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="flex items-center space-x-4 text-sm px-3 py-2">
|
<div class="flex items-center space-x-4 px-3 py-2 text-sm">
|
||||||
<p class="dark:text-white text-sm text-gray-500 font-semibold">
|
<p class="text-sm font-semibold text-gray-500 dark:text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.student')}:
|
{$t('course.navItem.submissions.grading_modal.student')}:
|
||||||
</p>
|
</p>
|
||||||
{#if data.student}
|
{#if data.student}
|
||||||
<div
|
<div
|
||||||
class="flex flex-row justify-center items-center bg-gray-100 dark:bg-neutral-700 rounded-md p-[6px]"
|
class="flex flex-row items-center justify-center rounded-md bg-gray-100 p-[6px] dark:bg-neutral-700"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Student avatar"
|
alt="Student avatar"
|
||||||
class="flex rounded-full h-5 w-5"
|
class="flex h-5 w-5 rounded-full"
|
||||||
src={data.student.avatar_url}
|
src={data.student.avatar_url}
|
||||||
/>
|
/>
|
||||||
<p class="dark:text-white font-semibold ml-2 text-sm line-clamp-1">
|
<p class="ml-2 line-clamp-1 text-sm font-semibold dark:text-white">
|
||||||
{data.student.fullname}
|
{data.student.fullname}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -298,8 +340,8 @@
|
|||||||
>
|
>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<div class="flex flex-col items-start text-sm px-3 py-2">
|
<div class="flex flex-col items-start px-3 py-2 text-sm">
|
||||||
<p class="dark:text-white text-gray-500 font-semibold">
|
<p class="font-semibold text-gray-500 dark:text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.status')}:
|
{$t('course.navItem.submissions.grading_modal.status')}:
|
||||||
</p>
|
</p>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@@ -310,8 +352,8 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-start text-sm px-3 py-2">
|
<div class="flex flex-col items-start px-3 py-2 text-sm">
|
||||||
<p class="dark:text-white text-gray-500 font-semibold">
|
<p class="font-semibold text-gray-500 dark:text-white">
|
||||||
{$t('course.navItem.submissions.grading_modal.add_comment')}:
|
{$t('course.navItem.submissions.grading_modal.add_comment')}:
|
||||||
</p>
|
</p>
|
||||||
<TextArea
|
<TextArea
|
||||||
@@ -322,14 +364,14 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col w-full space-y-3 px-3 py-2">
|
<div class="flex w-full flex-col space-y-3 px-3 py-2">
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
onClick={gradeWithAI}
|
onClick={gradeWithAI}
|
||||||
variant={VARIANTS.OUTLINED}
|
variant={VARIANTS.OUTLINED}
|
||||||
className="space-x-3 py-3 px-8 w-full "
|
className="space-x-3 py-3 px-8 w-full "
|
||||||
>
|
>
|
||||||
<img src="/ai.svg" alt="ai" />
|
<img src="/ai.svg" alt="ai" />
|
||||||
<p class="font-semibold text-sm">
|
<p class="text-sm font-semibold">
|
||||||
{$t('course.navItem.submissions.grading_modal.grade_with_ai')}
|
{$t('course.navItem.submissions.grading_modal.grade_with_ai')}
|
||||||
</p>
|
</p>
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Akzeptieren",
|
"accept_grade": "Akzeptieren",
|
||||||
"reject_grade": "Ablehnen",
|
"reject_grade": "Ablehnen",
|
||||||
"add_comment_placeholder": "Hinterlasse einen Kommentar",
|
"add_comment_placeholder": "Hinterlasse einen Kommentar",
|
||||||
|
"allocated": "Diese Punktzahl wurde vergeben, weil",
|
||||||
|
"total_try": "der Gesamtversuche:",
|
||||||
|
"options_correct": "Es wurden die richtigen Optionen ausgewählt",
|
||||||
|
"out_of": "aus",
|
||||||
|
"options_wrong": "und die Anzahl der falschen Auswahlen war",
|
||||||
"questions_tried": "Diese Punktzahl wurde aufgrund der Gesamtzahl der Versuche vergeben:",
|
"questions_tried": "Diese Punktzahl wurde aufgrund der Gesamtzahl der Versuche vergeben:",
|
||||||
"delete_prompt": "Löschen",
|
"delete_prompt": "Löschen",
|
||||||
"delete_error": "Die Übermittlung konnte nicht gelöscht werden",
|
"delete_error": "Die Übermittlung konnte nicht gelöscht werden",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "Sie haben nicht gerettete Änderungen. Bist du sicher, dass du gehen willst?"
|
"message": "Sie haben nicht gerettete Änderungen. Bist du sicher, dass du gehen willst?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -912,6 +912,11 @@
|
|||||||
"submit_grades": "Submit Grades",
|
"submit_grades": "Submit Grades",
|
||||||
"accept_grade": "Accept",
|
"accept_grade": "Accept",
|
||||||
"reject_grade": "Reject",
|
"reject_grade": "Reject",
|
||||||
|
"allocated": "Allocated this score because",
|
||||||
|
"total_try": "of total tries:",
|
||||||
|
"options_correct": "correct options were selected",
|
||||||
|
"out_of": "out of",
|
||||||
|
"options_wrong": "and the number of wrong selections were",
|
||||||
"questions_tried": "Allocated this score because of total tries:",
|
"questions_tried": "Allocated this score because of total tries:",
|
||||||
"delete_prompt": "Delete",
|
"delete_prompt": "Delete",
|
||||||
"delete_error": "Failed to delete submission",
|
"delete_error": "Failed to delete submission",
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Aceptar",
|
"accept_grade": "Aceptar",
|
||||||
"reject_grade": "Rechazar",
|
"reject_grade": "Rechazar",
|
||||||
"add_comment_placeholder": "Deja un comentario",
|
"add_comment_placeholder": "Deja un comentario",
|
||||||
|
"allocated": "Asignó esta puntuación porque",
|
||||||
|
"total_try": "de intentos totales:",
|
||||||
|
"options_correct": "se seleccionaron las opciones correctas",
|
||||||
|
"out_of": "fuera de",
|
||||||
|
"options_wrong": "y el número de selecciones incorrectas fue",
|
||||||
"questions_tried": "Se asignó esta puntuación debido al total de intentos:",
|
"questions_tried": "Se asignó esta puntuación debido al total de intentos:",
|
||||||
"delete_prompt": "Borrar",
|
"delete_prompt": "Borrar",
|
||||||
"delete_error": "No se pudo eliminar el envío",
|
"delete_error": "No se pudo eliminar el envío",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "Tienes cambios no salvos. ¿Estás seguro de que quieres irte?"
|
"message": "Tienes cambios no salvos. ¿Estás seguro de que quieres irte?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Accepter",
|
"accept_grade": "Accepter",
|
||||||
"reject_grade": "Rejeter",
|
"reject_grade": "Rejeter",
|
||||||
"add_comment_placeholder": "laissez un commentaire",
|
"add_comment_placeholder": "laissez un commentaire",
|
||||||
|
"allocated": "J'ai attribué ce score parce que",
|
||||||
|
"total_try": "du total d'essais :",
|
||||||
|
"options_correct": "les bonnes options ont été sélectionnées",
|
||||||
|
"out_of": "hors de",
|
||||||
|
"options_wrong": "et le nombre de mauvaises sélections était",
|
||||||
"questions_tried": "Attribué ce score en raison du nombre total d'essais :",
|
"questions_tried": "Attribué ce score en raison du nombre total d'essais :",
|
||||||
"delete_prompt": "Supprimer",
|
"delete_prompt": "Supprimer",
|
||||||
"delete_error": "Échec de la suppression de la soumission",
|
"delete_error": "Échec de la suppression de la soumission",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "Vous avez des changements non sauvés. Êtes-vous sûr de vouloir partir?"
|
"message": "Vous avez des changements non sauvés. Êtes-vous sûr de vouloir partir?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "स्वीकार करना",
|
"accept_grade": "स्वीकार करना",
|
||||||
"reject_grade": "अस्वीकार करना",
|
"reject_grade": "अस्वीकार करना",
|
||||||
"add_comment_placeholder": "एक टिप्पणी छोड़ें",
|
"add_comment_placeholder": "एक टिप्पणी छोड़ें",
|
||||||
|
"allocated": "यह अंक इसलिए आवंटित किया गया क्योंकि",
|
||||||
|
"total_try": "कुल प्रयासों में से:",
|
||||||
|
"options_correct": "सही विकल्प का चयन किया गया",
|
||||||
|
"out_of": "से बाहर",
|
||||||
|
"options_wrong": "और गलत चयनों की संख्या थी",
|
||||||
"questions_tried": "कुल प्रयासों के कारण यह स्कोर आवंटित किया गया:",
|
"questions_tried": "कुल प्रयासों के कारण यह स्कोर आवंटित किया गया:",
|
||||||
"delete_prompt": "मिटाना",
|
"delete_prompt": "मिटाना",
|
||||||
"delete_error": "सबमिशन हटाने में विफल",
|
"delete_error": "सबमिशन हटाने में विफल",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "आपके पास अनसुना परिवर्तन हैं। क्या आपकी वाकई छोड़ने की इच्छा है?"
|
"message": "आपके पास अनसुना परिवर्तन हैं। क्या आपकी वाकई छोड़ने की इच्छा है?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Aceitar",
|
"accept_grade": "Aceitar",
|
||||||
"reject_grade": "Rejeitar",
|
"reject_grade": "Rejeitar",
|
||||||
"add_comment_placeholder": "Deixe um comentário",
|
"add_comment_placeholder": "Deixe um comentário",
|
||||||
|
"allocated": "Alocou esta pontuação porque",
|
||||||
|
"total_try": "do total de tentativas:",
|
||||||
|
"options_correct": "opções corretas foram selecionadas",
|
||||||
|
"out_of": "fora de",
|
||||||
|
"options_wrong": "e o número de seleções erradas foi",
|
||||||
"questions_tried": "Alocada esta pontuação por causa do total de tentativas:",
|
"questions_tried": "Alocada esta pontuação por causa do total de tentativas:",
|
||||||
"delete_prompt": "Excluir",
|
"delete_prompt": "Excluir",
|
||||||
"delete_error": "Falha ao excluir o envio",
|
"delete_error": "Falha ao excluir o envio",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "Você tem mudanças não salvas. Tem certeza de que deseja sair?"
|
"message": "Você tem mudanças não salvas. Tem certeza de que deseja sair?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Принимать",
|
"accept_grade": "Принимать",
|
||||||
"reject_grade": "Отклонять",
|
"reject_grade": "Отклонять",
|
||||||
"add_comment_placeholder": "Оставить комментарий",
|
"add_comment_placeholder": "Оставить комментарий",
|
||||||
|
"allocated": "Присвоен этот балл, потому что",
|
||||||
|
"total_try": "общего числа попыток:",
|
||||||
|
"options_correct": "выбраны правильные варианты",
|
||||||
|
"out_of": "снаружи",
|
||||||
|
"options_wrong": "и количество неправильных выборов было",
|
||||||
"questions_tried": "Присвоен этот балл из-за общего количества попыток:",
|
"questions_tried": "Присвоен этот балл из-за общего количества попыток:",
|
||||||
"delete_prompt": "Удалить",
|
"delete_prompt": "Удалить",
|
||||||
"delete_error": "Не удалось удалить отправку",
|
"delete_error": "Не удалось удалить отправку",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "У вас есть неспасенные изменения. Вы уверены, что хотите уйти?"
|
"message": "У вас есть неспасенные изменения. Вы уверены, что хотите уйти?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,6 +515,11 @@
|
|||||||
"accept_grade": "Chấp nhận",
|
"accept_grade": "Chấp nhận",
|
||||||
"reject_grade": "Từ chối",
|
"reject_grade": "Từ chối",
|
||||||
"add_comment_placeholder": "Để lại một bình luận",
|
"add_comment_placeholder": "Để lại một bình luận",
|
||||||
|
"allocated": "Phân bổ số điểm này bởi vì",
|
||||||
|
"total_try": "trong tổng số lần thử:",
|
||||||
|
"options_correct": "các phương án đúng đã được chọn",
|
||||||
|
"out_of": "ra khỏi",
|
||||||
|
"options_wrong": "và số lựa chọn sai là",
|
||||||
"questions_tried": "Phân bổ số điểm này dựa trên tổng số lần thử:",
|
"questions_tried": "Phân bổ số điểm này dựa trên tổng số lần thử:",
|
||||||
"delete_prompt": "Xóa bỏ",
|
"delete_prompt": "Xóa bỏ",
|
||||||
"delete_error": "Không thể xóa bài nộp",
|
"delete_error": "Không thể xóa bài nộp",
|
||||||
@@ -1581,4 +1586,4 @@
|
|||||||
"message": "Bạn có những thay đổi chưa được lưu. Bạn có chắc bạn muốn rời đi?"
|
"message": "Bạn có những thay đổi chưa được lưu. Bạn có chắc bạn muốn rời đi?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Profile } from '.';
|
import { Option, Profile } from '.';
|
||||||
|
|
||||||
export interface SubmissionItem {
|
export interface SubmissionItem {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -37,6 +37,7 @@ export interface SubmissionIdData {
|
|||||||
order: number;
|
order: number;
|
||||||
points: number;
|
points: number;
|
||||||
question_type_id: number;
|
question_type_id: number;
|
||||||
|
options: Option[];
|
||||||
}[];
|
}[];
|
||||||
questionAnswers: {
|
questionAnswers: {
|
||||||
open_answer: string;
|
open_answer: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user