This commit is contained in:
2025-12-10 18:28:32 +01:00
parent 6d61be9c51
commit 1303a14493
108 changed files with 3366 additions and 1559 deletions

View File

@@ -32,57 +32,73 @@ interface Sponsorship {
drivers: number;
}
// Mock data - in production would come from repository
const MOCK_SPONSORSHIPS: Sponsorship[] = [
{
id: 'sp-1',
leagueId: 'league-1',
leagueName: 'GT3 Pro Championship',
tier: 'main',
status: 'active',
startDate: new Date('2025-01-01'),
endDate: new Date('2025-06-30'),
price: 1200,
impressions: 45200,
drivers: 32,
},
{
id: 'sp-2',
leagueId: 'league-2',
leagueName: 'Endurance Masters',
tier: 'main',
status: 'active',
startDate: new Date('2025-02-01'),
endDate: new Date('2025-07-31'),
price: 1000,
impressions: 38100,
drivers: 48,
},
{
id: 'sp-3',
leagueId: 'league-3',
leagueName: 'Formula Sim Series',
tier: 'secondary',
status: 'active',
startDate: new Date('2025-03-01'),
endDate: new Date('2025-08-31'),
price: 400,
impressions: 22800,
drivers: 24,
},
{
id: 'sp-4',
leagueId: 'league-4',
leagueName: 'Touring Car Cup',
tier: 'secondary',
status: 'pending',
startDate: new Date('2025-04-01'),
endDate: new Date('2025-09-30'),
price: 350,
impressions: 0,
drivers: 28,
},
];
interface SponsorshipDetailApi {
id: string;
leagueId: string;
leagueName: string;
seasonId: string;
seasonName: string;
seasonStartDate?: string;
seasonEndDate?: string;
tier: 'main' | 'secondary';
status: string;
pricing: {
amount: number;
currency: string;
};
metrics: {
drivers: number;
races: number;
completedRaces: number;
impressions: number;
};
createdAt: string;
activatedAt?: string;
}
interface SponsorSponsorshipsResponse {
sponsorId: string;
sponsorName: string;
sponsorships: SponsorshipDetailApi[];
summary: {
totalSponsorships: number;
activeSponsorships: number;
totalInvestment: number;
totalPlatformFees: number;
currency: string;
};
}
function mapSponsorshipStatus(status: string): 'active' | 'pending' | 'expired' {
switch (status) {
case 'active':
return 'active';
case 'pending':
return 'pending';
default:
return 'expired';
}
}
function mapApiToSponsorships(response: SponsorSponsorshipsResponse): Sponsorship[] {
return response.sponsorships.map((s) => {
const start = s.seasonStartDate ? new Date(s.seasonStartDate) : new Date(s.createdAt);
const end = s.seasonEndDate ? new Date(s.seasonEndDate) : start;
return {
id: s.id,
leagueId: s.leagueId,
leagueName: s.leagueName,
tier: s.tier,
status: mapSponsorshipStatus(s.status),
startDate: start,
endDate: end,
price: s.pricing.amount,
impressions: s.metrics.impressions,
drivers: s.metrics.drivers,
};
});
}
function SponsorshipCard({ sponsorship }: { sponsorship: Sponsorship }) {
const router = useRouter();
@@ -179,18 +195,59 @@ function SponsorshipCard({ sponsorship }: { sponsorship: Sponsorship }) {
export default function SponsorCampaignsPage() {
const router = useRouter();
const [filter, setFilter] = useState<'all' | 'active' | 'pending' | 'expired'>('all');
const filteredSponsorships = filter === 'all'
? MOCK_SPONSORSHIPS
: MOCK_SPONSORSHIPS.filter(s => s.status === filter);
const [sponsorships, setSponsorships] = useState<Sponsorship[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isMounted = true;
async function fetchSponsorships() {
try {
const response = await fetch('/api/sponsors/sponsorships');
if (!response.ok) {
if (!isMounted) return;
setSponsorships([]);
return;
}
const json: SponsorSponsorshipsResponse = await response.json();
if (!isMounted) return;
setSponsorships(mapApiToSponsorships(json));
} catch {
if (!isMounted) return;
setSponsorships([]);
} finally {
if (isMounted) {
setLoading(false);
}
}
}
fetchSponsorships();
return () => {
isMounted = false;
};
}, []);
const filteredSponsorships = filter === 'all'
? sponsorships
: sponsorships.filter(s => s.status === filter);
const stats = {
total: MOCK_SPONSORSHIPS.length,
active: MOCK_SPONSORSHIPS.filter(s => s.status === 'active').length,
pending: MOCK_SPONSORSHIPS.filter(s => s.status === 'pending').length,
totalInvestment: MOCK_SPONSORSHIPS.reduce((sum, s) => sum + s.price, 0),
total: sponsorships.length,
active: sponsorships.filter(s => s.status === 'active').length,
pending: sponsorships.filter(s => s.status === 'pending').length,
totalInvestment: sponsorships.reduce((sum, s) => sum + s.price, 0),
};
if (loading) {
return (
<div className="max-w-6xl mx-auto py-8 px-4">
<p className="text-gray-400">Loading sponsorships</p>
</div>
);
}
return (
<div className="max-w-6xl mx-auto py-8 px-4">
{/* Header */}