All files / components/domain QuizPhase.tsx

95% Statements 19/20
85.71% Branches 6/7
100% Functions 4/4
100% Lines 19/19

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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128    1x                 1x     1x                         9x           18x 18x 18x   18x   18x 7x   7x 7x 7x 7x     7x 2x 2x 2x                                                                                                   90x                                                    
'use client'
 
import { useState } from 'react'
import {
  Box,
  Typography,
  Container,
  Paper,
  LinearProgress,
  Stack,
  Chip,
} from '@mui/material'
import { VocabularyItem } from '@/core/domain/VocabularyItem'
import { QuizSession } from '@/core/domain/QuizSession'
import { QuizOption } from './QuizOption'
 
interface QuizPhaseProps {
  session: QuizSession
  currentQuestion: VocabularyItem
  shuffledOptions: string[]
  onAnswer: (word: string) => boolean
}
 
/**
 * QuizPhase Component
 * Displays the quiz interface with questions and answer options.
 */
export function QuizPhase({
  session,
  currentQuestion,
  shuffledOptions,
  onAnswer,
}: QuizPhaseProps) {
  const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null)
  const [isCorrect, setIsCorrect] = useState<boolean | null>(null)
  const [isAnimating, setIsAnimating] = useState(false)
 
  const progress = ((session.currentStep) / session.vocabularyItems.length) * 100
 
  const handleOptionClick = (word: string) => {
    Iif (isAnimating) return
 
    setSelectedAnswer(word)
    const correct = onAnswer(word)
    setIsCorrect(correct)
    setIsAnimating(true)
 
    // Reset for next question after animation
    setTimeout(() => {
      setSelectedAnswer(null)
      setIsCorrect(null)
      setIsAnimating(false)
    }, 1000)
  }
 
  return (
    <Container maxWidth="md" sx={{ py: 4 }}>
      <Paper sx={{ p: 4 }}>
        <Box sx={{ mb: 4 }}>
          <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
            <Typography variant="h5" component="h1" sx={{ fontWeight: 600 }}>
              Quiz Time
            </Typography>
            <Chip
              label={`Questão ${session.currentStep + 1} de ${session.vocabularyItems.length}`}
              color="primary"
              variant="outlined"
            />
          </Box>
          <LinearProgress
            variant="determinate"
            value={progress}
            sx={{ height: 8, borderRadius: 4 }}
          />
        </Box>
 
        <Paper
          elevation={0}
          sx={{
            p: 4,
            mb: 4,
            bgcolor: 'grey.100',
            borderRadius: 2,
            textAlign: 'center',
          }}
        >
          <Typography variant="body2" color="text.secondary" gutterBottom>
            Qual palavra inglesa corresponde a esta descrição?
          </Typography>
          <Typography
            variant="h5"
            component="p"
            sx={{ fontWeight: 500, color: 'text.primary' }}
            data-testid="quiz-description"
          >
            {currentQuestion.description}
          </Typography>
        </Paper>
 
        <Stack spacing={2}>
          {shuffledOptions.map((word) => (
            <QuizOption
              key={word}
              word={word}
              onClick={handleOptionClick}
              disabled={isAnimating}
              selected={selectedAnswer === word}
              isCorrect={
                selectedAnswer === word
                  ? isCorrect
                  : isCorrect === false && word === currentQuestion.word
                  ? true
                  : null
              }
            />
          ))}
        </Stack>
 
        <Box sx={{ mt: 4, textAlign: 'center' }}>
          <Typography variant="body2" color="text.secondary">
            Score: {session.score} / {session.currentStep}
          </Typography>
        </Box>
      </Paper>
    </Container>
  )
}