146 lines
4.5 KiB
TypeScript
146 lines
4.5 KiB
TypeScript
import type { LeagueVisibilityType } from '../../domain/value-objects/LeagueVisibility';
|
|
import type { StewardingDecisionMode } from '../../domain/entities/League';
|
|
|
|
export type LeagueStructureMode = 'solo' | 'fixedTeams';
|
|
|
|
/**
|
|
* League visibility determines public visibility and ranking status.
|
|
* - 'ranked': Public, competitive, affects driver ratings. Requires min 10 drivers.
|
|
* - 'unranked': Private, casual with friends. No rating impact. Any number of drivers.
|
|
*
|
|
* For backward compatibility, 'public'/'private' are also supported in the form,
|
|
* but the domain uses 'ranked'/'unranked'.
|
|
*/
|
|
export type LeagueVisibilityFormValue = LeagueVisibilityType | 'public' | 'private';
|
|
|
|
export interface LeagueStructureFormDTO {
|
|
mode: LeagueStructureMode;
|
|
maxDrivers: number;
|
|
maxTeams?: number;
|
|
driversPerTeam?: number;
|
|
multiClassEnabled?: boolean;
|
|
}
|
|
|
|
export interface LeagueChampionshipsFormDTO {
|
|
enableDriverChampionship: boolean;
|
|
enableTeamChampionship: boolean;
|
|
enableNationsChampionship: boolean;
|
|
enableTrophyChampionship: boolean;
|
|
}
|
|
|
|
export interface LeagueScoringFormDTO {
|
|
patternId?: string; // e.g. 'sprint-main-driver', 'club-ladder-solo'
|
|
// For now, keep customScoring optional and simple:
|
|
customScoringEnabled?: boolean;
|
|
}
|
|
|
|
export interface LeagueDropPolicyFormDTO {
|
|
strategy: 'none' | 'bestNResults' | 'dropWorstN';
|
|
n?: number;
|
|
}
|
|
|
|
export interface LeagueTimingsFormDTO {
|
|
practiceMinutes?: number;
|
|
qualifyingMinutes: number;
|
|
sprintRaceMinutes?: number;
|
|
mainRaceMinutes: number;
|
|
sessionCount: number;
|
|
roundsPlanned?: number;
|
|
|
|
seasonStartDate?: string; // ISO date YYYY-MM-DD
|
|
seasonEndDate?: string; // ISO date YYYY-MM-DD
|
|
raceStartTime?: string; // "HH:MM" 24h
|
|
timezoneId?: string; // IANA ID, e.g. "Europe/Berlin", or "track" for track local time
|
|
recurrenceStrategy?: 'weekly' | 'everyNWeeks' | 'monthlyNthWeekday';
|
|
intervalWeeks?: number;
|
|
weekdays?: import('../../domain/types/Weekday').Weekday[];
|
|
monthlyOrdinal?: 1 | 2 | 3 | 4;
|
|
monthlyWeekday?: import('../../domain/types/Weekday').Weekday;
|
|
}
|
|
|
|
/**
|
|
* Stewarding configuration for protests and penalties.
|
|
*/
|
|
export interface LeagueStewardingFormDTO {
|
|
/**
|
|
* How protest decisions are made
|
|
*/
|
|
decisionMode: StewardingDecisionMode;
|
|
/**
|
|
* Number of votes required to uphold/reject a protest
|
|
* Used with steward_vote, member_vote, steward_veto, member_veto modes
|
|
*/
|
|
requiredVotes?: number;
|
|
/**
|
|
* Whether to require a defense from the accused before deciding
|
|
*/
|
|
requireDefense: boolean;
|
|
/**
|
|
* Time limit (hours) for accused to submit defense
|
|
*/
|
|
defenseTimeLimit: number;
|
|
/**
|
|
* Time limit (hours) for voting to complete
|
|
*/
|
|
voteTimeLimit: number;
|
|
/**
|
|
* Time limit (hours) after race ends when protests can be filed
|
|
*/
|
|
protestDeadlineHours: number;
|
|
/**
|
|
* Time limit (hours) after race ends when stewarding is closed
|
|
*/
|
|
stewardingClosesHours: number;
|
|
/**
|
|
* Whether to notify the accused when a protest is filed
|
|
*/
|
|
notifyAccusedOnProtest: boolean;
|
|
/**
|
|
* Whether to notify eligible voters when a vote is required
|
|
*/
|
|
notifyOnVoteRequired: boolean;
|
|
}
|
|
|
|
export interface LeagueConfigFormModel {
|
|
leagueId?: string; // present for admin, omitted for create
|
|
basics: {
|
|
name: string;
|
|
description?: string;
|
|
/**
|
|
* League visibility/ranking mode.
|
|
* - 'ranked' (or legacy 'public'): Competitive, public, affects ratings. Min 10 drivers.
|
|
* - 'unranked' (or legacy 'private'): Casual with friends, no rating impact.
|
|
*/
|
|
visibility: LeagueVisibilityFormValue;
|
|
gameId: string;
|
|
/**
|
|
* League logo as base64 data URL (optional).
|
|
* Format: data:image/png;base64,... or data:image/jpeg;base64,...
|
|
*/
|
|
logoDataUrl?: string;
|
|
};
|
|
structure: LeagueStructureFormDTO;
|
|
championships: LeagueChampionshipsFormDTO;
|
|
scoring: LeagueScoringFormDTO;
|
|
dropPolicy: LeagueDropPolicyFormDTO;
|
|
timings: LeagueTimingsFormDTO;
|
|
stewarding: LeagueStewardingFormDTO;
|
|
}
|
|
|
|
/**
|
|
* Helper to normalize visibility values to new terminology.
|
|
* Maps 'public' -> 'ranked' and 'private' -> 'unranked'.
|
|
*/
|
|
export function normalizeVisibility(value: LeagueVisibilityFormValue): LeagueVisibilityType {
|
|
if (value === 'public' || value === 'ranked') return 'ranked';
|
|
return 'unranked';
|
|
}
|
|
|
|
/**
|
|
* Helper to convert new terminology to legacy for backward compatibility.
|
|
* Maps 'ranked' -> 'public' and 'unranked' -> 'private'.
|
|
*/
|
|
export function toLegacyVisibility(value: LeagueVisibilityFormValue): 'public' | 'private' {
|
|
if (value === 'ranked' || value === 'public') return 'public';
|
|
return 'private';
|
|
} |