refactor to adapters
This commit is contained in:
451
testing/fixtures/racing/RacingSponsorshipSeed.ts
Normal file
451
testing/fixtures/racing/RacingSponsorshipSeed.ts
Normal file
@@ -0,0 +1,451 @@
|
||||
import { League } from '@gridpilot/racing/domain/entities/League';
|
||||
import { Race } from '@gridpilot/racing/domain/entities/Race';
|
||||
import { Driver } from '@gridpilot/racing/domain/entities/Driver';
|
||||
import { Money } from '@gridpilot/racing/domain/value-objects/Money';
|
||||
import { SponsorshipPricing } from '@gridpilot/racing/domain/value-objects/SponsorshipPricing';
|
||||
import {
|
||||
SponsorshipRequest,
|
||||
type SponsorableEntityType,
|
||||
} from '@gridpilot/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;
|
||||
}
|
||||
Reference in New Issue
Block a user