From f3b5216a2baf5ecb78803e695246fdf029864bf1 Mon Sep 17 00:00:00 2001 From: larssand Date: Fri, 27 Mar 2026 18:12:44 +0100 Subject: [PATCH] fix event och tappa decoder connect --- src/app.js | 12 +++++--- src/event_manager_controller.js | 54 +++++++++++++++++++++++++++------ src/runtime_services.js | 23 +++++++++++--- 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/src/app.js b/src/app.js index 9f80357..0f6b188 100644 --- a/src/app.js +++ b/src/app.js @@ -127,7 +127,7 @@ const hydrateFromBackend = () => hydrateFromBackendHelper({ backend, t, getBacke const scheduleBackendSync = () => scheduleBackendSyncHelper({ getBackendSyncTimer: () => backendSyncTimer, setBackendSyncTimer: (value) => { backendSyncTimer = value; }, syncStateToBackend }); const syncStateToBackend = () => syncStateToBackendHelper({ backend, t, getBackendUrl, buildPersistableState, getLocalStateVersion: () => localStateVersion, getSyncedStateVersion: () => syncedStateVersion, setSyncedStateVersion: (value) => { syncedStateVersion = value; }, getLocalStateDirty: () => localStateDirty, setLocalStateDirty: (value) => { localStateDirty = value; } }); const pingBackend = () => pingBackendHelper({ backend, t, getBackendUrl }); -const checkAppVersion = () => checkAppVersionHelper({ getBackendUrl, getBaselineAppVersion: () => baselineAppVersion, setBaselineAppVersion: (value) => { baselineAppVersion = value; } }); +const checkAppVersion = () => checkAppVersionHelper({ getBackendUrl, getBaselineAppVersion: () => baselineAppVersion, setBaselineAppVersion: (value) => { baselineAppVersion = value; }, getPendingAppVersion: () => pendingAppVersion, setPendingAppVersion: (value) => { pendingAppVersion = value; }, getLocalStateDirty: () => localStateDirty }); const startAppVersionPolling = () => startAppVersionPollingHelper({ checkAppVersion, getAppVersionPollTimer: () => appVersionPollTimer, setAppVersionPollTimer: (value) => { appVersionPollTimer = value; } }); const startOverlaySync = () => startOverlaySyncHelper({ getOverlaySyncTimer: () => overlaySyncTimer, setOverlaySyncTimer: (value) => { overlaySyncTimer = value; }, getLocalStateDirty: () => localStateDirty, hydrateFromBackend, getCurrentView: () => currentView, renderView }); const startOverlayRotation = () => startOverlayRotationHelper({ getOverlayRotationTimer: () => overlayRotationTimer, setOverlayRotationTimer: (value) => { overlayRotationTimer = value; }, getOverlayRotationIndex: () => overlayRotationIndex, setOverlayRotationIndex: (value) => { overlayRotationIndex = value; }, getCurrentView: () => currentView, getOverlayViewMode: () => overlayViewMode, renderView }); @@ -1862,6 +1862,7 @@ let reconnectTimer = null; let backendSyncTimer = null; let appVersionPollTimer = null; let baselineAppVersion = ""; +let pendingAppVersion = ""; let localStateVersion = 0; let syncedStateVersion = 0; let localStateDirty = false; @@ -2098,16 +2099,17 @@ async function init() { setupLanguageControl(); updateHeaderState(); updateConnectionBadge(); + if (state.settings.wsUrl && state.settings.autoReconnect && !state.decoder.connected) { + connectDecoder(); + } }); startOverlaySync(); startOverlayRotation(); startOverlayLiveRefresh(); - if (overlayMode) { - if (state.settings.wsUrl) { - connectDecoder(); - } + if (overlayMode && state.settings.wsUrl && !state.decoder.connected) { + connectDecoder(); } } diff --git a/src/event_manager_controller.js b/src/event_manager_controller.js index 6e359a0..74b251e 100644 --- a/src/event_manager_controller.js +++ b/src/event_manager_controller.js @@ -489,20 +489,42 @@ export function renderEventManagerView(context) { persistRaceParticipants(); }); - document.getElementById("teamForm")?.addEventListener("submit", (e) => { - e.preventDefault(); - const form = new FormData(e.currentTarget); - const name = String(form.get("teamName") || "").trim(); - const driverIds = form.getAll("teamDriverIds").map(String).filter(Boolean); - const carIds = form.getAll("teamCarIds").map(String).filter(Boolean); - if (!name || (!driverIds.length && !carIds.length)) { + const getTeamCreateSelections = () => ({ + driverIds: Array.from(document.querySelectorAll('[form="teamForm"][name="teamDriverIds"]:checked')).map((node) => String(node.value)).filter(Boolean), + carIds: Array.from(document.querySelectorAll('[form="teamForm"][name="teamCarIds"]:checked')).map((node) => String(node.value)).filter(Boolean), + }); + + const commitTeamCreate = () => { + const formNode = document.getElementById("teamForm"); + if (!(formNode instanceof HTMLFormElement)) { return; } + const form = new FormData(formNode); + const name = String(form.get("teamName") || "").trim(); + const { driverIds, carIds } = getTeamCreateSelections(); + if (!name) { + setFormError("teamCreateError", t("validation.required_name")); + return; + } + if (!driverIds.length && !carIds.length) { + setFormError("teamCreateError", t("validation.invalid_selection")); + return; + } + setFormError("teamCreateError", ""); const createdTeam = normalizeRaceTeam({ id: uid("team"), name, driverIds, carIds }); event.raceConfig.teams = [...getEventTeams(event), createdTeam]; setSelectedTeamEditId(createdTeam.id); saveState(); rerenderEventManager(eventId); + }; + + document.getElementById("teamForm")?.addEventListener("submit", (e) => { + e.preventDefault(); + commitTeamCreate(); + }); + + document.getElementById("teamAddSave")?.addEventListener("click", () => { + commitTeamCreate(); }); raceTeams.forEach((team) => { @@ -543,12 +565,15 @@ export function renderEventManagerView(context) { rerenderEventManager(eventId); }); - document.getElementById("teamEditForm")?.addEventListener("submit", (submitEvent) => { - submitEvent.preventDefault(); + const commitTeamEdit = () => { if (!editingTeam) { return; } - const form = new FormData(submitEvent.currentTarget); + const formNode = document.getElementById("teamEditForm"); + if (!(formNode instanceof HTMLFormElement)) { + return; + } + const form = new FormData(formNode); const name = String(form.get("teamName") || "").trim(); const driverIds = form.getAll("teamDriverIds").map(String).filter(Boolean); const carIds = form.getAll("teamCarIds").map(String).filter(Boolean); @@ -567,6 +592,15 @@ export function renderEventManagerView(context) { setSelectedTeamEditId(null); saveState(); rerenderEventManager(eventId); + }; + + document.getElementById("teamEditForm")?.addEventListener("submit", (submitEvent) => { + submitEvent.preventDefault(); + commitTeamEdit(); + }); + + document.getElementById("teamEditSave")?.addEventListener("click", () => { + commitTeamEdit(); }); document.getElementById("raceFormatBasicToggle")?.addEventListener("click", () => { diff --git a/src/runtime_services.js b/src/runtime_services.js index ab8d0a9..3be8f65 100644 --- a/src/runtime_services.js +++ b/src/runtime_services.js @@ -171,14 +171,29 @@ export async function pingBackendHelper({ backend, t, getBackendUrl }) { } } -export async function checkAppVersionHelper({ getBackendUrl, getBaselineAppVersion, setBaselineAppVersion }) { +export async function checkAppVersionHelper({ getBackendUrl, getBaselineAppVersion, setBaselineAppVersion, getPendingAppVersion, setPendingAppVersion, getLocalStateDirty }) { try { const res = await fetch(`${getBackendUrl()}/api/app-version`, { cache: "no-store" }); if (!res.ok) return; const payload = await res.json(); const key = `${payload.revision}:${payload.updatedAt}`; - if (!getBaselineAppVersion()) { setBaselineAppVersion(key); return; } - if (key !== getBaselineAppVersion()) window.location.reload(); + if (!getBaselineAppVersion()) { + setBaselineAppVersion(key); + setPendingAppVersion(""); + return; + } + if (key === getBaselineAppVersion()) { + setPendingAppVersion(""); + return; + } + if (getPendingAppVersion() !== key) { + setPendingAppVersion(key); + return; + } + if (getLocalStateDirty()) { + return; + } + window.location.reload(); } catch {} } @@ -186,7 +201,7 @@ export function startAppVersionPollingHelper({ checkAppVersion, getAppVersionPol if (!window.location.protocol.startsWith("http")) return; clearInterval(getAppVersionPollTimer()); checkAppVersion(); - setAppVersionPollTimer(setInterval(checkAppVersion, 3000)); + setAppVersionPollTimer(setInterval(checkAppVersion, 5000)); } export function startOverlaySyncHelper({ getOverlaySyncTimer, setOverlaySyncTimer, getLocalStateDirty, hydrateFromBackend, getCurrentView, renderView }) {