refactor: update loading state management and enhance search functionality in ExercisesListPage
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 1m55s

- Replaced loading state with listFetching for clearer intent in managing exercise list fetching.
- Introduced search title suggestions for improved user experience during exercise searches.
- Updated UI elements to reflect changes in loading states and added datalist for search inputs, enhancing usability.
- Adjusted text for loading indicators to provide a more localized experience.
This commit is contained in:
Lars 2026-04-28 15:24:05 +02:00
parent 756263bad4
commit d5fbc2cd5c

View File

@ -34,7 +34,7 @@ function ExercisesListPage() {
skills: [],
})
const [catalogsReady, setCatalogsReady] = useState(false)
const [loading, setLoading] = useState(true)
const [listFetching, setListFetching] = useState(false)
const [loadingMore, setLoadingMore] = useState(false)
const [offset, setOffset] = useState(0)
const [hasMore, setHasMore] = useState(false)
@ -222,6 +222,12 @@ function ExercisesListPage() {
statusOptions,
])
/** Für Browser-/datalist-Vorschläge (aktuelle Treffer-Titel, begrenzt) */
const searchTitleSuggestions = useMemo(() => {
const titles = exercises.map((e) => (e.title || '').trim()).filter(Boolean)
return [...new Set(titles)].slice(0, 80)
}, [exercises])
const queryBase = useMemo(() => {
const q = {}
const n = (v) => (v === '' || v == null ? undefined : Number(v))
@ -284,7 +290,7 @@ function ExercisesListPage() {
if (!catalogsReady) return
let cancelled = false
const run = async () => {
setLoading(true)
setListFetching(true)
setOffset(0)
try {
const batch = await api.listExercises({ ...queryBase, limit: PAGE_SIZE, offset: 0 })
@ -298,7 +304,7 @@ function ExercisesListPage() {
alert('Fehler beim Laden: ' + err.message)
}
} finally {
if (!cancelled) setLoading(false)
if (!cancelled) setListFetching(false)
}
}
run()
@ -334,11 +340,11 @@ function ExercisesListPage() {
const resetAllFilters = useCallback(() => setFilters({ ...INITIAL_FILTERS }), [])
if (!catalogsReady || loading) {
if (!catalogsReady) {
return (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<div className="spinner"></div>
<p>Laden...</p>
<p>Lade Kataloge</p>
</div>
)
}
@ -363,13 +369,21 @@ function ExercisesListPage() {
<div className="card exercise-search-bar" style={{ marginBottom: '12px' }}>
<label className="form-label">Volltextsuche (Titel, Ziel, )</label>
<datalist id="exercise-search-titles">
{searchTitleSuggestions.map((t) => (
<option key={t} value={t} />
))}
</datalist>
<input
type="search"
className="form-input"
placeholder="Suchbegriffe…"
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
autoComplete="off"
autoComplete="on"
name="exercise-fulltext-search"
list="exercise-search-titles"
enterKeyHint="search"
style={{ marginBottom: '10px' }}
/>
<label className="form-label">Ergänzende Suche / KI-Vorbereitung (Beta)</label>
@ -379,7 +393,10 @@ function ExercisesListPage() {
placeholder="zweiter Begriff — zusätzliche Volltextsuche (ODER)"
value={aiSearchInput}
onChange={(e) => setAiSearchInput(e.target.value)}
autoComplete="off"
autoComplete="on"
name="exercise-ai-search"
list="exercise-search-titles"
enterKeyHint="search"
/>
<div className="exercise-search-bar__actions">
<button type="button" className="btn btn-secondary exercise-filter-trigger" onClick={() => setFilterModalOpen(true)}>
@ -416,7 +433,8 @@ function ExercisesListPage() {
</div>
) : null}
<p style={{ fontSize: '12px', color: 'var(--text3)', marginTop: '10px', marginBottom: 0 }}>
Vereins-/Trainerfilter folgen später. Fachliche Filter über Filter zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER.
Trefferliste aktualisiert sich kurz nach Eingabe. Titel der aktuellen Liste erscheinen als Vorschläge (Pfeil im
Feld). Fachliche Filter über Filter zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER.
</p>
</div>
@ -584,7 +602,12 @@ function ExercisesListPage() {
</div>
)}
{exercises.length === 0 ? (
{listFetching && exercises.length === 0 ? (
<div className="card" style={{ textAlign: 'center', padding: '2rem' }}>
<div className="spinner"></div>
<p style={{ color: 'var(--text2)', marginTop: '12px' }}>Lade Übungen</p>
</div>
) : exercises.length === 0 ? (
<div className="card">
<p style={{ color: 'var(--text2)', textAlign: 'center' }}>
Keine Übungen gefunden.
@ -592,6 +615,9 @@ function ExercisesListPage() {
</div>
) : (
<>
{listFetching ? (
<p style={{ fontSize: '13px', color: 'var(--text3)', marginBottom: '8px' }}>Aktualisiere Treffer</p>
) : null}
<p style={{ fontSize: '13px', color: 'var(--text2)', marginBottom: '10px' }}>
{exercises.length} angezeigt
{hasMore ? ' · es gibt weitere Einträge' : ''}