website refactor
This commit is contained in:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user