Add ExerciseAiQuickCreateTeaser Component and Update ExercisePickerModal
All checks were successful
Deploy Development / deploy (push) Successful in 40s
Test Suite / pytest-backend (push) Successful in 39s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m17s
All checks were successful
Deploy Development / deploy (push) Successful in 40s
Test Suite / pytest-backend (push) Successful in 39s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m17s
- Introduced the ExerciseAiQuickCreateTeaser component for a compact entry point in the exercise creation process. - Updated ExercisePickerModal to integrate the new teaser, allowing users to expand and create exercises directly from the search results. - Enhanced the quick create functionality with dynamic headlines and hints based on user input and context. - Refactored conditional rendering logic to improve user experience when no exercises are found.
This commit is contained in:
parent
5c882985e0
commit
a8633235f2
|
|
@ -3,6 +3,39 @@ import React from 'react'
|
|||
/**
|
||||
* 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({
|
||||
searchLabel,
|
||||
title,
|
||||
|
|
@ -19,6 +52,7 @@ export default function ExerciseAiQuickCreateOffer({
|
|||
showSketchField = true,
|
||||
sketchOptional = true,
|
||||
hint,
|
||||
headline,
|
||||
}) {
|
||||
const canRun =
|
||||
!busy &&
|
||||
|
|
@ -37,7 +71,7 @@ export default function ExerciseAiQuickCreateOffer({
|
|||
}}
|
||||
>
|
||||
<strong style={{ display: 'block', marginBottom: '6px', fontSize: '0.95rem' }}>
|
||||
Keine passende Übung gefunden
|
||||
{headline || 'Keine passende Übung gefunden'}
|
||||
</strong>
|
||||
<p style={{ margin: '0 0 12px', fontSize: '13px', color: 'var(--text2)', lineHeight: 1.45 }}>
|
||||
{hint ||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import SkillTreeMultiSelect from './SkillTreeMultiSelect'
|
|||
import ExerciseFocusRulePicker from './ExerciseFocusRulePicker'
|
||||
import CatalogRulePicker from './CatalogRulePicker'
|
||||
import ExerciseAiSuggestPreviewModal from './ExerciseAiSuggestPreviewModal'
|
||||
import ExerciseAiQuickCreateOffer from './ExerciseAiQuickCreateOffer'
|
||||
import ExerciseAiQuickCreateOffer, { ExerciseAiQuickCreateTeaser } from './ExerciseAiQuickCreateOffer'
|
||||
import { useExerciseAiQuickCreateFields } from '../hooks/useExerciseAiQuickCreateFields'
|
||||
import {
|
||||
buildQuickCreateAiPreview,
|
||||
|
|
@ -79,6 +79,7 @@ export default function ExercisePickerModal({
|
|||
const [quickSaving, setQuickSaving] = useState(false)
|
||||
const [quickAiError, setQuickAiError] = useState('')
|
||||
const [quickCreateDraft, setQuickCreateDraft] = useState(null)
|
||||
const [quickCreateExpanded, setQuickCreateExpanded] = useState(false)
|
||||
const [planningContextSummary, setPlanningContextSummary] = useState(null)
|
||||
const [planningTargetProfileSummary, setPlanningTargetProfileSummary] = useState(null)
|
||||
const [planningLlmRankApplied, setPlanningLlmRankApplied] = useState(false)
|
||||
|
|
@ -154,6 +155,7 @@ export default function ExercisePickerModal({
|
|||
: (searchInput || aiSearchInput).trim()
|
||||
setPlanningSubmittedQuery(q)
|
||||
setPlanningHasSearched(true)
|
||||
setQuickCreateExpanded(false)
|
||||
setList([])
|
||||
setPlanningSearchTick((t) => t + 1)
|
||||
}, [searchInput, aiSearchInput])
|
||||
|
|
@ -174,6 +176,10 @@ export default function ExercisePickerModal({
|
|||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!usePlanningSearch) setQuickCreateExpanded(false)
|
||||
}, [effectivePickerQuery, usePlanningSearch])
|
||||
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => setDebouncedSearch(searchInput.trim()), 350)
|
||||
return () => clearTimeout(t)
|
||||
|
|
@ -184,13 +190,45 @@ export default function ExercisePickerModal({
|
|||
return () => clearTimeout(t)
|
||||
}, [aiSearchInput])
|
||||
|
||||
const showQuickCreateOffer =
|
||||
const canOfferQuickCreate =
|
||||
enableQuickCreateDraft &&
|
||||
catalogsReady &&
|
||||
!loading &&
|
||||
list.length === 0 &&
|
||||
planningHasSearched &&
|
||||
(usePlanningSearch ? true : effectivePickerQuery.length >= 3)
|
||||
(usePlanningSearch ? planningHasSearched : 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(() => {
|
||||
if (!open) return
|
||||
|
|
@ -239,6 +277,7 @@ export default function ExercisePickerModal({
|
|||
setQuickSaving(false)
|
||||
setQuickAiError('')
|
||||
setQuickCreateDraft(null)
|
||||
setQuickCreateExpanded(false)
|
||||
setPlanningContextSummary(null)
|
||||
setPlanningTargetProfileSummary(null)
|
||||
setPlanningLlmRankApplied(false)
|
||||
|
|
@ -1060,21 +1099,8 @@ export default function ExercisePickerModal({
|
|||
<div className="spinner" />
|
||||
</div>
|
||||
) : list.length === 0 ? (
|
||||
showQuickCreateOffer ? (
|
||||
<ExerciseAiQuickCreateOffer
|
||||
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}
|
||||
/>
|
||||
showQuickCreateFull ? (
|
||||
renderQuickCreateOffer()
|
||||
) : (
|
||||
<p style={{ color: 'var(--text2)', textAlign: 'center', lineHeight: 1.5 }}>
|
||||
{usePlanningSearch
|
||||
|
|
@ -1223,6 +1249,15 @@ export default function ExercisePickerModal({
|
|||
</button>
|
||||
</div>
|
||||
)}
|
||||
{showQuickCreateTeaser ? (
|
||||
<ExerciseAiQuickCreateTeaser
|
||||
disabled={quickSaving}
|
||||
onExpand={() => setQuickCreateExpanded(true)}
|
||||
/>
|
||||
) : null}
|
||||
{showQuickCreateFull && quickCreateExpanded ? (
|
||||
<div style={{ marginTop: 4 }}>{renderQuickCreateOffer()}</div>
|
||||
) : null}
|
||||
{multiSelect && typeof onSelectExercises === 'function' ? (
|
||||
<div
|
||||
className="exercise-picker-multi-footer"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user