move static data

This commit is contained in:
2025-12-26 00:20:53 +01:00
parent c977defd6a
commit b6cbb81388
63 changed files with 1482 additions and 418 deletions

View File

@@ -0,0 +1,29 @@
/**
* Activity Configuration
*
* UI display configuration for activity feed items
*/
export type ActivityType = 'race' | 'league' | 'team' | 'driver' | 'platform';
export interface ActivityConfigData {
color: string;
}
export const activityConfig: Record<ActivityType, ActivityConfigData> = {
race: {
color: 'bg-warning-amber',
},
league: {
color: 'bg-primary-blue',
},
team: {
color: 'bg-purple-400',
},
driver: {
color: 'bg-performance-green',
},
platform: {
color: 'bg-racing-red',
},
} as const;

View File

@@ -0,0 +1,19 @@
/**
* Incident Configuration
*
* UI display configuration for incident badges
*/
export interface IncidentConfigData {
color: string;
}
export const getIncidentBadgeColor = (incidents: number): string => {
if (incidents === 0) return 'green';
if (incidents <= 2) return 'yellow';
return 'red';
};
export const incidentConfig = {
getIncidentBadgeColor,
} as const;

View File

@@ -0,0 +1,31 @@
/**
* League Role Display Configuration
*
* UI display configuration for league membership roles
*/
export type LeagueRole = 'owner' | 'admin' | 'steward' | 'member';
export interface LeagueRoleDisplayData {
text: string;
badgeClasses: string;
}
export const leagueRoleDisplay: Record<LeagueRole, LeagueRoleDisplayData> = {
owner: {
text: 'Owner',
badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
},
admin: {
text: 'Admin',
badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',
},
steward: {
text: 'Steward',
badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',
},
member: {
text: 'Member',
badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',
},
} as const;

View File

@@ -12,6 +12,14 @@ export type LeagueScoringPresetPrimaryChampionshipType =
| 'nations'
| 'trophy';
export interface LeagueScoringPresetTimingDefaults {
practiceMinutes: number;
qualifyingMinutes: number;
sprintRaceMinutes: number;
mainRaceMinutes: number;
sessionCount: number;
}
export interface LeagueScoringPreset {
id: string;
name: string;
@@ -20,6 +28,7 @@ export interface LeagueScoringPreset {
dropPolicySummary: string;
sessionSummary: string;
bonusSummary: string;
defaultTimings: LeagueScoringPresetTimingDefaults;
createConfig: (options: { seasonId: string }) => LeagueScoringConfig;
}
@@ -82,6 +91,13 @@ export const leagueScoringPresets: LeagueScoringPreset[] = [
dropPolicySummary: 'Best 6 results of 8 count towards the championship.',
sessionSummary: 'Sprint + Main',
bonusSummary: 'Fastest lap +1 point in main race if finishing P10 or better.',
defaultTimings: {
practiceMinutes: 20,
qualifyingMinutes: 30,
sprintRaceMinutes: 20,
mainRaceMinutes: 40,
sessionCount: 2,
},
createConfig: ({ seasonId }) => {
const fastestLapBonus: BonusRule = {
id: 'fastest-lap-main',
@@ -146,6 +162,13 @@ export const leagueScoringPresets: LeagueScoringPreset[] = [
dropPolicySummary: 'All race results count, no drop scores.',
sessionSummary: 'Main race only',
bonusSummary: 'No bonus points.',
defaultTimings: {
practiceMinutes: 20,
qualifyingMinutes: 20,
sprintRaceMinutes: 0,
mainRaceMinutes: 40,
sessionCount: 1,
},
createConfig: ({ seasonId }) => {
const sessionTypes: SessionType[] = ['main'];
@@ -190,6 +213,13 @@ export const leagueScoringPresets: LeagueScoringPreset[] = [
dropPolicySummary: 'Best 4 results of 6 count towards the championship.',
sessionSummary: 'Main race only',
bonusSummary: 'No bonus points.',
defaultTimings: {
practiceMinutes: 30,
qualifyingMinutes: 20,
sprintRaceMinutes: 0,
mainRaceMinutes: 120,
sessionCount: 1,
},
createConfig: ({ seasonId }) => {
const sessionTypes: SessionType[] = ['main'];

View File

@@ -0,0 +1,35 @@
/**
* League Tier Configuration
*
* UI display configuration for league tiers
*/
export type LeagueTier = 'premium' | 'standard' | 'starter';
export interface LeagueTierConfigData {
color: string;
bgColor: string;
border: string;
icon: string;
}
export const leagueTierConfig: Record<LeagueTier, LeagueTierConfigData> = {
premium: {
color: 'text-yellow-400',
bgColor: 'bg-yellow-500/10',
border: 'border-yellow-500/30',
icon: '⭐',
},
standard: {
color: 'text-primary-blue',
bgColor: 'bg-primary-blue/10',
border: 'border-primary-blue/30',
icon: '🏆',
},
starter: {
color: 'text-gray-400',
bgColor: 'bg-gray-500/10',
border: 'border-gray-500/30',
icon: '🚀',
},
} as const;

View File

@@ -0,0 +1,16 @@
/**
* Penalty Configuration
*
* Business logic configuration for protest decisions and penalties
*/
export type PenaltyType = 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points';
export const penaltiesWithoutValue: PenaltyType[] = ['disqualification', 'warning'];
export const defaultProtestReason = 'Protest upheld';
export const penaltyConfig = {
penaltiesWithoutValue,
defaultProtestReason,
} as const;

View File

@@ -0,0 +1,46 @@
/**
* Race Status Configuration
*
* UI display configuration for race status states
*/
import { Clock, PlayCircle, CheckCircle2, XCircle } from 'lucide-react';
export interface RaceStatusConfigData {
icon: any;
color: string;
bg: string;
border: string;
label: string;
}
export const raceStatusConfig: Record<string, RaceStatusConfigData> = {
scheduled: {
icon: Clock,
color: 'text-primary-blue',
bg: 'bg-primary-blue/10',
border: 'border-primary-blue/30',
label: 'Scheduled',
},
running: {
icon: PlayCircle,
color: 'text-performance-green',
bg: 'bg-performance-green/10',
border: 'border-performance-green/30',
label: 'LIVE',
},
completed: {
icon: CheckCircle2,
color: 'text-gray-400',
bg: 'bg-gray-500/10',
border: 'border-gray-500/30',
label: 'Completed',
},
cancelled: {
icon: XCircle,
color: 'text-warning-amber',
bg: 'bg-warning-amber/10',
border: 'border-warning-amber/30',
label: 'Cancelled',
},
} as const;

View File

@@ -0,0 +1,29 @@
/**
* Renewal Alert Configuration
*
* UI display configuration for renewal alerts
*/
export type RenewalType = 'league' | 'team' | 'driver' | 'race' | 'platform';
export interface RenewalConfigData {
icon: string;
}
export const renewalConfig: Record<RenewalType, RenewalConfigData> = {
league: {
icon: 'Trophy',
},
team: {
icon: 'Users',
},
driver: {
icon: 'Car',
},
race: {
icon: 'Flag',
},
platform: {
icon: 'Megaphone',
},
} as const;

View File

@@ -0,0 +1,28 @@
/**
* Role Hierarchy Configuration
*
* Business logic configuration for league role ordering and permissions
*/
export type LeagueMembershipRole = 'owner' | 'admin' | 'steward' | 'member';
export const roleOrder: Record<LeagueMembershipRole, number> = {
owner: 0,
admin: 1,
steward: 2,
member: 3,
};
export const getRoleOrder = (role: LeagueMembershipRole): number => {
return roleOrder[role] ?? 99;
};
export const isLeagueAdminOrHigherRole = (role: LeagueMembershipRole): boolean => {
return role === 'owner' || role === 'admin' || role === 'steward';
};
export const roleHierarchy = {
roleOrder,
getRoleOrder,
isLeagueAdminOrHigherRole,
} as const;

View File

@@ -0,0 +1,31 @@
/**
* Season Status Configuration
*
* UI display configuration for season states
*/
export type SeasonStatus = 'active' | 'upcoming' | 'completed';
export interface SeasonStatusConfigData {
color: string;
bg: string;
label: string;
}
export const seasonStatusConfig: Record<SeasonStatus, SeasonStatusConfigData> = {
active: {
color: 'text-performance-green',
bg: 'bg-performance-green/10',
label: 'Active Season',
},
upcoming: {
color: 'text-warning-amber',
bg: 'bg-warning-amber/10',
label: 'Starting Soon',
},
completed: {
color: 'text-gray-400',
bg: 'bg-gray-400/10',
label: 'Season Ended',
},
} as const;

View File

@@ -0,0 +1,162 @@
/**
* Site Configuration
*
* Platform-wide configuration and settings
*/
export interface SiteConfigData {
// Platform Information
platformName: string;
platformUrl: string;
// Contact Information
supportEmail: string;
sponsorEmail: string;
// Legal & Business Information
legal: {
companyName: string;
vatId: string;
registeredCountry: string;
registeredAddress: string;
};
// Platform Fees
fees: {
platformFeePercent: number;
description: string;
};
// VAT Information
vat: {
euReverseChargeApplies: boolean;
nonEuVatExempt: boolean;
standardRate: number;
notice: string;
euBusinessNotice: string;
nonEuNotice: string;
};
// Sponsorship Types Available
sponsorshipTypes: {
leagues: {
enabled: boolean;
title: string;
description: string;
};
teams: {
enabled: boolean;
title: string;
description: string;
};
drivers: {
enabled: boolean;
title: string;
description: string;
};
races: {
enabled: boolean;
title: string;
description: string;
};
platform: {
enabled: boolean;
title: string;
description: string;
};
};
// Feature Flags for Sponsorship Features
features: {
liveryPlacement: boolean;
leaguePageBranding: boolean;
racePageBranding: boolean;
profileBadges: boolean;
socialMediaMentions: boolean;
newsletterInclusion: boolean;
homepageAds: boolean;
sidebarAds: boolean;
broadcastOverlays: boolean;
};
}
export const siteConfig: SiteConfigData = {
// Platform Information
platformName: process.env.NEXT_PUBLIC_SITE_NAME ?? 'GridPilot',
platformUrl: process.env.NEXT_PUBLIC_SITE_URL ?? 'https://gridpilot.com',
// Contact Information
supportEmail: process.env.NEXT_PUBLIC_SUPPORT_EMAIL ?? 'support@example.com',
sponsorEmail: process.env.NEXT_PUBLIC_SPONSOR_EMAIL ?? 'sponsors@example.com',
// Legal & Business Information
legal: {
companyName: process.env.NEXT_PUBLIC_LEGAL_COMPANY_NAME ?? '',
vatId: process.env.NEXT_PUBLIC_LEGAL_VAT_ID ?? '',
registeredCountry: process.env.NEXT_PUBLIC_LEGAL_REGISTERED_COUNTRY ?? '',
registeredAddress: process.env.NEXT_PUBLIC_LEGAL_REGISTERED_ADDRESS ?? '',
},
// Platform Fees
fees: {
platformFeePercent: 10, // 10% platform fee on sponsorships
description: 'Platform fee supports maintenance, analytics, and secure payment processing.',
},
// VAT Information
vat: {
// Note: All prices displayed are exclusive of VAT
euReverseChargeApplies: true,
nonEuVatExempt: true,
standardRate: 20,
notice: 'All prices shown are exclusive of VAT. Applicable taxes will be calculated at checkout.',
euBusinessNotice: 'EU businesses with a valid VAT ID may apply reverse charge.',
nonEuNotice: 'Non-EU businesses are not charged VAT.',
},
// Sponsorship Types Available
sponsorshipTypes: {
leagues: {
enabled: true,
title: 'League Sponsorship',
description: 'Sponsor entire racing leagues and get your brand in front of all participants.',
},
teams: {
enabled: true,
title: 'Team Sponsorship',
description: 'Partner with competitive racing teams for long-term brand association.',
},
drivers: {
enabled: true,
title: 'Driver Sponsorship',
description: 'Support individual drivers and grow with rising sim racing talent.',
},
races: {
enabled: true,
title: 'Race Sponsorship',
description: 'Sponsor individual race events for targeted, high-impact exposure.',
},
platform: {
enabled: true,
title: 'Platform Advertising',
description: 'Reach the entire GridPilot audience with strategic platform placements.',
},
},
// Feature Flags for Sponsorship Features
features: {
// What sponsors can actually get (no broadcast control)
liveryPlacement: true,
leaguePageBranding: true,
racePageBranding: true,
profileBadges: true,
socialMediaMentions: true,
newsletterInclusion: true,
homepageAds: true,
sidebarAds: true,
// We don't control these
broadcastOverlays: false, // We don't control broadcast
},
} as const;
export type SiteConfig = typeof siteConfig;

View File

@@ -0,0 +1,31 @@
/**
* Skill Level Configuration
*
* UI display configuration for driver skill levels
*/
export type SkillLevel = 'beginner' | 'intermediate' | 'advanced' | 'expert';
export interface SkillLevelConfigData {
color: string;
icon: string;
}
export const skillLevelConfig: Record<SkillLevel, SkillLevelConfigData> = {
beginner: {
color: 'green',
icon: '🥉',
},
intermediate: {
color: 'yellow',
icon: '🥈',
},
advanced: {
color: 'orange',
icon: '🥇',
},
expert: {
color: 'red',
icon: '👑',
},
} as const;

View File

@@ -0,0 +1,52 @@
/**
* Sponsorship Configuration
*
* UI display configuration for sponsorship types and statuses
*/
export type SponsorshipType = 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
export type SponsorshipStatus = 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
export interface SponsorshipTypeConfigData {
label: string;
}
export interface SponsorshipStatusConfigData {
label: string;
}
export const sponsorshipTypeConfig: Record<SponsorshipType, SponsorshipTypeConfigData> = {
leagues: {
label: 'League',
},
teams: {
label: 'Team',
},
drivers: {
label: 'Driver',
},
races: {
label: 'Race',
},
platform: {
label: 'Platform',
},
} as const;
export const sponsorshipStatusConfig: Record<SponsorshipStatus, SponsorshipStatusConfigData> = {
active: {
label: 'Active',
},
pending_approval: {
label: 'Awaiting Approval',
},
approved: {
label: 'Approved',
},
rejected: {
label: 'Declined',
},
expired: {
label: 'Expired',
},
} as const;

View File

@@ -0,0 +1,53 @@
/**
* Timing Configuration
*
* Business logic configuration for scoring preset timings
*/
export interface Timings {
practiceMinutes?: number;
qualifyingMinutes?: number;
sprintRaceMinutes?: number;
mainRaceMinutes?: number;
sessionCount?: number;
[key: string]: unknown;
}
export interface TimingConfigData {
practiceMinutes: number;
qualifyingMinutes: number;
sprintRaceMinutes: number;
mainRaceMinutes: number;
sessionCount: number;
}
export const timingConfig: Record<string, TimingConfigData> = {
'sprint-main-driver': {
practiceMinutes: 20,
qualifyingMinutes: 30,
sprintRaceMinutes: 20,
mainRaceMinutes: 40,
sessionCount: 2,
},
'endurance-main-driver': {
practiceMinutes: 30,
qualifyingMinutes: 20,
sprintRaceMinutes: 0,
mainRaceMinutes: 120,
sessionCount: 1,
},
} as const;
export const applyTimingConfig = (patternId: string, currentTimings: Timings): Timings => {
const config = timingConfig[patternId];
if (!config) return currentTimings;
return {
...currentTimings,
practiceMinutes: currentTimings.practiceMinutes ?? config.practiceMinutes,
qualifyingMinutes: currentTimings.qualifyingMinutes ?? config.qualifyingMinutes,
sprintRaceMinutes: currentTimings.sprintRaceMinutes ?? config.sprintRaceMinutes,
mainRaceMinutes: currentTimings.mainRaceMinutes ?? config.mainRaceMinutes,
sessionCount: config.sessionCount,
};
};

View File

@@ -2,4 +2,19 @@ export * from './EnsureInitialData';
export * from './LeagueConstraints';
export * from './LeagueScoringPresets';
export * from './PointsSystems';
export * from './ScoringDemoSetup';
export * from './ScoringDemoSetup';
// New configuration exports
export * from './SiteConfig';
export * from './RaceStatusConfig';
export * from './LeagueRoleDisplay';
export * from './ActivityConfig';
export * from './RenewalConfig';
export * from './LeagueTierConfig';
export * from './SeasonStatusConfig';
export * from './SponsorshipConfig';
export * from './SkillLevelConfig';
export * from './IncidentConfig';
export * from './PenaltyConfig';
export * from './RoleHierarchy';
export * from './TimingConfig';