Authenticate with iRacing
++ Connect a demo iRacing identity to explore the GridPilot dashboard with seeded data. +
+ + Start iRacing demo login + +diff --git a/apps/website/app/auth/iracing/callback/route.ts b/apps/website/app/auth/iracing/callback/route.ts
new file mode 100644
index 000000000..8f64f98a5
--- /dev/null
+++ b/apps/website/app/auth/iracing/callback/route.ts
@@ -0,0 +1,41 @@
+import { cookies } from 'next/headers';
+import { NextResponse } from 'next/server';
+
+import { getAuthService } from '../../../../lib/auth';
+
+const SESSION_COOKIE = 'gp_demo_session';
+const STATE_COOKIE = 'gp_demo_auth_state';
+
+export async function GET(request: Request) {
+ const url = new URL(request.url);
+ const code = url.searchParams.get('code') ?? undefined;
+ const state = url.searchParams.get('state') ?? undefined;
+ const returnTo = url.searchParams.get('returnTo') ?? undefined;
+
+ if (!code || !state) {
+ return NextResponse.redirect('/auth/iracing');
+ }
+
+ const cookieStore = await cookies();
+ const storedState = cookieStore.get(STATE_COOKIE)?.value;
+
+ if (!storedState || storedState !== state) {
+ return NextResponse.redirect('/auth/iracing');
+ }
+
+ const authService = getAuthService();
+ const session = await authService.loginWithIracingCallback({ code, state, returnTo });
+
+ cookieStore.set(SESSION_COOKIE, JSON.stringify(session), {
+ httpOnly: true,
+ sameSite: 'lax',
+ path: '/',
+ secure: process.env.NODE_ENV === 'production',
+ });
+
+ cookieStore.delete(STATE_COOKIE);
+
+ const redirectTarget = returnTo || '/dashboard';
+ const absoluteRedirect = new URL(redirectTarget, url.origin).toString();
+ return NextResponse.redirect(absoluteRedirect);
+}
\ No newline at end of file
diff --git a/apps/website/app/auth/iracing/page.tsx b/apps/website/app/auth/iracing/page.tsx
new file mode 100644
index 000000000..bc366df5b
--- /dev/null
+++ b/apps/website/app/auth/iracing/page.tsx
@@ -0,0 +1,30 @@
+import Link from 'next/link';
+
+interface IracingAuthPageProps {
+ searchParams: Promise<{
+ returnTo?: string;
+ }>;
+}
+
+export default async function IracingAuthPage({ searchParams }: IracingAuthPageProps) {
+ const params = await searchParams;
+ const returnTo = params.returnTo ?? '/dashboard';
+ const startUrl = `/auth/iracing/start?returnTo=${encodeURIComponent(returnTo)}`;
+
+ return (
+
+ Connect a demo iRacing identity to explore the GridPilot dashboard with seeded data.
+
+ Personalized activity from your friends, leagues, and teams.
+ Authenticate with iRacing
+ Dashboard
+
{league.description}
-{activity.text}
-{activity.time}
-- Complete workflow prototype. Test freely — all data is temporary. -
-Set up your driver profile with racing number and iRacing ID.
- -Browse available leagues or create your own.
- -Create race events and manage your schedule.
- -Manage your driver profile
-Browse and join leagues
-View race schedule
-- Your races, your seasons, your progress — finally in one place. -
-+ Your races, your seasons, your progress — finally in one place. +
+- iRacing gives you physics. GridPilot gives you a career. -
- > - } - mockup={- Every race you run stays with you. -
-- Your racing career, finally in one place. -
- > - } - mockup={- Setting up league races used to mean clicking through iRacing's wizard 20 times. -
-- Automation instead of repetition. -
- > - } - mockup={+ iRacing gives you physics. GridPilot gives you a career. +
+ > + } + mockup={
- Right now, we're focused on making iRacing league racing better.
+
+ Every race you run stays with you.
+
+ Your racing career, finally in one place.
+
+ Setting up league races used to mean clicking through iRacing's wizard 20 times.
+
+ Automation instead of repetition.
+
+ Right now, we're focused on making iRacing league racing better.
+
+ But sims come and go. Your leagues, your teams, your rating — those stay.
+
+ GridPilot is built to outlast any single platform.
+
+ When the next sim arrives, your competitive identity moves with you.
+
+ Explore leagues, teams, and races that make up the GridPilot ecosystem.
- But sims come and go. Your leagues, your teams, your rating — those stay.
-
- GridPilot is built to outlast any single platform.
-
- When the next sim arrives, your competitive identity moves with you.
- {league.name}
+ {league.description}
+ {team.name}
+ {team.description}
+
+ No races scheduled in this demo snapshot.
+ {race.track} {race.car} {league.name}Discover the grid
+ Featured leagues
+
+
+ {topLeagues.slice(0, 4).map(league => (
+
+ Teams on the grid
+
+
+ {teams.slice(0, 4).map(team => (
+
+ Upcoming races
+
+
+ {upcomingRaces.map(race => (
+
+ )}
+
No drivers registered yet
diff --git a/apps/website/app/races/[id]/results/page.tsx b/apps/website/app/races/[id]/results/page.tsx index bcc354bab..38deac6e0 100644 --- a/apps/website/app/races/[id]/results/page.tsx +++ b/apps/website/app/races/[id]/results/page.tsx @@ -4,12 +4,12 @@ import { useState, useEffect } from 'react'; import { useRouter, useParams } from 'next/navigation'; import Button from '@/components/ui/Button'; import Card from '@/components/ui/Card'; -import ResultsTable from '@/components/alpha/ResultsTable'; -import ImportResultsForm from '@/components/alpha/ImportResultsForm'; -import { Race } from '@gridpilot/racing-domain/entities/Race'; -import { League } from '@gridpilot/racing-domain/entities/League'; -import { Result } from '@gridpilot/racing-domain/entities/Result'; -import { Driver } from '@gridpilot/racing-domain/entities/Driver'; +import ResultsTable from '@/components/races/ResultsTable'; +import ImportResultsForm from '@/components/races/ImportResultsForm'; +import { Race } from '@gridpilot/racing/domain/entities/Race'; +import { League } from '@gridpilot/racing/domain/entities/League'; +import { Result } from '@gridpilot/racing/domain/entities/Result'; +import { Driver } from '@gridpilot/racing/domain/entities/Driver'; import { getRaceRepository, getLeagueRepository, diff --git a/apps/website/app/races/page.tsx b/apps/website/app/races/page.tsx index 58598b32b..8cdd2eeae 100644 --- a/apps/website/app/races/page.tsx +++ b/apps/website/app/races/page.tsx @@ -4,10 +4,10 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import Button from '@/components/ui/Button'; import Card from '@/components/ui/Card'; -import RaceCard from '@/components/alpha/RaceCard'; -import ScheduleRaceForm from '@/components/alpha/ScheduleRaceForm'; -import { Race, RaceStatus } from '@gridpilot/racing-domain/entities/Race'; -import { League } from '@gridpilot/racing-domain/entities/League'; +import RaceCard from '@/components/races/RaceCard'; +import ScheduleRaceForm from '@/components/leagues/ScheduleRaceForm'; +import { Race, RaceStatus } from '@gridpilot/racing/domain/entities/Race'; +import { League } from '@gridpilot/racing/domain/entities/League'; import { getRaceRepository, getLeagueRepository } from '@/lib/di-container'; export default function RacesPage() { diff --git a/apps/website/app/social/page.tsx b/apps/website/app/social/page.tsx deleted file mode 100644 index 5ae5733be..000000000 --- a/apps/website/app/social/page.tsx +++ /dev/null @@ -1,170 +0,0 @@ -'use client'; - -import Card from '@/components/ui/Card'; - -// Mock data for highlights -const MOCK_HIGHLIGHTS = [ - { - id: '1', - type: 'race', - title: 'Epic finish in GT3 Championship', - description: 'Max Verstappen wins by 0.003 seconds', - time: '2 hours ago', - }, - { - id: '2', - type: 'league', - title: 'New league created: Endurance Masters', - description: '12 teams already registered', - time: '5 hours ago', - }, - { - id: '3', - type: 'achievement', - title: 'Sarah Chen unlocked "Century Club"', - description: '100 races completed', - time: '1 day ago', - }, -]; - -const TRENDING_DRIVERS = [ - { id: '1', name: 'Max Verstappen', metric: '+156 rating this week' }, - { id: '2', name: 'Emma Thompson', metric: '5 wins in a row' }, - { id: '3', name: 'Lewis Hamilton', metric: 'Most laps led' }, -]; - -const TRENDING_TEAMS = [ - { id: '1', name: 'Apex Racing', metric: '12 new members' }, - { id: '2', name: 'Speed Demons', metric: '3 championship wins' }, - { id: '3', name: 'Endurance Elite', metric: '24h race victory' }, -]; - -export default function SocialPage() { - return ( -- Stay updated with the racing community -
-- The activity feed will show real-time updates from your - friends, leagues, and teams. This feature is currently in - development for the alpha release. -
-- {highlight.description} -
-- {highlight.time} -
-- Friend features coming soon in alpha -
-