Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 31x 31x 31x 56x 29x 29x 24x 24x 23x 11x 13x 13x 13x 52x 13x | /**
* Pure transforms for the teacher Item Analysis table.
*
* Extracted from AnalysisTable.jsx so the response→row mapping can be unit
* tested without pulling in MaterialReactTable.
*
* Backend response shape (per question):
* {
* question_type, category, student_expectation, correct_answer, points,
* total_correct, total_incorrect, // percentage strings, e.g. "100.0%"
* student_answers: [{ letter, text, total }] // total = % of students who picked it
* }
*
* Developer: Allan Ninal
*/
/**
* Extracts a display-ready HTML string from a choice/answer entry: an
* erudition-math editor document ({ blocks: [...] }), a JSON-encoded blocks
* document ({ text: "..." }), or a plain HTML/text string.
*
* Math-editor formulas are stored inline as pre-rendered
* `<span class="mfe-formula" data-latex="…">…</span>` markup (MathLive's
* static output, produced by src/lib/tinymce/plugins/math-formula/plugin.js).
* That markup is returned as-is — the caller is responsible for sanitizing it
* with sanitizeRichText before dangerouslySetInnerHTML — so the table can
* render an actual rendered formula instead of collapsing it to its raw LaTeX
* source text.
*
* @param {Object|string} content
* @returns {string} HTML (or plain text) content, or "NA" when empty/unparseable
*/
export function extractContentHtml(content) {
Iif (!content) return "NA";
Eif (typeof content === "string") {
return content.trim() || "NA";
}
if (typeof content === "object") {
if (Array.isArray(content.blocks)) {
const html = content.blocks
.map((block) => block?.data?.text || "")
.join(" ")
.trim();
return html || "NA";
}
if (typeof content.text === "string") {
try {
const parsed = JSON.parse(content.text);
if (parsed && Array.isArray(parsed.blocks)) {
const html = parsed.blocks
.map((block) => block?.data?.text || "")
.join(" ")
.trim();
return html || "NA";
}
} catch {
// Not JSON — fall through to treating it as raw HTML/text below.
}
return content.text.trim() || "NA";
}
}
return "NA";
}
/**
* Builds a single answer-choice cell's HTML, combining the choice content
* with the percentage of students who selected it, e.g. "6 — 100.0%" (or the
* choice's rendered math markup followed by the same suffix).
*
* Returns "NA" for non-applicable choices (e.g. free-response placeholders,
* where the backend sends a {letter:"NA", text:"NA"} slot).
* @param {{letter?: string, text?: string|Object, total?: string|number}} option
* @returns {string} HTML string — sanitize before rendering
*/
export function formatChoiceCell(option) {
if (!option) return "NA";
const html = extractContentHtml(option.text);
if (html === "NA") return "NA";
const total = option.total;
if (total === undefined || total === null || total === "") return html;
return `${html} — ${total}`;
}
/**
* Maps the item-analysis API response into table rows.
* @param {{item_analysis: Array}} entry
* @returns {Array<Object>}
*/
export function transformData(entry) {
return (entry?.item_analysis || []).map((item, idx) => {
const answers = item.student_answers || [];
const answerCells = [];
for (let i = 0; i < 4; i++) {
answerCells[i] = formatChoiceCell(answers[i]);
}
return {
question_number: (idx + 1).toString(),
question_type: item.question_type,
category: item.category || "NA",
student_expectations: item.student_expectation || "NA",
answer_choiceA: answerCells[0],
answer_choiceB: answerCells[1],
answer_choiceC: answerCells[2],
answer_choiceD: answerCells[3],
correct_answer: item.correct_answer || "NA",
points: item.points || "NA",
percent_correct: item.total_correct,
percent_incorrect: item.total_incorrect,
};
});
}
|