// app/rankings/page.tsx // Rankings with pagination and adjustable page size import { query } from '@/lib/db'; import { TrophyIcon } from '@/components/ui/icons'; import Link from 'next/link'; export const dynamic = "force-dynamic"; interface RankingDriver { driver_guid: string; driver_name: string; user_rank: number; laps_completed: number; created_at: Date; } const PAGE_SIZE_OPTIONS = [25, 50, 100]; async function getRankings(page: number = 1, pageSize: number = 50): Promise<{ drivers: RankingDriver[]; totalCount: number }> { const offset = (page - 1) * pageSize; // Get total count const countResult = await query(`SELECT COUNT(*) as count FROM users`); const totalCount = countResult[0]?.count || 0; // Get paginated results const sql = ` SELECT driver_guid, driver_name, user_rank, laps_completed, created_at FROM users ORDER BY user_rank DESC LIMIT ${pageSize} OFFSET ${offset} `; const rows = await query(sql); return { drivers: rows as RankingDriver[], totalCount: totalCount }; } function getDriverClass(rank: number): { name: string; color: string } { if (rank >= 5000) return { name: 'S CLASS', color: 'text-white' }; if (rank >= 2500) return { name: 'A CLASS', color: 'text-white' }; if (rank >= 1750) return { name: 'B CLASS', color: 'text-white/80' }; if (rank >= 1250) return { name: 'C CLASS', color: 'text-white/60' }; return { name: 'D CLASS', color: 'text-white/40' }; } export default async function RankingsPage({ searchParams, }: { searchParams: Promise<{ page?: string; pageSize?: string }>; }) { // Await searchParams in Next.js 15+ const params = await searchParams; const currentPage = parseInt(params.page || '1'); const pageSize = parseInt(params.pageSize || '50'); const { drivers, totalCount } = await getRankings(currentPage, pageSize); const totalPages = Math.ceil(totalCount / pageSize); const startRank = (currentPage - 1) * pageSize + 1; return ( <> {/* Hero */}
DRIVER RANKINGS

LEADERBOARD

Global driver rankings based on performance, consistency, and clean racing

{totalCount.toLocaleString()} total drivers

{/* Class Explanation */}
{/* Rankings Table */}
{/* Page Size Selector */}
Items per page:
{PAGE_SIZE_OPTIONS.map((size) => ( {size} ))}
{drivers.map((driver, index) => { const driverClass = getDriverClass(driver.user_rank); const globalRank = startRank + index; const isPodium = globalRank <= 3; return ( ); })}
RANK DRIVER RATING CLASS LAPS STEAM ID
3 ? 'text-white/60' : ''} `}> {String(globalRank).padStart(2, '0')} {isPodium && ( {globalRank === 1 ? '█' : globalRank === 2 ? '▓' : '▒'} )} {driver.driver_name} {driver.user_rank.toLocaleString()} {driverClass.name} {driver.laps_completed.toLocaleString()} {driver.driver_guid}
{/* Pagination */} {totalPages > 1 && (
Page {currentPage} of {totalPages} • Showing {startRank}-{Math.min(startRank + pageSize - 1, totalCount)} of {totalCount.toLocaleString()}
{/* First Page */} {currentPage > 1 && ( «« )} {/* Previous Page */} {currentPage > 1 && ( ‹ PREV )} {/* Page Numbers */} {Array.from({ length: Math.min(5, totalPages) }, (_, i) => { let pageNum; if (totalPages <= 5) { pageNum = i + 1; } else if (currentPage <= 3) { pageNum = i + 1; } else if (currentPage >= totalPages - 2) { pageNum = totalPages - 4 + i; } else { pageNum = currentPage - 2 + i; } return ( {pageNum} ); })} {/* Next Page */} {currentPage < totalPages && ( NEXT › )} {/* Last Page */} {currentPage < totalPages && ( »» )}
)} {/* Info Box */}

RANKING SYSTEM

• Rating increases with clean racing and fast lap times

• Penalties applied for track cuts and collisions

• Class promotion based on consistent performance over multiple sessions

); } function ClassCard({ name, range, description }: { name: string; range: string; description: string; }) { return (
{name}
{range}
{description}
); }