diff --git a/apps/website/app/drivers/page.tsx b/apps/website/app/drivers/page.tsx index 57a21209c..cec1fc337 100644 --- a/apps/website/app/drivers/page.tsx +++ b/apps/website/app/drivers/page.tsx @@ -52,29 +52,10 @@ interface DriverListItem { // ============================================================================ // DEMO DATA // ============================================================================ - -const DEMO_DRIVERS: DriverListItem[] = [ - { id: 'demo-1', name: 'Max Verstappen', rating: 4250, skillLevel: 'pro', nationality: 'NL', racesCompleted: 156, wins: 47, podiums: 89, isActive: true, rank: 1 }, - { id: 'demo-2', name: 'Lewis Hamilton', rating: 4180, skillLevel: 'pro', nationality: 'GB', racesCompleted: 198, wins: 52, podiums: 112, isActive: true, rank: 2 }, - { id: 'demo-3', name: 'Charles Leclerc', rating: 3950, skillLevel: 'pro', nationality: 'MC', racesCompleted: 134, wins: 28, podiums: 67, isActive: true, rank: 3 }, - { id: 'demo-4', name: 'Lando Norris', rating: 3820, skillLevel: 'advanced', nationality: 'GB', racesCompleted: 112, wins: 18, podiums: 45, isActive: true, rank: 4 }, - { id: 'demo-5', name: 'Carlos Sainz', rating: 3750, skillLevel: 'advanced', nationality: 'ES', racesCompleted: 145, wins: 15, podiums: 52, isActive: true, rank: 5 }, - { id: 'demo-6', name: 'Oscar Piastri', rating: 3680, skillLevel: 'advanced', nationality: 'AU', racesCompleted: 78, wins: 8, podiums: 24, isActive: true, rank: 6 }, - { id: 'demo-7', name: 'George Russell', rating: 3620, skillLevel: 'advanced', nationality: 'GB', racesCompleted: 98, wins: 6, podiums: 31, isActive: true, rank: 7 }, - { id: 'demo-8', name: 'Fernando Alonso', rating: 3580, skillLevel: 'advanced', nationality: 'ES', racesCompleted: 256, wins: 32, podiums: 98, isActive: true, rank: 8 }, - { id: 'demo-9', name: 'Nico Hülkenberg', rating: 3420, skillLevel: 'advanced', nationality: 'DE', racesCompleted: 167, wins: 2, podiums: 18, isActive: true, rank: 9 }, - { id: 'demo-10', name: 'Yuki Tsunoda', rating: 3250, skillLevel: 'intermediate', nationality: 'JP', racesCompleted: 89, wins: 1, podiums: 8, isActive: true, rank: 10 }, - { id: 'demo-11', name: 'Alex Albon', rating: 3180, skillLevel: 'intermediate', nationality: 'TH', racesCompleted: 102, wins: 0, podiums: 4, isActive: true, rank: 11 }, - { id: 'demo-12', name: 'Kevin Magnussen', rating: 3050, skillLevel: 'intermediate', nationality: 'DK', racesCompleted: 145, wins: 0, podiums: 2, isActive: true, rank: 12 }, - { id: 'demo-13', name: 'Pierre Gasly', rating: 2980, skillLevel: 'intermediate', nationality: 'FR', racesCompleted: 124, wins: 1, podiums: 5, isActive: true, rank: 13 }, - { id: 'demo-14', name: 'Esteban Ocon', rating: 2920, skillLevel: 'intermediate', nationality: 'FR', racesCompleted: 118, wins: 1, podiums: 4, isActive: true, rank: 14 }, - { id: 'demo-15', name: 'Lance Stroll', rating: 2850, skillLevel: 'intermediate', nationality: 'CA', racesCompleted: 134, wins: 0, podiums: 3, isActive: true, rank: 15 }, - { id: 'demo-16', name: 'Zhou Guanyu', rating: 2650, skillLevel: 'intermediate', nationality: 'CN', racesCompleted: 67, wins: 0, podiums: 0, isActive: true, rank: 16 }, - { id: 'demo-17', name: 'Daniel Ricciardo', rating: 2500, skillLevel: 'intermediate', nationality: 'AU', racesCompleted: 189, wins: 8, podiums: 32, isActive: false, rank: 17 }, - { id: 'demo-18', name: 'Valtteri Bottas', rating: 2450, skillLevel: 'intermediate', nationality: 'FI', racesCompleted: 212, wins: 10, podiums: 67, isActive: false, rank: 18 }, - { id: 'demo-19', name: 'Logan Sargeant', rating: 1850, skillLevel: 'beginner', nationality: 'US', racesCompleted: 34, wins: 0, podiums: 0, isActive: false, rank: 19 }, - { id: 'demo-20', name: 'Nyck de Vries', rating: 1750, skillLevel: 'beginner', nationality: 'NL', racesCompleted: 12, wins: 0, podiums: 0, isActive: false, rank: 20 }, -]; +// +// In alpha, all driver listings come from the in-memory repositories wired +// through the DI container. We intentionally avoid hardcoded fallback driver +// lists here so that the demo data stays consistent across pages. // ============================================================================ // SKILL LEVEL CONFIG @@ -464,7 +445,7 @@ export default function DriversPage() { return rankA - rankB || b.rating - a.rating; }); - setDrivers(items.length > 0 ? items : DEMO_DRIVERS); + setDrivers(items); setLoading(false); }; @@ -472,7 +453,6 @@ export default function DriversPage() { }, []); const handleDriverClick = (driverId: string) => { - if (driverId.startsWith('demo-')) return; router.push(`/drivers/${driverId}`); }; diff --git a/apps/website/app/leaderboards/drivers/page.tsx b/apps/website/app/leaderboards/drivers/page.tsx index f0a27fa36..1d67ec42a 100644 --- a/apps/website/app/leaderboards/drivers/page.tsx +++ b/apps/website/app/leaderboards/drivers/page.tsx @@ -41,28 +41,6 @@ interface DriverListItem { rank: number; } -// ============================================================================ -// DEMO DATA -// ============================================================================ - -const DEMO_DRIVERS: DriverListItem[] = [ - { id: 'demo-1', name: 'Max Verstappen', rating: 4250, skillLevel: 'pro', nationality: 'NL', racesCompleted: 156, wins: 47, podiums: 89, rank: 1 }, - { id: 'demo-2', name: 'Lewis Hamilton', rating: 4180, skillLevel: 'pro', nationality: 'GB', racesCompleted: 198, wins: 52, podiums: 112, rank: 2 }, - { id: 'demo-3', name: 'Charles Leclerc', rating: 3950, skillLevel: 'pro', nationality: 'MC', racesCompleted: 134, wins: 28, podiums: 67, rank: 3 }, - { id: 'demo-4', name: 'Lando Norris', rating: 3820, skillLevel: 'advanced', nationality: 'GB', racesCompleted: 112, wins: 18, podiums: 45, rank: 4 }, - { id: 'demo-5', name: 'Carlos Sainz', rating: 3750, skillLevel: 'advanced', nationality: 'ES', racesCompleted: 145, wins: 15, podiums: 52, rank: 5 }, - { id: 'demo-6', name: 'Oscar Piastri', rating: 3680, skillLevel: 'advanced', nationality: 'AU', racesCompleted: 78, wins: 8, podiums: 24, rank: 6 }, - { id: 'demo-7', name: 'George Russell', rating: 3620, skillLevel: 'advanced', nationality: 'GB', racesCompleted: 98, wins: 6, podiums: 31, rank: 7 }, - { id: 'demo-8', name: 'Fernando Alonso', rating: 3580, skillLevel: 'advanced', nationality: 'ES', racesCompleted: 256, wins: 32, podiums: 98, rank: 8 }, - { id: 'demo-9', name: 'Nico Hülkenberg', rating: 3420, skillLevel: 'advanced', nationality: 'DE', racesCompleted: 167, wins: 2, podiums: 18, rank: 9 }, - { id: 'demo-10', name: 'Yuki Tsunoda', rating: 3250, skillLevel: 'intermediate', nationality: 'JP', racesCompleted: 89, wins: 1, podiums: 8, rank: 10 }, - { id: 'demo-11', name: 'Alex Albon', rating: 3180, skillLevel: 'intermediate', nationality: 'TH', racesCompleted: 102, wins: 0, podiums: 4, rank: 11 }, - { id: 'demo-12', name: 'Kevin Magnussen', rating: 3050, skillLevel: 'intermediate', nationality: 'DK', racesCompleted: 145, wins: 0, podiums: 2, rank: 12 }, - { id: 'demo-13', name: 'Pierre Gasly', rating: 2980, skillLevel: 'intermediate', nationality: 'FR', racesCompleted: 124, wins: 1, podiums: 5, rank: 13 }, - { id: 'demo-14', name: 'Esteban Ocon', rating: 2920, skillLevel: 'intermediate', nationality: 'FR', racesCompleted: 118, wins: 1, podiums: 4, rank: 14 }, - { id: 'demo-15', name: 'Lance Stroll', rating: 2850, skillLevel: 'intermediate', nationality: 'CA', racesCompleted: 134, wins: 0, podiums: 3, rank: 15 }, -]; - // ============================================================================ // SKILL LEVEL CONFIG // ============================================================================ @@ -247,7 +225,7 @@ export default function DriverLeaderboardPage() { }; }); - setDrivers(items.length > 0 ? items : DEMO_DRIVERS); + setDrivers(items); setLoading(false); }; diff --git a/apps/website/app/leaderboards/page.tsx b/apps/website/app/leaderboards/page.tsx index 9c23f1b9a..ed0102764 100644 --- a/apps/website/app/leaderboards/page.tsx +++ b/apps/website/app/leaderboards/page.tsx @@ -51,31 +51,6 @@ interface TeamDisplayData { performanceLevel: SkillLevel; } -// ============================================================================ -// DEMO DATA -// ============================================================================ - -const DEMO_DRIVERS: DriverListItem[] = [ - { id: 'demo-1', name: 'Max Verstappen', rating: 4250, skillLevel: 'pro', nationality: 'NL', wins: 47, podiums: 89, rank: 1 }, - { id: 'demo-2', name: 'Lewis Hamilton', rating: 4180, skillLevel: 'pro', nationality: 'GB', wins: 52, podiums: 112, rank: 2 }, - { id: 'demo-3', name: 'Charles Leclerc', rating: 3950, skillLevel: 'pro', nationality: 'MC', wins: 28, podiums: 67, rank: 3 }, - { id: 'demo-4', name: 'Lando Norris', rating: 3820, skillLevel: 'advanced', nationality: 'GB', wins: 18, podiums: 45, rank: 4 }, - { id: 'demo-5', name: 'Carlos Sainz', rating: 3750, skillLevel: 'advanced', nationality: 'ES', wins: 15, podiums: 52, rank: 5 }, - { id: 'demo-6', name: 'Oscar Piastri', rating: 3680, skillLevel: 'advanced', nationality: 'AU', wins: 8, podiums: 24, rank: 6 }, - { id: 'demo-7', name: 'George Russell', rating: 3620, skillLevel: 'advanced', nationality: 'GB', wins: 6, podiums: 31, rank: 7 }, - { id: 'demo-8', name: 'Fernando Alonso', rating: 3580, skillLevel: 'advanced', nationality: 'ES', wins: 32, podiums: 98, rank: 8 }, - { id: 'demo-9', name: 'Nico Hülkenberg', rating: 3420, skillLevel: 'advanced', nationality: 'DE', wins: 2, podiums: 18, rank: 9 }, - { id: 'demo-10', name: 'Yuki Tsunoda', rating: 3250, skillLevel: 'intermediate', nationality: 'JP', wins: 1, podiums: 8, rank: 10 }, -]; - -const DEMO_TEAMS: TeamDisplayData[] = [ - { id: 'demo-team-1', name: 'Apex Predators Racing', memberCount: 8, rating: 4850, totalWins: 47, totalRaces: 156, performanceLevel: 'pro' }, - { id: 'demo-team-2', name: 'Velocity Esports', memberCount: 12, rating: 5200, totalWins: 63, totalRaces: 198, performanceLevel: 'pro' }, - { id: 'demo-team-3', name: 'Nitro Motorsport', memberCount: 6, rating: 4720, totalWins: 38, totalRaces: 112, performanceLevel: 'pro' }, - { id: 'demo-team-4', name: 'Horizon Racing Collective', memberCount: 10, rating: 3800, totalWins: 24, totalRaces: 89, performanceLevel: 'advanced' }, - { id: 'demo-team-5', name: 'Phoenix Rising eSports', memberCount: 7, rating: 3650, totalWins: 19, totalRaces: 76, performanceLevel: 'advanced' }, -]; - // ============================================================================ // SKILL LEVEL CONFIG // ============================================================================ @@ -420,12 +395,12 @@ export default function LeaderboardsPage() { }), ); - setDrivers(driverItems.length > 0 ? driverItems : DEMO_DRIVERS); - setTeams(teamData.length > 0 ? teamData : DEMO_TEAMS); + setDrivers(driverItems); + setTeams(teamData); } catch (error) { console.error('Failed to load leaderboard data:', error); - setDrivers(DEMO_DRIVERS); - setTeams(DEMO_TEAMS); + setDrivers([]); + setTeams([]); } finally { setLoading(false); } @@ -435,12 +410,10 @@ export default function LeaderboardsPage() { }, []); const handleDriverClick = (driverId: string) => { - if (driverId.startsWith('demo-')) return; router.push(`/drivers/${driverId}`); }; const handleTeamClick = (teamId: string) => { - if (teamId.startsWith('demo-team-')) return; router.push(`/teams/${teamId}`); }; diff --git a/apps/website/app/teams/leaderboard/page.tsx b/apps/website/app/teams/leaderboard/page.tsx index 553772f19..f52fa844b 100644 --- a/apps/website/app/teams/leaderboard/page.tsx +++ b/apps/website/app/teams/leaderboard/page.tsx @@ -48,223 +48,6 @@ interface TeamDisplayData { languages?: string[]; } -// ============================================================================ -// DEMO TEAMS DATA -// ============================================================================ - -const DEMO_TEAMS: TeamDisplayData[] = [ - { - id: 'demo-team-1', - name: 'Apex Predators Racing', - description: 'Elite GT3 team competing at the highest level.', - memberCount: 8, - rating: 4850, - totalWins: 47, - totalRaces: 156, - performanceLevel: 'pro', - isRecruiting: true, - createdAt: new Date(Date.now() - 180 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇺🇸 North America', - languages: ['English'], - }, - { - id: 'demo-team-2', - name: 'Velocity Esports', - description: 'Professional sim racing team with sponsors.', - memberCount: 12, - rating: 5200, - totalWins: 63, - totalRaces: 198, - performanceLevel: 'pro', - isRecruiting: false, - createdAt: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇬🇧 Europe', - languages: ['English', 'German'], - }, - { - id: 'demo-team-3', - name: 'Nitro Motorsport', - description: 'Championship-winning sprint specialists.', - memberCount: 6, - rating: 4720, - totalWins: 38, - totalRaces: 112, - performanceLevel: 'pro', - isRecruiting: true, - createdAt: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇩🇪 Germany', - languages: ['German', 'English'], - }, - { - id: 'demo-team-4', - name: 'Horizon Racing Collective', - description: 'Ambitious team on the rise.', - memberCount: 10, - rating: 3800, - totalWins: 24, - totalRaces: 89, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇳🇱 Netherlands', - languages: ['Dutch', 'English'], - }, - { - id: 'demo-team-5', - name: 'Phoenix Rising eSports', - description: 'From the ashes to the podium.', - memberCount: 7, - rating: 3650, - totalWins: 19, - totalRaces: 76, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 45 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇫🇷 France', - languages: ['French', 'English'], - }, - { - id: 'demo-team-6', - name: 'Thunderbolt Racing', - description: 'Fast and furious sprint racing.', - memberCount: 5, - rating: 3420, - totalWins: 15, - totalRaces: 54, - performanceLevel: 'advanced', - isRecruiting: false, - createdAt: new Date(Date.now() - 120 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇮🇹 Italy', - languages: ['Italian', 'English'], - }, - { - id: 'demo-team-7', - name: 'Grid Starters', - description: 'Growing together as racers.', - memberCount: 9, - rating: 2800, - totalWins: 11, - totalRaces: 67, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇪🇸 Spain', - languages: ['Spanish', 'English'], - }, - { - id: 'demo-team-8', - name: 'Midnight Racers', - description: 'Night owls who love endurance racing.', - memberCount: 6, - rating: 2650, - totalWins: 8, - totalRaces: 42, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🌍 International', - languages: ['English'], - }, - { - id: 'demo-team-9', - name: 'Casual Speedsters', - description: 'Racing for fun, improving together.', - memberCount: 4, - rating: 2400, - totalWins: 5, - totalRaces: 31, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇵🇱 Poland', - languages: ['Polish', 'English'], - }, - { - id: 'demo-team-10', - name: 'Fresh Rubber Racing', - description: 'New team for new racers!', - memberCount: 3, - rating: 1800, - totalWins: 2, - totalRaces: 18, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇧🇷 Brazil', - languages: ['Portuguese', 'English'], - }, - { - id: 'demo-team-11', - name: 'Rookie Revolution', - description: 'First time racers welcome!', - memberCount: 5, - rating: 1650, - totalWins: 1, - totalRaces: 12, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇦🇺 Australia', - languages: ['English'], - }, - { - id: 'demo-team-12', - name: 'Pit Lane Pioneers', - description: 'Learning endurance racing from scratch.', - memberCount: 4, - rating: 1500, - totalWins: 0, - totalRaces: 8, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇯🇵 Japan', - languages: ['Japanese', 'English'], - }, - { - id: 'demo-team-13', - name: 'Shadow Squadron', - description: 'Elite drivers emerging from the shadows.', - memberCount: 6, - rating: 4100, - totalWins: 12, - totalRaces: 34, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇸🇪 Scandinavia', - languages: ['Swedish', 'Norwegian', 'English'], - }, - { - id: 'demo-team-14', - name: 'Turbo Collective', - description: 'Fast, furious, and friendly.', - memberCount: 4, - rating: 3200, - totalWins: 7, - totalRaces: 28, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 12 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇨🇦 Canada', - languages: ['English', 'French'], - }, -]; - // ============================================================================ // SKILL LEVEL CONFIG // ============================================================================ @@ -537,7 +320,7 @@ export default function TeamLeaderboardPage() { } }; - const teams = [...realTeams, ...DEMO_TEAMS]; + const teams = realTeams; const handleTeamClick = (teamId: string) => { if (teamId.startsWith('demo-team-')) { diff --git a/apps/website/app/teams/page.tsx b/apps/website/app/teams/page.tsx index 4915a3c33..1e81526cd 100644 --- a/apps/website/app/teams/page.tsx +++ b/apps/website/app/teams/page.tsx @@ -53,228 +53,6 @@ interface TeamDisplayData { languages?: string[]; } -// ============================================================================ -// DEMO TEAMS DATA -// ============================================================================ - -const DEMO_TEAMS: TeamDisplayData[] = [ - // Pro Teams - { - id: 'demo-team-1', - name: 'Apex Predators Racing', - description: 'Elite GT3 team competing at the highest level. Multiple championship winners seeking consistent drivers.', - memberCount: 8, - rating: 4850, - totalWins: 47, - totalRaces: 156, - performanceLevel: 'pro', - isRecruiting: true, - createdAt: new Date(Date.now() - 180 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇺🇸 North America', - languages: ['English'], - }, - { - id: 'demo-team-2', - name: 'Velocity Esports', - description: 'Professional sim racing team with sponsors. Competing in major endurance events worldwide.', - memberCount: 12, - rating: 5200, - totalWins: 63, - totalRaces: 198, - performanceLevel: 'pro', - isRecruiting: false, - createdAt: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇬🇧 Europe', - languages: ['English', 'German'], - }, - { - id: 'demo-team-3', - name: 'Nitro Motorsport', - description: 'Championship-winning sprint specialists. Fast, consistent, and always fighting for podiums.', - memberCount: 6, - rating: 4720, - totalWins: 38, - totalRaces: 112, - performanceLevel: 'pro', - isRecruiting: true, - createdAt: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇩🇪 Germany', - languages: ['German', 'English'], - }, - // Advanced Teams - { - id: 'demo-team-4', - name: 'Horizon Racing Collective', - description: 'Ambitious team on the rise. Building towards professional competition with dedicated drivers.', - memberCount: 10, - rating: 3800, - totalWins: 24, - totalRaces: 89, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇳🇱 Netherlands', - languages: ['Dutch', 'English'], - }, - { - id: 'demo-team-5', - name: 'Phoenix Rising eSports', - description: 'From the ashes to the podium. A team built on improvement and teamwork.', - memberCount: 7, - rating: 3650, - totalWins: 19, - totalRaces: 76, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 45 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇫🇷 France', - languages: ['French', 'English'], - }, - { - id: 'demo-team-6', - name: 'Thunderbolt Racing', - description: 'Fast and furious sprint racing. We live for wheel-to-wheel battles.', - memberCount: 5, - rating: 3420, - totalWins: 15, - totalRaces: 54, - performanceLevel: 'advanced', - isRecruiting: false, - createdAt: new Date(Date.now() - 120 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇮🇹 Italy', - languages: ['Italian', 'English'], - }, - // Intermediate Teams - { - id: 'demo-team-7', - name: 'Grid Starters', - description: 'Growing together as racers. Friendly competition with a focus on learning and fun.', - memberCount: 9, - rating: 2800, - totalWins: 11, - totalRaces: 67, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇪🇸 Spain', - languages: ['Spanish', 'English'], - }, - { - id: 'demo-team-8', - name: 'Midnight Racers', - description: 'Night owls who love endurance racing. Join us for late-night stints and good vibes.', - memberCount: 6, - rating: 2650, - totalWins: 8, - totalRaces: 42, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🌍 International', - languages: ['English'], - }, - { - id: 'demo-team-9', - name: 'Casual Speedsters', - description: 'Racing for fun, improving together. No pressure, just clean racing.', - memberCount: 4, - rating: 2400, - totalWins: 5, - totalRaces: 31, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇵🇱 Poland', - languages: ['Polish', 'English'], - }, - // Beginner Teams - { - id: 'demo-team-10', - name: 'Fresh Rubber Racing', - description: 'New team for new racers! Learn the basics together in a supportive environment.', - memberCount: 3, - rating: 1800, - totalWins: 2, - totalRaces: 18, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇧🇷 Brazil', - languages: ['Portuguese', 'English'], - }, - { - id: 'demo-team-11', - name: 'Rookie Revolution', - description: 'First time racers welcome! We all start somewhere.', - memberCount: 5, - rating: 1650, - totalWins: 1, - totalRaces: 12, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇦🇺 Australia', - languages: ['English'], - }, - { - id: 'demo-team-12', - name: 'Pit Lane Pioneers', - description: 'Learning endurance racing from scratch. Long races, longer friendships.', - memberCount: 4, - rating: 1500, - totalWins: 0, - totalRaces: 8, - performanceLevel: 'beginner', - isRecruiting: true, - createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), - specialization: 'endurance', - region: '🇯🇵 Japan', - languages: ['Japanese', 'English'], - }, - // Recently Added - { - id: 'demo-team-13', - name: 'Shadow Squadron', - description: 'Elite drivers emerging from the shadows. Watch out for us this season.', - memberCount: 6, - rating: 4100, - totalWins: 12, - totalRaces: 34, - performanceLevel: 'advanced', - isRecruiting: true, - createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), - specialization: 'mixed', - region: '🇸🇪 Scandinavia', - languages: ['Swedish', 'Norwegian', 'English'], - }, - { - id: 'demo-team-14', - name: 'Turbo Collective', - description: 'Fast, furious, and friendly. Sprint racing specialists looking for quick racers.', - memberCount: 4, - rating: 3200, - totalWins: 7, - totalRaces: 28, - performanceLevel: 'intermediate', - isRecruiting: true, - createdAt: new Date(Date.now() - 12 * 60 * 60 * 1000), - specialization: 'sprint', - region: '🇨🇦 Canada', - languages: ['English', 'French'], - }, -]; - // ============================================================================ // SKILL LEVEL CONFIG // ============================================================================ @@ -745,7 +523,7 @@ export default function TeamsPage() { } }; - const teams = [...realTeams, ...DEMO_TEAMS]; + const teams = realTeams; const handleTeamClick = (teamId: string) => { if (teamId.startsWith('demo-team-')) { diff --git a/apps/website/components/dev/DevToolbar.tsx b/apps/website/components/dev/DevToolbar.tsx index 2f1bb3b73..4ef58e6b3 100644 --- a/apps/website/components/dev/DevToolbar.tsx +++ b/apps/website/components/dev/DevToolbar.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useEffectiveDriverId } from '@/lib/currentDriver'; -import { getSendNotificationUseCase } from '@/lib/di-container'; +import { getSendNotificationUseCase, getRaceRepository, getLeagueRepository } from '@/lib/di-container'; import type { NotificationUrgency } from '@gridpilot/notifications/application'; import { Bell, @@ -170,38 +170,64 @@ export default function DevToolbar() { setSending(true); try { const sendNotification = getSendNotificationUseCase(); - + + const raceRepository = getRaceRepository(); + const leagueRepository = getLeagueRepository(); + + const [allRaces, allLeagues] = await Promise.all([ + raceRepository.findAll(), + leagueRepository.findAll(), + ]); + + const completedRaces = allRaces.filter((race: any) => race.status === 'completed'); + const scheduledRaces = allRaces.filter((race: any) => race.status === 'scheduled'); + + const primaryRace = completedRaces[0] ?? allRaces[0]; + const secondaryRace = scheduledRaces[0] ?? allRaces[1] ?? primaryRace; + const primaryLeague = allLeagues[0]; + let title: string; let body: string; let notificationType: 'protest_filed' | 'protest_defense_requested' | 'protest_vote_required'; let actionUrl: string; switch (selectedType) { - case 'protest_filed': + case 'protest_filed': { + const raceId = primaryRace?.id; title = '🚨 Protest Filed Against You'; - body = 'Max Verstappen has filed a protest against you for unsafe rejoining at Turn 3, Lap 12 during the Spa-Francorchamps race.'; + body = + 'A protest has been filed against you for unsafe rejoining during a recent race. Please review the incident details.'; notificationType = 'protest_filed'; - actionUrl = '/races/race-1/stewarding'; + actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races'; break; - case 'defense_requested': + } + case 'defense_requested': { + const raceId = secondaryRace?.id ?? primaryRace?.id; title = '⚖️ Defense Requested'; - body = 'A steward has requested your defense regarding the incident at Turn 1 in the Monza race. Please provide your side of the story within 48 hours.'; + body = + 'A steward has requested your defense regarding a recent incident. Please provide your side of the story within 48 hours.'; notificationType = 'protest_defense_requested'; - actionUrl = '/races/race-2/stewarding'; + actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races'; break; - case 'vote_required': + } + case 'vote_required': { + const leagueId = primaryLeague?.id; title = '🗳️ Your Vote Required'; - body = 'As a league steward, you are required to vote on the protest: Driver A vs Driver B - Causing a collision at Eau Rouge.'; + body = + 'As a league steward, you are required to vote on an open protest. Please review the case and cast your vote.'; notificationType = 'protest_vote_required'; - actionUrl = '/leagues/league-1/stewarding'; + actionUrl = leagueId ? `/leagues/${leagueId}/stewarding` : '/leagues'; break; + } } - // For modal urgency, add actions - const actions = selectedUrgency === 'modal' ? [ - { label: 'View Protest', type: 'primary' as const, href: actionUrl, actionId: 'view' }, - { label: 'Dismiss', type: 'secondary' as const, actionId: 'dismiss' }, - ] : undefined; + const actions = + selectedUrgency === 'modal' + ? [ + { label: 'View Protest', type: 'primary' as const, href: actionUrl, actionId: 'view' }, + { label: 'Dismiss', type: 'secondary' as const, actionId: 'dismiss' }, + ] + : undefined; await sendNotification.execute({ recipientId: currentDriverId, @@ -214,9 +240,12 @@ export default function DevToolbar() { actions, data: { protestId: `demo-protest-${Date.now()}`, - raceId: 'race-1', - leagueId: 'league-1', - deadline: selectedUrgency === 'modal' ? new Date(Date.now() + 48 * 60 * 60 * 1000) : undefined, + raceId: primaryRace?.id, + leagueId: primaryLeague?.id, + deadline: + selectedUrgency === 'modal' + ? new Date(Date.now() + 48 * 60 * 60 * 1000) + : undefined, }, }); diff --git a/apps/website/components/drivers/DriverProfile.tsx b/apps/website/components/drivers/DriverProfile.tsx index d4f5a8918..22befaca5 100644 --- a/apps/website/components/drivers/DriverProfile.tsx +++ b/apps/website/components/drivers/DriverProfile.tsx @@ -9,6 +9,7 @@ import DriverRankings from './DriverRankings'; import PerformanceMetrics from './PerformanceMetrics'; import { useEffect, useState } from 'react'; import { getDriverStats, getLeagueRankings, getGetDriverTeamQuery, getAllDriverRankings } from '@/lib/di-container'; +import { getPrimaryLeagueIdForDriver } from '@/lib/leagueMembership'; import type { GetDriverTeamQueryResultDTO } from '@gridpilot/racing/application/dto/TeamCommandAndQueryDTO'; interface DriverProfileProps { @@ -19,7 +20,10 @@ interface DriverProfileProps { export default function DriverProfile({ driver, isOwnProfile = false, onEditClick }: DriverProfileProps) { const driverStats = getDriverStats(driver.id); - const leagueRank = getLeagueRankings(driver.id, 'league-1'); + const primaryLeagueId = getPrimaryLeagueIdForDriver(driver.id); + const leagueRank = primaryLeagueId + ? getLeagueRankings(driver.id, primaryLeagueId) + : { rank: 0, totalDrivers: 0, percentile: 0 }; const allRankings = getAllDriverRankings(); const [teamData, setTeamData] = useState(null); @@ -53,7 +57,7 @@ export default function DriverProfile({ driver, isOwnProfile = false, onEditClic }, { type: 'league' as const, - name: 'European GT Championship', + name: 'Primary League', rank: leagueRank.rank, totalDrivers: leagueRank.totalDrivers, percentile: leagueRank.percentile, diff --git a/apps/website/components/drivers/ProfileStats.tsx b/apps/website/components/drivers/ProfileStats.tsx index dd82b5151..02c6ba629 100644 --- a/apps/website/components/drivers/ProfileStats.tsx +++ b/apps/website/components/drivers/ProfileStats.tsx @@ -3,6 +3,7 @@ import Card from '../ui/Card'; import RankBadge from './RankBadge'; import { getDriverStats, getAllDriverRankings, getLeagueRankings } from '@/lib/di-container'; +import { getPrimaryLeagueIdForDriver } from '@/lib/leagueMembership'; interface ProfileStatsProps { driverId?: string; @@ -19,7 +20,9 @@ interface ProfileStatsProps { export default function ProfileStats({ driverId, stats }: ProfileStatsProps) { const driverStats = driverId ? getDriverStats(driverId) : null; const allRankings = getAllDriverRankings(); - const leagueRank = driverId ? getLeagueRankings(driverId, 'league-1') : null; + const primaryLeagueId = driverId ? getPrimaryLeagueIdForDriver(driverId) : null; + const leagueRank = + driverId && primaryLeagueId ? getLeagueRankings(driverId, primaryLeagueId) : null; const defaultStats = stats || (driverStats ? { @@ -115,7 +118,7 @@ export default function ProfileStats({ driverId, stats }: ProfileStatsProps) {
-
European GT Championship
+
Primary League
{leagueRank.rank} of {leagueRank.totalDrivers} drivers
diff --git a/apps/website/components/feed/FeedItemCard.tsx b/apps/website/components/feed/FeedItemCard.tsx index 6b2738e63..c3a4fad64 100644 --- a/apps/website/components/feed/FeedItemCard.tsx +++ b/apps/website/components/feed/FeedItemCard.tsx @@ -2,7 +2,7 @@ import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import Image from 'next/image'; import type { FeedItem } from '@gridpilot/social/domain/entities/FeedItem'; -import { friends } from '@gridpilot/testing-support'; +import { getDriverRepository, getImageService, getSocialRepository } from '@/lib/di-container'; function timeAgo(timestamp: Date): string { const diffMs = Date.now() - timestamp.getTime(); @@ -15,16 +15,39 @@ function timeAgo(timestamp: Date): string { return `${diffDays} d ago`; } -function getActor(item: FeedItem) { +async function resolveActor(item: FeedItem) { + const driverRepo = getDriverRepository(); + const imageService = getImageService(); + const socialRepo = getSocialRepository(); + if (item.actorFriendId) { - const friend = friends.find(f => f.driverId === item.actorFriendId); - if (friend) { - return { - name: friend.displayName, - avatarUrl: friend.avatarUrl - }; + // Try social graph first (friend display name/avatar) + try { + const friend = await socialRepo.getFriendByDriverId?.(item.actorFriendId); + if (friend) { + return { + name: friend.displayName ?? friend.driverName ?? `Driver ${item.actorFriendId}`, + avatarUrl: friend.avatarUrl ?? imageService.getDriverAvatar(item.actorFriendId), + }; + } + } catch { + // fall through to driver lookup + } + + // Fallback to driver entity + image service + try { + const driver = await driverRepo.findById(item.actorFriendId); + if (driver) { + return { + name: driver.name, + avatarUrl: imageService.getDriverAvatar(driver.id), + }; + } + } catch { + // ignore and return null below } } + return null; } @@ -33,7 +56,22 @@ interface FeedItemCardProps { } export default function FeedItemCard({ item }: FeedItemCardProps) { - const actor = getActor(item); + const [actor, setActor] = useState<{ name: string; avatarUrl: string } | null>(null); + + useEffect(() => { + let cancelled = false; + + void (async () => { + const resolved = await resolveActor(item); + if (!cancelled) { + setActor(resolved); + } + })(); + + return () => { + cancelled = true; + }; + }, [item]); return (
@@ -68,7 +106,7 @@ export default function FeedItemCard({ item }: FeedItemCardProps) { {timeAgo(item.timestamp)}
- {(item.ctaHref && item.ctaLabel) && ( + {item.ctaHref && item.ctaLabel && (