Files
gridpilot.gg/apps/website/templates/SponsorCampaignsTemplate.tsx
2026-01-18 16:43:32 +01:00

169 lines
5.1 KiB
TypeScript

import { BillingSummaryPanel } from '@/components/sponsors/BillingSummaryPanel';
import { SponsorContractCard } from '@/components/sponsors/SponsorContractCard';
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
import { Button } from '@/ui/Button';
import { Container } from '@/ui/Container';
import { Icon } from '@/ui/Icon';
import { Box } from '@/ui/primitives/Box';
import { Stack } from '@/ui/primitives/Stack';
import {
BarChart3,
Check,
Clock,
Eye,
LucideIcon,
Search
} from 'lucide-react';
import React from 'react';
export type SponsorshipType = 'all' | 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
export type SponsorshipStatus = 'all' | 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
export interface SponsorCampaignsViewData {
sponsorships: Array<{
id: string;
type: string;
status: string;
leagueName: string;
seasonName: string;
tier: string;
pricing: { amount: number; currency: string };
metrics: { impressions: number };
seasonStartDate?: Date;
seasonEndDate?: Date;
}>;
stats: {
total: number;
active: number;
pending: number;
approved: number;
rejected: number;
totalInvestment: number;
totalImpressions: number;
};
}
interface SponsorCampaignsTemplateProps {
viewData: SponsorCampaignsViewData;
filteredSponsorships: SponsorCampaignsViewData['sponsorships'];
typeFilter: SponsorshipType;
setTypeFilter: (type: SponsorshipType) => void;
searchQuery: string;
setSearchQuery: (query: string) => void;
}
export function SponsorCampaignsTemplate({
viewData,
filteredSponsorships,
typeFilter,
setTypeFilter,
searchQuery,
setSearchQuery
}: SponsorCampaignsTemplateProps) {
const billingStats: Array<{
label: string;
value: string | number;
icon: LucideIcon;
variant: 'success' | 'warning' | 'info' | 'default';
}> = [
{
label: 'Active Campaigns',
value: viewData.stats.active,
icon: Check,
variant: 'success',
},
{
label: 'Pending Approval',
value: viewData.stats.pending,
icon: Clock,
variant: viewData.stats.pending > 0 ? 'warning' : 'default',
},
{
label: 'Total Investment',
value: `$${viewData.stats.totalInvestment.toLocaleString()}`,
icon: BarChart3,
variant: 'info',
},
{
label: 'Total Impressions',
value: `${(viewData.stats.totalImpressions / 1000).toFixed(0)}k`,
icon: Eye,
variant: 'default',
},
];
return (
<Container size="lg" py={8}>
<Stack gap={8}>
<SponsorDashboardHeader
sponsorName="Sponsor"
onRefresh={() => console.log('Refresh')}
/>
<BillingSummaryPanel stats={billingStats} />
<Box>
<Stack direction={{ base: 'col', lg: 'row' }} gap={4} mb={6}>
<Box position="relative" flexGrow={1}>
<Box position="absolute" left={3} top="1/2" transform="-translate-y-1/2">
<Icon icon={Search} size={4} color="text-gray-500" />
</Box>
<Box
as="input"
type="text"
placeholder="Search sponsorships..."
value={searchQuery}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchQuery(e.target.value)}
w="full"
pl={10}
pr={4}
py={2}
rounded="lg"
border
borderColor="border-charcoal-outline"
bg="bg-iron-gray/50"
color="text-white"
outline="none"
focusBorderColor="border-primary-blue"
/>
</Box>
<Stack direction="row" gap={2} overflow="auto" pb={{ base: 2, lg: 0 }}>
{(['all', 'leagues', 'teams', 'drivers'] as const).map((type) => (
<Button
key={type}
variant={typeFilter === type ? 'primary' : 'secondary'}
size="sm"
onClick={() => setTypeFilter(type)}
>
{type.charAt(0).toUpperCase() + type.slice(1)}
</Button>
))}
</Stack>
</Stack>
<Box display="grid" gridCols={{ base: 1, lg: 2 }} gap={4}>
{filteredSponsorships.map((s) => {
return (
<SponsorContractCard
key={s.id}
id={s.id}
type="league"
status={s.status}
title={s.leagueName}
subtitle={s.seasonName}
tier={s.tier}
investment={`$${s.pricing.amount.toLocaleString()}`}
impressions={s.metrics.impressions.toLocaleString()}
startDate={s.seasonStartDate ? new Date(s.seasonStartDate).toLocaleDateString() : undefined}
endDate={s.seasonEndDate ? new Date(s.seasonEndDate).toLocaleDateString() : undefined}
/>
);
})}
</Box>
</Box>
</Stack>
</Container>
);
}