wip
This commit is contained in:
@@ -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 */}
|
||||
|
||||
@@ -52,64 +52,6 @@ interface SponsorDashboardData {
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback mock data for demo mode
|
||||
const MOCK_DASHBOARD: SponsorDashboardData = {
|
||||
sponsorId: 'demo-sponsor',
|
||||
sponsorName: 'Demo Sponsor',
|
||||
metrics: {
|
||||
impressions: 124500,
|
||||
impressionsChange: 12.5,
|
||||
uniqueViewers: 8420,
|
||||
viewersChange: 8.3,
|
||||
races: 24,
|
||||
drivers: 156,
|
||||
exposure: 87.5,
|
||||
exposureChange: 5.2,
|
||||
},
|
||||
sponsoredLeagues: [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'GT3 Pro Championship',
|
||||
tier: 'main',
|
||||
drivers: 32,
|
||||
races: 12,
|
||||
impressions: 45200,
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
name: 'Endurance Masters',
|
||||
tier: 'main',
|
||||
drivers: 48,
|
||||
races: 6,
|
||||
impressions: 38100,
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
id: 'league-3',
|
||||
name: 'Formula Sim Series',
|
||||
tier: 'secondary',
|
||||
drivers: 24,
|
||||
races: 8,
|
||||
impressions: 22800,
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
id: 'league-4',
|
||||
name: 'Touring Car Cup',
|
||||
tier: 'secondary',
|
||||
drivers: 28,
|
||||
races: 10,
|
||||
impressions: 18400,
|
||||
status: 'upcoming',
|
||||
},
|
||||
],
|
||||
investment: {
|
||||
activeSponsorships: 4,
|
||||
totalInvestment: 2400,
|
||||
costPerThousandViews: 19.28,
|
||||
},
|
||||
};
|
||||
|
||||
function MetricCard({
|
||||
title,
|
||||
@@ -205,15 +147,13 @@ export default function SponsorDashboardPage() {
|
||||
try {
|
||||
const response = await fetch('/api/sponsors/dashboard');
|
||||
if (response.ok) {
|
||||
const dashboardData = await response.json();
|
||||
const dashboardData: SponsorDashboardData = await response.json();
|
||||
setData(dashboardData);
|
||||
} else {
|
||||
// Use mock data for demo mode
|
||||
setData(MOCK_DASHBOARD);
|
||||
setError('Failed to load sponsor dashboard');
|
||||
}
|
||||
} catch {
|
||||
// Use mock data on error
|
||||
setData(MOCK_DASHBOARD);
|
||||
setError('Failed to load sponsor dashboard');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -230,7 +170,19 @@ export default function SponsorDashboardPage() {
|
||||
);
|
||||
}
|
||||
|
||||
const dashboardData = data || MOCK_DASHBOARD;
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto py-8 px-4">
|
||||
<div className="rounded-lg bg-warning-amber/10 border border-warning-amber/30 p-4">
|
||||
<p className="text-sm text-warning-amber">
|
||||
{error ?? 'No sponsor dashboard data available yet.'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const dashboardData = data;
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto py-8 px-4">
|
||||
|
||||
Reference in New Issue
Block a user