diff --git a/web/src/pages/LessonPage.tsx b/web/src/pages/LessonPage.tsx index 0d26a21..908d410 100644 --- a/web/src/pages/LessonPage.tsx +++ b/web/src/pages/LessonPage.tsx @@ -7,6 +7,7 @@ import Typography from '@mui/material/Typography'; import CircularProgress from '@mui/material/CircularProgress'; import CloseIcon from '@mui/icons-material/Close'; import { useLesson } from '../hooks/useLesson'; +import { useSpeech } from '../hooks/useSpeech'; import { getLesson } from '../content/loader'; import { apiClient } from '../api/client'; import { ProgressBar } from '../components/layout/ProgressBar'; @@ -81,6 +82,8 @@ export function LessonPage() { nextExercise, } = useLesson(); + const { speak } = useSpeech(); + const lesson = useMemo( () => (topicId && lessonId ? getLesson(topicId, lessonId) : null), [topicId, lessonId], @@ -119,6 +122,25 @@ export function LessonPage() { const currentExercise: Exercise | undefined = state.exercises[state.currentIndex]; + // Auto-play pronunciation when a new task is loaded + useEffect(() => { + if (!currentExercise || state.isChecked) return; + + let textToSpeak: string | null = null; + + if (currentExercise.type === 'speak') { + textToSpeak = currentExercise.phrase; + } else if (currentExercise.promptAudio) { + textToSpeak = currentExercise.audioText ?? currentExercise.prompt; + } + + if (textToSpeak) { + speak(textToSpeak); + } + // Only trigger when the exercise index changes, not on every re-render + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [state.currentIndex, state.exercises]); + const handleCheck = useCallback(() => { if (!currentExercise) return; const correct = isAnswerCorrect(currentExercise, state.selectedAnswer);