From 41c7bb352a65d2ca59d3b633fc5b460d26069eb9 Mon Sep 17 00:00:00 2001 From: James Pattinson Date: Thu, 23 Oct 2025 20:31:23 +0000 Subject: [PATCH] ICAO code expansion --- web/admin.html | 61 ++++++++++++++++++++++++++++++-------------------- web/index.html | 61 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 35 deletions(-) diff --git a/web/admin.html b/web/admin.html index 8026299..219c9a8 100644 --- a/web/admin.html +++ b/web/admin.html @@ -1256,40 +1256,57 @@ document.getElementById('departures-loading').style.display = 'none'; } - function displayArrivals(arrivals) { + // ICAO code to airport name cache + const airportNameCache = {}; + + async function getAirportDisplay(code) { + if (!code || code.length !== 4 || !/^[A-Z]{4}$/.test(code)) return code; + if (airportNameCache[code]) return `${code}
${airportNameCache[code]}`; + try { + const resp = await authenticatedFetch(`/api/v1/airport/lookup/${code}`); + if (resp.ok) { + const data = await resp.json(); + if (data && data.length && data[0].name) { + airportNameCache[code] = data[0].name; + return `${code}
${data[0].name}`; + } + } + } catch {} + return code; + } + + async function displayArrivals(arrivals) { const tbody = document.getElementById('arrivals-table-body'); const recordCount = document.getElementById('arrivals-count'); - recordCount.textContent = arrivals.length; - if (arrivals.length === 0) { document.getElementById('arrivals-no-data').style.display = 'block'; return; } - tbody.innerHTML = ''; document.getElementById('arrivals-table-content').style.display = 'block'; - - arrivals.forEach(ppr => { + for (const ppr of arrivals) { const row = document.createElement('tr'); row.onclick = () => openPPRModal(ppr.id); - // Create notes indicator if notes exist const notesIndicator = ppr.notes && ppr.notes.trim() ? ` 📝 ${ppr.notes} ` : ''; - // Display callsign as main item if present, registration below; otherwise show registration const aircraftDisplay = ppr.ac_call && ppr.ac_call.trim() ? `${ppr.ac_call}
${ppr.ac_reg}` : `${ppr.ac_reg}`; - + // Lookup airport name for in_from + let fromDisplay = ppr.in_from; + if (ppr.in_from && ppr.in_from.length === 4 && /^[A-Z]{4}$/.test(ppr.in_from)) { + fromDisplay = await getAirportDisplay(ppr.in_from); + } row.innerHTML = ` ${aircraftDisplay}${notesIndicator} ${ppr.ac_type} - ${ppr.in_from} + ${fromDisplay} ${formatTimeOnly(ppr.eta)} ${ppr.pob_in} ${ppr.fuel || '-'} @@ -1302,45 +1319,42 @@ `; - tbody.appendChild(row); - }); + } } - function displayDepartures(departures) { + async function displayDepartures(departures) { const tbody = document.getElementById('departures-table-body'); const recordCount = document.getElementById('departures-count'); - recordCount.textContent = departures.length; - if (departures.length === 0) { document.getElementById('departures-no-data').style.display = 'block'; return; } - tbody.innerHTML = ''; document.getElementById('departures-table-content').style.display = 'block'; - - departures.forEach(ppr => { + for (const ppr of departures) { const row = document.createElement('tr'); row.onclick = () => openPPRModal(ppr.id); - // Create notes indicator if notes exist const notesIndicator = ppr.notes && ppr.notes.trim() ? ` 📝 ${ppr.notes} ` : ''; - // Display callsign as main item if present, registration below; otherwise show registration const aircraftDisplay = ppr.ac_call && ppr.ac_call.trim() ? `${ppr.ac_call}
${ppr.ac_reg}` : `${ppr.ac_reg}`; - + // Lookup airport name for out_to + let toDisplay = ppr.out_to || '-'; + if (ppr.out_to && ppr.out_to.length === 4 && /^[A-Z]{4}$/.test(ppr.out_to)) { + toDisplay = await getAirportDisplay(ppr.out_to); + } row.innerHTML = ` ${aircraftDisplay}${notesIndicator} ${ppr.ac_type} - ${ppr.out_to || '-'} + ${toDisplay} ${ppr.etd ? formatTimeOnly(ppr.etd) : '-'} ${ppr.pob_out || ppr.pob_in} ${ppr.fuel || '-'} @@ -1354,9 +1368,8 @@ `; - tbody.appendChild(row); - }); + } } function formatTimeOnly(dateStr) { diff --git a/web/index.html b/web/index.html index f23a683..af05fb0 100644 --- a/web/index.html +++ b/web/index.html @@ -252,13 +252,40 @@ return `${status}`; } - // Create PPR item HTML - function createPPRItem(ppr) { + // ICAO code to airport name cache + const airportNameCache = {}; + + async function getAirportDisplay(code) { + if (!code || code.length !== 4 || !/^[A-Z]{4}$/.test(code)) return code; + if (airportNameCache[code]) return `${code}
${airportNameCache[code]}`; + try { + const resp = await fetch(`/api/v1/airport/lookup/${code}`); + if (resp.ok) { + const data = await resp.json(); + if (data && data.length && data[0].name) { + airportNameCache[code] = data[0].name; + return `${code}
${data[0].name}`; + } + } + } catch {} + return code; + } + + // Create PPR item HTML (async) + async function createPPRItem(ppr) { // Display callsign as main item if present, registration below; otherwise show registration const aircraftDisplay = ppr.ac_call && ppr.ac_call.trim() ? `${ppr.ac_call}
${ppr.ac_reg}` : ppr.ac_reg; - + // Lookup airport name for in_from/out_to + let fromDisplay = ppr.in_from; + if (ppr.in_from && ppr.in_from.length === 4 && /^[A-Z]{4}$/.test(ppr.in_from)) { + fromDisplay = await getAirportDisplay(ppr.in_from); + } + let toDisplay = ppr.out_to; + if (ppr.out_to && ppr.out_to.length === 4 && /^[A-Z]{4}$/.test(ppr.out_to)) { + toDisplay = await getAirportDisplay(ppr.out_to); + } return `
@@ -269,6 +296,14 @@ Type ${ppr.ac_type}
+
+ From + ${fromDisplay || '-'} +
+
+ To + ${toDisplay || '-'} +
Time ${formatDateTime(ppr.eta || ppr.etd)} @@ -298,19 +333,21 @@ try { const response = await fetch('/api/v1/public/arrivals'); const arrivals = await response.json(); - const loadingEl = document.getElementById('arrivals-loading'); const listEl = document.getElementById('arrivals-list'); const countEl = document.getElementById('arrivals-count'); - loadingEl.style.display = 'none'; listEl.style.display = 'block'; - if (arrivals.length === 0) { listEl.innerHTML = createNoDataMessage('arrivals'); countEl.textContent = '0 flights'; } else { - listEl.innerHTML = arrivals.map(createPPRItem).join(''); + // Render each item async + const htmlArr = []; + for (const ppr of arrivals) { + htmlArr.push(await createPPRItem(ppr)); + } + listEl.innerHTML = htmlArr.join(''); countEl.textContent = `${arrivals.length} flight${arrivals.length !== 1 ? 's' : ''}`; } } catch (error) { @@ -330,19 +367,21 @@ try { const response = await fetch('/api/v1/public/departures'); const departures = await response.json(); - const loadingEl = document.getElementById('departures-loading'); const listEl = document.getElementById('departures-list'); const countEl = document.getElementById('departures-count'); - loadingEl.style.display = 'none'; listEl.style.display = 'block'; - if (departures.length === 0) { listEl.innerHTML = createNoDataMessage('departures'); countEl.textContent = '0 flights'; } else { - listEl.innerHTML = departures.map(createPPRItem).join(''); + // Render each item async + const htmlArr = []; + for (const ppr of departures) { + htmlArr.push(await createPPRItem(ppr)); + } + listEl.innerHTML = htmlArr.join(''); countEl.textContent = `${departures.length} flight${departures.length !== 1 ? 's' : ''}`; } } catch (error) {