/* ============ Flight Lookup App ============ */ const HISTORY_KEY = "flight-lookup-history"; const THEME_KEY = "flight-lookup-theme"; const LANG_KEY = "flight-lookup-lang"; const MAX_HISTORY = 8; const DEBOUNCE_MS = 250; // ---- DOM refs ---- const airlineInput = document.getElementById("airline"); const flightInput = document.getElementById("flight-number"); const form = document.getElementById("lookup-form"); const suggestionsBox = document.getElementById("airline-suggestions"); const resultBox = document.getElementById("result"); const historyList = document.getElementById("history-list"); const historySection = document.getElementById("history-section"); const langSelect = document.getElementById("lang"); const themeToggle = document.getElementById("theme-toggle"); let lastFlight = null; let debounceTimer = null; let activeSuggestion = -1; let suggestionItems = []; // ============ Theme ============ function initTheme() { const saved = localStorage.getItem(THEME_KEY); const prefersLight = window.matchMedia("(prefers-color-scheme: light)").matches; const theme = saved || (prefersLight ? "light" : "dark"); document.documentElement.setAttribute("data-theme", theme); } function toggleTheme() { const current = document.documentElement.getAttribute("data-theme") || "dark"; const next = current === "dark" ? "light" : "dark"; document.documentElement.setAttribute("data-theme", next); localStorage.setItem(THEME_KEY, next); } // ============ Language ============ function initLang() { const saved = localStorage.getItem(LANG_KEY); if (saved && SUPPORTED_LANGS.includes(saved)) { setLang(saved); } else { setLang("en"); } langSelect.value = currentLang; } function onLangChange() { const lang = langSelect.value; localStorage.setItem(LANG_KEY, lang); setLang(lang); applyTranslations(); if (lastFlight) { renderResult(lastFlight); } } // ============ History ============ function getHistory() { try { return JSON.parse(localStorage.getItem(HISTORY_KEY)) || []; } catch { return []; } } function saveHistory(entry) { let history = getHistory(); history = history.filter((h) => h.code !== entry.code); history.unshift(entry); history = history.slice(0, MAX_HISTORY); localStorage.setItem(HISTORY_KEY, JSON.stringify(history)); renderHistory(); } function renderHistory() { const history = getHistory(); if (!history.length) { historySection.classList.add("hidden"); return; } historySection.classList.remove("hidden"); historyList.innerHTML = ""; for (const entry of history) { const li = document.createElement("li"); const btn = document.createElement("button"); btn.className = "history-item"; btn.type = "button"; const route = entry.from && entry.to ? ` ${entry.from} \u2192 ${entry.to}` : ""; btn.innerHTML = `${entry.code}${route}`; btn.addEventListener("click", () => { airlineInput.value = entry.airlineCode; flightInput.value = entry.flightNumber; doLookup(entry.airlineCode, entry.flightNumber); }); li.appendChild(btn); historyList.appendChild(li); } } // ============ Airline suggestions ============ function showSuggestions(query) { activeSuggestion = -1; if (!query || query.length < 1) { hideSuggestions(); return; } const matches = searchAirlines(query); if (!matches.length) { hideSuggestions(); return; } suggestionItems = matches; suggestionsBox.innerHTML = ""; matches.forEach((airline, i) => { const div = document.createElement("div"); div.className = "suggestion"; div.dataset.index = i; div.innerHTML = `${airline.code} ${airline.name}`; div.addEventListener("mousedown", (e) => { e.preventDefault(); selectSuggestion(airline); }); suggestionsBox.appendChild(div); }); suggestionsBox.classList.remove("hidden"); } function hideSuggestions() { suggestionsBox.classList.add("hidden"); suggestionItems = []; activeSuggestion = -1; } function selectSuggestion(airline) { airlineInput.value = airline.code; hideSuggestions(); flightInput.focus(); } function moveSuggestion(delta) { if (!suggestionItems.length) return; activeSuggestion = (activeSuggestion + delta + suggestionItems.length) % suggestionItems.length; const items = suggestionsBox.querySelectorAll(".suggestion"); items.forEach((el, i) => el.classList.toggle("active", i === activeSuggestion)); if (items[activeSuggestion]) { items[activeSuggestion].scrollIntoView({ block: "nearest" }); } } function commitSuggestion() { if (activeSuggestion >= 0 && suggestionItems[activeSuggestion]) { selectSuggestion(suggestionItems[activeSuggestion]); } } // ============ Lookup ============ function doLookup(airlineCode, flightNumber) { hideSuggestions(); showLoading(); lookupFlight(airlineCode, flightNumber) .then((flight) => { if (flight) { lastFlight = flight; renderResult(flight); saveHistory({ code: `${flight.airlineCode}${flight.flightNumber}`, airlineCode: flight.airlineCode, flightNumber: flight.flightNumber, from: flight.origin ? flight.origin.code : null, to: flight.destination ? flight.destination.code : null, }); } else { showError(t("noFlightFound", { flight: `${airlineCode} ${flightNumber}` })); } }) .catch(() => { showError(t("networkError")); }); } function showLoading() { resultBox.className = "result loading"; resultBox.innerHTML = `
${t("searching")}`; } function showError(message) { lastFlight = null; resultBox.className = "result error"; resultBox.textContent = message; } function renderResult(flight) { const statusText = t(flight.status) || flight.status; const shareUrl = `${location.origin}${location.pathname}?f=${flight.airlineCode}${flight.flightNumber}`; const isLive = flight.live && flight.position; let body; if (isLive) { body = renderLiveBody(flight); } else { body = renderMockBody(flight); } resultBox.className = "result" + (isLive ? " live" : ""); resultBox.innerHTML = `