website refactor
This commit is contained in:
@@ -2,6 +2,41 @@ import { redirect } from 'next/navigation';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { DriverProfilePageQuery } from '@/lib/page-queries/DriverProfilePageQuery';
|
||||
import { DriverProfilePageClient } from '@/client-wrapper/DriverProfilePageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
import { JsonLd } from '@/ui/JsonLd';
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
const result = await DriverProfilePageQuery.execute(id);
|
||||
|
||||
if (result.isErr()) {
|
||||
return MetadataHelper.generate({
|
||||
title: 'Driver Not Found',
|
||||
description: 'The requested driver profile could not be found on GridPilot.',
|
||||
path: `/drivers/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
const viewData = result.unwrap();
|
||||
const driver = viewData.currentDriver;
|
||||
|
||||
if (!driver) {
|
||||
return MetadataHelper.generate({
|
||||
title: 'Driver Not Found',
|
||||
description: 'The requested driver profile could not be found on GridPilot.',
|
||||
path: `/drivers/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
return MetadataHelper.generate({
|
||||
title: driver.name,
|
||||
description: driver.bio || `View the professional sim racing profile of ${driver.name} on GridPilot. Career statistics, race history, and performance metrics in the iRacing community.`,
|
||||
path: `/drivers/${id}`,
|
||||
image: driver.avatarUrl,
|
||||
type: 'profile',
|
||||
});
|
||||
}
|
||||
|
||||
export default async function DriverProfilePage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
@@ -21,9 +56,24 @@ export default async function DriverProfilePage({ params }: { params: Promise<{
|
||||
}
|
||||
|
||||
const viewData = result.unwrap();
|
||||
const driver = viewData.currentDriver;
|
||||
|
||||
const jsonLd = driver ? {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Person',
|
||||
name: driver.name,
|
||||
description: driver.bio,
|
||||
image: driver.avatarUrl,
|
||||
url: `https://gridpilot.com/drivers/${driver.id}`,
|
||||
knowsAbout: ['Sim Racing', 'iRacing'],
|
||||
} : null;
|
||||
|
||||
return (
|
||||
<DriverProfilePageClient
|
||||
viewData={viewData}
|
||||
/>
|
||||
<>
|
||||
{jsonLd && <JsonLd data={jsonLd} />}
|
||||
<DriverProfilePageClient
|
||||
viewData={viewData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@ import { redirect } from 'next/navigation';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { DriversPageQuery } from '@/lib/page-queries/DriversPageQuery';
|
||||
import { DriversPageClient } from '@/client-wrapper/DriversPageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Sim Racing Drivers',
|
||||
description: 'Explore the elite roster of sim racing drivers on GridPilot. Detailed performance metrics, career history, and professional driver profiles for the iRacing community.',
|
||||
path: '/drivers',
|
||||
});
|
||||
|
||||
export default async function Page() {
|
||||
const result = await DriversPageQuery.execute();
|
||||
|
||||
@@ -3,6 +3,15 @@ import { LeaderboardsPageQuery } from '@/lib/page-queries/LeaderboardsPageQuery'
|
||||
import { LeaderboardsPageClient } from '@/client-wrapper/LeaderboardsPageClient';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { logger } from '@/lib/infrastructure/logging/logger';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
import { JsonLd } from '@/ui/JsonLd';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Global Leaderboards',
|
||||
description: 'See who leads the pack on GridPilot. Comprehensive global leaderboards for drivers and teams, featuring performance rankings and career statistics.',
|
||||
path: '/leaderboards',
|
||||
});
|
||||
|
||||
export default async function LeaderboardsPage() {
|
||||
const result = await LeaderboardsPageQuery.execute();
|
||||
@@ -24,5 +33,27 @@ export default async function LeaderboardsPage() {
|
||||
|
||||
// Success
|
||||
const viewData = result.unwrap();
|
||||
return <LeaderboardsPageClient viewData={viewData} />;
|
||||
}
|
||||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
name: 'Global Driver Leaderboard',
|
||||
description: 'Top performing sim racing drivers on GridPilot',
|
||||
itemListElement: viewData.drivers.slice(0, 10).map((d, i) => ({
|
||||
'@type': 'ListItem',
|
||||
position: i + 1,
|
||||
item: {
|
||||
'@type': 'Person',
|
||||
name: d.name,
|
||||
url: `https://gridpilot.com/drivers/${d.id}`,
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<JsonLd data={jsonLd} />
|
||||
<LeaderboardsPageClient viewData={viewData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,11 +3,36 @@ import { LeagueOverviewTemplate } from '@/templates/LeagueOverviewTemplate';
|
||||
import { LeagueDetailPageQuery } from '@/lib/page-queries/LeagueDetailPageQuery';
|
||||
import { LeagueDetailViewDataBuilder } from '@/lib/builders/view-data/LeagueDetailViewDataBuilder';
|
||||
import { ErrorBanner } from '@/ui/ErrorBanner';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
import { JsonLd } from '@/ui/JsonLd';
|
||||
|
||||
interface Props {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
const result = await LeagueDetailPageQuery.execute(id);
|
||||
|
||||
if (result.isErr()) {
|
||||
return MetadataHelper.generate({
|
||||
title: 'League Not Found',
|
||||
description: 'The requested league could not be found on GridPilot.',
|
||||
path: `/leagues/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
const data = result.unwrap();
|
||||
const league = data.league;
|
||||
|
||||
return MetadataHelper.generate({
|
||||
title: league.name,
|
||||
description: league.description || `Join ${league.name} on GridPilot. Professional iRacing league with automated results, standings, and obsessive attention to detail.`,
|
||||
path: `/leagues/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function Page({ params }: Props) {
|
||||
const { id } = await params;
|
||||
// Execute the PageQuery
|
||||
@@ -36,6 +61,7 @@ export default async function Page({ params }: Props) {
|
||||
}
|
||||
|
||||
const data = result.unwrap();
|
||||
const league = data.league;
|
||||
|
||||
// Build ViewData using the builder
|
||||
// Note: This would need additional data (owner, scoring config, etc.) in real implementation
|
||||
@@ -47,8 +73,19 @@ export default async function Page({ params }: Props) {
|
||||
races: [],
|
||||
sponsors: [],
|
||||
});
|
||||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SportsOrganization',
|
||||
name: league.name,
|
||||
description: league.description,
|
||||
url: `https://gridpilot.com/leagues/${league.id}`,
|
||||
};
|
||||
|
||||
return (
|
||||
<LeagueOverviewTemplate viewData={viewData} />
|
||||
<>
|
||||
<JsonLd data={jsonLd} />
|
||||
<LeagueOverviewTemplate viewData={viewData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { LeaguesPageClient } from './LeaguesPageClient';
|
||||
import { LeaguesPageQuery } from '@/lib/page-queries/LeaguesPageQuery';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'iRacing Leagues',
|
||||
description: 'Find and join the most professional iRacing leagues on GridPilot. Automated results, professional race control, and obsessive attention to detail for every series.',
|
||||
path: '/leagues',
|
||||
});
|
||||
|
||||
export default async function Page() {
|
||||
// Execute the PageQuery
|
||||
|
||||
@@ -3,6 +3,15 @@ import { PageDataFetcher } from '@/lib/page/PageDataFetcher';
|
||||
import { HomePageQuery } from '@/lib/page-queries/HomePageQuery';
|
||||
import { notFound, redirect } from 'next/navigation';
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
import { JsonLd } from '@/ui/JsonLd';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Professional iRacing League Management Platform',
|
||||
description: 'Experience the pinnacle of sim racing organization. GridPilot provides obsessive detail in race management, automated standings, and professional-grade tools for serious iRacing leagues.',
|
||||
path: '/',
|
||||
});
|
||||
|
||||
export default async function Page() {
|
||||
if (await HomePageQuery.shouldRedirectToDashboard()) {
|
||||
@@ -17,6 +26,24 @@ export default async function Page() {
|
||||
if (!data) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
name: 'GridPilot',
|
||||
url: 'https://gridpilot.com',
|
||||
description: 'Professional iRacing League Management Platform',
|
||||
potentialAction: {
|
||||
'@type': 'SearchAction',
|
||||
target: 'https://gridpilot.com/search?q={search_term_string}',
|
||||
'query-input': 'required name=search_term_string',
|
||||
},
|
||||
};
|
||||
|
||||
return <HomePageClient viewData={data} />;
|
||||
return (
|
||||
<>
|
||||
<JsonLd data={jsonLd} />
|
||||
<HomePageClient viewData={data} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { notFound } from 'next/navigation';
|
||||
import { PageWrapper } from '@/components/shared/state/PageWrapper';
|
||||
import { RaceDetailPageQuery } from '@/lib/page-queries/races/RaceDetailPageQuery';
|
||||
import { RaceDetailPageClient } from '@/client-wrapper/RaceDetailPageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
interface RaceDetailPageProps {
|
||||
params: Promise<{
|
||||
@@ -9,6 +11,30 @@ interface RaceDetailPageProps {
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: RaceDetailPageProps): Promise<Metadata> {
|
||||
const { id: raceId } = await params;
|
||||
const result = await RaceDetailPageQuery.execute({ raceId, driverId: '' });
|
||||
|
||||
if (result.isErr()) {
|
||||
return MetadataHelper.generate({
|
||||
title: 'Race Not Found',
|
||||
description: 'The requested race details could not be found on GridPilot.',
|
||||
path: `/races/${raceId}`,
|
||||
});
|
||||
}
|
||||
|
||||
const viewData = result.unwrap();
|
||||
const race = viewData.race;
|
||||
const leagueName = viewData.league?.name;
|
||||
const title = leagueName ? `${race.track} - ${leagueName}` : `${race.track} - ${race.car}`;
|
||||
|
||||
return MetadataHelper.generate({
|
||||
title: `${title} | Race Results`,
|
||||
description: `Detailed race results, standings, and session reports for the ${race.car} race at ${race.track}${leagueName ? ` in ${leagueName}` : ''} on GridPilot. Professional iRacing event coverage with obsessive detail.`,
|
||||
path: `/races/${raceId}`,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function RaceDetailPage({ params }: RaceDetailPageProps) {
|
||||
const { id: raceId } = await params;
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { RacesPageQuery } from '@/lib/page-queries/races/RacesPageQuery';
|
||||
import { RacesPageClient } from '@/client-wrapper/RacesPageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Upcoming & Recent Races',
|
||||
description: 'Stay updated with the latest sim racing action on GridPilot. View upcoming events, live race results, and detailed session reports from professional iRacing leagues.',
|
||||
path: '/races',
|
||||
});
|
||||
|
||||
export default async function Page() {
|
||||
const query = new RacesPageQuery();
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { TeamDetailPageQuery } from '@/lib/page-queries/TeamDetailPageQuery';
|
||||
import { TeamDetailPageClient } from '@/client-wrapper/TeamDetailPageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
import { JsonLd } from '@/ui/JsonLd';
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
const result = await TeamDetailPageQuery.execute(id);
|
||||
|
||||
if (result.isErr()) {
|
||||
return MetadataHelper.generate({
|
||||
title: 'Team Not Found',
|
||||
description: 'The requested team could not be found on GridPilot.',
|
||||
path: `/teams/${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
const viewData = result.unwrap();
|
||||
const team = viewData.team;
|
||||
|
||||
return MetadataHelper.generate({
|
||||
title: team.name,
|
||||
description: team.description || `Explore ${team.name} on GridPilot. View team roster, race history, and performance statistics in professional iRacing leagues.`,
|
||||
path: `/teams/${id}`,
|
||||
// image: team.logoUrl, // If logoUrl exists in viewData
|
||||
});
|
||||
}
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
@@ -15,5 +41,30 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
|
||||
notFound();
|
||||
}
|
||||
|
||||
return <TeamDetailPageClient viewData={result.unwrap()} />;
|
||||
const viewData = result.unwrap();
|
||||
const team = viewData.team;
|
||||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SportsTeam',
|
||||
name: team.name,
|
||||
description: team.description,
|
||||
url: `https://gridpilot.com/teams/${team.id}`,
|
||||
member: viewData.memberships.map(m => ({
|
||||
'@type': 'OrganizationRole',
|
||||
member: {
|
||||
'@type': 'Person',
|
||||
name: m.driverName,
|
||||
url: `https://gridpilot.com/drivers/${m.driverId}`,
|
||||
},
|
||||
roleName: m.role,
|
||||
})),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<JsonLd data={jsonLd} />
|
||||
<TeamDetailPageClient viewData={viewData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { TeamLeaderboardPageQuery } from '@/lib/page-queries/TeamLeaderboardPageQuery';
|
||||
import { TeamLeaderboardPageWrapper } from '@/client-wrapper/TeamLeaderboardPageWrapper';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Team Leaderboard',
|
||||
description: 'The definitive ranking of sim racing teams on GridPilot. Compare team performance, championship points, and overall standing in the professional iRacing community.',
|
||||
path: '/teams/leaderboard',
|
||||
});
|
||||
|
||||
export default async function TeamLeaderboardPage() {
|
||||
const query = new TeamLeaderboardPageQuery();
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import { TeamsPageQuery } from '@/lib/page-queries/TeamsPageQuery';
|
||||
import { TeamsPageClient } from '@/client-wrapper/TeamsPageClient';
|
||||
import { Metadata } from 'next';
|
||||
import { MetadataHelper } from '@/lib/seo/MetadataHelper';
|
||||
|
||||
export const metadata: Metadata = MetadataHelper.generate({
|
||||
title: 'Sim Racing Teams',
|
||||
description: 'Discover the most competitive sim racing teams on GridPilot. Track team performance, rosters, and achievements across the professional iRacing landscape.',
|
||||
path: '/teams',
|
||||
});
|
||||
|
||||
export default async function Page() {
|
||||
const query = new TeamsPageQuery();
|
||||
|
||||
Reference in New Issue
Block a user