import { loadDashboardData } from "./data.js"; import { aggregateOverview, compactNumber, percent, renderAgeRisk, renderCohortDotPlot, renderCoverageHeatmap, renderNoCalibration, renderOutcomeTrend, renderUtahCoverage, } from "./charts.js"; const ROUTES = Object.freeze({ overview: "Overview", reliability: "Reliability explorer", estimator: "Next-test estimator", methods: "Data & methods", }); const UTAH_COUNTIES = [ "Beaver", "Box Elder", "Cache", "Carbon", "Daggett", "Davis", "Duchesne", "Emery", "Garfield", "Grand", "Iron", "Juab", "Kane", "Millard", "Morgan", "Piute", "Rich", "Salt Lake", "San Juan", "Sanpete", "Sevier", "Summit", "Tooele", "Uintah", "Utah", "Wasatch", "Washington", "Wayne", "Weber", ]; let dashboardData = null; let visibleScorecards = []; function byId(id) { return document.getElementById(id); } function setText(id, value) { const element = byId(id); if (element) element.textContent = value; } function normalizeCounty(value) { return String(value).trim().toLowerCase().replaceAll("_", " ").replace(/\s+/g, " "); } function displayCategory(value) { return String(value) .replaceAll("_", " ") .toLowerCase() .replace(/\b\w/g, (letter) => letter.toUpperCase()); } function routeFromHash() { const candidate = window.location.hash.replace(/^#/, "").toLowerCase(); return Object.hasOwn(ROUTES, candidate) ? candidate : "overview"; } function showRoute({ announce = true, focus = false } = {}) { const route = routeFromHash(); for (const view of document.querySelectorAll("[data-view]")) { view.hidden = view.dataset.view !== route; } for (const link of document.querySelectorAll("[data-route]")) { if (link.dataset.route === route) link.setAttribute("aria-current", "page"); else link.removeAttribute("aria-current"); } document.title = `${ROUTES[route]} · Utah Vehicle Health`; if (announce) setText("route-announcer", `${ROUTES[route]} view`); if (focus) { const heading = document.querySelector(`[data-view="${route}"] h1`); if (heading) { heading.setAttribute("tabindex", "-1"); heading.focus({ preventScroll: true }); heading.scrollIntoView({ behavior: "smooth", block: "start" }); } } } function initializeRouting() { showRoute({ announce: false, focus: false }); window.addEventListener("hashchange", () => showRoute({ focus: true })); } function setHeaderStatus(state, message) { const status = byId("header-status"); if (!status) return; status.dataset.state = state; const text = status.querySelector("span:last-child"); if (text) text.textContent = message; } function setPreviewBanner(manifest) { const preview = manifest.development_preview || !manifest.population_estimate_allowed; const banner = byId("preview-banner"); banner.hidden = !preview; if (!preview) return; setText("preview-title", "Development preview"); setText( "preview-copy", "These suppressed sample aggregates are not population estimates and must not be used for individual decisions.", ); } function setUnavailable(error) { const safeMessage = error instanceof Error && error.message ? `${error.message} No estimates are being shown.` : "The approved aggregate files could not be validated. No estimates are being shown."; for (const state of document.querySelectorAll("[data-unavailable]")) { state.hidden = false; const copy = state.querySelector("[data-unavailable-message]"); if (copy) copy.textContent = safeMessage; } for (const region of document.querySelectorAll("[data-requires-data]")) { region.hidden = true; } const banner = byId("preview-banner"); banner.hidden = false; setText("preview-title", "Data unavailable"); setText("preview-copy", "This static shell could not validate every required public aggregate. No fallback or estimated values are displayed."); setHeaderStatus("error", "Approved data unavailable"); } function populateSelect(id, values, formatter = displayCategory) { const select = byId(id); if (!select) return; for (const value of values) { const option = document.createElement("option"); option.value = String(value); option.textContent = formatter(value); select.append(option); } } function disableUnsupportedFilter(id, explanation) { const select = byId(id); if (!select) return; select.disabled = true; select.title = explanation; select.options[0].textContent = explanation; } function renderCountyList(coveredCounties) { const container = byId("county-coverage-list"); container.replaceChildren(); const normalized = new Set(coveredCounties.map(normalizeCounty)); for (const county of UTAH_COUNTIES) { const chip = document.createElement("span"); chip.className = "county-chip"; chip.dataset.covered = String(normalized.has(normalizeCounty(county))); chip.textContent = county; container.append(chip); } } function renderOverview(data) { const rows = data.overview.rows; const periods = aggregateOverview(rows); const totalSupport = rows.reduce((sum, row) => sum + row.support_rounded, 0); const weightedNonpass = rows.reduce( (sum, row) => sum + row.support_rounded * row.nonpass_rate, 0, ); const nonpassRate = totalSupport > 0 ? weightedNonpass / totalSupport : 0; const counties = [...new Set(rows.map((row) => row.public_county))].sort(); const latest = periods[periods.length - 1]; setText("kpi-eligible", `≈${compactNumber(totalSupport)}`); setText("kpi-pass", `≈${percent(1 - nonpassRate)}`); setText("kpi-nonpass", `≈${percent(nonpassRate)}`); setText("kpi-counties", String(counties.length)); setText("data-cutoff", latest ? `${latest.year} Q${latest.quarter}` : "Unavailable"); setText( "model-version", `Release ${data.manifest.release_id.slice(0, 8)} · ${data.manifest.model_versions.join(" / ")}`, ); renderOutcomeTrend(byId("outcome-trend-chart"), rows); setText( "outcome-trend-note", "The current approved bundle publishes binary non-pass rates only. Four-class outcome mix and blank rates are not inferred or displayed.", ); renderAgeRisk(byId("age-risk-chart"), data.ageRisk.rows); renderUtahCoverage(byId("utah-coverage-map"), counties); renderCountyList(counties); } function scorecardLabel(row) { return `${row.prior_make} ${row.prior_model}`.trim(); } function sortedScorecards(rows, mode) { const sorted = [...rows]; if (mode === "risk-desc") sorted.sort((a, b) => b.nonpass_rate - a.nonpass_rate); else if (mode === "risk-asc") sorted.sort((a, b) => a.nonpass_rate - b.nonpass_rate); else if (mode === "name") sorted.sort((a, b) => scorecardLabel(a).localeCompare(scorecardLabel(b))); else sorted.sort((a, b) => b.support_rounded - a.support_rounded); return sorted; } function renderScorecardCards(rows) { const container = byId("cohort-cards"); container.replaceChildren(); for (const row of rows.slice(0, 18)) { const article = document.createElement("article"); article.className = "cohort-card"; const heading = document.createElement("h3"); heading.textContent = scorecardLabel(row); const meta = document.createElement("div"); meta.className = "cohort-card__meta"; meta.textContent = `${compactNumber(row.support_rounded)} rounded support`; const bar = document.createElement("div"); bar.className = "risk-bar"; bar.setAttribute("aria-hidden", "true"); const fill = document.createElement("span"); fill.style.width = `${Math.min(100, row.nonpass_rate * 100)}%`; bar.append(fill); const value = document.createElement("div"); value.className = "cohort-card__value"; const strong = document.createElement("strong"); strong.textContent = percent(row.nonpass_rate); const small = document.createElement("small"); small.textContent = "Observed non-pass"; value.append(strong, small); article.append(heading, meta, bar, value); container.append(article); } } function updateExplorer() { if (!dashboardData) return; const query = byId("cohort-search").value.trim().toLowerCase(); const sortMode = byId("result-sort").value; const matches = dashboardData.scorecards.rows.filter((row) => scorecardLabel(row).toLowerCase().includes(query), ); visibleScorecards = sortedScorecards(matches, sortMode); setText( "result-summary", `${visibleScorecards.length} supported cohort${visibleScorecards.length === 1 ? "" : "s"}; showing up to 18 cards and 12 chart rows.`, ); byId("empty-results").hidden = visibleScorecards.length > 0; renderCohortDotPlot(byId("cohort-dot-plot"), visibleScorecards); renderScorecardCards(visibleScorecards); } function initializeExplorer(data) { populateSelect("filter-county", data.filters.public_counties); populateSelect("filter-age", data.filters.age_bands, (value) => String(value)); populateSelect( "filter-period", data.filters.periods.map((period) => period.year), (value) => String(value), ); // Current scorecards are make/model aggregates only. These planned controls // remain visible but disabled so the UI never implies unsupported slicing. disableUnsupportedFilter("filter-county", "Unavailable at current scorecard grain"); disableUnsupportedFilter("filter-age", "Unavailable at current scorecard grain"); disableUnsupportedFilter("filter-fuel", "Fuel not published in this bundle"); disableUnsupportedFilter("filter-program", "Program not published in this bundle"); disableUnsupportedFilter("filter-period", "Period not published in this scorecard"); const adjusted = document.querySelector('input[name="risk-view"][value="adjusted"]'); adjusted.disabled = true; adjusted.parentElement.title = "Model-adjusted cohort scorecards are not published."; byId("cohort-search").addEventListener("input", updateExplorer); byId("result-sort").addEventListener("change", updateExplorer); byId("reset-filters").addEventListener("click", () => { byId("explorer-filters").reset(); byId("cohort-search").value = ""; byId("result-sort").value = "support"; updateExplorer(); }); updateExplorer(); } function chooseDiagnostic(rows) { const partitionRank = { calibrate: 3, tune: 2, train: 1 }; return [...rows].sort((left, right) => { const preferredLeft = left.model === "logistic_platt" ? 1 : 0; const preferredRight = right.model === "logistic_platt" ? 1 : 0; return ( preferredRight - preferredLeft || (partitionRank[right.partition] ?? 0) - (partitionRank[left.partition] ?? 0) ); })[0]; } function renderMethods(data) { renderCoverageHeatmap(byId("coverage-heatmap"), data.coverage.rows); const diagnostic = chooseDiagnostic(data.diagnostics.rows); setText( "diagnostic-scope-label", diagnostic ? `${diagnostic.partition === "calibrate" ? "Calibration cohort" : "Development diagnostics"} · ${diagnostic.model}` : "Development diagnostics · model unavailable", ); setText("diagnostic-ap", diagnostic ? diagnostic.average_precision.toFixed(3) : "—"); setText("diagnostic-brier", diagnostic ? diagnostic.brier.toFixed(3) : "—"); setText("diagnostic-n", "Not published"); renderNoCalibration(byId("calibration-chart")); } function renderDashboard(data) { dashboardData = data; setPreviewBanner(data.manifest); renderOverview(data); initializeExplorer(data); renderMethods(data); setHeaderStatus( "ready", data.manifest.development_preview ? "Validated development aggregates" : "Validated public aggregates", ); } async function initialize() { initializeRouting(); try { const data = await loadDashboardData(); renderDashboard(data); } catch (error) { console.error("Dashboard data contract rejected the public assets.", error); setUnavailable(error); } } initialize(); export { displayCategory, normalizeCounty, routeFromHash };