Files
gridpilot.gg/testing/fixtures/racing/RacingSponsorshipSeed.ts
2025-12-16 11:52:26 +01:00

451 lines
14 KiB
TypeScript

import { League } from '@core/racing/domain/entities/League';
import { Race } from '@core/racing/domain/entities/Race';
import { Driver } from '@core/racing/domain/entities/Driver';
import { Money } from '@core/racing/domain/value-objects/Money';
import { SponsorshipPricing } from '@core/racing/domain/value-objects/SponsorshipPricing';
import {
SponsorshipRequest,
type SponsorableEntityType,
} from '@core/racing/domain/entities/SponsorshipRequest';
import type { DemoTeamDTO } from './RacingSeedCore';
/**
* Demo sponsor data for seeding.
*/
export interface DemoSponsorDTO {
id: string;
name: string;
contactEmail: string;
logoUrl: string;
websiteUrl: string;
tagline: string;
}
/**
* Demo season sponsorship data.
* This remains a simple DTO since the SeasonSponsorship
* domain entity is instantiated in the DI config.
*/
export interface DemoSeasonSponsorshipDTO {
id: string;
seasonId: string;
sponsorId: string;
tier: 'main' | 'secondary';
pricingAmount: number;
pricingCurrency: 'USD' | 'EUR' | 'GBP';
status: 'pending' | 'active' | 'cancelled';
description?: string;
}
/**
* Demo sponsorship request data for seeding.
* Backed directly by the SponsorshipRequest domain entity.
*/
export type DemoSponsorshipRequestDTO = SponsorshipRequest;
/**
* Demo sponsorship pricing configuration for entities, using the
* SponsorshipPricing value object to keep pricing logic in the domain.
*/
export interface DemoSponsorshipPricingDTO {
entityType: SponsorableEntityType;
entityId: string;
pricing: SponsorshipPricing;
}
/**
* Demo sponsors data - realistic sim racing sponsors.
*/
export const DEMO_SPONSORS: DemoSponsorDTO[] = [
{
id: 'sponsor-fanatec',
name: 'Fanatec',
contactEmail: 'partnerships@fanatec.com',
logoUrl: '/images/sponsors/fanatec.svg',
websiteUrl: 'https://fanatec.com',
tagline: "The world's leading sim racing hardware",
},
{
id: 'sponsor-simucube',
name: 'Simucube',
contactEmail: 'sponsors@simucube.com',
logoUrl: '/images/sponsors/simucube.svg',
websiteUrl: 'https://simucube.com',
tagline: 'Professional Direct Drive Wheels',
},
{
id: 'sponsor-heusinkveld',
name: 'Heusinkveld',
contactEmail: 'info@heusinkveld.com',
logoUrl: '/images/sponsors/heusinkveld.svg',
websiteUrl: 'https://heusinkveld.com',
tagline: 'Sim Racing Pedals & Hardware',
},
{
id: 'sponsor-trak-racer',
name: 'Trak Racer',
contactEmail: 'partnerships@trakracer.com',
logoUrl: '/images/sponsors/trak-racer.svg',
websiteUrl: 'https://trakracer.com',
tagline: 'Premium Racing Simulators & Cockpits',
},
{
id: 'sponsor-simlab',
name: 'Sim-Lab',
contactEmail: 'sponsor@sim-lab.eu',
logoUrl: '/images/sponsors/simlab.svg',
websiteUrl: 'https://sim-lab.eu',
tagline: 'Aluminum Profile Sim Racing Rigs',
},
{
id: 'sponsor-motionrig',
name: 'MotionRig Pro',
contactEmail: 'business@motionrigpro.com',
logoUrl: '/images/sponsors/motionrig.svg',
websiteUrl: 'https://motionrigpro.com',
tagline: 'Feel every turn, every bump',
},
];
/**
* Create season sponsorships linking sponsors to leagues.
*/
export function createSeasonSponsorships(
leagues: League[],
sponsors: DemoSponsorDTO[],
): DemoSeasonSponsorshipDTO[] {
const sponsorships: DemoSeasonSponsorshipDTO[] = [];
const FANATEC_ID = sponsors.find((s) => s.id === 'sponsor-fanatec')?.id ?? 'sponsor-fanatec';
const HEUSINKVELD_ID =
sponsors.find((s) => s.id === 'sponsor-heusinkveld')?.id ?? 'sponsor-heusinkveld';
const SIMUCUBE_ID = sponsors.find((s) => s.id === 'sponsor-simucube')?.id ?? 'sponsor-simucube';
const TRAK_RACER_ID =
sponsors.find((s) => s.id === 'sponsor-trak-racer')?.id ?? 'sponsor-trak-racer';
const SIMLAB_ID = sponsors.find((s) => s.id === 'sponsor-simlab')?.id ?? 'sponsor-simlab';
const MOTIONRIG_ID =
sponsors.find((s) => s.id === 'sponsor-motionrig')?.id ?? 'sponsor-motionrig';
// GridPilot Sprint Series - sponsored by Fanatec (main) + Heusinkveld & Simucube (secondary)
const sprintLeague = leagues.find((l) => l.name === 'GridPilot Sprint Series');
if (sprintLeague) {
sponsorships.push({
id: `sponsorship-${sprintLeague.id}-fanatec`,
seasonId: `season-${sprintLeague.id}-demo`,
sponsorId: FANATEC_ID,
tier: 'main',
pricingAmount: 5000,
pricingCurrency: 'USD',
status: 'active',
description: 'Main sponsor for the Sprint Series - premium wheel branding',
});
sponsorships.push({
id: `sponsorship-${sprintLeague.id}-heusinkveld`,
seasonId: `season-${sprintLeague.id}-demo`,
sponsorId: HEUSINKVELD_ID,
tier: 'secondary',
pricingAmount: 2000,
pricingCurrency: 'USD',
status: 'active',
});
sponsorships.push({
id: `sponsorship-${sprintLeague.id}-simucube`,
seasonId: `season-${sprintLeague.id}-demo`,
sponsorId: SIMUCUBE_ID,
tier: 'secondary',
pricingAmount: 2000,
pricingCurrency: 'USD',
status: 'active',
});
}
// GridPilot Endurance Cup - sponsored by Trak Racer (main) + Sim-Lab (secondary)
const enduranceLeague = leagues.find((l) => l.name === 'GridPilot Endurance Cup');
if (enduranceLeague) {
sponsorships.push({
id: `sponsorship-${enduranceLeague.id}-trakracer`,
seasonId: `season-${enduranceLeague.id}-demo`,
sponsorId: TRAK_RACER_ID,
tier: 'main',
pricingAmount: 7500,
pricingCurrency: 'USD',
status: 'active',
description: 'Endurance series naming rights',
});
sponsorships.push({
id: `sponsorship-${enduranceLeague.id}-simlab`,
seasonId: `season-${enduranceLeague.id}-demo`,
sponsorId: SIMLAB_ID,
tier: 'secondary',
pricingAmount: 3000,
pricingCurrency: 'USD',
status: 'active',
});
}
// GridPilot Club Ladder - sponsored by MotionRig Pro (main)
const clubLeague = leagues.find((l) => l.name === 'GridPilot Club Ladder');
if (clubLeague) {
sponsorships.push({
id: `sponsorship-${clubLeague.id}-motionrig`,
seasonId: `season-${clubLeague.id}-demo`,
sponsorId: MOTIONRIG_ID,
tier: 'main',
pricingAmount: 3500,
pricingCurrency: 'USD',
status: 'active',
description: 'Club ladder motion platform showcase',
});
}
return sponsorships;
}
/**
* Create sponsorship pricing configurations for demo entities.
* Uses the SponsorshipPricing value object to ensure domain consistency
* and to provide a mix of season, team, driver and race offerings.
*/
export function createSponsorshipPricings(
leagues: League[],
teams: DemoTeamDTO[],
drivers: Driver[],
races: Race[],
): DemoSponsorshipPricingDTO[] {
const pricings: DemoSponsorshipPricingDTO[] = [];
// League/Season pricing - all leagues can accept sponsorships, with varied configs
leagues.forEach((league, index) => {
let pricing = SponsorshipPricing.defaultLeague();
// Vary league pricing/availability for demo richness
if (index % 3 === 1) {
// Some leagues closed for applications
pricing = pricing.setAcceptingApplications(false);
} else if (index % 3 === 2) {
// Some leagues with main-only sponsorship
pricing = pricing.updateSecondarySlot({ available: false, maxSlots: 0 });
} else {
// Slightly higher price for featured leagues
pricing = pricing.updateMainSlot({
price: Money.create(1000 + index * 50, 'USD'),
});
}
pricings.push({
entityType: 'season',
entityId: `season-${league.id}-demo`,
pricing,
});
});
// Team pricing - first 10 teams accept sponsorships using team defaults,
// with some teams pausing applications.
teams.slice(0, 10).forEach((team, index) => {
let pricing = SponsorshipPricing.defaultTeam();
if (index % 4 === 1) {
// Teams with main + secondary but not currently accepting
pricing = pricing.setAcceptingApplications(false);
} else if (index % 4 === 2) {
// Teams with only secondary slots
pricing = pricing.updateMainSlot({ available: false, maxSlots: 0 });
} else if (index % 4 === 3) {
// Teams with premium main slot pricing
pricing = pricing.updateMainSlot({
price: Money.create(750 + index * 25, 'USD'),
});
}
pricings.push({
entityType: 'team',
entityId: team.id,
pricing,
});
});
// Driver pricing - first 20 drivers accept sponsorships with varied availability.
drivers.slice(0, 20).forEach((driver, index) => {
let pricing = SponsorshipPricing.defaultDriver();
if (index % 3 === 0) {
// Higher profile drivers
pricing = pricing.updateMainSlot({
price: Money.create(250 + index * 10, 'USD'),
});
} else if (index % 3 === 1) {
// Drivers temporarily not accepting sponsorships
pricing = pricing.setAcceptingApplications(false);
}
pricings.push({
entityType: 'driver',
entityId: driver.id,
pricing,
});
});
// Race pricing - upcoming races can have title sponsors with different tiers
const upcomingRaces = races.filter((r) => r.status === 'scheduled').slice(0, 10);
upcomingRaces.forEach((race, index) => {
let pricing = SponsorshipPricing.defaultRace();
if (index % 2 === 0) {
// Premium events with higher pricing
pricing = pricing.updateMainSlot({
price: Money.create(350 + index * 30, 'USD'),
});
}
pricings.push({
entityType: 'race',
entityId: race.id,
pricing,
});
});
return pricings;
}
/**
* Create demo sponsorship requests (some pending, some accepted/rejected).
* Uses the SponsorshipRequest domain entity and Money value object so that
* all downstream sponsor flows can rely on domain behavior.
*/
export function createSponsorshipRequests(
sponsors: DemoSponsorDTO[],
leagues: League[],
teams: DemoTeamDTO[],
drivers: Driver[],
races: Race[],
): DemoSponsorshipRequestDTO[] {
const requests: DemoSponsorshipRequestDTO[] = [];
const now = new Date();
const SIMUCUBE_ID = sponsors.find((s) => s.id === 'sponsor-simucube')?.id ?? 'sponsor-simucube';
const HEUSINKVELD_ID =
sponsors.find((s) => s.id === 'sponsor-heusinkveld')?.id ?? 'sponsor-heusinkveld';
const TRAK_RACER_ID =
sponsors.find((s) => s.id === 'sponsor-trak-racer')?.id ?? 'sponsor-trak-racer';
const MOTIONRIG_ID =
sponsors.find((s) => s.id === 'sponsor-motionrig')?.id ?? 'sponsor-motionrig';
const SIMLAB_ID = sponsors.find((s) => s.id === 'sponsor-simlab')?.id ?? 'sponsor-simlab';
// Pending request: Simucube wants to sponsor a driver
if (drivers.length > 6) {
const targetDriver = drivers[5];
if (targetDriver) {
requests.push(
SponsorshipRequest.create({
id: 'req-simucube-driver-1',
sponsorId: SIMUCUBE_ID,
entityType: 'driver',
entityId: targetDriver.id,
tier: 'main',
offeredAmount: Money.create(250, 'USD'),
message:
'We would love to sponsor your racing career! Simucube offers the best direct drive wheels in sim racing.',
createdAt: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000), // 2 days ago
}),
);
}
}
// Pending request: Heusinkveld wants to sponsor a team
if (teams.length > 3) {
const targetTeam = teams[2];
if (targetTeam) {
requests.push(
SponsorshipRequest.create({
id: 'req-heusinkveld-team-1',
sponsorId: HEUSINKVELD_ID,
entityType: 'team',
entityId: targetTeam.id,
tier: 'main',
offeredAmount: Money.create(550, 'USD'),
message:
'Heusinkveld pedals are known for their precision. We believe your team embodies the same values.',
createdAt: new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000), // 3 days ago
}),
);
}
}
// Pending request: Trak Racer wants to sponsor a race
const upcomingRace = races.find((r) => r.status === 'scheduled');
if (upcomingRace) {
requests.push(
SponsorshipRequest.create({
id: 'req-trakracer-race-1',
sponsorId: TRAK_RACER_ID,
entityType: 'race',
entityId: upcomingRace.id,
tier: 'main',
offeredAmount: Money.create(350, 'USD'),
message: 'We would like to be the title sponsor for this exciting race event!',
createdAt: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
}),
);
}
// Pending request: MotionRig Pro wants secondary spot on a league season
const clubLeague = leagues.find((l) => l.name === 'Sprint Challenge League');
if (clubLeague) {
requests.push(
SponsorshipRequest.create({
id: 'req-motionrig-league-1',
sponsorId: MOTIONRIG_ID,
entityType: 'season',
entityId: `season-${clubLeague.id}-demo`,
tier: 'secondary',
offeredAmount: Money.create(1500, 'USD'),
message:
'MotionRig Pro would love to be a secondary sponsor. Our motion platforms are perfect for your competitive drivers.',
createdAt: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000), // 5 days ago
}),
);
}
// Already accepted request (for history)
if (teams.length > 0) {
const acceptedTeam = teams[0];
if (acceptedTeam) {
requests.push(
SponsorshipRequest.create({
id: 'req-simlab-team-accepted',
sponsorId: SIMLAB_ID,
entityType: 'team',
entityId: acceptedTeam.id,
tier: 'secondary',
offeredAmount: Money.create(300, 'USD'),
message: 'Sim-Lab rigs are the foundation of any competitive setup.',
status: 'accepted',
createdAt: new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000), // 30 days ago
}),
);
}
}
// Already rejected request (for history)
if (drivers.length > 10) {
const rejectedDriver = drivers[10];
if (rejectedDriver) {
requests.push(
SponsorshipRequest.create({
id: 'req-motionrig-driver-rejected',
sponsorId: MOTIONRIG_ID,
entityType: 'driver',
entityId: rejectedDriver.id,
tier: 'main',
offeredAmount: Money.create(150, 'USD'),
message: 'Would you like to represent MotionRig Pro?',
status: 'rejected',
createdAt: new Date(now.getTime() - 20 * 24 * 60 * 60 * 1000), // 20 days ago
}),
);
}
}
return requests;
}