From 738571d958308cc12f0379533ddb7caac5e4194f Mon Sep 17 00:00:00 2001 From: rene Date: Tue, 19 May 2026 18:28:56 +0200 Subject: [PATCH] Fix: Verlauf-Tab kein Endlos-Spinner + Save-422 bei null-Feldern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Verlauf: _verlaufLoading-Flag verhindert parallele Loads - Verlauf: el nach await neu holen (stale DOM-Referenz nach Re-Render) - Verlauf: bei _renderContent() Shell nur rendern wenn keine Sessions im Cache - Backend: hund_stimmung/zufriedenheit als Optional[str/int] β†’ akzeptiert null --- backend/routes/training.py | 4 ++-- backend/static/js/pages/uebungen.js | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/backend/routes/training.py b/backend/routes/training.py index 291a81a..aaaa855 100644 --- a/backend/routes/training.py +++ b/backend/routes/training.py @@ -323,8 +323,8 @@ class SessionCreate(BaseModel): datum: Optional[str] = None wiederholungen: int = 1 erfolgsquote: int = 50 - hund_stimmung: str = "aufmerksam" - zufriedenheit: int = 3 + hund_stimmung: Optional[str] = "aufmerksam" + zufriedenheit: Optional[int] = 3 notiz: Optional[str] = None tagebuch_eintrag: bool = False # ignoriert β€” Training hat eigenes Protokoll diff --git a/backend/static/js/pages/uebungen.js b/backend/static/js/pages/uebungen.js index c14e9f8..057a942 100644 --- a/backend/static/js/pages/uebungen.js +++ b/backend/static/js/pages/uebungen.js @@ -549,6 +549,7 @@ window.Page_uebungen = (() => { _exerciseStats = {}; _verlaufSessions = []; _verlaufOffset = 0; + _verlaufLoading = false; _render(); _loadStatsAndBadges(); _loadVirtualTrainer(); @@ -994,7 +995,6 @@ window.Page_uebungen = (() => { if (trainerEl) trainerEl.style.display = showIf(isExerciseTab); if (suggestEl) suggestEl.style.display = showIf(isExerciseTab); if (bannerEl) bannerEl.style.display = showIf(isExerciseTab); - if (isVerlauf) _loadVerlauf(); switch (_activeTab) { case 'grundkommandos': @@ -1016,7 +1016,16 @@ window.Page_uebungen = (() => { break; } case 'grundlagen': el.innerHTML = _renderGrundlagen(); break; - case 'verlauf': el.innerHTML = _renderVerlaufShell(); break; + case 'verlauf': { + if (_verlaufSessions.length > 0) { + el.innerHTML = `
`; + _renderVerlaufList(el.querySelector('#verlauf-list')); + } else { + el.innerHTML = _renderVerlaufShell(); + _loadVerlauf(); + } + break; + } case 'ki-trainer': if (!App.hasPro(_appState?.user)) { el.innerHTML = `
@@ -1977,6 +1986,7 @@ window.Page_uebungen = (() => { let _verlaufSessions = []; let _verlaufOffset = 0; let _verlaufHasMore = false; + let _verlaufLoading = false; const _VERLAUF_LIMIT = 30; const _ERFOLG_EMOJI = { 0: 'πŸ˜“', 25: '😐', 50: 'πŸ™‚', 75: '😊', 100: 'πŸŽ‰' }; @@ -2001,19 +2011,24 @@ window.Page_uebungen = (() => { } async function _loadVerlauf(append = false) { + if (_verlaufLoading) return; const dogId = _dogId(); if (!dogId) return; - const el = _container.querySelector('#verlauf-list'); - if (!el) return; if (!append) { _verlaufSessions = []; _verlaufOffset = 0; } + _verlaufLoading = true; const data = await _apiGet( `/api/training/sessions?dog_id=${dogId}&limit=${_VERLAUF_LIMIT + 1}&offset=${_verlaufOffset}` ).catch(() => null); + _verlaufLoading = false; + + // Element nach await neu holen β€” kΓΆnnte durch Re-Render veraltet sein + const el = _container?.querySelector('#verlauf-list'); + if (!el) return; if (!data) { if (!append) el.innerHTML = `
Fehler beim Laden.
`;