Resolved answer mapping & formatting: Enhanced quiz-logic to handle text-to-key answer resolution and updated app.js indentation/logic.
This commit is contained in:
+38
-6
@@ -507,17 +507,49 @@ function SoloQuizPage({ params, navigate }) {
|
|||||||
|
|
||||||
const checkAnswer = () => {
|
const checkAnswer = () => {
|
||||||
const rawCorrect = (q['Richtige Antwort'] || '').trim();
|
const rawCorrect = (q['Richtige Antwort'] || '').trim();
|
||||||
let correct, ok;
|
let correctKeysResolved, ok;
|
||||||
|
|
||||||
if (typ === 'freitext') {
|
if (typ === 'freitext') {
|
||||||
correct = []; setCorrectText(rawCorrect);
|
correctKeysResolved = [];
|
||||||
|
setCorrectText(rawCorrect);
|
||||||
ok = normalizeText(selected[0]) === normalizeText(rawCorrect);
|
ok = normalizeText(selected[0]) === normalizeText(rawCorrect);
|
||||||
} else {
|
} else {
|
||||||
correct = rawCorrect.split(',').map((s) => s.trim().toUpperCase()).filter(Boolean);
|
// Resolve correct answer: could be keys ("A","B") or text ("Wahr","Falsch")
|
||||||
const correctSet = new Set(correct);
|
const parts = rawCorrect.split(',').map((s) => s.trim()).filter(Boolean);
|
||||||
|
const validKeys = new Set(['A', 'B', 'C', 'D']);
|
||||||
|
const allAreKeys = parts.length > 0 && parts.every((p) => validKeys.has(p.toUpperCase()));
|
||||||
|
|
||||||
|
if (allAreKeys) {
|
||||||
|
correctKeysResolved = parts.map((p) => p.toUpperCase());
|
||||||
|
} else {
|
||||||
|
// Match text against answer options
|
||||||
|
correctKeysResolved = [];
|
||||||
|
for (const part of parts) {
|
||||||
|
const partLower = part.toLowerCase().trim();
|
||||||
|
// Search in all answers (including shuffled ones which keep their original keys)
|
||||||
|
const allAnswers = [];
|
||||||
|
['A', 'B', 'C', 'D'].forEach((k) => {
|
||||||
|
if (q[`Antwort ${k}`]) allAnswers.push({ key: k, text: q[`Antwort ${k}`] });
|
||||||
|
});
|
||||||
|
for (const ans of allAnswers) {
|
||||||
|
if (ans.text.toLowerCase().trim() === partLower) {
|
||||||
|
correctKeysResolved.push(ans.key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback
|
||||||
|
if (correctKeysResolved.length === 0) {
|
||||||
|
correctKeysResolved = parts.map((p) => p.toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const correctSet = new Set(correctKeysResolved);
|
||||||
const selectedSet = new Set(selected.map((s) => s.toUpperCase()));
|
const selectedSet = new Set(selected.map((s) => s.toUpperCase()));
|
||||||
ok = correct.length === selectedSet.size && correct.every((c) => selectedSet.has(c));
|
ok = correctKeysResolved.length === selectedSet.size && correctKeysResolved.every((c) => selectedSet.has(c));
|
||||||
}
|
}
|
||||||
setCorrectKeys(correct);
|
|
||||||
|
setCorrectKeys(correctKeysResolved);
|
||||||
setIsCorrect(ok);
|
setIsCorrect(ok);
|
||||||
setShowFeedback(true);
|
setShowFeedback(true);
|
||||||
|
|
||||||
|
|||||||
+40
-5
@@ -25,14 +25,50 @@ function checkFreitext(userAnswer, correctAnswer) {
|
|||||||
return normalizeText(userAnswer) === normalizeText(correctAnswer);
|
return normalizeText(userAnswer) === normalizeText(correctAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve correct answer(s) to keys (A/B/C/D).
|
||||||
|
* Handles both:
|
||||||
|
* - "A" or "A,C" (key-based)
|
||||||
|
* - "Falsch" or "Stuttgart" (text-based → resolved to matching key)
|
||||||
|
*/
|
||||||
function parseCorrectAnswers(question) {
|
function parseCorrectAnswers(question) {
|
||||||
const raw = (question['Richtige Antwort'] || '').trim();
|
const raw = (question['Richtige Antwort'] || '').trim();
|
||||||
const typ = getTyp(question);
|
const typ = getTyp(question);
|
||||||
if (typ === 'freitext') return [raw];
|
if (typ === 'freitext') return [raw];
|
||||||
return raw
|
|
||||||
.split(',')
|
const parts = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
||||||
.map((s) => s.trim().toUpperCase())
|
const validKeys = new Set(['A', 'B', 'C', 'D']);
|
||||||
.filter(Boolean);
|
|
||||||
|
// Check if all parts are valid keys already
|
||||||
|
const allAreKeys = parts.length > 0 && parts.every((p) => validKeys.has(p.toUpperCase()));
|
||||||
|
if (allAreKeys) {
|
||||||
|
return parts.map((p) => p.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise: try to match each part against the answer texts
|
||||||
|
const resolved = [];
|
||||||
|
for (const part of parts) {
|
||||||
|
const partLower = part.toLowerCase().trim();
|
||||||
|
const keys = ['A', 'B', 'C', 'D'];
|
||||||
|
let found = false;
|
||||||
|
for (const k of keys) {
|
||||||
|
const answerText = (question[`Antwort ${k}`] || '').trim();
|
||||||
|
if (answerText && answerText.toLowerCase() === partLower) {
|
||||||
|
resolved.push(k);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If it looks like a key anyway (single char), use it
|
||||||
|
if (!found && part.length === 1 && validKeys.has(part.toUpperCase())) {
|
||||||
|
resolved.push(part.toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved.length > 0) return resolved;
|
||||||
|
|
||||||
|
// Fallback: return as-is uppercase
|
||||||
|
return parts.map((p) => p.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
function countOptions(question) {
|
function countOptions(question) {
|
||||||
@@ -104,7 +140,6 @@ function sanitizeQuestion(question) {
|
|||||||
kategorie: extractFieldValue(question['Kategorie'], ''),
|
kategorie: extractFieldValue(question['Kategorie'], ''),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rewrite image URL to use proxy
|
|
||||||
const bild = question['Bild'];
|
const bild = question['Bild'];
|
||||||
if (bild && Array.isArray(bild) && bild.length > 0 && bild[0].url) {
|
if (bild && Array.isArray(bild) && bild.length > 0 && bild[0].url) {
|
||||||
sanitized.bild = `/api/img?url=${encodeURIComponent(bild[0].url)}`;
|
sanitized.bild = `/api/img?url=${encodeURIComponent(bild[0].url)}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user