From 11e3ce87701aaf76f77ce1b180dab083854f98fb Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 5 Jun 2026 22:14:37 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Gef=C3=BChrter=20Pair-Review-Flow=20(Wi?= =?UTF-8?q?zard)=20pro=20Objekt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit '🚀 Review-Flow starten' läuft die Pairs des Objekts der Reihe nach durch: Inline bearbeiten + speichern oder 'Speichern & übersetzen' (Prüf-Grid), Reviewed/Blocked — danach automatisch das nächste Pair, bis alle durch sind. Orchestrierungs-Hülle um EditPairForm + PairReviewModal, keine Logik dupliziert. Co-Authored-By: Claude Opus 4.8 --- src/pages/ContentCreation.jsx | 96 ++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/src/pages/ContentCreation.jsx b/src/pages/ContentCreation.jsx index 68f542c..5b67645 100644 --- a/src/pages/ContentCreation.jsx +++ b/src/pages/ContentCreation.jsx @@ -1180,12 +1180,90 @@ function AutoCreateAllButton({ currentPicture, objects }) { ); } +// ─── Geführter Review-Flow (Wizard) ────────────────────────────────────────── +// Läuft die Pairs des ausgewählten Objekts der Reihe nach durch. Wiederverwendung: +// EditPairForm (Editor + alle Aktionen) und PairReviewModal (Übersetzungs-Prüf-Grid). + +function PairReviewWizard({ pairs, allObjects, onClose, onPairsReload }) { + const [queue] = useState(() => pairs); // Snapshot — stabile Navigation + const [index, setIndex] = useState(0); + const [reviewData, setReviewData] = useState(null); // { pair, content } | null + const pair = queue[index]; + + function advance() { + if (index + 1 < queue.length) { setIndex(index + 1); setReviewData(null); } + else onClose(); + } + + async function handleTranslate(p) { + const res = await apiPost(`/pairs/${p.id}/translate`, {}); + setReviewData({ pair: p, content: res.content }); + } + + async function handleRetranslate(p) { + const res = await apiPost(`/pairs/${p.id}/translate`, { overwrite: true }); + setReviewData({ pair: p, content: res.content }); + } + + if (!pair) { onClose(); return null; } + + return ( +
+
+ {/* Header mit Fortschritt + Navigation */} +
+ 🚀 + + Pair {index + 1}/{queue.length} + + {pair.answer_type} + {pair.id?.slice(0, 8)}… +
+ + + +
+
+ + {/* Body — vollständiger Editor pro Pair (remountet via key) */} +
+ { onPairsReload(); advance(); }} + onCancel={onClose} + onDeleted={() => { onPairsReload(); advance(); }} + onSavedAndTranslate={(savedPair) => handleTranslate(savedPair)} + /> +
+
+ + {reviewData && ( + setReviewData(null)} + onDone={() => { onPairsReload(); advance(); }} + onRetranslate={() => handleRetranslate(reviewData.pair)} + /> + )} +
+ ); +} + // ─── Right panel: Pairs ─────────────────────────────────────────────────────── function PairsPanel({ selectedObject, allObjects, objectPairs, loadingPairs, onPairSaved, onPairsReload, onReloadAll }) { const [editingId, setEditingId] = useState(null); const [translatingId, setTranslatingId] = useState(null); const [reviewData, setReviewData] = useState(null); // { pair, content } + const [wizardOpen, setWizardOpen] = useState(false); async function handleTranslate(pair) { setTranslatingId(pair.id); @@ -1214,10 +1292,17 @@ function PairsPanel({ selectedObject, allObjects, objectPairs, loadingPairs, onP return ( ); }