122 lines
4.1 KiB
TypeScript
122 lines
4.1 KiB
TypeScript
import { notFound } from 'next/navigation';
|
|
import { LeagueDetailPageQuery } from '@/lib/page-queries/LeagueDetailPageQuery';
|
|
import { LeagueDetailTemplate } from '@/templates/LeagueDetailTemplate';
|
|
import { LeagueDetailViewDataBuilder } from '@/lib/builders/view-data/LeagueDetailViewDataBuilder';
|
|
import { DriverService } from '@/lib/services/drivers/DriverService';
|
|
import { Text } from '@/ui/Text';
|
|
|
|
export default async function LeagueLayout({
|
|
children,
|
|
params,
|
|
}: {
|
|
children: React.ReactNode;
|
|
params: Promise<{ id: string }>;
|
|
}) {
|
|
const { id: leagueId } = await params;
|
|
|
|
// Execute PageQuery to get league data
|
|
const [result, currentDriver] = await Promise.all([
|
|
LeagueDetailPageQuery.execute(leagueId),
|
|
new DriverService().getCurrentDriver(),
|
|
]);
|
|
|
|
if (result.isErr()) {
|
|
const error = result.getError();
|
|
if (error === 'notFound' || error === 'redirect') {
|
|
notFound();
|
|
}
|
|
// Return error state
|
|
return (
|
|
<LeagueDetailTemplate
|
|
viewData={{
|
|
leagueId,
|
|
name: 'Error',
|
|
description: 'Failed to load league',
|
|
info: { name: 'Error', description: 'Error', membersCount: 0, racesCount: 0, avgSOF: 0, structure: '', scoring: '', createdAt: '' },
|
|
runningRaces: [],
|
|
sponsors: [],
|
|
ownerSummary: null,
|
|
adminSummaries: [],
|
|
stewardSummaries: [],
|
|
memberSummaries: [],
|
|
sponsorInsights: null,
|
|
league: {
|
|
id: leagueId,
|
|
name: 'Error',
|
|
game: 'Unknown',
|
|
tier: 'starter',
|
|
season: 'Unknown',
|
|
description: 'Error',
|
|
drivers: 0,
|
|
races: 0,
|
|
completedRaces: 0,
|
|
totalImpressions: 0,
|
|
avgViewsPerRace: 0,
|
|
engagement: 0,
|
|
rating: 0,
|
|
seasonStatus: 'completed',
|
|
seasonDates: { start: '', end: '' },
|
|
sponsorSlots: {
|
|
main: { price: 0, status: 'occupied' },
|
|
secondary: { price: 0, total: 0, occupied: 0 }
|
|
}
|
|
},
|
|
drivers: [],
|
|
races: [],
|
|
seasonProgress: { completedRaces: 0, totalRaces: 0, percentage: 0 },
|
|
recentResults: [],
|
|
walletBalance: 0,
|
|
pendingProtestsCount: 0,
|
|
pendingJoinRequestsCount: 0
|
|
}}
|
|
tabs={[]}
|
|
>
|
|
<Text align="center">Failed to load league</Text>
|
|
</LeagueDetailTemplate>
|
|
);
|
|
}
|
|
|
|
const data = result.unwrap();
|
|
|
|
const viewData = LeagueDetailViewDataBuilder.build({
|
|
league: data.league,
|
|
owner: data.owner,
|
|
scoringConfig: data.scoringConfig,
|
|
memberships: data.memberships,
|
|
races: data.races,
|
|
sponsors: data.sponsors,
|
|
});
|
|
|
|
// Define tab configuration
|
|
const baseTabs = [
|
|
{ label: 'Overview', href: `/leagues/${leagueId}`, exact: true },
|
|
{ label: 'Schedule', href: `/leagues/${leagueId}/schedule`, exact: false },
|
|
{ label: 'Standings', href: `/leagues/${leagueId}/standings`, exact: false },
|
|
{ label: 'Roster', href: `/leagues/${leagueId}/roster`, exact: false },
|
|
{ label: 'Rulebook', href: `/leagues/${leagueId}/rulebook`, exact: false },
|
|
];
|
|
|
|
// Check if user is admin or owner
|
|
const isOwner = currentDriver && data.league.ownerId === currentDriver.id;
|
|
const isAdmin = currentDriver && data.memberships.members?.some(m => m.driverId === currentDriver.id && m.role === 'admin');
|
|
const hasAdminAccess = isOwner || isAdmin;
|
|
|
|
const adminTabs = hasAdminAccess ? [
|
|
{ label: 'Schedule Admin', href: `/leagues/${leagueId}/schedule/admin`, exact: false },
|
|
{ label: 'Sponsorships', href: `/leagues/${leagueId}/sponsorships`, exact: false },
|
|
{ label: 'Stewarding', href: `/leagues/${leagueId}/stewarding`, exact: false },
|
|
{ label: 'Wallet', href: `/leagues/${leagueId}/wallet`, exact: false },
|
|
{ label: 'Settings', href: `/leagues/${leagueId}/settings`, exact: false },
|
|
] : [];
|
|
|
|
const tabs = [...baseTabs, ...adminTabs];
|
|
|
|
return (
|
|
<LeagueDetailTemplate
|
|
viewData={viewData}
|
|
tabs={tabs}
|
|
>
|
|
{children}
|
|
</LeagueDetailTemplate>
|
|
);
|
|
} |