fix event

This commit is contained in:
larssand
2026-03-25 19:23:29 +01:00
parent 563ef66c16
commit a550346094
2 changed files with 173 additions and 40 deletions

View File

@@ -13,6 +13,10 @@ const NAV_ITEMS = [
];
const SESSION_TYPES = ["open_practice", "free_practice", "practice", "qualification", "heat", "final", "team_race"];
function getSessionTypeChoices(mode) {
return mode === "track" ? SESSION_TYPES.filter((type) => type !== "team_race") : SESSION_TYPES;
}
const STORAGE_KEY = "rc_timing_control_v1";
const DEFAULT_LANGUAGE = "sv";
const DEFAULT_THEME = "dark";
@@ -385,6 +389,24 @@ const TRANSLATIONS = {
"events.print_team_results": "Skriv ut lagrapport",
"events.pdf_team_results": "PDF lagrapport",
"events.add_session": "Lägg till session",
"events.session_type_label": "Sessionstyp",
"events.session_type_hint_track": "Välj vilken del av sponsor-eventet du skapar: träning, kval, heat eller final. Eventet i sig är redan ett sponsor-event.",
"events.session_type_hint_race": "Välj vilken session i racet du skapar: träning, kval, heat, final eller lagrace.",
"events.session_duration_label": "Längd (min)",
"events.session_duration_hint": "Ordinarie körtid för sessionen i minuter.",
"events.session_followup_label": "Follow-up (sek)",
"events.session_followup_hint": "Extra tid efter ordinarie sluttid så sista bilarna kan fullfölja.",
"events.session_start_mode_label": "Starttyp",
"events.session_start_mode_hint": "Mass-start, positionsstart eller individuell staggered start.",
"events.session_seed_laps_label": "Seedning bästa varv",
"events.session_seed_laps_hint": "0 = av. Använd 2 eller 3 för practice/kval-seedning.",
"events.session_seed_method_label": "Seedmetod",
"events.session_seed_method_hint": "Hur de bästa varven ska räknas: summa, snitt eller följdvarv.",
"events.session_stagger_gap_label": "Stagger-gap (sek)",
"events.session_stagger_gap_hint": "Används bara för staggered start. 0 = ingen extra lucka.",
"events.session_max_cars_label": "Max bilar (valfritt)",
"events.session_max_cars_hint": "Sätt gräns om just den sessionen bara ska ha ett visst antal bilar.",
"events.edit_session_help": "Ändra sessionens namn, typ, tid och seed-/startinställningar här.",
"events.set_active": "Sätt aktiv",
"events.assignments": "Tilldelningar",
"events.na": "ej relevant",
@@ -1174,6 +1196,24 @@ const TRANSLATIONS = {
"events.print_team_results": "Print team report",
"events.pdf_team_results": "PDF team report",
"events.add_session": "Add Session",
"events.session_type_label": "Session type",
"events.session_type_hint_track": "Choose which part of the sponsor event you are creating: practice, qualifying, heat or final. The event itself is already a sponsor event.",
"events.session_type_hint_race": "Choose which race session you are creating: practice, qualifying, heat, final or team race.",
"events.session_duration_label": "Duration (min)",
"events.session_duration_hint": "Main running time for the session in minutes.",
"events.session_followup_label": "Follow-up (sec)",
"events.session_followup_hint": "Extra time after the main timer so the last cars can finish.",
"events.session_start_mode_label": "Start mode",
"events.session_start_mode_hint": "Mass start, position start or individual staggered start.",
"events.session_seed_laps_label": "Seed best laps",
"events.session_seed_laps_hint": "0 = off. Use 2 or 3 for practice/qualifying seeding.",
"events.session_seed_method_label": "Seed method",
"events.session_seed_method_hint": "How to count the best laps: sum, average or consecutive laps.",
"events.session_stagger_gap_label": "Stagger gap (sec)",
"events.session_stagger_gap_hint": "Only used for staggered starts. 0 = no extra gap.",
"events.session_max_cars_label": "Max cars (optional)",
"events.session_max_cars_hint": "Set a limit if this session should only allow a certain number of cars.",
"events.edit_session_help": "Edit the session name, type, timing and seed/start settings here.",
"events.set_active": "Set Active",
"events.assignments": "Assignments",
"events.na": "n/a",
@@ -4300,6 +4340,8 @@ function renderEventManager(eventId) {
.join("");
const branding = normalizeBrandingConfig(event.branding);
const editingSession = sessions.find((session) => session.id === selectedSessionEditId) || null;
const sessionTypeChoices = getSessionTypeChoices(event.mode);
const sessionTypeHintKey = event.mode === "track" ? "events.session_type_hint_track" : "events.session_type_hint_race";
const racePresets = getRaceFormatPresets();
const selectedPreset = racePresets.find((preset) => preset.id === event.raceConfig.presetId) || racePresets[0];
const isEndurancePreset = event.mode === "race" && selectedPreset?.id === "endurance";
@@ -4326,26 +4368,63 @@ function renderEventManager(eventId) {
</div>
<div class="panel-body">
<form id="sessionForm" class="form-grid cols-5">
<input required name="name" placeholder="${t("events.session_name")}" />
<select name="type">
${SESSION_TYPES.map((s) => `<option value="${s}">${getSessionTypeLabel(s)}</option>`).join("")}
</select>
<input required type="number" min="1" name="durationMin" placeholder="${t("events.duration_placeholder")}" />
<input type="number" min="0" step="1" name="followUpSec" placeholder="${t("events.follow_up_sec")}" value="${event.mode === "race" ? event.raceConfig.followUpSec || 0 : 0}" />
<select name="startMode">
<option value="mass">${t("events.start_mode_mass")}</option>
<option value="position">${t("events.start_mode_position")}</option>
<option value="staggered">${t("events.start_mode_staggered")}</option>
</select>
<input type="number" min="0" name="seedBestLapCount" placeholder="${t("events.seed_best_laps")}" />
<select name="seedMethod">
<option value="best_sum">${t("events.seed_method_best_sum")}</option>
<option value="average">${t("events.seed_method_average")}</option>
<option value="consecutive">${t("events.seed_method_consecutive")}</option>
</select>
<input type="number" min="0" step="1" name="staggerGapSec" placeholder="${t("events.stagger_gap_sec")}" />
<input type="number" min="1" name="maxCars" placeholder="${t("events.max_cars_placeholder")}" />
<button class="btn btn-primary" type="submit">${t("events.add_session")}</button>
<label>
${t("events.session_name")}
<input required name="name" placeholder="${t("events.session_name")}" />
</label>
<label>
${t("events.session_type_label")}
<select name="type">
${sessionTypeChoices.map((s) => `<option value="${s}">${getSessionTypeLabel(s)}</option>`).join("")}
</select>
<small>${t(sessionTypeHintKey)}</small>
</label>
<label>
${t("events.session_duration_label")}
<input required type="number" min="1" name="durationMin" placeholder="${t("events.duration_placeholder")}" />
<small>${t("events.session_duration_hint")}</small>
</label>
<label>
${t("events.session_followup_label")}
<input type="number" min="0" step="1" name="followUpSec" placeholder="${t("events.follow_up_sec")}" value="${event.mode === "race" ? event.raceConfig.followUpSec || 0 : 0}" />
<small>${t("events.session_followup_hint")}</small>
</label>
<label>
${t("events.session_start_mode_label")}
<select name="startMode">
<option value="mass">${t("events.start_mode_mass")}</option>
<option value="position">${t("events.start_mode_position")}</option>
<option value="staggered">${t("events.start_mode_staggered")}</option>
</select>
<small>${t("events.session_start_mode_hint")}</small>
</label>
<label>
${t("events.session_seed_laps_label")}
<input type="number" min="0" name="seedBestLapCount" placeholder="${t("events.seed_best_laps")}" />
<small>${t("events.session_seed_laps_hint")}</small>
</label>
<label>
${t("events.session_seed_method_label")}
<select name="seedMethod">
<option value="best_sum">${t("events.seed_method_best_sum")}</option>
<option value="average">${t("events.seed_method_average")}</option>
<option value="consecutive">${t("events.seed_method_consecutive")}</option>
</select>
<small>${t("events.session_seed_method_hint")}</small>
</label>
<label>
${t("events.session_stagger_gap_label")}
<input type="number" min="0" step="1" name="staggerGapSec" placeholder="${t("events.stagger_gap_sec")}" />
<small>${t("events.session_stagger_gap_hint")}</small>
</label>
<label>
${t("events.session_max_cars_label")}
<input type="number" min="1" name="maxCars" placeholder="${t("events.max_cars_placeholder")}" />
<small>${t("events.session_max_cars_hint")}</small>
</label>
<div class="actions-inline align-end">
<button class="btn btn-primary" type="submit">${t("events.add_session")}</button>
</div>
</form>
<p class="hint">${t("events.seed_best_laps_hint")}</p>
<p class="hint">${t("events.free_practice_note")}</p>
@@ -5000,26 +5079,63 @@ function renderEventManager(eventId) {
<button class="btn" id="sessionEditCancel">${t("common.cancel")}</button>
</div>
<form id="sessionEditForm" class="panel-body form-grid cols-5">
<input name="name" required value="${escapeHtml(editingSession.name)}" placeholder="${t("events.session_name")}" />
<select name="type">
${SESSION_TYPES.map(
(item) => `<option value="${item}" ${item === editingSession.type ? "selected" : ""}>${getSessionTypeLabel(item)}</option>`
).join("")}
</select>
<input name="durationMin" required type="number" min="1" value="${editingSession.durationMin || 5}" />
<input name="followUpSec" type="number" min="0" step="1" value="${editingSession.followUpSec || 0}" />
<select name="startMode">
<option value="mass" ${normalizeStartMode(editingSession.startMode) === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${normalizeStartMode(editingSession.startMode) === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
</select>
<input name="seedBestLapCount" type="number" min="0" step="1" value="${editingSession.seedBestLapCount || 0}" />
<select name="seedMethod">
<option value="best_sum" ${editingSession.seedMethod === "best_sum" ? "selected" : ""}>${t("events.seed_method_best_sum")}</option>
<option value="average" ${editingSession.seedMethod === "average" ? "selected" : ""}>${t("events.seed_method_average")}</option>
<option value="consecutive" ${editingSession.seedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
</select>
<input name="staggerGapSec" type="number" min="0" step="1" value="${editingSession.staggerGapSec || 0}" />
<div class="span-5"><p class="hint">${t("events.edit_session_help")}</p></div>
<label>
${t("events.session_name")}
<input name="name" required value="${escapeHtml(editingSession.name)}" placeholder="${t("events.session_name")}" />
</label>
<label>
${t("events.session_type_label")}
<select name="type">
${sessionTypeChoices.map(
(item) => `<option value="${item}" ${item === editingSession.type ? "selected" : ""}>${getSessionTypeLabel(item)}</option>`
).join("")}
</select>
<small>${t(sessionTypeHintKey)}</small>
</label>
<label>
${t("events.session_duration_label")}
<input name="durationMin" required type="number" min="1" value="${editingSession.durationMin || 5}" />
<small>${t("events.session_duration_hint")}</small>
</label>
<label>
${t("events.session_followup_label")}
<input name="followUpSec" type="number" min="0" step="1" value="${editingSession.followUpSec || 0}" />
<small>${t("events.session_followup_hint")}</small>
</label>
<label>
${t("events.session_start_mode_label")}
<select name="startMode">
<option value="mass" ${normalizeStartMode(editingSession.startMode) === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${normalizeStartMode(editingSession.startMode) === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
</select>
<small>${t("events.session_start_mode_hint")}</small>
</label>
<label>
${t("events.session_seed_laps_label")}
<input name="seedBestLapCount" type="number" min="0" step="1" value="${editingSession.seedBestLapCount || 0}" />
<small>${t("events.session_seed_laps_hint")}</small>
</label>
<label>
${t("events.session_seed_method_label")}
<select name="seedMethod">
<option value="best_sum" ${editingSession.seedMethod === "best_sum" ? "selected" : ""}>${t("events.seed_method_best_sum")}</option>
<option value="average" ${editingSession.seedMethod === "average" ? "selected" : ""}>${t("events.seed_method_average")}</option>
<option value="consecutive" ${editingSession.seedMethod === "consecutive" ? "selected" : ""}>${t("events.seed_method_consecutive")}</option>
</select>
<small>${t("events.session_seed_method_hint")}</small>
</label>
<label>
${t("events.session_stagger_gap_label")}
<input name="staggerGapSec" type="number" min="0" step="1" value="${editingSession.staggerGapSec || 0}" />
<small>${t("events.session_stagger_gap_hint")}</small>
</label>
<label>
${t("events.session_max_cars_label")}
<input name="maxCars" type="number" min="1" value="${editingSession.maxCars || ""}" />
<small>${t("events.session_max_cars_hint")}</small>
</label>
<p class="form-error" id="sessionEditError" hidden></p>
<div class="actions-inline">
<button class="btn btn-primary" type="submit">${t("common.save")}</button>
@@ -5215,6 +5331,7 @@ function renderEventManager(eventId) {
? String(form.get("seedMethod")).toLowerCase()
: "best_sum";
editingSession.staggerGapSec = Math.max(0, Number(form.get("staggerGapSec") || 0) || 0);
editingSession.maxCars = Number(form.get("maxCars") || 0) || null;
selectedSessionEditId = null;
saveState();
renderEventManager(eventId);