diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index da1c06e..507772d 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -296,7 +296,9 @@ export default { vocabTrainerSelectedChoice: null, vocabTrainerAnswered: false, vocabTrainerLastCorrect: false, - vocabTrainerDirection: 'L2R' // L2R: learning->reference, R2L: reference->learning + vocabTrainerDirection: 'L2R', // L2R: learning->reference, R2L: reference->learning + isCheckingLessonCompletion: false, // Flag um Endlosschleife zu verhindern + isNavigatingToNext: false // Flag um mehrfache Navigation zu verhindern }; }, computed: { @@ -583,6 +585,9 @@ export default { } }, async checkLessonCompletion() { + // Verhindere mehrfache Ausführung + if (this.isCheckingLessonCompletion || this.isNavigatingToNext) return; + // Prüfe ob alle Übungen korrekt beantwortet wurden if (!this.lesson || !this.lesson.grammarExercises) return; @@ -593,13 +598,15 @@ export default { }); if (allCompleted) { - // Berechne Gesamt-Score - const totalExercises = allExercises.length; - const correctExercises = allExercises.filter(ex => this.exerciseResults[ex.id]?.correct).length; - const score = Math.round((correctExercises / totalExercises) * 100); + this.isCheckingLessonCompletion = true; - // Aktualisiere Fortschritt try { + // Berechne Gesamt-Score + const totalExercises = allExercises.length; + const correctExercises = allExercises.filter(ex => this.exerciseResults[ex.id]?.correct).length; + const score = Math.round((correctExercises / totalExercises) * 100); + + // Aktualisiere Fortschritt await apiClient.put(`/api/vocab/lessons/${this.lessonId}/progress`, { completed: true, score: score, @@ -610,16 +617,24 @@ export default { await this.navigateToNextLesson(); } catch (e) { console.error('Fehler beim Aktualisieren des Fortschritts:', e); + this.isCheckingLessonCompletion = false; } } }, async navigateToNextLesson() { + // Verhindere mehrfache Navigation + if (this.isNavigatingToNext) return; + this.isNavigatingToNext = true; + try { // Lade Kurs mit allen Lektionen const courseRes = await apiClient.get(`/api/vocab/courses/${this.courseId}`); const course = courseRes.data; - if (!course.lessons || course.lessons.length === 0) return; + if (!course.lessons || course.lessons.length === 0) { + this.isNavigatingToNext = false; + return; + } // Finde aktuelle Lektion const currentLessonIndex = course.lessons.findIndex(l => l.id === parseInt(this.lessonId)); @@ -631,13 +646,21 @@ export default { // Zeige Erfolgs-Meldung und leite weiter if (confirm(this.$t('socialnetwork.vocab.courses.lessonCompleted') + '\n' + this.$t('socialnetwork.vocab.courses.goToNextLesson'))) { this.$router.push(`/socialnetwork/vocab/courses/${this.courseId}/lessons/${nextLesson.id}`); + } else { + // Benutzer hat abgebrochen - Flag zurücksetzen + this.isNavigatingToNext = false; + this.isCheckingLessonCompletion = false; } } else { // Letzte Lektion - zeige Abschluss-Meldung alert(this.$t('socialnetwork.vocab.courses.allLessonsCompleted')); + this.isNavigatingToNext = false; + this.isCheckingLessonCompletion = false; } } catch (e) { console.error('Fehler beim Laden der nächsten Lektion:', e); + this.isNavigatingToNext = false; + this.isCheckingLessonCompletion = false; } }, back() { @@ -779,9 +802,15 @@ export default { // Im Typing-Modus: Automatisch zur nächsten Frage nach kurzer Pause (nur bei richtiger Antwort) if (this.vocabTrainerMode === 'typing' && this.vocabTrainerLastCorrect) { - setTimeout(() => { - this.nextVocabQuestion(); - }, 500); + // Prüfe ob noch Fragen vorhanden sind + if (this.vocabTrainerPool && this.vocabTrainerPool.length > 0) { + setTimeout(() => { + // Prüfe erneut, ob noch Fragen vorhanden sind (könnte sich geändert haben) + if (this.vocabTrainerPool && this.vocabTrainerPool.length > 0 && this.vocabTrainerActive) { + this.nextVocabQuestion(); + } + }, 500); + } } // Im Typing-Modus bei falscher Antwort: Eingabefeld fokussieren für erneuten Versuch