import { redirect } from 'next/navigation'; import Image from 'next/image'; import Link from 'next/link'; import { Calendar, Trophy, Users, Star, Clock, Flag, TrendingUp, ChevronRight, Zap, Target, Award, Activity, Play, Bell, Medal, Crown, Heart, MessageCircle, UserPlus, } from 'lucide-react'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import { getAuthService } from '@/lib/auth'; import { getFeedRepository, getRaceRepository, getResultRepository, getDriverRepository, getLeagueRepository, getStandingRepository, getSocialRepository, getDriverStats, getImageService, getLeagueMembershipRepository, } from '@/lib/di-container'; import type { FeedItem } from '@gridpilot/social/domain/entities/FeedItem'; import type { Race } from '@gridpilot/racing/domain/entities/Race'; import type { Driver } from '@gridpilot/racing/domain/entities/Driver'; export const dynamic = 'force-dynamic'; // Helper functions function getCountryFlag(countryCode: string): string { const code = countryCode.toUpperCase(); if (code.length === 2) { const codePoints = [...code].map(char => 127397 + char.charCodeAt(0)); return String.fromCodePoint(...codePoints); } return '🏁'; } function timeUntil(date: Date): string { const now = new Date(); const diffMs = date.getTime() - now.getTime(); if (diffMs < 0) return 'Started'; const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffHours / 24); if (diffDays > 0) { return `${diffDays}d ${diffHours % 24}h`; } if (diffHours > 0) { const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60)); return `${diffHours}h ${diffMinutes}m`; } const diffMinutes = Math.floor(diffMs / (1000 * 60)); return `${diffMinutes}m`; } function timeAgo(timestamp: Date): string { const diffMs = Date.now() - timestamp.getTime(); const diffMinutes = Math.floor(diffMs / 60000); if (diffMinutes < 1) return 'Just now'; if (diffMinutes < 60) return `${diffMinutes}m ago`; const diffHours = Math.floor(diffMinutes / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; } function getGreeting(): string { const hour = new Date().getHours(); if (hour < 12) return 'Good morning'; if (hour < 18) return 'Good afternoon'; return 'Good evening'; } export default async function DashboardPage() { const authService = getAuthService(); const session = await authService.getCurrentSession(); if (!session) { redirect('/auth/iracing?returnTo=/dashboard'); } const feedRepository = getFeedRepository(); const raceRepository = getRaceRepository(); const resultRepository = getResultRepository(); const driverRepository = getDriverRepository(); const leagueRepository = getLeagueRepository(); const standingRepository = getStandingRepository(); const socialRepository = getSocialRepository(); const leagueMembershipRepository = getLeagueMembershipRepository(); const imageService = getImageService(); const currentDriverId = session.user.primaryDriverId ?? ''; const currentDriver = await driverRepository.findById(currentDriverId); const [feedItems, allRaces, allResults, allLeagues, friends] = await Promise.all([ feedRepository.getFeedForDriver(currentDriverId), raceRepository.findAll(), resultRepository.findAll(), leagueRepository.findAll(), socialRepository.getFriends(currentDriverId), ]); // Get driver's leagues by checking membership in each league const driverLeagues: typeof allLeagues = []; for (const league of allLeagues) { const membership = await leagueMembershipRepository.getMembership(league.id, currentDriverId); if (membership && membership.status === 'active') { driverLeagues.push(league); } } const driverLeagueIds = driverLeagues.map(l => l.id); // Upcoming races (prioritize driver's leagues) const upcomingRaces = allRaces .filter((race) => race.status === 'scheduled') .sort((a, b) => a.scheduledAt.getTime() - b.scheduledAt.getTime()); const myUpcomingRaces = upcomingRaces.filter(r => driverLeagueIds.includes(r.leagueId)); const otherUpcomingRaces = upcomingRaces.filter(r => !driverLeagueIds.includes(r.leagueId)); const nextRace = myUpcomingRaces[0] || otherUpcomingRaces[0]; // Recent results for driver const driverResults = allResults.filter(r => r.driverId === currentDriverId); const recentResults = driverResults.slice(0, 5); // Get stats const driverStats = getDriverStats(currentDriverId); // Get standings for driver's leagues const leagueStandings = await Promise.all( driverLeagues.slice(0, 3).map(async (league) => { const standings = await standingRepository.findByLeagueId(league.id); const driverStanding = standings.find(s => s.driverId === currentDriverId); return { league, position: driverStanding?.position ?? 0, points: driverStanding?.points ?? 0, totalDrivers: standings.length, }; }) ); // Calculate quick stats const totalRaces = driverStats?.totalRaces ?? 0; const wins = driverStats?.wins ?? 0; const podiums = driverStats?.podiums ?? 0; const rating = driverStats?.rating ?? 1500; const globalRank = driverStats?.overallRank ?? 0; return (
{/* Hero Section */}
{/* Background Pattern */}
{/* Welcome Message */}
{currentDriver && (
{currentDriver.name}
)}

{getGreeting()},

{currentDriver?.name ?? 'Racer'} {currentDriver ? getCountryFlag(currentDriver.country) : '🏁'}

{rating}
#{globalRank}
{totalRaces} races completed
{/* Quick Actions */}
{/* Quick Stats Row */}

{wins}

Wins

{podiums}

Podiums

{driverStats?.consistency ?? 0}%

Consistency

{driverLeagues.length}

Active Leagues

{/* Main Content */}
{/* Left Column - Main Content */}
{/* Next Race Card */} {nextRace && (
Next Race
{myUpcomingRaces.includes(nextRace) && ( Your League )}

{nextRace.track}

{nextRace.car}

{nextRace.scheduledAt.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric', })} {nextRace.scheduledAt.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', })}

Starts in

{timeUntil(nextRace.scheduledAt)}

)} {/* League Standings Preview */} {leagueStandings.length > 0 && (

Your Championship Standings

View all
{leagueStandings.map(({ league, position, points, totalDrivers }) => (
{position > 0 ? `P${position}` : '-'}

{league.name}

{points} points • {totalDrivers} drivers

{position <= 3 && position > 0 && ( )}
))}
)} {/* Activity Feed */}

Recent Activity

{feedItems.length > 0 ? (
{feedItems.slice(0, 5).map((item) => ( ))}
) : (

No activity yet

Join leagues and add friends to see activity here

)}
{/* Right Column - Sidebar */}
{/* Upcoming Races */}

Upcoming Races

View all
{upcomingRaces.length > 0 ? (
{upcomingRaces.slice(0, 5).map((race) => { const isMyRace = driverLeagueIds.includes(race.leagueId); return (

{race.track}

{isMyRace && ( )}

{race.car}

{race.scheduledAt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} {timeUntil(race.scheduledAt)}
); })}
) : (

No upcoming races

)}
{/* Friends */}

Friends

{friends.length} friends
{friends.length > 0 ? (
{friends.slice(0, 6).map((friend) => (
{friend.name}

{friend.name}

{getCountryFlag(friend.country)}

))} {friends.length > 6 && ( +{friends.length - 6} more )}
) : (

No friends yet

)}
); } // Feed Item Row Component function FeedItemRow({ item, imageService }: { item: FeedItem; imageService: any }) { const getActivityIcon = (type: string) => { if (type.includes('win')) return { icon: Trophy, color: 'text-yellow-400 bg-yellow-400/10' }; if (type.includes('podium')) return { icon: Medal, color: 'text-warning-amber bg-warning-amber/10' }; if (type.includes('join')) return { icon: UserPlus, color: 'text-performance-green bg-performance-green/10' }; if (type.includes('friend')) return { icon: Heart, color: 'text-pink-400 bg-pink-400/10' }; if (type.includes('league')) return { icon: Flag, color: 'text-primary-blue bg-primary-blue/10' }; if (type.includes('race')) return { icon: Play, color: 'text-red-400 bg-red-400/10' }; return { icon: Activity, color: 'text-gray-400 bg-gray-400/10' }; }; const { icon: Icon, color } = getActivityIcon(item.type); return (

{item.headline}

{item.body && (

{item.body}

)}

{timeAgo(item.timestamp)}

{item.ctaHref && ( )}
); }