Spaces:
Running
Running
Update cointube.jsx
Browse files- cointube.jsx +12 -32
cointube.jsx
CHANGED
|
@@ -23,22 +23,18 @@ import {
|
|
| 23 |
limit
|
| 24 |
} from 'firebase/firestore';
|
| 25 |
|
| 26 |
-
// --- CAMBIO IMPORTANTE: Inicialización Global ---
|
| 27 |
-
// Definimos la configuración usando las variables de entorno de Hugging Face (Vite)
|
| 28 |
const firebaseConfig = {
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
};
|
| 36 |
|
| 37 |
-
// Inicializamos Firebase inmediatamente
|
| 38 |
const app = initializeApp(firebaseConfig);
|
| 39 |
const auth = getAuth(app);
|
| 40 |
const db = getFirestore(app);
|
| 41 |
-
// ------------------------------------------------
|
| 42 |
|
| 43 |
const ADMIN_EMAIL = "dimensionalpulsar@gmail.com";
|
| 44 |
const VIDEO_COST = 10000;
|
|
@@ -47,11 +43,6 @@ const DEFAULT_VIDEO_TITLE = "Cuentos de Terror";
|
|
| 47 |
|
| 48 |
export default function App() {
|
| 49 |
|
| 50 |
-
// Ya no necesitamos 'configError' porque cargamos la config directa
|
| 51 |
-
// Pero mantenemos 'firebaseReady' para no romper tu lógica visual,
|
| 52 |
-
// aunque ahora siempre será true desde el inicio.
|
| 53 |
-
const [firebaseReady, setFirebaseReady] = useState(true);
|
| 54 |
-
|
| 55 |
const [videos, setVideos] = useState([]);
|
| 56 |
const [leaderboard, setLeaderboard] = useState([]);
|
| 57 |
const [user, setUser] = useState(null);
|
|
@@ -70,10 +61,7 @@ export default function App() {
|
|
| 70 |
const localCoinBufferRef = useRef(0);
|
| 71 |
const initialLoadRef = useRef(true);
|
| 72 |
|
| 73 |
-
// --- NOTA: Eliminé el useEffect del 'fetch' porque ya inicializamos arriba ---
|
| 74 |
-
|
| 75 |
useEffect(() => {
|
| 76 |
-
if (!auth) return;
|
| 77 |
const unsubscribeAuth = onAuthStateChanged(auth, (user) => {
|
| 78 |
if (user) {
|
| 79 |
setUser(user);
|
|
@@ -86,10 +74,10 @@ export default function App() {
|
|
| 86 |
setAuthReady(true);
|
| 87 |
});
|
| 88 |
return () => unsubscribeAuth();
|
| 89 |
-
}, []);
|
| 90 |
|
| 91 |
useEffect(() => {
|
| 92 |
-
if (!userId
|
| 93 |
const profileRef = doc(db, 'users', userId);
|
| 94 |
const unsubscribeProfile = onSnapshot(profileRef, (docSnap) => {
|
| 95 |
if (docSnap.exists()) {
|
|
@@ -105,10 +93,9 @@ export default function App() {
|
|
| 105 |
}
|
| 106 |
}, (error) => console.error(error));
|
| 107 |
return () => unsubscribeProfile();
|
| 108 |
-
}, [userId, user]);
|
| 109 |
|
| 110 |
useEffect(() => {
|
| 111 |
-
if (!db) return;
|
| 112 |
const q = query(collection(db, 'videos'), orderBy('createdAt', 'desc'), limit(50));
|
| 113 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 114 |
const fetchedVideos = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
|
@@ -134,7 +121,6 @@ export default function App() {
|
|
| 134 |
}, [currentVideoId]);
|
| 135 |
|
| 136 |
useEffect(() => {
|
| 137 |
-
if (!db) return;
|
| 138 |
const q = query(collection(db, 'users'), orderBy('coins', 'desc'), limit(100));
|
| 139 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 140 |
let usersList = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
|
@@ -162,7 +148,7 @@ export default function App() {
|
|
| 162 |
}, []);
|
| 163 |
|
| 164 |
const saveCoinBuffer = useCallback(() => {
|
| 165 |
-
if (localCoinBufferRef.current > 0 && userId
|
| 166 |
const coinsToSave = localCoinBufferRef.current;
|
| 167 |
localCoinBufferRef.current = 0;
|
| 168 |
const profileRef = doc(db, 'users', userId);
|
|
@@ -198,7 +184,7 @@ export default function App() {
|
|
| 198 |
else stopCoinInterval();
|
| 199 |
|
| 200 |
if (state === window.YT.PlayerState.ENDED) {
|
| 201 |
-
if (currentVideoId === DEFAULT_VIDEO_ID && userId
|
| 202 |
const profileRef = doc(db, 'users', userId);
|
| 203 |
updateDoc(profileRef, { watchedDefaultVideo: true });
|
| 204 |
}
|
|
@@ -251,7 +237,6 @@ export default function App() {
|
|
| 251 |
};
|
| 252 |
|
| 253 |
const handleGoogleLogin = async () => {
|
| 254 |
-
if (!auth) return;
|
| 255 |
const provider = new GoogleAuthProvider();
|
| 256 |
try {
|
| 257 |
await signInWithPopup(auth, provider);
|
|
@@ -261,7 +246,6 @@ export default function App() {
|
|
| 261 |
};
|
| 262 |
|
| 263 |
const handleLogout = async () => {
|
| 264 |
-
if (!auth) return;
|
| 265 |
stopCoinInterval();
|
| 266 |
await signOut(auth);
|
| 267 |
};
|
|
@@ -270,13 +254,12 @@ export default function App() {
|
|
| 270 |
return (
|
| 271 |
<div className="flex flex-col items-center justify-center h-full w-full">
|
| 272 |
<div className="spinner mb-4"></div>
|
| 273 |
-
<p className="text-lg text-gray-400">
|
| 274 |
</div>
|
| 275 |
);
|
| 276 |
}
|
| 277 |
|
| 278 |
if (authReady && !user) {
|
| 279 |
-
// ... (TU UI DE LOGIN SE MANTIENE IGUAL)
|
| 280 |
return (
|
| 281 |
<div className="flex flex-col items-center justify-center h-full w-full bg-gray-900 p-4">
|
| 282 |
<div className="max-w-md w-full bg-gray-800 rounded-2xl shadow-2xl p-8 text-center border border-gray-700">
|
|
@@ -310,7 +293,6 @@ export default function App() {
|
|
| 310 |
);
|
| 311 |
}
|
| 312 |
|
| 313 |
-
// El resto del return (header, main, etc) sigue igual que en tu código original...
|
| 314 |
return (
|
| 315 |
<div className="h-full w-full max-w-7xl mx-auto flex flex-col p-4 md:p-6">
|
| 316 |
|
|
@@ -439,8 +421,6 @@ export default function App() {
|
|
| 439 |
);
|
| 440 |
}
|
| 441 |
|
| 442 |
-
// Los componentes PromoCheck y PromoUnlocked se mantienen igual,
|
| 443 |
-
// solo asegúrate de que PromoUnlocked reciba 'db' como prop, lo cual ya haces.
|
| 444 |
function PromoCheck({ user, userProfile, userId, adminEmail, videoCost, db }) {
|
| 445 |
const isAdmin = user?.email === adminEmail;
|
| 446 |
const coins = userProfile?.coins || 0;
|
|
|
|
| 23 |
limit
|
| 24 |
} from 'firebase/firestore';
|
| 25 |
|
|
|
|
|
|
|
| 26 |
const firebaseConfig = {
|
| 27 |
+
apiKey: "AIzaSyDJx6_b3JxctCW1RoDE-bm4zp7rrWT9lqA",
|
| 28 |
+
authDomain: "cointube-f7695.firebaseapp.com",
|
| 29 |
+
projectId: "cointube-f7695",
|
| 30 |
+
storageBucket: "cointube-f7695.firebasestorage.app",
|
| 31 |
+
messagingSenderId: "710177637377",
|
| 32 |
+
appId: "1:710177637377:web:10605b43eea6eac446ac00"
|
| 33 |
};
|
| 34 |
|
|
|
|
| 35 |
const app = initializeApp(firebaseConfig);
|
| 36 |
const auth = getAuth(app);
|
| 37 |
const db = getFirestore(app);
|
|
|
|
| 38 |
|
| 39 |
const ADMIN_EMAIL = "dimensionalpulsar@gmail.com";
|
| 40 |
const VIDEO_COST = 10000;
|
|
|
|
| 43 |
|
| 44 |
export default function App() {
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
const [videos, setVideos] = useState([]);
|
| 47 |
const [leaderboard, setLeaderboard] = useState([]);
|
| 48 |
const [user, setUser] = useState(null);
|
|
|
|
| 61 |
const localCoinBufferRef = useRef(0);
|
| 62 |
const initialLoadRef = useRef(true);
|
| 63 |
|
|
|
|
|
|
|
| 64 |
useEffect(() => {
|
|
|
|
| 65 |
const unsubscribeAuth = onAuthStateChanged(auth, (user) => {
|
| 66 |
if (user) {
|
| 67 |
setUser(user);
|
|
|
|
| 74 |
setAuthReady(true);
|
| 75 |
});
|
| 76 |
return () => unsubscribeAuth();
|
| 77 |
+
}, []);
|
| 78 |
|
| 79 |
useEffect(() => {
|
| 80 |
+
if (!userId) return;
|
| 81 |
const profileRef = doc(db, 'users', userId);
|
| 82 |
const unsubscribeProfile = onSnapshot(profileRef, (docSnap) => {
|
| 83 |
if (docSnap.exists()) {
|
|
|
|
| 93 |
}
|
| 94 |
}, (error) => console.error(error));
|
| 95 |
return () => unsubscribeProfile();
|
| 96 |
+
}, [userId, user]);
|
| 97 |
|
| 98 |
useEffect(() => {
|
|
|
|
| 99 |
const q = query(collection(db, 'videos'), orderBy('createdAt', 'desc'), limit(50));
|
| 100 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 101 |
const fetchedVideos = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
|
|
|
| 121 |
}, [currentVideoId]);
|
| 122 |
|
| 123 |
useEffect(() => {
|
|
|
|
| 124 |
const q = query(collection(db, 'users'), orderBy('coins', 'desc'), limit(100));
|
| 125 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 126 |
let usersList = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
|
|
|
| 148 |
}, []);
|
| 149 |
|
| 150 |
const saveCoinBuffer = useCallback(() => {
|
| 151 |
+
if (localCoinBufferRef.current > 0 && userId) {
|
| 152 |
const coinsToSave = localCoinBufferRef.current;
|
| 153 |
localCoinBufferRef.current = 0;
|
| 154 |
const profileRef = doc(db, 'users', userId);
|
|
|
|
| 184 |
else stopCoinInterval();
|
| 185 |
|
| 186 |
if (state === window.YT.PlayerState.ENDED) {
|
| 187 |
+
if (currentVideoId === DEFAULT_VIDEO_ID && userId) {
|
| 188 |
const profileRef = doc(db, 'users', userId);
|
| 189 |
updateDoc(profileRef, { watchedDefaultVideo: true });
|
| 190 |
}
|
|
|
|
| 237 |
};
|
| 238 |
|
| 239 |
const handleGoogleLogin = async () => {
|
|
|
|
| 240 |
const provider = new GoogleAuthProvider();
|
| 241 |
try {
|
| 242 |
await signInWithPopup(auth, provider);
|
|
|
|
| 246 |
};
|
| 247 |
|
| 248 |
const handleLogout = async () => {
|
|
|
|
| 249 |
stopCoinInterval();
|
| 250 |
await signOut(auth);
|
| 251 |
};
|
|
|
|
| 254 |
return (
|
| 255 |
<div className="flex flex-col items-center justify-center h-full w-full">
|
| 256 |
<div className="spinner mb-4"></div>
|
| 257 |
+
<p className="text-lg text-gray-400">Cargando...</p>
|
| 258 |
</div>
|
| 259 |
);
|
| 260 |
}
|
| 261 |
|
| 262 |
if (authReady && !user) {
|
|
|
|
| 263 |
return (
|
| 264 |
<div className="flex flex-col items-center justify-center h-full w-full bg-gray-900 p-4">
|
| 265 |
<div className="max-w-md w-full bg-gray-800 rounded-2xl shadow-2xl p-8 text-center border border-gray-700">
|
|
|
|
| 293 |
);
|
| 294 |
}
|
| 295 |
|
|
|
|
| 296 |
return (
|
| 297 |
<div className="h-full w-full max-w-7xl mx-auto flex flex-col p-4 md:p-6">
|
| 298 |
|
|
|
|
| 421 |
);
|
| 422 |
}
|
| 423 |
|
|
|
|
|
|
|
| 424 |
function PromoCheck({ user, userProfile, userId, adminEmail, videoCost, db }) {
|
| 425 |
const isAdmin = user?.email === adminEmail;
|
| 426 |
const coins = userProfile?.coins || 0;
|