diff --git a/src/pages/ContentCreation.jsx b/src/pages/ContentCreation.jsx index 31d8297..0fd24d2 100644 --- a/src/pages/ContentCreation.jsx +++ b/src/pages/ContentCreation.jsx @@ -6,15 +6,21 @@ import { STATUS_COLORS } from '../lib/tables'; // ─── Word / placeholder helpers ─────────────────────────────────────────────── function tokenize(text, wordMap) { - const titles = Object.keys(wordMap); - if (!titles.length || !text) return [{ text }]; - const escaped = titles.sort((a, b) => b.length - a.length) - .map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); - const re = new RegExp(`(${escaped.join('|')})`, 'gi'); - return text.split(re).filter(s => s !== '').map(part => ({ - text: part, - word: wordMap[part.toLowerCase()] || null, - })); + try { + const titles = Object.keys(wordMap).filter(k => k && k.length > 0); + if (!titles.length || !text) return [{ text: text || '' }]; + const escaped = titles.sort((a, b) => b.length - a.length) + .map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) + .filter(e => e.length > 0); + if (!escaped.length) return [{ text }]; + const re = new RegExp(`(${escaped.join('|')})`, 'gi'); + return text.split(re).filter(s => s != null && s !== '').map(part => ({ + text: part, + word: wordMap[part.toLowerCase()] || null, + })); + } catch { + return [{ text: text || '', word: null }]; + } } function withPlaceholders(text, wordMap, objectAssignments = {}) { @@ -206,19 +212,27 @@ function PairForm({ objectId, allObjects, onPairSaved }) { useEffect(() => { if (!allText.trim()) { setWordMap({}); return; } const t = setTimeout(async () => { - const tokens = [...new Set(allText.split(/[\s.,!?;:()\[\]"']+/).filter(w => w.length >= 2))]; - if (!tokens.length) return; - const results = await Promise.allSettled( - tokens.map(async w => { - const data = await apiFetch(`/words?search=${encodeURIComponent(w)}&limit=5`); - const candidates = Array.isArray(data) ? data : []; - const match = candidates.find(word => fuzzyMatch(w, word[`titel_${lang}`] || word.titel_de || '')); - return match ? { key: w.toLowerCase(), word: match } : null; - }) - ); - const map = {}; - results.forEach(r => { if (r.status === 'fulfilled' && r.value) map[r.value.key] = r.value.word; }); - setWordMap(map); + try { + const tokens = [...new Set(allText.split(/[\s.,!?;:()\[\]"']+/).filter(w => w.length >= 2))]; + if (!tokens.length) return; + const results = await Promise.allSettled( + tokens.map(async w => { + try { + const data = await apiFetch(`/words?search=${encodeURIComponent(w)}&limit=5`); + const candidates = Array.isArray(data) ? data.filter(Boolean) : []; + const match = candidates.find(word => word && word.id && fuzzyMatch(w, word[`titel_${lang}`] || word.titel_de || '')); + return match ? { key: w.toLowerCase(), word: match } : null; + } catch { return null; } + }) + ); + const map = {}; + results.forEach(r => { + if (r.status === 'fulfilled' && r.value && r.value.key && r.value.word?.id) { + map[r.value.key] = r.value.word; + } + }); + setWordMap(map); + } catch { /* ignore word detection errors */ } }, 600); return () => clearTimeout(t); }, [allText, lang]); @@ -228,7 +242,7 @@ function PairForm({ objectId, allObjects, onPairSaved }) { setCreatingWord(true); try { const w = await apiPost('/words', { [`titel_${lang}`]: wordInput.trim() }); - setWordMap(prev => ({ ...prev, [selection.trim().toLowerCase()]: w })); + if (w?.id) setWordMap(prev => ({ ...prev, [selection.trim().toLowerCase()]: w })); setWordInput(''); } catch (e) { alert('Fehler: ' + e.message); } finally { setCreatingWord(false); } @@ -287,6 +301,9 @@ function PairForm({ objectId, allObjects, onPairSaved }) { }); await apiLink(`/objects/${objectId}/pairs/${pair.id}`); setType(''); setYesNoAnswer(null); + setQuestion(''); setPositive(''); setNegative(''); + setWordMap({}); setObjectAssignments({}); + setPositiveWords([]); setNegativeWords([]); setSavedFlash(true); setTimeout(() => setSavedFlash(false), 2000); onPairSaved(pair); } catch (e) { alert('Fehler: ' + e.message); } @@ -384,8 +401,9 @@ function PairForm({ objectId, allObjects, onPairSaved }) { {Object.keys(wordMap).length > 0 && (