Some checks failed
CI / lint-typecheck (pull_request) Failing after 12s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
308 lines
11 KiB
TypeScript
308 lines
11 KiB
TypeScript
|
|
|
|
import { BillingSummaryPanel } from '@/components/sponsors/BillingSummaryPanel';
|
|
import { MetricCard } from '@/components/sponsors/MetricCard';
|
|
import { RenewalAlert } from '@/components/sponsors/RenewalAlert';
|
|
import { Activity, SponsorActivityPanel } from '@/components/sponsors/SponsorActivityPanel';
|
|
import { SponsorContractCard } from '@/components/sponsors/SponsorContractCard';
|
|
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
|
|
import { SponsorshipCategoryCard } from '@/components/sponsors/SponsorshipCategoryCard';
|
|
import { routes } from '@/lib/routing/RouteConfig';
|
|
import type { SponsorDashboardViewData } from '@/lib/view-data/SponsorDashboardViewData';
|
|
import { Box } from '@/ui/Box';
|
|
import { Button } from '@/ui/Button';
|
|
import { Card } from '@/ui/Card';
|
|
import { Container } from '@/ui/Container';
|
|
import { Grid } from '@/ui/Grid';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Link } from '@/ui/Link';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Text } from '@/ui/Text';
|
|
import {
|
|
Bell,
|
|
Car,
|
|
ChevronRight,
|
|
Clock,
|
|
DollarSign,
|
|
Eye,
|
|
Flag,
|
|
LucideIcon,
|
|
Megaphone,
|
|
Plus,
|
|
TrendingUp,
|
|
Trophy,
|
|
Users
|
|
} from 'lucide-react';
|
|
|
|
interface SponsorDashboardTemplateProps {
|
|
viewData: SponsorDashboardViewData;
|
|
}
|
|
|
|
export function SponsorDashboardTemplate({ viewData }: SponsorDashboardTemplateProps) {
|
|
const categoryData = viewData.categoryData;
|
|
|
|
const billingStats: Array<{
|
|
label: string;
|
|
value: string | number;
|
|
icon: LucideIcon;
|
|
variant: 'info' | 'success' | 'default' | 'warning';
|
|
}> = [
|
|
{
|
|
label: 'Total Investment',
|
|
value: viewData.formattedTotalInvestment,
|
|
icon: DollarSign,
|
|
variant: 'info',
|
|
},
|
|
{
|
|
label: 'Active Sponsorships',
|
|
value: viewData.activeSponsorships,
|
|
icon: Trophy,
|
|
variant: 'success',
|
|
},
|
|
{
|
|
label: 'Cost per 1K Views',
|
|
value: viewData.costPerThousandViews,
|
|
icon: Eye,
|
|
variant: 'default',
|
|
},
|
|
{
|
|
label: 'Upcoming Renewals',
|
|
value: viewData.upcomingRenewals.length,
|
|
icon: Bell,
|
|
variant: viewData.upcomingRenewals.length > 0 ? 'warning' : 'default',
|
|
},
|
|
];
|
|
|
|
const activities: Activity[] = viewData.recentActivity.map((a: any) => ({
|
|
id: a.id,
|
|
type: 'sponsorship_approved', // Mapping logic would go here
|
|
title: a.message,
|
|
description: a.formattedImpressions ? `${a.formattedImpressions} impressions` : '',
|
|
timestamp: a.time,
|
|
icon: Clock,
|
|
color: a.typeColor || 'primary-accent',
|
|
}));
|
|
|
|
return (
|
|
<Container size="lg" spacing="md">
|
|
<Stack gap={8}>
|
|
{/* Header */}
|
|
<SponsorDashboardHeader
|
|
sponsorName={viewData.sponsorName}
|
|
onRefresh={() => console.log('Refresh')}
|
|
/>
|
|
|
|
{/* Billing Summary */}
|
|
<BillingSummaryPanel stats={billingStats} />
|
|
|
|
{/* Key Metrics */}
|
|
<Grid responsiveGridCols={{ base: 1, sm: 2, lg: 4 }} gap={4}>
|
|
<MetricCard
|
|
title="Total Impressions"
|
|
value={viewData.totalImpressions}
|
|
change={viewData.metrics.impressionsChange}
|
|
icon={Eye}
|
|
delay={0}
|
|
/>
|
|
<MetricCard
|
|
title="Unique Viewers"
|
|
value="12.5k"
|
|
change={viewData.metrics.impressionsChange}
|
|
icon={Users}
|
|
delay={0.1}
|
|
/>
|
|
<MetricCard
|
|
title="Engagement Rate"
|
|
value="4.2%"
|
|
change={viewData.metrics.impressionsChange}
|
|
icon={TrendingUp}
|
|
suffix="%"
|
|
delay={0.2}
|
|
/>
|
|
<MetricCard
|
|
title="Total Investment"
|
|
value={viewData.totalInvestment}
|
|
icon={DollarSign}
|
|
prefix="$"
|
|
delay={0.3}
|
|
/>
|
|
</Grid>
|
|
|
|
{/* Main Content Grid */}
|
|
<Grid responsiveGridCols={{ base: 1, lg: 12 }} gap={6}>
|
|
<Box responsiveColSpan={{ base: 1, lg: 8 }}>
|
|
<Stack gap={6}>
|
|
{/* Sponsorship Categories */}
|
|
<Box>
|
|
<Stack direction="row" align="center" justify="between" mb={4}>
|
|
<Heading level={3}>Your Sponsorships</Heading>
|
|
<Link href={routes.sponsor.campaigns}>
|
|
<Button variant="secondary" size="sm">
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Text>View All</Text>
|
|
<Icon icon={ChevronRight} size={4} />
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
</Stack>
|
|
|
|
<Grid responsiveGridCols={{ base: 2, md: 3, lg: 5 }} gap={4}>
|
|
<SponsorshipCategoryCard
|
|
icon={Trophy}
|
|
title="Leagues"
|
|
countLabel={categoryData.leagues.countLabel}
|
|
impressionsLabel={categoryData.leagues.impressionsLabel}
|
|
color="primary-accent"
|
|
href="/sponsor/campaigns?type=leagues"
|
|
/>
|
|
<SponsorshipCategoryCard
|
|
icon={Users}
|
|
title="Teams"
|
|
countLabel={categoryData.teams.countLabel}
|
|
impressionsLabel={categoryData.teams.impressionsLabel}
|
|
color="var(--color-warning)"
|
|
href="/sponsor/campaigns?type=teams"
|
|
/>
|
|
<SponsorshipCategoryCard
|
|
icon={Car}
|
|
title="Drivers"
|
|
countLabel={categoryData.drivers.countLabel}
|
|
impressionsLabel={categoryData.drivers.impressionsLabel}
|
|
color="var(--color-success)"
|
|
href="/sponsor/campaigns?type=drivers"
|
|
/>
|
|
<SponsorshipCategoryCard
|
|
icon={Flag}
|
|
title="Races"
|
|
countLabel={categoryData.races.countLabel}
|
|
impressionsLabel={categoryData.races.impressionsLabel}
|
|
color="var(--color-warning)"
|
|
href="/sponsor/campaigns?type=races"
|
|
/>
|
|
<SponsorshipCategoryCard
|
|
icon={Megaphone}
|
|
title="Platform Ads"
|
|
countLabel={categoryData.platform.countLabel}
|
|
impressionsLabel={categoryData.platform.impressionsLabel}
|
|
color="critical-red"
|
|
href="/sponsor/campaigns?type=platform"
|
|
/>
|
|
</Grid>
|
|
</Box>
|
|
|
|
{/* Top Performing Sponsorships */}
|
|
<Box>
|
|
<Stack direction="row" align="center" justify="between" mb={4}>
|
|
<Heading level={3}>Top Performing</Heading>
|
|
<Link href={routes.public.leagues}>
|
|
<Button variant="secondary" size="sm">
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Plus} size={4} />
|
|
<Text>Find More</Text>
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
</Stack>
|
|
<Grid responsiveGridCols={{ base: 1, md: 2 }} gap={4}>
|
|
<SponsorContractCard
|
|
id="sample-1"
|
|
type="league"
|
|
status="active"
|
|
title="Sample League"
|
|
subtitle="Season 5 • GT3 Series"
|
|
tier="Main Sponsor"
|
|
investment="$2,500"
|
|
impressions="1.2M"
|
|
startDate="2025-10-01"
|
|
endDate="2026-02-15"
|
|
/>
|
|
<SponsorContractCard
|
|
id="sample-2"
|
|
type="team"
|
|
status="active"
|
|
title="Apex Racing Team"
|
|
subtitle="Endurance Championship"
|
|
tier="Secondary Sponsor"
|
|
investment="$1,200"
|
|
impressions="450k"
|
|
startDate="2025-11-15"
|
|
endDate="2026-03-20"
|
|
/>
|
|
</Grid>
|
|
</Box>
|
|
</Stack>
|
|
</Box>
|
|
|
|
<Box responsiveColSpan={{ base: 1, lg: 4 }}>
|
|
<Stack gap={6}>
|
|
{/* Recent Activity */}
|
|
<SponsorActivityPanel activities={activities} />
|
|
|
|
{/* Quick Actions */}
|
|
<Card>
|
|
<Stack gap={4}>
|
|
<Heading level={3}>Quick Actions</Heading>
|
|
<Stack gap={2}>
|
|
<Link href={routes.public.leagues}>
|
|
<Button variant="secondary" fullWidth>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Trophy} size={4} />
|
|
<Text>Find Leagues to Sponsor</Text>
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
<Link href={routes.public.teams}>
|
|
<Button variant="secondary" fullWidth>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Users} size={4} />
|
|
<Text>Browse Teams</Text>
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
<Link href={routes.public.drivers}>
|
|
<Button variant="secondary" fullWidth>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Car} size={4} />
|
|
<Text>Discover Drivers</Text>
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
<Link href={routes.sponsor.billing}>
|
|
<Button variant="secondary" fullWidth>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={DollarSign} size={4} />
|
|
<Text>Manage Billing</Text>
|
|
</Stack>
|
|
</Button>
|
|
</Link>
|
|
</Stack>
|
|
</Stack>
|
|
</Card>
|
|
|
|
{/* Renewal Alerts */}
|
|
{viewData.upcomingRenewals.length > 0 && (
|
|
<Card>
|
|
<Stack gap={4}>
|
|
<Heading level={3}>
|
|
<Stack direction="row" align="center" gap={2}>
|
|
<Icon icon={Bell} size={5} color="warning-amber" />
|
|
<Text>Upcoming Renewals</Text>
|
|
</Stack>
|
|
</Heading>
|
|
<Stack gap={3}>
|
|
{viewData.upcomingRenewals.map((renewal: any) => (
|
|
<RenewalAlert key={renewal.id} renewal={renewal} />
|
|
))}
|
|
</Stack>
|
|
</Stack>
|
|
</Card>
|
|
)}
|
|
</Stack>
|
|
</Box>
|
|
</Grid>
|
|
</Stack>
|
|
</Container>
|
|
);
|
|
}
|