Spaces:
Running
Running
Update cointube.jsx
Browse files- cointube.jsx +35 -19
cointube.jsx
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
| 13 |
onSnapshot,
|
| 14 |
setDoc,
|
| 15 |
updateDoc,
|
| 16 |
-
deleteDoc,
|
| 17 |
collection,
|
| 18 |
addDoc,
|
| 19 |
increment,
|
|
@@ -126,13 +126,23 @@ export default function App() {
|
|
| 126 |
return () => unsubscribe();
|
| 127 |
}, [firebaseReady]);
|
| 128 |
|
| 129 |
-
// --- 5. RANKING ---
|
| 130 |
useEffect(() => {
|
| 131 |
if (!firebaseReady || !db) return;
|
| 132 |
-
|
|
|
|
| 133 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 134 |
-
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
});
|
| 137 |
return () => unsubscribe();
|
| 138 |
}, [firebaseReady]);
|
|
@@ -218,9 +228,8 @@ export default function App() {
|
|
| 218 |
if (playerRef.current) playerRef.current.loadVideoById(video.videoId);
|
| 219 |
};
|
| 220 |
|
| 221 |
-
// --- FUNCION NUEVA: BORRAR VIDEO (SOLO ADMIN) ---
|
| 222 |
const handleDeleteVideo = async (e, videoId) => {
|
| 223 |
-
e.stopPropagation();
|
| 224 |
if (!confirm("¿Estás seguro de que quieres ELIMINAR este video?")) return;
|
| 225 |
|
| 226 |
try {
|
|
@@ -335,12 +344,10 @@ export default function App() {
|
|
| 335 |
{videos.map((video) => (
|
| 336 |
<button key={video.id} onClick={() => loadVideo(video)} className={`w-full text-left p-2 rounded flex justify-between items-center group ${video.videoId === currentVideoId ? 'bg-blue-900 border-l-2 border-blue-500' : 'bg-gray-700 hover:bg-gray-600'}`}>
|
| 337 |
<div className="text-sm text-white truncate flex-1">{video.title}</div>
|
| 338 |
-
|
| 339 |
-
{/* BOTÓN DE BORRAR (SOLO ADMIN) */}
|
| 340 |
{user?.email === ADMIN_EMAIL && (
|
| 341 |
<span
|
| 342 |
onClick={(e) => handleDeleteVideo(e, video.id)}
|
| 343 |
-
className="ml-2 text-red-500 hover:text-red-300 font-bold px-2 py-1 rounded bg-red-900/50 hover:bg-red-900"
|
| 344 |
title="Borrar Video"
|
| 345 |
>
|
| 346 |
X
|
|
@@ -351,19 +358,28 @@ export default function App() {
|
|
| 351 |
</div>
|
| 352 |
</div>
|
| 353 |
|
| 354 |
-
{/* RANKING
|
| 355 |
<div className="bg-gray-800 rounded p-4 flex-1 flex flex-col min-h-[200px]">
|
| 356 |
<h3 className="text-yellow-500 text-sm uppercase font-bold mb-2">Ranking Global</h3>
|
| 357 |
<div className="overflow-y-auto flex-1 pr-2 custom-scrollbar space-y-2">
|
| 358 |
-
{leaderboard.
|
| 359 |
-
|
| 360 |
-
{
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
</div>
|
| 366 |
-
)
|
| 367 |
</div>
|
| 368 |
</div>
|
| 369 |
</aside>
|
|
|
|
| 13 |
onSnapshot,
|
| 14 |
setDoc,
|
| 15 |
updateDoc,
|
| 16 |
+
deleteDoc,
|
| 17 |
collection,
|
| 18 |
addDoc,
|
| 19 |
increment,
|
|
|
|
| 126 |
return () => unsubscribe();
|
| 127 |
}, [firebaseReady]);
|
| 128 |
|
| 129 |
+
// --- 5. RANKING (FILTRADO POR GMAIL Y PUNTOS > 0) ---
|
| 130 |
useEffect(() => {
|
| 131 |
if (!firebaseReady || !db) return;
|
| 132 |
+
// Pedimos 100 para tener margen de filtrado
|
| 133 |
+
const q = query(collection(db, 'users'), orderBy('coins', 'desc'), limit(100));
|
| 134 |
const unsubscribe = onSnapshot(q, (snapshot) => {
|
| 135 |
+
let usersList = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
| 136 |
+
|
| 137 |
+
// --- FILTROS NUEVOS ---
|
| 138 |
+
usersList = usersList.filter(u =>
|
| 139 |
+
u.coins > 0 && // Que tenga monedas
|
| 140 |
+
u.email &&
|
| 141 |
+
u.email.endsWith('@gmail.com') // Que sea Gmail
|
| 142 |
+
);
|
| 143 |
+
|
| 144 |
+
// Nos quedamos con los top 20 después de filtrar
|
| 145 |
+
setLeaderboard(usersList.slice(0, 20));
|
| 146 |
});
|
| 147 |
return () => unsubscribe();
|
| 148 |
}, [firebaseReady]);
|
|
|
|
| 228 |
if (playerRef.current) playerRef.current.loadVideoById(video.videoId);
|
| 229 |
};
|
| 230 |
|
|
|
|
| 231 |
const handleDeleteVideo = async (e, videoId) => {
|
| 232 |
+
e.stopPropagation();
|
| 233 |
if (!confirm("¿Estás seguro de que quieres ELIMINAR este video?")) return;
|
| 234 |
|
| 235 |
try {
|
|
|
|
| 344 |
{videos.map((video) => (
|
| 345 |
<button key={video.id} onClick={() => loadVideo(video)} className={`w-full text-left p-2 rounded flex justify-between items-center group ${video.videoId === currentVideoId ? 'bg-blue-900 border-l-2 border-blue-500' : 'bg-gray-700 hover:bg-gray-600'}`}>
|
| 346 |
<div className="text-sm text-white truncate flex-1">{video.title}</div>
|
|
|
|
|
|
|
| 347 |
{user?.email === ADMIN_EMAIL && (
|
| 348 |
<span
|
| 349 |
onClick={(e) => handleDeleteVideo(e, video.id)}
|
| 350 |
+
className="ml-2 text-red-500 hover:text-red-300 font-bold px-2 py-1 rounded bg-red-900/50 hover:bg-red-900 cursor-pointer"
|
| 351 |
title="Borrar Video"
|
| 352 |
>
|
| 353 |
X
|
|
|
|
| 358 |
</div>
|
| 359 |
</div>
|
| 360 |
|
| 361 |
+
{/* RANKING ACTUALIZADO */}
|
| 362 |
<div className="bg-gray-800 rounded p-4 flex-1 flex flex-col min-h-[200px]">
|
| 363 |
<h3 className="text-yellow-500 text-sm uppercase font-bold mb-2">Ranking Global</h3>
|
| 364 |
<div className="overflow-y-auto flex-1 pr-2 custom-scrollbar space-y-2">
|
| 365 |
+
{leaderboard.length > 0 ? (
|
| 366 |
+
leaderboard.map((u, i) => (
|
| 367 |
+
<div key={u.id || i} className="flex justify-between items-center p-2 bg-gray-700 rounded">
|
| 368 |
+
{/* Correo en letra pequeña, sin #1 */}
|
| 369 |
+
<span className="text-xs text-gray-300 truncate mr-2" title={u.email}>
|
| 370 |
+
{u.email}
|
| 371 |
+
</span>
|
| 372 |
+
{/* Monedas */}
|
| 373 |
+
<span className="text-yellow-400 font-mono text-sm whitespace-nowrap">
|
| 374 |
+
{Math.floor(u.coins)}
|
| 375 |
+
</span>
|
| 376 |
+
</div>
|
| 377 |
+
))
|
| 378 |
+
) : (
|
| 379 |
+
<div className="text-center text-gray-500 text-sm py-4">
|
| 380 |
+
Esperando usuarios con monedas...
|
| 381 |
</div>
|
| 382 |
+
)}
|
| 383 |
</div>
|
| 384 |
</div>
|
| 385 |
</aside>
|