diff --git a/src/pages/StatementCreation.jsx b/src/pages/StatementCreation.jsx index 21477af..cb464fb 100644 --- a/src/pages/StatementCreation.jsx +++ b/src/pages/StatementCreation.jsx @@ -156,16 +156,22 @@ function WordTag({ word, onRemove }) { } // ─── PairForm ───────────────────────────────────────────────────────────────── +const PAIR_TYPES = [ + { value: 'text', label: 'Text', hint: 'Nur positives Statement' }, + { value: 'yes_no', label: 'Ja / Nein', hint: 'Frage + Ja/Nein Antwort' }, + { value: 'question', label: 'Frage', hint: 'Frage + Positiv + Negativ' }, + { value: 'word', label: 'Wort', hint: 'Frage + Positive/Negative Wörter' }, +]; + function PairForm({ objectId, onPairSaved }) { const lang = getUserLang(); const [showForm, setShowForm] = useState(false); + const [savedFlash, setSavedFlash] = useState(false); - // Type checkboxes - const [typeText, setTypeText] = useState(false); - const [typeYesNo, setTypeYesNo] = useState(false); - const [typeWord, setTypeWord] = useState(false); + // Single type dropdown + const [type, setType] = useState(''); - // Text fields + // Text fields — carried over between saves const [question, setQuestion] = useState(''); const [positive, setPositive] = useState(''); const [negative, setNegative] = useState(''); @@ -174,16 +180,17 @@ function PairForm({ objectId, onPairSaved }) { const [creatingWord, setCreatingWord] = useState(false); // Yes/No answer - const [yesNoAnswer, setYesNoAnswer] = useState(null); // null | true | false + const [yesNoAnswer, setYesNoAnswer] = useState(null); - // Word pickers + // Word pickers — carried over between saves const [positiveWords, setPositiveWords] = useState([]); const [negativeWords, setNegativeWords] = useState([]); const [saving, setSaving] = useState(false); - // Auto-detect words from text fields (only when Text type active) - const allText = typeText ? `${question} ${positive} ${negative}` : ''; + // Auto-detect words in sentence fields + const needsWordDetection = type === 'text' || type === 'question'; + const allText = needsWordDetection ? `${question} ${positive} ${negative}` : ''; useEffect(() => { if (!allText.trim()) { setWordMap({}); return; } const t = setTimeout(async () => { @@ -212,40 +219,32 @@ function PairForm({ objectId, onPairSaved }) { finally { setCreatingWord(false); } } - // Validation - const atLeastOne = typeText || typeYesNo || typeWord; - const textOk = !typeText || positive.trim().length > 0; - const negativeOk = !negative.trim() || (question.trim().length > 0 && positive.trim().length > 0); - const canSave = atLeastOne && textOk && negativeOk; + function canSave() { + if (!type) return false; + if (type === 'text') return positive.trim().length > 0; + if (type === 'yes_no') return true; + if (type === 'question') return question.trim().length > 0 && positive.trim().length > 0; + if (type === 'word') return positiveWords.length > 0 || negativeWords.length > 0; + return false; + } function validationHint() { - if (!atLeastOne) return 'Wähle mindestens einen Typ (Text / Ja·Nein / Wort).'; - if (!textOk) return 'Text: Positive Aussage ist Pflicht.'; - if (!negativeOk) return 'Negative Aussage erfordert Frage + Positive Aussage.'; + if (!type) return 'Bitte einen Typ wählen.'; + if (type === 'text' && !positive.trim()) return 'Statement ist Pflicht.'; + if (type === 'question' && !question.trim()) return 'Frage ist Pflicht.'; + if (type === 'question' && !positive.trim()) return 'Positive Aussage ist Pflicht.'; + if (type === 'word' && !positiveWords.length && !negativeWords.length) + return 'Mindestens ein Wort erforderlich.'; return ''; } - function reset() { - setTypeText(false); setTypeYesNo(false); setTypeWord(false); - setQuestion(''); setPositive(''); setNegative(''); - setWordMap({}); setYesNoAnswer(null); - setPositiveWords([]); setNegativeWords([]); - setShowForm(false); - } - async function handleSave() { - if (!canSave) return; + if (!canSave()) return; setSaving(true); try { - const answerTypes = [ - ...(typeText ? ['text'] : []), - ...(typeYesNo ? ['yes_no'] : []), - ...(typeWord ? ['word'] : []), - ]; - - // Question (only if Text + question text filled) + // Question record — for yes_no, question, word (if text filled) let questionId = null; - if (typeText && question.trim()) { + if (type !== 'text' && question.trim()) { const q = await apiPost('/questions', { [`sentence_${lang}`]: withPlaceholders(question, wordMap), status: 'draft', @@ -254,87 +253,97 @@ function PairForm({ objectId, onPairSaved }) { } // Positive statement - const posBody = { status: 'draft' }; - if (typeText && positive.trim()) - posBody[`positive_sentence_${lang}`] = withPlaceholders(positive, wordMap); - if (typeYesNo && yesNoAnswer !== null) - posBody.answer = yesNoAnswer; - - const posStmt = await apiPost('/statements', posBody); - - // Link positive words to positive statement - if (typeWord && positiveWords.length) - await Promise.all(positiveWords.map(w => apiLink(`/statements/${posStmt.id}/positive-words/${w.id}`))); - - // Negative statement (Text + negative text, OR Word + negativeWords) - let negStmtId = null; - const hasNegText = typeText && negative.trim(); - const hasNegWords = typeWord && negativeWords.length > 0; - - if (hasNegText || hasNegWords) { - const negBody = { status: 'draft' }; - if (hasNegText) - negBody[`negative_sentence_${lang}`] = withPlaceholders(negative, wordMap); - const negStmt = await apiPost('/statements', negBody); - negStmtId = negStmt.id; - if (hasNegWords) - await Promise.all(negativeWords.map(w => apiLink(`/statements/${negStmt.id}/negative-words/${w.id}`))); + let posStmtId = null; + if (type === 'text' || type === 'question') { + const posBody = { status: 'draft' }; + if (positive.trim()) + posBody[`positive_sentence_${lang}`] = withPlaceholders(positive, wordMap); + const s = await apiPost('/statements', posBody); + posStmtId = s.id; + } else if (type === 'yes_no') { + const posBody = { status: 'draft' }; + if (yesNoAnswer !== null) posBody.answer = yesNoAnswer; + const s = await apiPost('/statements', posBody); + posStmtId = s.id; + } else if (type === 'word' && positiveWords.length) { + const s = await apiPost('/statements', { status: 'draft' }); + posStmtId = s.id; + await Promise.all(positiveWords.map(w => apiLink(`/statements/${posStmtId}/positive-words/${w.id}`))); } - // Pair + // Negative statement + let negStmtId = null; + if (type === 'question' && negative.trim()) { + const negBody = { status: 'draft', [`negative_sentence_${lang}`]: withPlaceholders(negative, wordMap) }; + const s = await apiPost('/statements', negBody); + negStmtId = s.id; + } else if (type === 'word' && negativeWords.length) { + const s = await apiPost('/statements', { status: 'draft' }); + negStmtId = s.id; + await Promise.all(negativeWords.map(w => apiLink(`/statements/${negStmtId}/negative-words/${w.id}`))); + } + + // Create pair const pair = await apiPost('/pairs', { - answer_type: answerTypes, + answer_type: type, question_id: questionId, - positive_statement_id: posStmt.id, + positive_statement_id: posStmtId, negative_statement_id: negStmtId, status: 'draft', }); await apiLink(`/objects/${objectId}/pairs/${pair.id}`); - reset(); - onPairSaved({ ...pair, question: questionId ? { [`sentence_${lang}`]: question } : null, - positive_statement: posStmt, negative_statement: null }); + // Carry-over: keep all text/word values, only reset type to prompt re-selection + setType(''); + setYesNoAnswer(null); + setSavedFlash(true); + setTimeout(() => setSavedFlash(false), 2000); + onPairSaved(pair); } catch (e) { alert('Fehler: ' + e.message); } finally { setSaving(false); } } return (
Antwort
+Frage + Positive Aussage erforderlich.
- )} -Positive Wörter
+Negative Wörter
+Antwort
-Positive Wörter
-Negative Wörter
-{validationHint()}
} + {type && !canSave() && ( +{validationHint()}
+ )}