Compare commits

..

3 Commits

Author SHA1 Message Date
7564f23ef1 fix: use allObjects._words to restore objectAssignments on EditPairForm load
Replace async word search with synchronous lookup via allObjects._words,
which is already populated. Eliminates race conditions and fetch failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:19:56 +02:00
08d22a1440 fix: restore objectAssignments during load by fetching word IDs directly
Instead of waiting for the wordMap effect to reconcile, look up word IDs
for each label→objectId pair immediately in load() so objectAssignments
is set before the user sees the form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:12:48 +02:00
93975f40c7 fix: restore objectAssignments in EditPairForm on load
Extract {{label.o:objectId}} refs from raw sentence text before resolving
placeholders, then reconcile with wordMap once it's built so the object
assignment dropdown reflects the saved state on re-open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 22:08:47 +02:00

View File

@@ -483,7 +483,6 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
const [creatingWord, setCreatingWord] = useState(false);
const [confirmDelete, setConfirmDelete] = useState(false);
const [deleting, setDeleting] = useState(false);
useEffect(() => { setWordInput(selection); }, [selection]);
async function handleDelete() {
@@ -498,14 +497,24 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
useEffect(() => {
async function load() {
try {
// Collect all label→objectId refs from raw placeholder text across all fields
const labelToObjId = {};
function extractObjectRefs(rawText) {
const re = /\{\{([^.}]+)\.o:([0-9a-f-]{36})\}\}/gi;
let m;
while ((m = re.exec(rawText)) !== null) labelToObjId[m[1].toLowerCase()] = m[2];
}
if (pair.question_id) {
const q = await apiFetch(`/questions/${pair.question_id}`);
setQuestion(await resolvePlaceholders(q[`sentence_${lang}`] || q.sentence_de || '', allObjects));
const rawQ = q[`sentence_${lang}`] || q.sentence_de || '';
extractObjectRefs(rawQ);
setQuestion(await resolvePlaceholders(rawQ, allObjects));
}
if (pair.positive_statement_id) {
const s = await apiFetch(`/statements/${pair.positive_statement_id}`);
const raw = s[`positive_sentence_${lang}`] || s.positive_sentence_de || '';
if (raw) setPositive(await resolvePlaceholders(raw, allObjects));
if (raw) { extractObjectRefs(raw); setPositive(await resolvePlaceholders(raw, allObjects)); }
if (s.answer !== null && s.answer !== undefined) setYesNoAnswer(s.answer);
if (s.positive_word_ids?.length) {
const words = await Promise.all(s.positive_word_ids.map(id => apiFetch(`/words/${id}`).catch(() => null)));
@@ -515,12 +524,27 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
if (pair.negative_statement_id) {
const s = await apiFetch(`/statements/${pair.negative_statement_id}`);
const raw = s[`negative_sentence_${lang}`] || s.negative_sentence_de || '';
if (raw) setNegative(await resolvePlaceholders(raw, allObjects));
if (raw) { extractObjectRefs(raw); setNegative(await resolvePlaceholders(raw, allObjects)); }
if (s.negative_word_ids?.length) {
const words = await Promise.all(s.negative_word_ids.map(id => apiFetch(`/words/${id}`).catch(() => null)));
setNegativeWords(words.filter(Boolean));
}
}
// Look up word IDs via allObjects._words (already loaded, no fetch needed)
if (Object.keys(labelToObjId).length) {
const assignments = {};
Object.entries(labelToObjId).forEach(([label, objId]) => {
const obj = (allObjects || []).find(o => o.id === objId);
const word = (obj?._words || []).find(w =>
(w.titel_de || '').toLowerCase() === label ||
(w.titel_en || '').toLowerCase() === label ||
(w.titel_sv || '').toLowerCase() === label
);
if (word) assignments[word.id] = objId;
});
if (Object.keys(assignments).length) setObjectAssignments(assignments);
}
} catch (e) { console.error(e); }
finally { setLoading(false); }
}