import { useState, useEffect } from 'react'; import { Get } from '../../../scripts/pocketbase/Get'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; import type { User, LimitedUser } from '../../../schemas/pocketbase/schema'; import { Collections } from '../../../schemas/pocketbase/schema'; interface LeaderboardUser { id: string; name: string; points: number; avatar?: string; major?: string; } // Trophy icon SVG for the rankings const TrophyIcon = ({ className }: { className: string }) => ( ); export default function LeaderboardTable() { const [users, setUsers] = useState([]); const [filteredUsers, setFilteredUsers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [currentUserRank, setCurrentUserRank] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [currentPage, setCurrentPage] = useState(1); const [isAuthenticated, setIsAuthenticated] = useState(false); const usersPerPage = 10; const [currentUserId, setCurrentUserId] = useState(null); const get = Get.getInstance(); const auth = Authentication.getInstance(); // Set the current user ID once on component mount useEffect(() => { try { // Use the Authentication class directly const isLoggedIn = auth.isAuthenticated(); setIsAuthenticated(isLoggedIn); if (isLoggedIn) { const user = auth.getCurrentUser(); if (user && user.id) { setCurrentUserId(user.id); } else { setLoading(false); } } else { setLoading(false); } } catch (err) { console.error('Error checking authentication:', err); setLoading(false); } }, []); useEffect(() => { const fetchLeaderboard = async () => { try { setLoading(true); // Fetch users without sorting - we'll sort on client side const response = await get.getList(Collections.LIMITED_USERS, 1, 100, '', '', { fields: ['id', 'name', 'points', 'avatar', 'major'] }); // First get the current user separately so we can include them even if they have 0 points let currentUserData = null; if (isAuthenticated && currentUserId) { currentUserData = response.items.find((user: Partial) => user.id === currentUserId); } // Parse points from JSON string and convert to number const processedUsers = response.items.map((user: any) => { let pointsValue = 0; try { if (user.points) { // Parse the JSON string to get the points value const pointsData = JSON.parse(user.points); pointsValue = typeof pointsData === 'number' ? pointsData : 0; } } catch (e) { console.error('Error parsing points data:', e); } return { id: user.id, name: user.name, major: user.major, avatar: user.avatar, // Include avatar if it exists points: user.points, parsedPoints: pointsValue }; }); // Filter and map to our leaderboard user format, and sort client-side let leaderboardUsers = processedUsers .filter(user => user.parsedPoints > 0) .sort((a, b) => (b.parsedPoints || 0) - (a.parsedPoints || 0)) .map((user, index: number) => { // Check if this is the current user if (isAuthenticated && user.id === currentUserId) { setCurrentUserRank(index + 1); } return { id: user.id || '', name: user.name || 'Anonymous User', points: user.parsedPoints, avatar: user.avatar, major: user.major }; }); // Include current user even if they have 0 points, // but don't include in ranking if they have no points if (isAuthenticated && currentUserId) { // Find current user in processed users const currentUserProcessed = processedUsers.find(user => user.id === currentUserId); // If current user exists and isn't already in the leaderboard (has 0 points) if (currentUserProcessed && !leaderboardUsers.some(user => user.id === currentUserId)) { leaderboardUsers.push({ id: currentUserProcessed.id || '', name: currentUserProcessed.name || 'Anonymous User', points: currentUserProcessed.parsedPoints || 0, avatar: currentUserProcessed.avatar, major: currentUserProcessed.major }); } } setUsers(leaderboardUsers); setFilteredUsers(leaderboardUsers); } catch (err) { console.error('Error fetching leaderboard:', err); setError('Failed to load leaderboard data'); } finally { setLoading(false); } }; fetchLeaderboard(); }, [get, isAuthenticated, currentUserId]); useEffect(() => { if (searchQuery.trim() === '') { setFilteredUsers(users); setCurrentPage(1); return; } const filtered = users.filter(user => user.name.toLowerCase().includes(searchQuery.toLowerCase()) || (user.major && user.major.toLowerCase().includes(searchQuery.toLowerCase())) ); setFilteredUsers(filtered); setCurrentPage(1); }, [searchQuery, users]); // Get current users for pagination const indexOfLastUser = currentPage * usersPerPage; const indexOfFirstUser = indexOfLastUser - usersPerPage; const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser); const totalPages = Math.ceil(filteredUsers.length / usersPerPage); const paginate = (pageNumber: number) => setCurrentPage(pageNumber); if (loading) { return (
); } if (error) { return (
{error}
); } if (users.length === 0) { return (

No users with points found

); } return (
{/* Search bar */}
setSearchQuery(e.target.value)} />
{/* Leaderboard table */}
{currentUsers.map((user, index) => { const actualRank = user.points > 0 ? indexOfFirstUser + index + 1 : null; const isCurrentUser = user.id === currentUserId; return ( ); })}
Rank User Points
{actualRank ? ( actualRank <= 3 ? ( {actualRank === 1 && } {actualRank === 2 && } {actualRank === 3 && } ) : ( {actualRank} ) ) : ( Not Ranked )}
{user.avatar ? ( {user.name} ) : ( {user.name.charAt(0).toUpperCase()} )}
{user.name}
{user.major && (
{user.major}
)}
{user.points}
{/* Pagination */} {totalPages > 1 && (
)} {/* Show current user rank if not in current page */} {isAuthenticated && currentUserRank && !currentUsers.some(user => user.id === currentUserId) && (

Your rank: #{currentUserRank}

)} {/* Current user with 0 points */} {isAuthenticated && currentUserId && !currentUserRank && currentUsers.some(user => user.id === currentUserId) && (

Participate in events to earn points and get ranked!

)}
); }