Skip to content

Commit 1d03c86

Browse files
committed
fix: reparando SpaceComputer con un error de loop
1 parent a1a2e90 commit 1d03c86

5 files changed

Lines changed: 52 additions & 89 deletions

File tree

src/App.tsx

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { useState, useEffect } from "react";
2-
import { EventConfigProvider } from "./context/EventConfigContext";
32
import { MainLayout } from "./components/Layout/MainLayout";
43
import { IntroScreen } from "./components/Intro/IntroScreen";
54
import { HypothesisScreen } from "./components/Hypothesis/HypothesisScreen";
@@ -18,14 +17,22 @@ import type { GamePhase, Hypothesis } from "./types";
1817
import { Phase1Collider } from "./components/Games/Phase1Collider/Phase1Collider";
1918
import { Phase2Equation } from "./components/Games/Phase2Equation/Phase2Equation";
2019
import { Phase3Synthesis } from "./components/Games/Phase3Synthesis/Phase3Synthesis";
21-
import { logger } from "./utils/logger";
20+
import { logger } from "@/utils/logger";
2221

23-
function AppContent() {
22+
function App() {
2423
const [currentPhase, setCurrentPhase] = useState<GamePhase>("intro");
2524
const [isSaving, setIsSaving] = useState(false);
2625
const [isInitialized, setIsInitialized] = useState(false);
2726

28-
// ✅ HOOKS SIEMPRE AL INICIO - Antes de cualquier return condicional
27+
// Detectar si estamos en la ruta de admin
28+
const isAdminRoute = window.location.pathname === "/admin-stats-2025";
29+
30+
// Si es ruta admin, mostrar AdminPanel directamente
31+
if (isAdminRoute) {
32+
return <AdminPanel />;
33+
}
34+
35+
// Inicializar draft al montar el componente
2936
useEffect(() => {
3037
if (!hasDraft()) {
3138
initializeDraft();
@@ -36,41 +43,42 @@ function AppContent() {
3643
setIsInitialized(true);
3744
}, []);
3845

39-
// Detectar si estamos en la ruta de admin
40-
const isAdminRoute = window.location.pathname === "/admin-stats-2025";
41-
42-
// Si es ruta admin, mostrar AdminPanel directamente
43-
if (isAdminRoute) {
44-
return <AdminPanel />;
45-
}
46-
4746
const handleStart = () => {
4847
setCurrentPhase("hypothesis");
4948
};
5049

5150
const handleHypothesisSelect = (hypothesis: Hypothesis) => {
51+
// Sobrescribir hipótesis en localStorage (permite cambiar de opinión)
5252
updateHypothesis(hypothesis);
5353
logger.log(`✅ Hipótesis ${hypothesis} guardada en draft`);
54+
55+
// Navegar a InputScreen
5456
setCurrentPhase("input");
5557
};
5658

5759
const handleInputSubmit = async (data: InputData) => {
5860
logger.log("📝 Datos de input guardados en draft:", data);
5961

62+
// Verificar si el draft está listo para enviar
6063
const draft = getDraft();
6164

6265
if (isDraftPartiallyComplete(draft)) {
66+
// Si ya tiene todo lo necesario (hipótesis + datos personales)
67+
// Ir a los juegos primero
6368
setCurrentPhase("collider");
69+
6470
logger.log("🎮 Navegando a juegos. Draft completo:", draft);
6571
} else {
6672
alert("Faltan datos. Por favor completa el formulario.");
6773
}
6874
};
6975

7076
const handleInputBack = () => {
77+
// El draft se mantiene, solo volvemos a la fase anterior
7178
setCurrentPhase("hypothesis");
7279
};
7380

81+
// Función para enviar TODO a Firebase (llamar después de los 3 juegos)
7482
const handleFinalSubmit = async () => {
7583
setIsSaving(true);
7684

@@ -80,10 +88,16 @@ function AppContent() {
8088
logger.log("🚀 Enviando predicción completa a Firebase...");
8189
logger.log("📦 Draft final:", draft);
8290

91+
// Enviar a Firebase
8392
await submitPrediction(draft);
8493

8594
logger.log("✅ Predicción enviada exitosamente");
8695

96+
// IMPORTANTE: NO limpiar el draft todavía
97+
// SuccessScreen lo necesita para mostrar los datos
98+
// Se limpiará cuando el usuario cierre o recargue
99+
100+
// Navegar a pantalla de éxito
87101
setCurrentPhase("submitted");
88102
} catch (error) {
89103
logger.error("❌ Error al enviar predicción:", error);
@@ -93,18 +107,24 @@ function AppContent() {
93107
}
94108
};
95109

110+
// Handlers para los juegos
96111
const handleColliderComplete = (score: number) => {
97112
logger.log(`🎮 Collider completado: ${score} pts`);
113+
// updateGameScore("collider", score) ya se llama dentro del juego
98114
setCurrentPhase("equation");
99115
};
100116

101117
const handleEquationComplete = (score: number) => {
102118
logger.log(`🎮 Equation completado: ${score} pts`);
119+
// updateGameScore("equation", score) ya se llama dentro del juego
103120
setCurrentPhase("synthesis");
104121
};
105122

106123
const handleSynthesisComplete = async (score: number) => {
107124
logger.log(`🎮 Synthesis completado: ${score} pts`);
125+
// updateGameScore("synthesis", score) ya se llama dentro del juego
126+
127+
// Después del último juego, enviar TODO a Firebase
108128
await handleFinalSubmit();
109129
};
110130

@@ -120,6 +140,7 @@ function AppContent() {
120140

121141
return (
122142
<MainLayout currentPhase={currentPhase}>
143+
{/* Loading overlay cuando se envía a Firebase */}
123144
{isSaving && (
124145
<div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50 backdrop-blur-sm">
125146
<div className="bg-gray-900 border-2 border-cyan-500 rounded-xl p-8 text-center">
@@ -134,33 +155,38 @@ function AppContent() {
134155
</div>
135156
)}
136157

158+
{/* Fase Intro */}
137159
{currentPhase === "intro" && <IntroScreen onStart={handleStart} />}
160+
161+
{/* Fase Hypothesis */}
138162
{currentPhase === "hypothesis" && (
139163
<HypothesisScreen onHypothesisSelect={handleHypothesisSelect} />
140164
)}
165+
166+
{/* Fase Input */}
141167
{currentPhase === "input" && (
142168
<InputScreen onSubmit={handleInputSubmit} onBack={handleInputBack} />
143169
)}
170+
171+
{/* Juego 1: Collider */}
144172
{currentPhase === "collider" && (
145173
<Phase1Collider onComplete={handleColliderComplete} />
146174
)}
175+
176+
{/* Juego 2: Equation */}
147177
{currentPhase === "equation" && (
148178
<Phase2Equation onComplete={handleEquationComplete} />
149179
)}
180+
181+
{/* Juego 3: Synthesis */}
150182
{currentPhase === "synthesis" && (
151183
<Phase3Synthesis onComplete={handleSynthesisComplete} />
152184
)}
185+
186+
{/* Pantalla de éxito - SuccessScreen */}
153187
{currentPhase === "submitted" && <SuccessScreen />}
154188
</MainLayout>
155189
);
156190
}
157191

158-
function App() {
159-
return (
160-
<EventConfigProvider>
161-
<AppContent />
162-
</EventConfigProvider>
163-
);
164-
}
165-
166192
export default App;

src/components/Layout/SpaceComputer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { useMemo } from "react";
22
import { useCountdown } from "../../hooks/useCountdown";
3-
import { useEventConfigContext } from "../../context/EventConfigContext";
3+
import { useEventConfig } from "../../hooks/useEventConfig";
44
import type { GamePhase } from "../../types";
55

66
interface SpaceComputerProps {
77
currentPhase: GamePhase;
88
}
99

1010
export function SpaceComputer({ currentPhase }: SpaceComputerProps) {
11-
const { config } = useEventConfigContext();
11+
const { config } = useEventConfig();
1212

13-
// Memorizar la fecha target para evitar que cambie en cada render
13+
// Memorizar la fecha target para evitar que cambie en cada render
1414
const targetDate = useMemo(() => {
1515
return (
1616
config?.revealDate || new Date("2025-10-26T19:00:00-03:00").getTime()

src/context/EventConfigContext.tsx

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/hooks/useEventConfig.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,22 @@ import { useState, useEffect } from "react";
22
import { doc, getDoc } from "firebase/firestore";
33
import { db } from "../lib/firebase";
44
import type { EventConfig } from "../types";
5-
import { logger } from "../utils/logger";
6-
import { rateLimiter, RATE_LIMITS } from "../utils/rateLimiters";
5+
import { logger } from "@/utils/logger";
76

87
export function useEventConfig() {
98
const [config, setConfig] = useState<EventConfig | null>(null);
109
const [loading, setLoading] = useState(true);
1110
const [error, setError] = useState<string | null>(null);
1211

1312
useEffect(() => {
14-
let isMounted = true;
15-
1613
const fetchConfig = async () => {
17-
// ✅ Verificar rate limit ANTES de hacer la petición
18-
if (!rateLimiter.isAllowed("fetchConfig", RATE_LIMITS.CONFIG_FETCH)) {
19-
logger.warn("⚠️ Rate limit: fetchConfig bloqueado temporalmente");
20-
return;
21-
}
22-
2314
try {
2415
setLoading(true);
2516
setError(null);
2617

2718
const docRef = doc(db, "config", "event");
2819
const docSnap = await getDoc(docRef);
2920

30-
// Solo actualizar si el componente sigue montado
31-
if (!isMounted) return;
32-
3321
if (docSnap.exists()) {
3422
setConfig(docSnap.data() as EventConfig);
3523
logger.log("✅ Configuración cargada desde Firestore");
@@ -38,25 +26,16 @@ export function useEventConfig() {
3826
logger.error("❌ Documento config/event no existe");
3927
}
4028
} catch (err) {
41-
if (!isMounted) return;
42-
4329
const errorMessage =
4430
err instanceof Error ? err.message : "Error desconocido";
4531
setError(`Error al cargar configuración: ${errorMessage}`);
4632
logger.error("❌ Error en useEventConfig:", err);
4733
} finally {
48-
if (isMounted) {
49-
setLoading(false);
50-
}
34+
setLoading(false);
5135
}
5236
};
5337

5438
fetchConfig();
55-
56-
// Cleanup: marcar componente como desmontado
57-
return () => {
58-
isMounted = false;
59-
};
6039
}, []);
6140

6241
return { config, loading, error };

src/main.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
import { StrictMode } from "react";
21
import { createRoot } from "react-dom/client";
32
import "./index.css";
43
import App from "./App.tsx";
54
import { initSentry } from "./lib/sentry";
65

76
initSentry();
87

9-
createRoot(document.getElementById("root")!).render(
10-
<StrictMode>
11-
<App />
12-
</StrictMode>
13-
);
8+
createRoot(document.getElementById("root")!).render(<App />);

0 commit comments

Comments
 (0)