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>
This commit is contained in:
2026-05-28 22:12:48 +02:00
parent 93975f40c7
commit 08d22a1440

View File

@@ -483,10 +483,6 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
const [creatingWord, setCreatingWord] = useState(false); const [creatingWord, setCreatingWord] = useState(false);
const [confirmDelete, setConfirmDelete] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false);
const [deleting, setDeleting] = useState(false); const [deleting, setDeleting] = useState(false);
// Stores label→objectId extracted from raw placeholder text during load,
// used to restore objectAssignments once wordMap is built.
const labelToObjectId = useRef({});
useEffect(() => { setWordInput(selection); }, [selection]); useEffect(() => { setWordInput(selection); }, [selection]);
async function handleDelete() { async function handleDelete() {
@@ -499,16 +495,16 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
} }
useEffect(() => { useEffect(() => {
labelToObjectId.current = {};
function extractObjectRefs(rawText) {
const re = /\{\{([^.}]+)\.o:([0-9a-f-]{36})\}\}/gi;
let m;
while ((m = re.exec(rawText)) !== null) {
labelToObjectId.current[m[1].toLowerCase()] = m[2];
}
}
async function load() { async function load() {
try { 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) { if (pair.question_id) {
const q = await apiFetch(`/questions/${pair.question_id}`); const q = await apiFetch(`/questions/${pair.question_id}`);
const rawQ = q[`sentence_${lang}`] || q.sentence_de || ''; const rawQ = q[`sentence_${lang}`] || q.sentence_de || '';
@@ -534,6 +530,22 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
setNegativeWords(words.filter(Boolean)); setNegativeWords(words.filter(Boolean));
} }
} }
// Directly look up word IDs for each extracted label and set objectAssignments
if (Object.keys(labelToObjId).length) {
const assignments = {};
await Promise.all(Object.entries(labelToObjId).map(async ([label, objId]) => {
try {
const words = await apiFetch(`/words?search=${encodeURIComponent(label)}&limit=5`);
const word = Array.isArray(words) && words.find(w =>
(w.titel_de || '').toLowerCase() === label ||
(w.titel_en || '').toLowerCase() === label
);
if (word) assignments[word.id] = objId;
} catch { /* ignore */ }
}));
if (Object.keys(assignments).length) setObjectAssignments(assignments);
}
} catch (e) { console.error(e); } } catch (e) { console.error(e); }
finally { setLoading(false); } finally { setLoading(false); }
} }
@@ -564,17 +576,6 @@ function EditPairForm({ pair, allObjects, onSaved, onCancel, onDeleted }) {
} }
}); });
setWordMap(map); setWordMap(map);
// Restore objectAssignments from placeholders extracted during load
if (Object.keys(labelToObjectId.current).length) {
setObjectAssignments(prev => {
const restored = {};
Object.entries(map).forEach(([label, w]) => {
const objId = labelToObjectId.current[label.toLowerCase()];
if (objId) restored[w.id] = objId;
});
return Object.keys(restored).length ? { ...restored, ...prev } : prev;
});
}
} catch { /* ignore word detection errors */ } } catch { /* ignore word detection errors */ }
}, 600); }, 600);
return () => clearTimeout(t); return () => clearTimeout(t);