Optimierung KI-Scuhe + Ki-Überarbeitungen der Übungen #49
|
|
@ -3,6 +3,39 @@ import React from 'react'
|
||||||
/**
|
/**
|
||||||
* Inline-Angebot: aus Suchstring neue Übung per KI anlegen (Fokusbereich + optional Titel/Skizze).
|
* Inline-Angebot: aus Suchstring neue Übung per KI anlegen (Fokusbereich + optional Titel/Skizze).
|
||||||
*/
|
*/
|
||||||
|
/** Kompakter Einstieg unter Trefferliste — expandiert zum vollen Formular. */
|
||||||
|
export function ExerciseAiQuickCreateTeaser({ onExpand, disabled = false }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="card"
|
||||||
|
style={{
|
||||||
|
padding: '12px 16px',
|
||||||
|
marginTop: 16,
|
||||||
|
borderColor: 'var(--border)',
|
||||||
|
background: 'var(--surface2)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: '10px 12px',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: '0.92rem', lineHeight: 1.45 }}>
|
||||||
|
<strong>Nichts Richtiges dabei?</strong>{' '}
|
||||||
|
<span style={{ color: 'var(--text2)' }}>Neue Übung mit KI anlegen und direkt übernehmen.</span>
|
||||||
|
</span>
|
||||||
|
<button type="button" className="btn btn-secondary" disabled={disabled} onClick={() => onExpand?.()}>
|
||||||
|
Neue Übung anlegen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function ExerciseAiQuickCreateOffer({
|
export default function ExerciseAiQuickCreateOffer({
|
||||||
searchLabel,
|
searchLabel,
|
||||||
title,
|
title,
|
||||||
|
|
@ -19,6 +52,7 @@ export default function ExerciseAiQuickCreateOffer({
|
||||||
showSketchField = true,
|
showSketchField = true,
|
||||||
sketchOptional = true,
|
sketchOptional = true,
|
||||||
hint,
|
hint,
|
||||||
|
headline,
|
||||||
}) {
|
}) {
|
||||||
const canRun =
|
const canRun =
|
||||||
!busy &&
|
!busy &&
|
||||||
|
|
@ -37,7 +71,7 @@ export default function ExerciseAiQuickCreateOffer({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<strong style={{ display: 'block', marginBottom: '6px', fontSize: '0.95rem' }}>
|
<strong style={{ display: 'block', marginBottom: '6px', fontSize: '0.95rem' }}>
|
||||||
Keine passende Übung gefunden
|
{headline || 'Keine passende Übung gefunden'}
|
||||||
</strong>
|
</strong>
|
||||||
<p style={{ margin: '0 0 12px', fontSize: '13px', color: 'var(--text2)', lineHeight: 1.45 }}>
|
<p style={{ margin: '0 0 12px', fontSize: '13px', color: 'var(--text2)', lineHeight: 1.45 }}>
|
||||||
{hint ||
|
{hint ||
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import SkillTreeMultiSelect from './SkillTreeMultiSelect'
|
||||||
import ExerciseFocusRulePicker from './ExerciseFocusRulePicker'
|
import ExerciseFocusRulePicker from './ExerciseFocusRulePicker'
|
||||||
import CatalogRulePicker from './CatalogRulePicker'
|
import CatalogRulePicker from './CatalogRulePicker'
|
||||||
import ExerciseAiSuggestPreviewModal from './ExerciseAiSuggestPreviewModal'
|
import ExerciseAiSuggestPreviewModal from './ExerciseAiSuggestPreviewModal'
|
||||||
import ExerciseAiQuickCreateOffer from './ExerciseAiQuickCreateOffer'
|
import ExerciseAiQuickCreateOffer, { ExerciseAiQuickCreateTeaser } from './ExerciseAiQuickCreateOffer'
|
||||||
import { useExerciseAiQuickCreateFields } from '../hooks/useExerciseAiQuickCreateFields'
|
import { useExerciseAiQuickCreateFields } from '../hooks/useExerciseAiQuickCreateFields'
|
||||||
import {
|
import {
|
||||||
buildQuickCreateAiPreview,
|
buildQuickCreateAiPreview,
|
||||||
|
|
@ -79,6 +79,7 @@ export default function ExercisePickerModal({
|
||||||
const [quickSaving, setQuickSaving] = useState(false)
|
const [quickSaving, setQuickSaving] = useState(false)
|
||||||
const [quickAiError, setQuickAiError] = useState('')
|
const [quickAiError, setQuickAiError] = useState('')
|
||||||
const [quickCreateDraft, setQuickCreateDraft] = useState(null)
|
const [quickCreateDraft, setQuickCreateDraft] = useState(null)
|
||||||
|
const [quickCreateExpanded, setQuickCreateExpanded] = useState(false)
|
||||||
const [planningContextSummary, setPlanningContextSummary] = useState(null)
|
const [planningContextSummary, setPlanningContextSummary] = useState(null)
|
||||||
const [planningTargetProfileSummary, setPlanningTargetProfileSummary] = useState(null)
|
const [planningTargetProfileSummary, setPlanningTargetProfileSummary] = useState(null)
|
||||||
const [planningLlmRankApplied, setPlanningLlmRankApplied] = useState(false)
|
const [planningLlmRankApplied, setPlanningLlmRankApplied] = useState(false)
|
||||||
|
|
@ -154,6 +155,7 @@ export default function ExercisePickerModal({
|
||||||
: (searchInput || aiSearchInput).trim()
|
: (searchInput || aiSearchInput).trim()
|
||||||
setPlanningSubmittedQuery(q)
|
setPlanningSubmittedQuery(q)
|
||||||
setPlanningHasSearched(true)
|
setPlanningHasSearched(true)
|
||||||
|
setQuickCreateExpanded(false)
|
||||||
setList([])
|
setList([])
|
||||||
setPlanningSearchTick((t) => t + 1)
|
setPlanningSearchTick((t) => t + 1)
|
||||||
}, [searchInput, aiSearchInput])
|
}, [searchInput, aiSearchInput])
|
||||||
|
|
@ -174,6 +176,10 @@ export default function ExercisePickerModal({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!usePlanningSearch) setQuickCreateExpanded(false)
|
||||||
|
}, [effectivePickerQuery, usePlanningSearch])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const t = setTimeout(() => setDebouncedSearch(searchInput.trim()), 350)
|
const t = setTimeout(() => setDebouncedSearch(searchInput.trim()), 350)
|
||||||
return () => clearTimeout(t)
|
return () => clearTimeout(t)
|
||||||
|
|
@ -184,13 +190,45 @@ export default function ExercisePickerModal({
|
||||||
return () => clearTimeout(t)
|
return () => clearTimeout(t)
|
||||||
}, [aiSearchInput])
|
}, [aiSearchInput])
|
||||||
|
|
||||||
const showQuickCreateOffer =
|
const canOfferQuickCreate =
|
||||||
enableQuickCreateDraft &&
|
enableQuickCreateDraft &&
|
||||||
catalogsReady &&
|
catalogsReady &&
|
||||||
!loading &&
|
!loading &&
|
||||||
list.length === 0 &&
|
(usePlanningSearch ? planningHasSearched : effectivePickerQuery.length >= 3)
|
||||||
planningHasSearched &&
|
|
||||||
(usePlanningSearch ? true : effectivePickerQuery.length >= 3)
|
const showQuickCreateFull = canOfferQuickCreate && (list.length === 0 || quickCreateExpanded)
|
||||||
|
const showQuickCreateTeaser = canOfferQuickCreate && list.length > 0 && !quickCreateExpanded
|
||||||
|
|
||||||
|
const quickCreateHeadline = usePlanningSearch
|
||||||
|
? 'Nichts Richtiges dabei?'
|
||||||
|
: list.length > 0
|
||||||
|
? 'Neue Übung anlegen'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const quickCreateHint = usePlanningSearch
|
||||||
|
? effectivePickerQuery
|
||||||
|
? `Aus Planungsanfrage „${effectivePickerQuery}“ oder eigener Idee — KI schlägt Texte vor, danach bearbeiten und übernehmen.`
|
||||||
|
: 'Aus Planungskontext oder eigener Idee — KI schlägt Texte vor, danach bearbeiten und übernehmen.'
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const renderQuickCreateOffer = () => (
|
||||||
|
<ExerciseAiQuickCreateOffer
|
||||||
|
searchLabel={effectivePickerQuery || undefined}
|
||||||
|
title={quickTitle}
|
||||||
|
onTitleChange={setQuickTitle}
|
||||||
|
sketch={quickSketch}
|
||||||
|
onSketchChange={setQuickSketch}
|
||||||
|
focusAreaId={quickFocusAreaId}
|
||||||
|
onFocusAreaChange={setQuickFocusAreaId}
|
||||||
|
focusAreas={catalogs.focusAreas}
|
||||||
|
catalogsReady={catalogsReady}
|
||||||
|
busy={quickSaving}
|
||||||
|
error={quickAiError}
|
||||||
|
onRunAi={runQuickCreateAiSuggest}
|
||||||
|
headline={quickCreateHeadline}
|
||||||
|
hint={quickCreateHint}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) return
|
if (!open) return
|
||||||
|
|
@ -239,6 +277,7 @@ export default function ExercisePickerModal({
|
||||||
setQuickSaving(false)
|
setQuickSaving(false)
|
||||||
setQuickAiError('')
|
setQuickAiError('')
|
||||||
setQuickCreateDraft(null)
|
setQuickCreateDraft(null)
|
||||||
|
setQuickCreateExpanded(false)
|
||||||
setPlanningContextSummary(null)
|
setPlanningContextSummary(null)
|
||||||
setPlanningTargetProfileSummary(null)
|
setPlanningTargetProfileSummary(null)
|
||||||
setPlanningLlmRankApplied(false)
|
setPlanningLlmRankApplied(false)
|
||||||
|
|
@ -1060,21 +1099,8 @@ export default function ExercisePickerModal({
|
||||||
<div className="spinner" />
|
<div className="spinner" />
|
||||||
</div>
|
</div>
|
||||||
) : list.length === 0 ? (
|
) : list.length === 0 ? (
|
||||||
showQuickCreateOffer ? (
|
showQuickCreateFull ? (
|
||||||
<ExerciseAiQuickCreateOffer
|
renderQuickCreateOffer()
|
||||||
searchLabel={effectivePickerQuery}
|
|
||||||
title={quickTitle}
|
|
||||||
onTitleChange={setQuickTitle}
|
|
||||||
sketch={quickSketch}
|
|
||||||
onSketchChange={setQuickSketch}
|
|
||||||
focusAreaId={quickFocusAreaId}
|
|
||||||
onFocusAreaChange={setQuickFocusAreaId}
|
|
||||||
focusAreas={catalogs.focusAreas}
|
|
||||||
catalogsReady={catalogsReady}
|
|
||||||
busy={quickSaving}
|
|
||||||
error={quickAiError}
|
|
||||||
onRunAi={runQuickCreateAiSuggest}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<p style={{ color: 'var(--text2)', textAlign: 'center', lineHeight: 1.5 }}>
|
<p style={{ color: 'var(--text2)', textAlign: 'center', lineHeight: 1.5 }}>
|
||||||
{usePlanningSearch
|
{usePlanningSearch
|
||||||
|
|
@ -1223,6 +1249,15 @@ export default function ExercisePickerModal({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{showQuickCreateTeaser ? (
|
||||||
|
<ExerciseAiQuickCreateTeaser
|
||||||
|
disabled={quickSaving}
|
||||||
|
onExpand={() => setQuickCreateExpanded(true)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{showQuickCreateFull && quickCreateExpanded ? (
|
||||||
|
<div style={{ marginTop: 4 }}>{renderQuickCreateOffer()}</div>
|
||||||
|
) : null}
|
||||||
{multiSelect && typeof onSelectExercises === 'function' ? (
|
{multiSelect && typeof onSelectExercises === 'function' ? (
|
||||||
<div
|
<div
|
||||||
className="exercise-picker-multi-footer"
|
className="exercise-picker-multi-footer"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user