All files / hooks useQuiz.ts

100% Statements 42/42
100% Branches 6/6
100% Functions 11/11
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101    2x               2x 2x                                       32x 31x 31x   31x     31x 31x 20x 100x 145x     31x 31x 20x     31x 31x 20x     31x 31x 20x     31x 8x 8x 8x     31x   13x   12x 12x     12x 2x     12x         31x 1x 1x     31x                        
'use client'
 
import { useState, useCallback, useMemo } from 'react'
import { VocabularyItem } from '@/core/domain/VocabularyItem'
import {
  QuizSession,
  createQuizSession,
  getCurrentQuestion,
  isQuizComplete,
  getResultMessage,
} from '@/core/domain/QuizSession'
import { EvaluateQuizAnswerUseCase } from '@/core/application/use-cases/EvaluateAnswer'
 
export type QuizPhase = 'memorization' | 'quiz' | 'results'
 
interface UseQuizReturn {
  phase: QuizPhase
  session: QuizSession | null
  currentQuestion: VocabularyItem | null
  shuffledOptions: string[]
  isComplete: boolean
  resultMessage: string
  startQuiz: () => void
  submitAnswer: (word: string) => boolean
  resetQuiz: () => void
}
 
/**
 * useQuiz Hook
 * Manages the quiz state and transitions between phases.
 */
export function useQuiz(vocabularyItems: VocabularyItem[]): UseQuizReturn {
  const [phase, setPhase] = useState<QuizPhase>('memorization')
  const [session, setSession] = useState<QuizSession | null>(null)
 
  const evaluateUseCase = useMemo(() => new EvaluateQuizAnswerUseCase(), [])
 
  // Shuffle the word options for the current question
  const shuffledOptions = useMemo(() => {
    if (!session) return []
    return [...session.vocabularyItems]
      .map((item) => item.word)
      .sort(() => Math.random() - 0.5)
  }, [session])
 
  const currentQuestion = useMemo(() => {
    if (!session) return null
    return getCurrentQuestion(session)
  }, [session])
 
  const isComplete = useMemo(() => {
    if (!session) return false
    return isQuizComplete(session)
  }, [session])
 
  const resultMessage = useMemo(() => {
    if (!session) return ''
    return getResultMessage(session)
  }, [session])
 
  const startQuiz = useCallback(() => {
    const newSession = createQuizSession(vocabularyItems)
    setSession(newSession)
    setPhase('quiz')
  }, [vocabularyItems])
 
  const submitAnswer = useCallback(
    (word: string): boolean => {
      if (!session) return false
 
      const result = evaluateUseCase.execute(session, word)
      setSession(result.updatedSession)
 
      // Check if quiz is complete after this answer
      if (isQuizComplete(result.updatedSession)) {
        setPhase('results')
      }
 
      return result.isCorrect
    },
    [session, evaluateUseCase]
  )
 
  const resetQuiz = useCallback(() => {
    setSession(null)
    setPhase('memorization')
  }, [])
 
  return {
    phase,
    session,
    currentQuestion,
    shuffledOptions,
    isComplete,
    resultMessage,
    startQuiz,
    submitAnswer,
    resetQuiz,
  }
}