From bee5a8453a2bc99db7ef87ae4831af93ebf1c6f8 Mon Sep 17 00:00:00 2001 From: larssand Date: Thu, 26 Mar 2026 19:23:38 +0100 Subject: [PATCH] Extract shared event and session helpers into module --- src/app.js | 97 +++++---------------------------------------- src/event_common.js | 87 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 src/event_common.js diff --git a/src/app.js b/src/app.js index 5be9189..a6d1d65 100644 --- a/src/app.js +++ b/src/app.js @@ -11,6 +11,7 @@ import { getSessionTypeLabel as getSessionTypeLabelLogic, getStatusLabel as getS import { renderDashboardView, renderClassesView, renderDriversView, renderCarsView } from "./core_views.js"; import { renderGuideView, renderOverlayPageView } from "./misc_views.js"; +import { getSessionsForEventHelper, getModeLabelHelper, normalizeStartModeHelper, getStartModeLabelHelper, getClassNameHelper, getEventNameHelper, renderAssignmentListView, renderSessionsTableView } from "./event_common.js"; import { renderTimingView, renderJudgingView } from "./timing_views.js"; @@ -101,6 +102,14 @@ const renderFinalMatrix = (event) => renderFinalMatrixHelper(event, { t, escapeH const buildPrintBrandBlock = (branding) => buildPrintBrandBlockHelper(branding, { escapeHtml }); const buildRaceStartListsHtml = (event) => buildRaceStartListsHtmlHelper(event, { t, state, escapeHtml, resolveEventBranding, getSessionsForEvent, getSessionSortWeight, getClassName, buildPrintBrandBlock, getSessionGridEntries, getSessionTypeLabel, getStartModeLabel, renderTable }); const buildRaceResultsHtml = (event) => buildRaceResultsHtmlHelper(event, { t, escapeHtml, resolveEventBranding, getClassName, buildPrintBrandBlock, renderRaceStandingsTableView, buildPracticeStandings, buildQualifyingStandings, buildFinalStandings, renderTeamRaceStandings }); +const getSessionsForEvent = (eventId) => getSessionsForEventHelper(state, eventId); +const getModeLabel = (mode) => getModeLabelHelper(mode, { t }); +const normalizeStartMode = (mode) => normalizeStartModeHelper(mode); +const getStartModeLabel = (mode) => getStartModeLabelHelper(mode, { t, normalizeStartMode }); +const getClassName = (classId) => getClassNameHelper(state, classId, { t }); +const getEventName = (eventId) => getEventNameHelper(state, eventId, { t }); +const renderAssignmentList = (eventId) => renderAssignmentListView(eventId, { state, t, escapeHtml, getSessionsForEvent, getSessionTypeLabel, saveState, renderAssignmentList }); +const renderSessionsTable = (sessions) => renderSessionsTableView(sessions, { t, renderTable, escapeHtml, getEventName, getSessionTypeLabel, getStatusLabel, getModeLabel }); const buildTeamRaceResultsHtml = (event) => buildTeamRaceResultsHtmlHelper(event, { t, escapeHtml, resolveEventBranding, getClassName, buildPrintBrandBlock, buildTeamRaceStandings, renderTable, formatLap, renderTeamStintLog }); const renderDashboard = () => renderDashboardView({ state, dom, t, backend, getActiveSession, getStatusLabel, getSessionTypeLabel, getEventName, getModeLabel, getBackendUrl, formatLap, renderSessionsTable, setCurrentView: (view) => { currentView = view; }, renderNav, renderView, connectDecoder, disconnectDecoder, openOverlayWindow, ensureAudioContext, playPassingBeep, playFinishSiren, escapeHtml }); const renderClasses = () => renderClassesView({ state, dom, t, selectedClassEditId: () => selectedClassEditId, setSelectedClassEditId: (value) => { selectedClassEditId = value; }, uid, saveState, renderView, renderTable, escapeHtml, setFormError, bindModalShell }); @@ -5091,50 +5100,6 @@ function renderEventManager(eventId) { } } -function renderAssignmentList(eventId) { - const block = document.getElementById("assignmentList"); - if (!block) { - return; - } - - const sessions = getSessionsForEvent(eventId); - block.innerHTML = sessions - .map((s) => { - const items = (s.assignments || []) - .map((a) => { - const driver = state.drivers.find((d) => d.id === a.driverId); - const car = state.cars.find((c) => c.id === a.carId); - return ` -
  • - ${escapeHtml(driver?.name || t("common.unknown_driver"))} -> ${escapeHtml(car?.name || t("common.unknown_car"))} (${escapeHtml( - car?.transponder || "-" - )}) - -
  • - `; - }) - .join(""); - - return ` -
    -

    ${escapeHtml(s.name)} (${escapeHtml(getSessionTypeLabel(s.type))})

    - -
    - `; - }) - .join(""); - - sessions.forEach((s) => { - (s.assignments || []).forEach((a) => { - document.getElementById(`as-delete-${a.id}`)?.addEventListener("click", () => { - s.assignments = s.assignments.filter((x) => x.id !== a.id); - saveState(); - renderAssignmentList(eventId); - }); - }); - }); -} - function getQuickAddState(transponder) { const normalized = String(transponder || "").trim(); const driver = state.drivers.find((item) => String(item.transponder || "").trim() === normalized) || null; @@ -5330,30 +5295,6 @@ function renderRecentPassings(session) { } -function getSessionsForEvent(eventId) { - return state.sessions.filter((s) => s.eventId === eventId); -} - -function getModeLabel(mode) { - return mode === "track" ? t("mode.track") : t("mode.race"); -} - -function normalizeStartMode(mode) { - return ["mass", "position", "staggered"].includes(String(mode || "").toLowerCase()) ? String(mode).toLowerCase() : "mass"; -} - -function getStartModeLabel(mode) { - return t(`events.start_mode_${normalizeStartMode(mode)}`); -} - -function getClassName(classId) { - return state.classes.find((x) => x.id === classId)?.name || t("common.unknown"); -} - -function getEventName(eventId) { - return state.events.find((x) => x.id === eventId)?.name || t("common.unknown_event"); -} - function getFreePracticeSessions(eventId) { return getSessionsForEvent(eventId).filter((session) => session.type === "free_practice"); } @@ -5710,26 +5651,6 @@ function resolveCompetitor(session, transponder) { }; } -function renderSessionsTable(sessions) { - if (!sessions.length) { - return `

    ${t("session.none_yet")}

    `; - } - return renderTable( - [t("table.event"), t("table.session"), t("table.type"), t("table.status"), t("table.mode")], - sessions.map( - (s) => ` - - ${escapeHtml(getEventName(s.eventId))} - ${escapeHtml(s.name)} - ${escapeHtml(getSessionTypeLabel(s.type))} - ${escapeHtml(getStatusLabel(s.status))} - ${getModeLabel(s.mode)} - - ` - ) - ); -} - function renderSimpleList(items, labelFn, idFn) { if (!items.length) { return `

    ${t("common.no_entries")}

    `; diff --git a/src/event_common.js b/src/event_common.js new file mode 100644 index 0000000..ae4dd80 --- /dev/null +++ b/src/event_common.js @@ -0,0 +1,87 @@ +export function getSessionsForEventHelper(state, eventId) { + return state.sessions.filter((s) => s.eventId === eventId); +} + +export function getModeLabelHelper(mode, { t }) { + return mode === "track" ? t("mode.track") : t("mode.race"); +} + +export function normalizeStartModeHelper(mode) { + return ["mass", "position", "staggered"].includes(String(mode || "").toLowerCase()) ? String(mode).toLowerCase() : "mass"; +} + +export function getStartModeLabelHelper(mode, { t, normalizeStartMode }) { + return t(`events.start_mode_${normalizeStartMode(mode)}`); +} + +export function getClassNameHelper(state, classId, { t }) { + return state.classes.find((x) => x.id === classId)?.name || t("common.unknown"); +} + +export function getEventNameHelper(state, eventId, { t }) { + return state.events.find((x) => x.id === eventId)?.name || t("common.unknown_event"); +} + +export function renderAssignmentListView(eventId, deps) { + const { state, t, escapeHtml, getSessionsForEvent, getSessionTypeLabel, saveState, renderAssignmentList } = deps; + const block = document.getElementById("assignmentList"); + if (!block) { + return; + } + + const sessions = getSessionsForEvent(eventId); + block.innerHTML = sessions + .map((s) => { + const items = (s.assignments || []) + .map((a) => { + const driver = state.drivers.find((d) => d.id === a.driverId); + const car = state.cars.find((c) => c.id === a.carId); + return ` +
  • + ${escapeHtml(driver?.name || t("common.unknown_driver"))} -> ${escapeHtml(car?.name || t("common.unknown_car"))} (${escapeHtml(car?.transponder || "-")}) + +
  • + `; + }) + .join(""); + + return ` +
    +

    ${escapeHtml(s.name)} (${escapeHtml(getSessionTypeLabel(s.type))})

    + +
    + `; + }) + .join(""); + + sessions.forEach((s) => { + (s.assignments || []).forEach((a) => { + document.getElementById(`as-delete-${a.id}`)?.addEventListener("click", () => { + s.assignments = s.assignments.filter((x) => x.id !== a.id); + saveState(); + renderAssignmentList(eventId); + }); + }); + }); +} + +export function renderSessionsTableView(sessions, deps) { + const { t, renderTable, escapeHtml, getEventName, getSessionTypeLabel, getStatusLabel, getModeLabel } = deps; + if (!sessions.length) { + return `

    ${t("session.none_yet")}

    `; + } + return renderTable( + [t("table.event"), t("table.session"), t("table.type"), t("table.status"), t("table.mode")], + sessions.map( + (s) => ` + + ${escapeHtml(getEventName(s.eventId))} + ${escapeHtml(s.name)} + ${escapeHtml(getSessionTypeLabel(s.type))} + ${escapeHtml(getStatusLabel(s.status))} + ${getModeLabel(s.mode)} + + ` + ) + ); +}