Add simplified Open Practice flow and reorganize

This commit is contained in:
larssand
2026-08-24 19:25:21 +02:00
parent 5a6e51c51b
commit 2e6866a013
13 changed files with 481 additions and 55 deletions

View File

@@ -150,6 +150,7 @@ export function applyRaceFormatPreset(event, presetId, { getRaceFormatPresets })
return;
}
Object.assign(event.raceConfig, preset.values, { presetId: preset.id });
event.raceConfig.practiceOnly = false;
}
@@ -187,6 +188,7 @@ export function buildRaceFormatConfigFromForm(form, event, { normalizeStartMode,
participantsConfigured: event.raceConfig.participantsConfigured !== false,
finalsSource: String(form.get("finalsSource") || "qualifying") === "practice" ? "practice" : "qualifying",
teams: getEventTeams(event),
practiceOnly: event.raceConfig.practiceOnly === true,
};
}
@@ -228,6 +230,7 @@ export function normalizeEvent(event, { normalizeBrandingConfig, normalizeStartM
participantsConfigured: Boolean(event?.raceConfig?.participantsConfigured),
finalsSource: event?.raceConfig?.finalsSource === "practice" ? "practice" : "qualifying",
teams: Array.isArray(event?.raceConfig?.teams) ? event.raceConfig.teams.map((team) => normalizeRaceTeam(team)).filter((team) => team.name) : [],
practiceOnly: event?.raceConfig?.practiceOnly === true,
},
};
}
@@ -264,6 +267,7 @@ export function resolveEventBranding(event, { normalizeBrandingConfig, state })
export function getRaceManageStatuses(event, sessions, raceDrivers, raceTeams, selectedPreset, { t, buildPracticeStandings, buildQualifyingStandings, buildFinalStandings }) {
const cfg = event.raceConfig || {};
const isPracticeOnly = cfg.practiceOnly === true;
const participantCount = cfg.participantsConfigured ? (cfg.driverIds || []).length : raceDrivers.length;
const isEndurancePreset = selectedPreset?.id === "endurance";
const practiceCount = sessions.filter((session) => ["practice", "free_practice", "open_practice"].includes(session.type)).length;
@@ -280,6 +284,28 @@ export function getRaceManageStatuses(event, sessions, raceDrivers, raceTeams, s
const lapWindowValid = Math.max(0, Number(cfg.maxLapMs || 0) || 0) > Math.max(0, Number(cfg.minLapMs || 0) || 0);
const resultSourceCount = [practiceRows, qualifyingRows, finalRows].filter((rows) => rows.length > 0).length;
if (isPracticeOnly) {
const openPracticeCount = sessions.filter((session) => session.type === "open_practice").length;
return {
setup: {
status: openPracticeCount > 0 ? "complete" : "pending",
detail: t("events.open_practice_all_transponders"),
},
format: {
status: "complete",
detail: t("events.open_practice_untimed"),
},
generation: {
status: openPracticeCount > 0 ? "complete" : "pending",
detail: `${openPracticeCount} ${t("events.detail_sessions")}`,
},
live: {
status: startedCount > 0 || resultSourceCount > 0 ? "complete" : "pending",
detail: `${startedCount} ${t("events.detail_active")} · ${resultSourceCount} ${t("events.detail_results")}`,
},
};
}
const setupStatus = participantCount > 0 && (!isEndurancePreset || raceTeams.length > 0)
? "complete"
: participantCount > 0 || raceTeams.length > 0
@@ -395,6 +421,31 @@ export function buildRaceSession(eventId, name, type, durationMin, overrides = {
});
}
export function buildOpenPracticeBundle(input = {}, { normalizeEvent, buildRaceSession, uid }) {
const name = String(input.name || "Open Practice").trim() || "Open Practice";
const event = normalizeEvent({
id: uid("event"),
name,
date: String(input.date || new Date().toISOString().slice(0, 10)),
classId: "",
mode: "race",
});
event.raceConfig = {
...event.raceConfig,
presetId: "custom",
practiceOnly: true,
driverIds: [],
participantsConfigured: false,
teams: [],
};
const session = buildRaceSession(event.id, name, "open_practice", 1, {
driverIds: [],
startMode: "mass",
followUpSec: 0,
});
return { event, session };
}
export function buildTrackSession(eventId, name, type, durationMin, { normalizeSession, uid }) {
return normalizeSession({
id: uid("session"),