125 lines
4.7 KiB
TypeScript
125 lines
4.7 KiB
TypeScript
|
|
import { useEffect, useRef, useState } from 'react'
|
||
|
|
import type { Pregunta, Categoria } from '../../types'
|
||
|
|
|
||
|
|
interface QuestionModalProps {
|
||
|
|
pregunta: Pregunta
|
||
|
|
categoria: Categoria
|
||
|
|
mostrarFeedback: boolean
|
||
|
|
feedbackCorrecto: boolean
|
||
|
|
onResponder: (indice: number | null) => void
|
||
|
|
onCerrar: () => void
|
||
|
|
}
|
||
|
|
|
||
|
|
const LETRAS = ['A', 'B', 'C', 'D']
|
||
|
|
const TIEMPO_LIMITE = 30
|
||
|
|
|
||
|
|
export default function QuestionModal({ pregunta, categoria, mostrarFeedback, feedbackCorrecto, onResponder, onCerrar }: QuestionModalProps) {
|
||
|
|
const [tiempo, setTiempo] = useState(TIEMPO_LIMITE)
|
||
|
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||
|
|
const tiempoAgotadoRef = useRef(false)
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (mostrarFeedback) {
|
||
|
|
if (intervalRef.current) clearInterval(intervalRef.current)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
setTiempo(TIEMPO_LIMITE)
|
||
|
|
tiempoAgotadoRef.current = false
|
||
|
|
intervalRef.current = setInterval(() => {
|
||
|
|
setTiempo((prev) => {
|
||
|
|
if (prev <= 1) {
|
||
|
|
clearInterval(intervalRef.current!)
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
return prev - 1
|
||
|
|
})
|
||
|
|
}, 1000)
|
||
|
|
|
||
|
|
return () => { if (intervalRef.current) clearInterval(intervalRef.current) }
|
||
|
|
}, [pregunta.id, mostrarFeedback])
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (tiempo === 0 && !mostrarFeedback && !tiempoAgotadoRef.current) {
|
||
|
|
tiempoAgotadoRef.current = true
|
||
|
|
onResponder(null)
|
||
|
|
}
|
||
|
|
}, [tiempo, mostrarFeedback])
|
||
|
|
|
||
|
|
const porcentaje = (tiempo / TIEMPO_LIMITE) * 100
|
||
|
|
const colorBarra = porcentaje > 50 ? '#22c55e' : porcentaje > 25 ? '#f97316' : '#ef4444'
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 px-4">
|
||
|
|
<div className="bg-white rounded-2xl border-4 w-full max-w-xl shadow-2xl overflow-hidden" style={{ borderColor: categoria.color }}>
|
||
|
|
|
||
|
|
{!mostrarFeedback && (
|
||
|
|
<>
|
||
|
|
{/* Header con categoría */}
|
||
|
|
<div className="px-6 py-4 flex flex-col items-center gap-1" style={{ backgroundColor: categoria.color }}>
|
||
|
|
<span className="text-3xl">{categoria.emoji}</span>
|
||
|
|
<p className="text-white/80 text-sm font-medium">{categoria.nombre}</p>
|
||
|
|
<p className="text-white font-bold text-lg text-center">{pregunta.pregunta}</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Temporizador */}
|
||
|
|
<div className="px-5 pt-4">
|
||
|
|
<div className="flex items-center justify-between mb-1">
|
||
|
|
<span className="text-sm font-medium text-gray-500">Tiempo restante</span>
|
||
|
|
<span className="text-sm font-bold" style={{ color: colorBarra }}>{tiempo}s</span>
|
||
|
|
</div>
|
||
|
|
<div className="w-full bg-gray-200 rounded-full h-3 overflow-hidden">
|
||
|
|
<div
|
||
|
|
className="h-3 rounded-full transition-all duration-1000"
|
||
|
|
style={{ width: `${porcentaje}%`, backgroundColor: colorBarra }}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Opciones */}
|
||
|
|
<div className="p-5 flex flex-col gap-3">
|
||
|
|
{pregunta.opciones.map((opcion, i) => (
|
||
|
|
<button
|
||
|
|
key={i}
|
||
|
|
onClick={() => onResponder(i)}
|
||
|
|
className="flex items-stretch w-full rounded-lg border border-gray-200 bg-gray-50 hover:shadow-md hover:-translate-y-0.5 transition-all duration-200 overflow-hidden text-left"
|
||
|
|
>
|
||
|
|
<span
|
||
|
|
className="text-white font-bold w-10 flex items-center justify-center shrink-0"
|
||
|
|
style={{ backgroundColor: categoria.color }}
|
||
|
|
>
|
||
|
|
{LETRAS[i]}
|
||
|
|
</span>
|
||
|
|
<span className="px-4 py-3 text-gray-700 font-medium">{opcion}</span>
|
||
|
|
</button>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Feedback */}
|
||
|
|
{mostrarFeedback && (
|
||
|
|
<div className="p-8 flex flex-col items-center gap-4 text-center">
|
||
|
|
<span className="text-5xl">{feedbackCorrecto ? '🎉' : '❌'}</span>
|
||
|
|
<h3 className={`text-2xl font-bold ${feedbackCorrecto ? 'text-green-600' : 'text-red-500'}`}>
|
||
|
|
{feedbackCorrecto ? '¡Correcto!' : '¡Incorrecto!'}
|
||
|
|
</h3>
|
||
|
|
{feedbackCorrecto
|
||
|
|
? <p className="text-gray-600">{pregunta.retroalimentacion}</p>
|
||
|
|
: <p className="text-gray-600">{tiempo === 0 ? 'Se agotó el tiempo.' : 'Respuesta incorrecta.'}</p>
|
||
|
|
}
|
||
|
|
<button
|
||
|
|
onClick={onCerrar}
|
||
|
|
className="mt-2 text-white font-semibold px-8 py-2.5 rounded-xl transition-colors"
|
||
|
|
style={{ backgroundColor: categoria.color }}
|
||
|
|
>
|
||
|
|
Continuar
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|