wip
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { SeasonScheduleGenerator } from '../../domain/services/SeasonScheduleGenerator';
|
||||
import type { LeagueSchedulePreviewDTO, LeagueScheduleDTO } from '../dto/LeagueScheduleDTO';
|
||||
import { scheduleDTOToSeasonSchedule } from '../dto/LeagueScheduleDTO';
|
||||
|
||||
interface PreviewLeagueScheduleQueryParams {
|
||||
schedule: LeagueScheduleDTO;
|
||||
maxRounds?: number;
|
||||
}
|
||||
|
||||
export class PreviewLeagueScheduleQuery {
|
||||
constructor(
|
||||
private readonly scheduleGenerator: typeof SeasonScheduleGenerator = SeasonScheduleGenerator,
|
||||
) {}
|
||||
|
||||
execute(params: PreviewLeagueScheduleQueryParams): LeagueSchedulePreviewDTO {
|
||||
const seasonSchedule = scheduleDTOToSeasonSchedule(params.schedule);
|
||||
|
||||
const maxRounds =
|
||||
params.maxRounds && params.maxRounds > 0
|
||||
? Math.min(params.maxRounds, seasonSchedule.plannedRounds)
|
||||
: seasonSchedule.plannedRounds;
|
||||
|
||||
const slots = this.scheduleGenerator.generateSlotsUpTo(seasonSchedule, maxRounds);
|
||||
|
||||
const rounds = slots.map((slot) => ({
|
||||
roundNumber: slot.roundNumber,
|
||||
scheduledAt: slot.scheduledAt.toISOString(),
|
||||
timezoneId: slot.timezone.getId(),
|
||||
}));
|
||||
|
||||
const summary = this.buildSummary(params.schedule, rounds);
|
||||
|
||||
return {
|
||||
rounds,
|
||||
summary,
|
||||
};
|
||||
}
|
||||
|
||||
private buildSummary(
|
||||
schedule: LeagueScheduleDTO,
|
||||
rounds: Array<{ roundNumber: number; scheduledAt: string; timezoneId: string }>,
|
||||
): string {
|
||||
if (rounds.length === 0) {
|
||||
return 'No rounds scheduled.';
|
||||
}
|
||||
|
||||
const first = new Date(rounds[0].scheduledAt);
|
||||
const last = new Date(rounds[rounds.length - 1].scheduledAt);
|
||||
|
||||
const firstDate = first.toISOString().slice(0, 10);
|
||||
const lastDate = last.toISOString().slice(0, 10);
|
||||
|
||||
const timePart = schedule.raceStartTime;
|
||||
const tz = schedule.timezoneId;
|
||||
|
||||
let recurrenceDescription: string;
|
||||
|
||||
if (schedule.recurrenceStrategy === 'weekly') {
|
||||
const days = (schedule.weekdays ?? []).join(', ');
|
||||
recurrenceDescription = `Every ${days}`;
|
||||
} else if (schedule.recurrenceStrategy === 'everyNWeeks') {
|
||||
const interval = schedule.intervalWeeks ?? 1;
|
||||
const days = (schedule.weekdays ?? []).join(', ');
|
||||
recurrenceDescription = `Every ${interval} week(s) on ${days}`;
|
||||
} else if (schedule.recurrenceStrategy === 'monthlyNthWeekday') {
|
||||
const ordinalLabel = this.ordinalToLabel(schedule.monthlyOrdinal ?? 1);
|
||||
const weekday = schedule.monthlyWeekday ?? 'Mon';
|
||||
recurrenceDescription = `Every ${ordinalLabel} ${weekday}`;
|
||||
} else {
|
||||
recurrenceDescription = 'Custom recurrence';
|
||||
}
|
||||
|
||||
return `${recurrenceDescription} at ${timePart} ${tz}, starting ${firstDate} — ${rounds.length} rounds from ${firstDate} to ${lastDate}.`;
|
||||
}
|
||||
|
||||
private ordinalToLabel(ordinal: 1 | 2 | 3 | 4): string {
|
||||
switch (ordinal) {
|
||||
case 1:
|
||||
return '1st';
|
||||
case 2:
|
||||
return '2nd';
|
||||
case 3:
|
||||
return '3rd';
|
||||
case 4:
|
||||
return '4th';
|
||||
default:
|
||||
return `${ordinal}th`;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user