From d57313084ff8b11785cb8b092cb66a6c145fac68 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 27 May 2026 13:46:06 +0200 Subject: [PATCH] fix: robust placeholder resolution + readable pair cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolvePlaceholders: replace fragile [wo] char class with general /^(.+?)\.[a-z]+:[0-9a-f-]{36}$/i — handles any type prefix safely - Add sync stripPlaceholders() helper for card display (no async needed) - PairsPanel cards now show actual sentence text instead of UUID stubs, using enriched pair.question / pair.positive_statement data from API Co-Authored-By: Claude Sonnet 4.6 --- src/pages/ContentCreation.jsx | 59 ++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/src/pages/ContentCreation.jsx b/src/pages/ContentCreation.jsx index 88d2008..b1621fd 100644 --- a/src/pages/ContentCreation.jsx +++ b/src/pages/ContentCreation.jsx @@ -31,26 +31,42 @@ function withPlaceholders(text, wordMap, objectAssignments = {}) { return result; } +// Sync helper — strips placeholders to their label for display (no async needed) +function stripPlaceholders(text) { + if (!text) return ''; + return text.replace(/\{\{([^}]+)\}\}/g, (_, inner) => { + // New format: "label.type:uuid" + const m = inner.match(/^(.+?)\.[a-z]+:[0-9a-f-]{36}$/i); + return m ? m[1] : inner; + }); +} + async function resolvePlaceholders(text, allObjects) { if (!text) return ''; - // New format: {{label.w:uuid}} or {{label.o:uuid}} — label is embedded, no lookup needed - text = text.replace(/\{\{([^.}]+)\.[wo]:([^}]+)\}\}/g, (_, label) => label); - // Old format fallback: {{uuid}} - const matches = [...text.matchAll(/\{\{([^}]+)\}\}/g)]; - if (!matches.length) return text; - const uuids = [...new Set(matches.map(m => m[1]))]; + const oldUuids = []; + // Single pass: handle both new and old format + let result = text.replace(/\{\{([^}]+)\}\}/g, (fullMatch, inner) => { + // New format: "label.type:uuid" — extract label directly, no lookup needed + const newFmt = inner.match(/^(.+?)\.[a-z]+:([0-9a-f-]{36})$/i); + if (newFmt) return newFmt[1]; + // Old format: bare uuid — collect for async lookup + const oldFmt = inner.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i); + if (oldFmt) { oldUuids.push(inner); return fullMatch; } + return inner; + }); + if (!oldUuids.length) return result; + // Resolve remaining bare UUIDs const idMap = {}; (allObjects || []).forEach(obj => { - if (uuids.includes(obj.id)) { - const label = (obj._words || []).slice(0, 2).map(w => w.titel_de).filter(Boolean).join('/') || 'Objekt'; - idMap[obj.id] = label; + if (oldUuids.includes(obj.id)) { + idMap[obj.id] = (obj._words || []).slice(0, 2).map(w => w.titel_de).filter(Boolean).join('/') || 'Objekt'; } }); - await Promise.all(uuids.filter(id => !idMap[id]).map(async id => { + await Promise.all(oldUuids.filter(id => !idMap[id]).map(async id => { try { const w = await apiFetch(`/words/${id}`); if (w) idMap[id] = w.titel_de || w.titel_en || id; } catch { idMap[id] = id; } })); - return text.replace(/\{\{([^}]+)\}\}/g, (_, id) => idMap[id] || id); + return result.replace(/\{\{([^}]+)\}\}/g, (_, id) => idMap[id] || id); } // ─── Fuzzy word matching ────────────────────────────────────────────────────── @@ -842,9 +858,24 @@ function PairsPanel({ selectedObject, allObjects, objectPairs, loadingPairs, onP - {pair.question_id &&

F: {pair.question_id.slice(0,8)}…

} - {pair.positive_statement_id &&

+ {pair.positive_statement_id.slice(0,8)}…

} - {pair.negative_statement_id &&

− {pair.negative_statement_id.slice(0,8)}…

} + {pair.question && ( +

+ F: + {stripPlaceholders(pair.question.sentence_de || pair.question.sentence_en || '')} +

+ )} + {pair.positive_statement && (pair.positive_statement.positive_sentence_de || pair.positive_statement.positive_sentence_en) && ( +

+ + + {stripPlaceholders(pair.positive_statement.positive_sentence_de || pair.positive_statement.positive_sentence_en || '')} +

+ )} + {pair.negative_statement && (pair.negative_statement.negative_sentence_de || pair.negative_statement.negative_sentence_en) && ( +

+ + {stripPlaceholders(pair.negative_statement.negative_sentence_de || pair.negative_statement.negative_sentence_en || '')} +

+ )} )}