website refactor

This commit is contained in:
2026-01-17 15:46:55 +01:00
parent 4d5ce9bfd6
commit 72a626ce71
346 changed files with 19308 additions and 8605 deletions

View File

@@ -1,14 +1,16 @@
'use client';
import React from 'react';
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
import { PricingTableShell, PricingTier } from '@/components/sponsors/PricingTableShell';
import { BillingSummaryPanel } from '@/components/sponsors/BillingSummaryPanel';
import { SponsorBrandingPreview } from '@/components/sponsors/SponsorBrandingPreview';
import { SponsorStatusChip } from '@/components/sponsors/SponsorStatusChip';
import {
Trophy,
Users,
Calendar,
Eye,
TrendingUp,
ExternalLink,
Star,
Flag,
BarChart3,
Megaphone,
@@ -28,9 +30,6 @@ import { Grid } from '@/ui/Grid';
import { GridItem } from '@/ui/GridItem';
import { Surface } from '@/ui/Surface';
import { Icon } from '@/ui/Icon';
import { Badge } from '@/ui/Badge';
import { SponsorTierCard } from '@/components/sponsors/SponsorTierCard';
import { NumberDisplay } from '@/lib/display-objects/NumberDisplay';
import { siteConfig } from '@/lib/siteConfig';
import { routes } from '@/lib/routing/RouteConfig';
@@ -118,6 +117,60 @@ export function SponsorLeagueDetailTemplate({
}: SponsorLeagueDetailTemplateProps) {
const league = viewData.league;
const billingStats: Array<{
label: string;
value: string | number;
icon: LucideIcon;
variant: 'info' | 'success' | 'warning' | 'default';
}> = [
{
label: 'Total Views',
value: league.formattedTotalImpressions,
icon: Eye,
variant: 'info',
},
{
label: 'Avg/Race',
value: league.formattedAvgViewsPerRace,
icon: TrendingUp,
variant: 'success',
},
{
label: 'Engagement',
value: `${league.engagement}%`,
icon: BarChart3,
variant: 'warning',
},
{
label: 'Races Left',
value: league.racesLeft,
icon: Calendar,
variant: 'default',
},
];
const pricingTiers: PricingTier[] = [
{
id: 'main',
name: 'Main Sponsor',
price: league.sponsorSlots.main.price,
period: 'Season',
description: 'Exclusive primary branding across all league assets.',
features: league.sponsorSlots.main.benefits,
available: league.sponsorSlots.main.available,
isPopular: true,
},
{
id: 'secondary',
name: 'Secondary Sponsor',
price: league.sponsorSlots.secondary.price,
period: 'Season',
description: 'Supporting branding on cars and broadcast overlays.',
features: league.sponsorSlots.secondary.benefits,
available: league.sponsorSlots.secondary.available > 0,
}
];
return (
<Container size="lg" py={8}>
<Stack gap={8}>
@@ -137,49 +190,13 @@ export function SponsorLeagueDetailTemplate({
</Box>
{/* Header */}
<Stack direction="row" align="start" justify="between" wrap gap={6}>
<Box flexGrow={1}>
<Stack direction="row" align="center" gap={3} mb={2}>
<Badge variant="primary"> {league.tier}</Badge>
<Badge variant="success">Active Season</Badge>
<Surface variant="muted" rounded="lg" padding={1} bg="bg-neutral-800/50" px={2}>
<Stack direction="row" align="center" gap={1}>
<Icon icon={Star} size={3.5} color="#facc15" />
<Text size="sm" weight="medium" color="text-white">{league.rating}</Text>
</Stack>
</Surface>
</Stack>
<Heading level={1}>{league.name}</Heading>
<Text color="text-gray-400" block mt={2}>
{league.game} {league.season} {league.completedRaces}/{league.races} races completed
</Text>
<Text color="text-gray-400" block mt={4} maxWidth="42rem">
{league.description}
</Text>
</Box>
<Stack direction="row" gap={3}>
<Link href={routes.league.detail(league.id)}>
<Button variant="secondary" icon={<Icon icon={ExternalLink} size={4} />}>
View League
</Button>
</Link>
{(league.sponsorSlots.main.available || league.sponsorSlots.secondary.available > 0) && (
<Button variant="primary" onClick={() => setActiveTab('sponsor')} icon={<Icon icon={Megaphone} size={4} />}>
Become a Sponsor
</Button>
)}
</Stack>
</Stack>
<SponsorDashboardHeader
sponsorName="Sponsor"
onRefresh={() => console.log('Refresh')}
/>
{/* Quick Stats */}
<Grid cols={5} gap={4}>
<StatCard icon={Eye} label="Total Views" value={league.formattedTotalImpressions} color="#3b82f6" />
<StatCard icon={TrendingUp} label="Avg/Race" value={league.formattedAvgViewsPerRace} color="#10b981" />
<StatCard icon={Users} label="Drivers" value={league.drivers} color="#a855f7" />
<StatCard icon={BarChart3} label="Engagement" value={`${league.engagement}%`} color="#f59e0b" />
<StatCard icon={Calendar} label="Races Left" value={league.racesLeft} color="#ef4444" />
</Grid>
<BillingSummaryPanel stats={billingStats} />
{/* Tabs */}
<Box borderBottom borderColor="border-neutral-800">
@@ -321,11 +338,11 @@ export function SponsorLeagueDetailTemplate({
<Box>
{race.status === 'completed' ? (
<Box textAlign="right">
<Text weight="semibold" color="text-white" block>{NumberDisplay.format(race.views)}</Text>
<Text weight="semibold" color="text-white" block>{race.views.toLocaleString()}</Text>
<Text size="xs" color="text-gray-500">views</Text>
</Box>
) : (
<Badge variant="warning">Upcoming</Badge>
<SponsorStatusChip status="pending" label="Upcoming" />
)}
</Box>
</Stack>
@@ -336,85 +353,65 @@ export function SponsorLeagueDetailTemplate({
)}
{activeTab === 'sponsor' && (
<Stack gap={6}>
<Grid cols={2} gap={6}>
<SponsorTierCard
type="main"
available={league.sponsorSlots.main.available}
price={league.sponsorSlots.main.price}
benefits={league.sponsorSlots.main.benefits}
isSelected={selectedTier === 'main'}
onClick={() => setSelectedTier('main')}
<Grid cols={12} gap={6}>
<GridItem colSpan={12} lgSpan={8}>
<PricingTableShell
title="Sponsorship Tiers"
tiers={pricingTiers}
selectedId={selectedTier}
onSelect={(id) => setSelectedTier(id as 'main' | 'secondary')}
/>
<SponsorTierCard
type="secondary"
available={league.sponsorSlots.secondary.available > 0}
availableCount={league.sponsorSlots.secondary.available}
totalCount={league.sponsorSlots.secondary.total}
price={league.sponsorSlots.secondary.price}
benefits={league.sponsorSlots.secondary.benefits}
isSelected={selectedTier === 'secondary'}
onClick={() => setSelectedTier('secondary')}
/>
</Grid>
<Card>
<Box mb={4}>
<Heading level={2} icon={<Icon icon={CreditCard} size={5} color="#3b82f6" />}>
Sponsorship Summary
</Heading>
</Box>
<Stack gap={3} mb={6}>
<InfoRow label="Selected Tier" value={`${selectedTier.charAt(0).toUpperCase() + selectedTier.slice(1)} Sponsor`} />
<InfoRow label="Season Price" value={`$${selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price}`} />
<InfoRow label={`Platform Fee (${siteConfig.fees.platformFeePercent}%)`} value={`$${((selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price) * siteConfig.fees.platformFeePercent / 100).toFixed(2)}`} />
<Box pt={4} borderTop borderColor="border-neutral-800">
<Stack direction="row" align="center" justify="between">
<Text weight="semibold" color="text-white">Total (excl. VAT)</Text>
<Text size="xl" weight="bold" color="text-white">
${((selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price) * (1 + siteConfig.fees.platformFeePercent / 100)).toFixed(2)}
</Text>
</GridItem>
<GridItem colSpan={12} lgSpan={4}>
<Stack gap={6}>
<SponsorBrandingPreview
name="Your Brand"
/>
<Card>
<Box mb={4}>
<Heading level={2} icon={<Icon icon={CreditCard} size={5} color="#3b82f6" />}>
Sponsorship Summary
</Heading>
</Box>
<Stack gap={3} mb={6}>
<InfoRow label="Selected Tier" value={`${selectedTier.charAt(0).toUpperCase() + selectedTier.slice(1)} Sponsor`} />
<InfoRow label="Season Price" value={`$${selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price}`} />
<InfoRow label={`Platform Fee (${siteConfig.fees.platformFeePercent}%)`} value={`$${((selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price) * siteConfig.fees.platformFeePercent / 100).toFixed(2)}`} />
<Box pt={4} borderTop borderColor="border-neutral-800">
<Stack direction="row" align="center" justify="between">
<Text weight="semibold" color="text-white">Total (excl. VAT)</Text>
<Text size="xl" weight="bold" color="text-white">
${((selectedTier === 'main' ? league.sponsorSlots.main.price : league.sponsorSlots.secondary.price) * (1 + siteConfig.fees.platformFeePercent / 100)).toFixed(2)}
</Text>
</Stack>
</Box>
</Stack>
</Box>
</Stack>
<Text size="xs" color="text-gray-500" block mb={4}>
{siteConfig.vat.notice}
</Text>
<Text size="xs" color="text-gray-500" block mb={4}>
{siteConfig.vat.notice}
</Text>
<Stack direction="row" gap={3}>
<Button variant="primary" fullWidth icon={<Icon icon={Megaphone} size={4} />}>
Request Sponsorship
</Button>
<Button variant="secondary" icon={<Icon icon={FileText} size={4} />}>
Download Info Pack
</Button>
<Stack direction="row" gap={3}>
<Button variant="primary" fullWidth icon={<Icon icon={Megaphone} size={4} />}>
Request Sponsorship
</Button>
<Button variant="secondary" icon={<Icon icon={FileText} size={4} />}>
Download Info Pack
</Button>
</Stack>
</Card>
</Stack>
</Card>
</Stack>
</GridItem>
</Grid>
)}
</Stack>
</Container>
);
}
function StatCard({ icon, label, value, color }: { icon: LucideIcon, label: string, value: string | number, color: string }) {
return (
<Card>
<Stack direction="row" align="center" gap={3}>
<Surface variant="muted" rounded="lg" padding={2} bg={`${color}1A`}>
<Icon icon={icon} size={5} color={color} />
</Surface>
<Box>
<Text size="xl" weight="bold" color="text-white" block>{value}</Text>
<Text size="xs" color="text-gray-500" block>{label}</Text>
</Box>
</Stack>
</Card>
);
}
function InfoRow({ label, value, color = 'text-white', last }: { label: string, value: string | number, color?: string, last?: boolean }) {
return (
<Box py={2} borderBottom={!last} borderColor="border-neutral-800/50">