Spaces:
Paused
Paused
| import { isListeningQuiz } from '@/utils/mockQuiz.js' | |
| function normalizeText(s) { | |
| return String(s ?? '').trim().toLowerCase() | |
| } | |
| export function isCorrectAnswer({ question, userAnswer }) { | |
| const q = question || {} | |
| // Multi-answers (gap filling, multiple-choice-many) | |
| if (Array.isArray(q.correct_answers) && q.correct_answers.length) { | |
| if (Array.isArray(userAnswer)) { | |
| const ua = userAnswer.map(normalizeText).sort().join('|') | |
| const ca = q.correct_answers.map(normalizeText).sort().join('|') | |
| return ua === ca | |
| } | |
| const ua = normalizeText(userAnswer) | |
| return q.correct_answers.some((a) => normalizeText(a) === ua) | |
| } | |
| if (q.correct_answer !== undefined && q.correct_answer !== null && q.correct_answer !== '') { | |
| return normalizeText(userAnswer) === normalizeText(q.correct_answer) | |
| } | |
| return false | |
| } | |
| export function scoreQuiz({ quiz, flat, answers }) { | |
| const detailed = [] | |
| let correct = 0 | |
| for (const item of flat) { | |
| const q = item.question | |
| const userAnswer = answers?.[q?.id] | |
| const ok = isCorrectAnswer({ question: q, userAnswer }) | |
| if (ok) correct += 1 | |
| detailed.push({ | |
| order: q?.order, | |
| questionId: q?.id, | |
| text: q?.text, | |
| userAnswer, | |
| correct_answer: q?.correct_answer, | |
| correct_answers: q?.correct_answers, | |
| isCorrect: ok, | |
| explain: q?.explain || '', | |
| }) | |
| } | |
| return { | |
| correct, | |
| total: flat.length, | |
| estimatedBand: estimateBand({ quiz, raw: correct }), | |
| detailed, | |
| } | |
| } | |
| export function estimateBand({ quiz, raw }) { | |
| const listening = isListeningQuiz(quiz) | |
| const score = Number(raw) || 0 | |
| // Approximate IELTS conversion (common Cambridge ranges). Works for both Reading/Listening. | |
| const table = listening | |
| ? [ | |
| [39, 9], [37, 8.5], [35, 8], [32, 7.5], [30, 7], [26, 6.5], [23, 6], [18, 5.5], | |
| [16, 5], [13, 4.5], [11, 4], [8, 3.5], [6, 3], [4, 2.5], [0, 2], | |
| ] | |
| : [ | |
| [39, 9], [37, 8.5], [35, 8], [33, 7.5], [30, 7], [27, 6.5], [23, 6], [19, 5.5], | |
| [15, 5], [13, 4.5], [10, 4], [8, 3.5], [6, 3], [4, 2.5], [0, 2], | |
| ] | |
| for (const [min, band] of table) { | |
| if (score >= min) return band | |
| } | |
| return 0 | |
| } | |