Files
gridpilot.gg/apps/website/templates/SponsorCampaignsTemplate.tsx
2026-01-19 14:07:49 +01:00

169 lines
4.9 KiB
TypeScript

import { BillingSummaryPanel } from '@/components/sponsors/BillingSummaryPanel';
import { SponsorContractCard } from '@/components/sponsors/SponsorContractCard';
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Container } from '@/ui/Container';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/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;
formattedInvestment: string;
formattedImpressions: string;
formattedStartDate?: string;
formattedEndDate?: string;
}>;
stats: {
total: number;
active: number;
pending: number;
approved: number;
rejected: number;
formattedTotalInvestment: string;
formattedTotalImpressions: string;
};
}
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.formattedTotalInvestment,
icon: BarChart3,
variant: 'info',
},
{
label: 'Total Impressions',
value: viewData.stats.formattedTotalImpressions,
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.formattedInvestment}
impressions={s.formattedImpressions}
startDate={s.formattedStartDate}
endDate={s.formattedEndDate}
/>
);
})}
</Box>
</Box>
</Stack>
</Container>
);
}