@@ -144,7 +144,7 @@ export default function FeedbackModal({
>
{datoCurioso}
diff --git a/src/components/game/Ruleta/RuletaSVG.tsx b/src/components/game/Ruleta/RuletaSVG.tsx
index 3c3d0e5..a7f596f 100644
--- a/src/components/game/Ruleta/RuletaSVG.tsx
+++ b/src/components/game/Ruleta/RuletaSVG.tsx
@@ -71,8 +71,8 @@ export default function RuletaSVG({ categorias, rotacion, isSpinning, onClick }:
return (
- {/* ─── Puntero (fuera del SVG, fijo arriba) ─── */}
-
+ {/* ─── Puntero ─── */}
+
- {/* ─── SVG principal (ruleta + anillo + soporte) ─── */}
+ {/* ─── SVG principal ─── */}
{/* Logo izquierdo */}
-
+
)
diff --git a/src/components/screens/Cover.tsx b/src/components/screens/Cover.tsx
index a616adc..4de1263 100644
--- a/src/components/screens/Cover.tsx
+++ b/src/components/screens/Cover.tsx
@@ -32,15 +32,17 @@ export default function Cover({ onStart }: CoverProps) {
className="rounded-3xl p-8 shadow-lg"
style={{ background: 'linear-gradient(180deg, #ffffff 0%, #d8dcec 100%)' }}
>
-
+
Las reglas son muy sencillas: la ruleta girará, la suerte elegirá una categoría
y te tocará responder una pregunta. Contarás con 30 segundos para responder
cada una.
-
+
No se trata de encontrar la respuesta perfecta, sino de reflexionar y responder
- desde tu experiencia y perspectiva. ¡Prepárate para poner a prueba tus
- conocimientos y disfrutar de la dinámica!
+ desde tu experiencia y perspectiva.
+
+
+ ¡Prepárate para poner a prueba tus conocimientos y disfrutar de la dinámica!
diff --git a/src/components/screens/Game.tsx b/src/components/screens/Game.tsx
index dbda716..b0706b2 100644
--- a/src/components/screens/Game.tsx
+++ b/src/components/screens/Game.tsx
@@ -13,9 +13,9 @@ const LETRAS = ['A', 'B', 'C', 'D']
/** Mapeo de nombre de categoría → imagen PNG */
const CAT_IMG: Record
= {
'Agua': 'agua.png',
- 'Residuos': 'residuos.png',
+ 'Residuos y Circularidad': 'residuos.png',
'Energía': 'energia.png',
- 'Electromovilidad': 'movilidad.png',
+ 'Electromovilidad y Transporte Sostenible': 'movilidad.png',
}
export default function Game({ onEnd }: GameProps) {
@@ -44,7 +44,7 @@ export default function Game({ onEnd }: GameProps) {
backgroundColor: '#ed1f24',
borderRadius: '0px 0px 0px 25px',
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
- maxWidth: '520px',
+ maxWidth: '700px',
}}
>
{/* Círculo blanco con imagen de categoría */}
@@ -52,29 +52,45 @@ export default function Game({ onEnd }: GameProps) {
)}
20 ? '26px' : '30px' }}
>
{categoria.nombre}
)}
+ {/* ─── Contador de preguntas (bajo la barra roja) ─── */}
+
+
+
+ {Math.min(estado.preguntasRespondidas + 1, MAX_PREGUNTAS)}/{MAX_PREGUNTAS}
+
+
+
+
{/* ─── Contenido principal: Ruleta + Panel de pregunta ─── */}
@@ -148,10 +164,10 @@ export default function Game({ onEnd }: GameProps) {
background: 'linear-gradient(180deg, #ffffff 0%, #d8dcec 100%)',
}}
>
-
+
Gira la ruleta para obtener una pregunta
-
+
Cada respuesta correcta te acerca al objetivo de {MAX_PREGUNTAS} preguntas
diff --git a/src/components/screens/Intro.tsx b/src/components/screens/Intro.tsx
index d5e2569..e20c7d5 100644
--- a/src/components/screens/Intro.tsx
+++ b/src/components/screens/Intro.tsx
@@ -139,11 +139,14 @@ export default function Intro() {
{/* ─── Columna derecha (40%): texto ─────────── */}
-
+
{/* Texto introductorio */}
-
+
Hoy vamos a poner a prueba nuestros conocimientos y a reflexionar juntos sobre
- cómo nuestras acciones impactan el planeta. En esta ruleta tenemos{' '}
+ cómo nuestras acciones impactan el planeta.
+
+
+ En esta ruleta tenemos{' '}
4 ejes fundamentales para el futuro:
@@ -157,10 +160,13 @@ export default function Intro() {
src={`./img/${imagenes[i]}`}
alt={cat.nombre}
className="shrink-0 object-contain"
- style={{ width: '75px', height: '78px' }}
+ style={{
+ width: i === 1 ? '48px' : '60px',
+ height: i === 1 ? '50px' : '62px',
+ }}
/>
-
+
{cat.nombre}
{cat.nombre2 ? ` ${cat.nombre2}` : ''}
{cat.nombre3 ? ` ${cat.nombre3}` : ''}
diff --git a/src/components/screens/Result.tsx b/src/components/screens/Result.tsx
index e32fc47..40fcbb9 100644
--- a/src/components/screens/Result.tsx
+++ b/src/components/screens/Result.tsx
@@ -45,13 +45,13 @@ export default function Result(_props: ResultProps) {
>
Recorrimos desde la gestión del agua y los residuos, hasta la transición hacia energías más limpias y la movilidad del futuro. Más allá de las respuestas correctas o los puntos, lo verdaderamente importante es que la sostenibilidad no se queda en esta pantalla: se construye con las decisiones que tomamos todos los días.
Muchísimas gracias a todos por su participación, su energía y sus aportaciones.
@@ -77,7 +77,7 @@ export default function Result(_props: ResultProps) {
>
¡Nos llevamos grandes aprendizajes para seguir cuidando el planeta juntos!
diff --git a/src/hooks/useRuleta.ts b/src/hooks/useRuleta.ts
index d3bb486..7f2c85b 100644
--- a/src/hooks/useRuleta.ts
+++ b/src/hooks/useRuleta.ts
@@ -67,6 +67,17 @@ export function useRuleta() {
})
const rotacionRef = useRef(0)
+ const isSpinningRef = useRef(false)
+ const completadoRef = useRef(false)
+ const usadasRef = useRef>({})
+ const poolRef = useRef(poolInicial)
+ const girarRef = useRef<() => void>(() => {})
+
+ useEffect(() => {
+ usadasRef.current = estado.preguntasUsadasPorCategoria
+ poolRef.current = estado.preguntasPool
+ completadoRef.current = estado.completado
+ }, [estado.preguntasUsadasPorCategoria, estado.preguntasPool, estado.completado])
// ─── Temporizador por pregunta ───────────────────────────────────────────
useEffect(() => {
@@ -89,6 +100,12 @@ export function useRuleta() {
feedbackCorrecto: false,
completado,
aprobado,
+ preguntasUsadasPorCategoria: {
+ ...prev.preguntasUsadasPorCategoria,
+ ...(prev.categoriaActual
+ ? { [prev.categoriaActual.id]: (prev.preguntasUsadasPorCategoria[prev.categoriaActual.id] ?? 0) + 1 }
+ : {}),
+ },
}
}
@@ -99,38 +116,29 @@ export function useRuleta() {
return () => clearInterval(interval)
}, [estado.preguntaActual?.id, estado.mostrarFeedback, estado.completado])
- /**
- * Busca la siguiente pregunta disponible.
- * 1. Intenta usar la categoría donde cayó la ruleta (si le quedan preguntas).
- * 2. Si no, recorre las demás categorías en orden circular.
- * 3. Retorna null si ya se usaron las 12 preguntas.
- */
- function obtenerSiguientePregunta(
- catIndice: number,
- usadasPorCat: Record,
- pool: Record,
- ): { pregunta: Pregunta; categoria: Categoria } | null {
- // Recorrer desde catIndice en círculo
- for (let vuelta = 0; vuelta < SECCIONES; vuelta++) {
- const idx = (catIndice + vuelta) % SECCIONES
- const cat = categorias[idx]
- const usadas = usadasPorCat[cat.id] ?? 0
- const preguntasCat = pool[cat.id] ?? []
- if (usadas < preguntasCat.length) {
- return { pregunta: preguntasCat[usadas], categoria: cat }
- }
- }
- return null
- }
-
function girar() {
- if (estado.isSpinning || estado.completado) return
+ if (isSpinningRef.current || completadoRef.current) return
+ const hayDisponibles = categorias.some((cat) => {
+ const usadas = usadasRef.current[cat.id] ?? 0
+ return usadas < (poolRef.current[cat.id]?.length ?? 0)
+ })
+ if (!hayDisponibles) {
+ setEstado((prev) => ({
+ ...prev,
+ completado: true,
+ aprobado: prev.correctas >= MIN_CORRECTAS,
+ }))
+ return
+ }
+
+ isSpinningRef.current = true
sounds.wheelSpin?.play()
const vueltas = 3 + Math.random() * 2
- const anguloFinal = Math.random() * 360
- const rotacionTotal = rotacionRef.current + vueltas * 360 + anguloFinal
+ const anguloExtra = Math.random() * 360
+ const delta = vueltas * 360 + anguloExtra
+ const rotacionTotal = rotacionRef.current + delta
rotacionRef.current = rotacionTotal
setEstado((prev) => ({ ...prev, isSpinning: true, rotacion: rotacionTotal }))
@@ -138,33 +146,29 @@ export function useRuleta() {
setTimeout(() => {
const anguloNormalizado = ((360 - (rotacionRef.current % 360)) + 360) % 360
const indiceCategoria = Math.floor(anguloNormalizado / ANGULO_SECCION) % SECCIONES
+ const cat = categorias[indiceCategoria]
+ const usadas = usadasRef.current[cat.id] ?? 0
+ const preguntasCat = poolRef.current[cat.id] ?? []
- setEstado((prev) => {
- const resultado = obtenerSiguientePregunta(
- indiceCategoria,
- prev.preguntasUsadasPorCategoria,
- prev.preguntasPool,
- )
+ // Categoría sin preguntas → re-girar
+ if (usadas >= preguntasCat.length) {
+ isSpinningRef.current = false
+ setEstado((prev) => ({ ...prev, isSpinning: false }))
+ setTimeout(() => girarRef.current(), 600)
+ return
+ }
- if (!resultado) {
- // Ya no hay preguntas — marcar como completado
- return {
- ...prev,
- completado: true,
- aprobado: prev.correctas >= MIN_CORRECTAS,
- }
- }
-
- return {
- ...prev,
- preguntaActual: resultado.pregunta,
- categoriaActual: resultado.categoria,
- tiempoRestante: TIEMPO_LIMITE,
- }
- })
+ setEstado((prev) => ({
+ ...prev,
+ preguntaActual: preguntasCat[usadas],
+ categoriaActual: cat,
+ tiempoRestante: TIEMPO_LIMITE,
+ }))
}, 4000)
}
+ girarRef.current = girar
+
function responder(indiceOpcion: number) {
if (!estado.preguntaActual || !estado.categoriaActual) return
const esCorrecta = indiceOpcion === estado.preguntaActual.correcta
@@ -194,6 +198,7 @@ export function useRuleta() {
}
function cerrarFeedback() {
+ isSpinningRef.current = false
setEstado((prev) => ({
...prev,
preguntaActual: null,