diff --git a/public/img/01.png b/public/img/01.png index e678abd..7957263 100644 Binary files a/public/img/01.png and b/public/img/01.png differ diff --git a/public/img/02.png b/public/img/02.png index 80db249..58d6bd2 100644 Binary files a/public/img/02.png and b/public/img/02.png differ diff --git a/public/img/fondo1.jpg b/public/img/fondo1.jpg index a37a752..224fd1e 100644 Binary files a/public/img/fondo1.jpg and b/public/img/fondo1.jpg differ diff --git a/src/components/game/FeedbackModal.tsx b/src/components/game/FeedbackModal.tsx index d6497a0..9ca1c3b 100644 --- a/src/components/game/FeedbackModal.tsx +++ b/src/components/game/FeedbackModal.tsx @@ -77,8 +77,8 @@ export default function FeedbackModal({

Reflexión: {reflexion}

@@ -144,7 +144,7 @@ export default function FeedbackModal({ > ¿Sabías qué? @@ -152,7 +152,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 ─── */} +
Indicador
- {/* ─── SVG principal (ruleta + anillo + soporte) ─── */} + {/* ─── SVG principal ─── */} {/* Logo izquierdo */}
- TIP + TIP
) 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) {
{categoria.nombre}
)} 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,