Admin panel sync improvements, Baserow field handling (Single Select support), and UI emoji swap

This commit is contained in:
2026-04-16 17:01:12 +02:00
parent ec7b4d1f71
commit 247cca0803
4 changed files with 111 additions and 43 deletions
+27 -13
View File
@@ -26,6 +26,23 @@ function shuffleArray(arr) {
return a;
}
/**
* Extract value from Baserow Single Select field.
* Can be { id: 6, value: "MC", color: "..." } or plain string or null.
*/
function fieldVal(field, fallback) {
if (!field) return fallback || '';
if (typeof field === 'string') return field;
if (typeof field === 'object' && field.value !== undefined) return field.value;
return String(field);
}
function normalizeText(t) {
return (t || '').toLowerCase()
.replace(/[äÄ]/g, 'ae').replace(/[öÖ]/g, 'oe').replace(/[üÜ]/g, 'ue').replace(/ß/g, 'ss')
.replace(/[^a-z0-9]/g, '');
}
/* ================================================================== */
/* Shared Components */
/* ================================================================== */
@@ -123,7 +140,7 @@ function AnswerGrid({ question, selected, onToggle, disabled }) {
function HomePage({ navigate }) {
return (
<div className="min-h-screen flex flex-col items-center justify-center p-6">
<img src="/img/logo.png" alt="Quizalarm" className="w-24 h-24 mb-2" />
<div className="text-6xl mb-2">🚨</div>
<h1 className="text-5xl font-extrabold mb-2 fire-gradient">Quizalarm</h1>
<p className="text-gray-400 mb-10 text-lg">Lernen. Quizzen. Wissen.</p>
<div className="w-full max-w-sm space-y-4">
@@ -402,6 +419,7 @@ function SoloQuizPage({ params, navigate }) {
useEffect(() => {
api.get(`/api/sets/${params.setId}/questions`).then((qs) => {
console.log(`Loaded ${qs.length} questions, sample Typ:`, qs[0]?.['Typ']);
if (params.shuffle) {
for (let i = qs.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
@@ -412,7 +430,6 @@ function SoloQuizPage({ params, navigate }) {
}).catch((e) => setError(e.message));
}, []);
// Shuffle answers when question changes
useEffect(() => {
if (questions.length === 0 || index >= questions.length) return;
const q = questions[index];
@@ -427,16 +444,14 @@ function SoloQuizPage({ params, navigate }) {
if (!questions.length) return <div className="min-h-screen flex items-center justify-center animate-pulse text-xl text-amber-400">Lade Fragen...</div>;
const q = questions[index];
const typ = (q['Typ'] || 'MC').toLowerCase();
const typ = fieldVal(q['Typ'], 'MC').toLowerCase();
const sanitized = {
frage: q['Frage'] || q['frage'] || '(Kein Fragetext)',
typ: q['Typ'] || q['typ'] || 'MC',
frage: q['Frage'] || '(Kein Fragetext)',
typ: fieldVal(q['Typ'], 'MC'),
bild: q['Bild'] && Array.isArray(q['Bild']) && q['Bild'].length ? q['Bild'][0].url : null,
antworten: shuffledAnswers,
};
const normalizeText = (t) => (t || '').toLowerCase().replace(/[äÄ]/g, 'ae').replace(/[öÖ]/g, 'oe').replace(/[üÜ]/g, 'ue').replace(/ß/g, 'ss').replace(/[^a-z0-9]/g, '');
const checkAnswer = () => {
const rawCorrect = (q['Richtige Antwort'] || '').trim();
let correct, ok;
@@ -520,11 +535,10 @@ function SoloResultPage({ params, navigate }) {
const byCategory = {};
results.forEach((r, i) => {
const q = questions[i];
const cat = (q && (q['Kategorie'] || q['kategorie'])) || 'Ohne Kategorie';
const catName = typeof cat === 'object' && cat.value ? cat.value : cat;
if (!byCategory[catName]) byCategory[catName] = { total: 0, correct: 0 };
byCategory[catName].total++;
if (r.Richtig) byCategory[catName].correct++;
const cat = fieldVal(q?.['Kategorie'], 'Ohne Kategorie') || 'Ohne Kategorie';
if (!byCategory[cat]) byCategory[cat] = { total: 0, correct: 0 };
byCategory[cat].total++;
if (r.Richtig) byCategory[cat].correct++;
});
return (
@@ -573,7 +587,7 @@ function MyResultsPage({ navigate }) {
if (results) {
results.forEach((r) => {
const sid = r['Session_ID'] || 'Unbekannt';
if (!sessions[sid]) sessions[sid] = { modus: r['Modus'], fragenset: r['Fragenset'], date: r['Zeitstempel'], answers: [] };
if (!sessions[sid]) sessions[sid] = { modus: fieldVal(r['Modus'], ''), fragenset: r['Fragenset'], date: r['Zeitstempel'], answers: [] };
sessions[sid].answers.push(r);
});
}