diff --git a/src/pages/GitRank.jsx b/src/pages/GitRank.jsx index 2383c61..2f253de 100644 --- a/src/pages/GitRank.jsx +++ b/src/pages/GitRank.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useMemo } from "react"; import { Search, Filter, Star, Trophy, RefreshCw, GitCommit, Calendar, BookOpen, AlertCircle, CheckCircle2 } from "lucide-react"; -import { collection, query, where, onSnapshot, doc, runTransaction } from "firebase/firestore"; +import { collection, query, where, doc, updateDoc, orderBy, limit, startAfter, onSnapshot, getDocs, runTransaction } from "firebase/firestore"; import { useSearchParams } from "react-router-dom"; import { db } from "../lib/firebase"; import { useAuth } from "../context/AuthContext"; @@ -14,6 +14,11 @@ export const GitRank = () => { const [searchParams] = useSearchParams(); const [searchTerm, setSearchTerm] = useState(searchParams.get("search") || ""); const [selectedLanguage, setSelectedLanguage] = useState("All"); + + // Pagination States + const [lastVisible, setLastVisible] = useState(null); + const [hasMore, setHasMore] = useState(true); + const [loadingMore, setLoadingMore] = useState(false); // Real-time leaderboard state const [usersList, setUsersList] = useState([]); @@ -31,19 +36,14 @@ export const GitRank = () => { const languages = ["All", "TypeScript", "Rust", "Go", "Python", "Kotlin", "Ruby", "JavaScript"]; - // 1. Real-time Leaderboard Listener + // 1. Real-time Leaderboard Listener (Initial 50 Users) useEffect(() => { - // Only listen if user is logged in (due to read rules requiring authentication) - if (!user) { - const timer = setTimeout(() => { - setLoadingUsers(false); - }, 0); - return () => clearTimeout(timer); - } + setLoadingUsers(true); const q = query( collection(db, "users"), - where("onboardingStatus", "==", "complete") + orderBy("points.totalPoints", "desc"), + limit(50) ); const unsubscribe = onSnapshot( @@ -54,16 +54,16 @@ export const GitRank = () => { users.push(doc.data()); }); - // Sort by totalPoints descending - users.sort((a, b) => (b.points?.totalPoints || 0) - (a.points?.totalPoints || 0)); - - // Assign ranks const ranked = users.map((u, i) => ({ ...u, rank: i + 1 })); setUsersList(ranked); + + // Setup pagination cursors + setLastVisible(snapshot.docs[snapshot.docs.length - 1]); + setHasMore(snapshot.docs.length === 50); setLoadingUsers(false); }, (error) => { @@ -73,7 +73,50 @@ export const GitRank = () => { ); return () => unsubscribe(); - }, [user]); + }, []); + + // Pagination Function (Fetch next 50) + const loadMoreUsers = async () => { + if (!lastVisible || !hasMore || loadingMore) return; + + setLoadingMore(true); + try { + const nextQuery = query( + collection(db, "users"), + orderBy("points.totalPoints", "desc"), + startAfter(lastVisible), + limit(50) + ); + + const snapshot = await getDocs(nextQuery); + + if (snapshot.empty) { + setHasMore(false); + setLoadingMore(false); + return; + } + + const newUsers = []; + snapshot.forEach((doc) => { + newUsers.push(doc.data()); + }); + + setUsersList((prevUsers) => { + const combinedUsers = [...prevUsers, ...newUsers]; + return combinedUsers.map((u, i) => ({ + ...u, + rank: i + 1 + })); + }); + + setLastVisible(snapshot.docs[snapshot.docs.length - 1]); + setHasMore(snapshot.docs.length === 50); + } catch (error) { + console.error("Error fetching more users:", error); + } finally { + setLoadingMore(false); + } + }; // 2. Fetch GitHub Events/Repos for Charts useEffect(() => { @@ -901,8 +944,36 @@ export const GitRank = () => { )} + + {/* PAGINATION CONTROLS ADDED HERE */} + {hasMore && ( +
+ +
+ )} + + {!hasMore && usersList.length > 0 && ( +
+ You've reached the end of the leaderboard! 🏆 +
+ )} + {/* 🚀 👆 YAHAN TAK 👆 🚀 */} + ); }; -export default GitRank; +export default GitRank; \ No newline at end of file