diff --git a/web/admin.html b/web/admin.html index 6469f5f..ba1b5c8 100644 --- a/web/admin.html +++ b/web/admin.html @@ -942,6 +942,7 @@ let sessionExpiryWarningShown = false; let sessionExpiryCheckInterval = null; let etdManuallyEdited = false; // Track if user has manually edited ETD + let loadPPRsTimeout = null; // Debounce timer for loadPPRs to prevent duplicate refreshes // WebSocket connection for real-time updates function connectWebSocket() { @@ -1405,9 +1406,18 @@ // Load PPR records - now loads all tables async function loadPPRs() { if (!accessToken) return; - - // Load all tables simultaneously - await Promise.all([loadArrivals(), loadDepartures(), loadDeparted(), loadParked(), loadUpcoming()]); + + // Debounce: prevent duplicate refreshes if called multiple times in quick succession + // (e.g., from form submission + WebSocket update at the same time) + if (loadPPRsTimeout) { + clearTimeout(loadPPRsTimeout); + } + + loadPPRsTimeout = setTimeout(async () => { + // Load all tables simultaneously + await Promise.all([loadArrivals(), loadDepartures(), loadDeparted(), loadParked(), loadUpcoming()]); + loadPPRsTimeout = null; + }, 100); // Wait 100ms before executing to batch multiple calls } // Load arrivals (NEW and CONFIRMED status for PPR, DEPARTED for local flights) @@ -1629,26 +1639,15 @@ function displayDeparted(departed) { const tbody = document.getElementById('departed-table-body'); - // Deduplicate departed flights by ID to prevent duplicates from race conditions - const seenIds = new Set(); - const uniqueDeparted = departed.filter(flight => { - if (seenIds.has(flight.id)) { - console.warn(`Duplicate departed flight detected and filtered: ID ${flight.id}`); - return false; - } - seenIds.add(flight.id); - return true; - }); + document.getElementById('departed-count').textContent = departed.length; - document.getElementById('departed-count').textContent = uniqueDeparted.length; - - if (uniqueDeparted.length === 0) { + if (departed.length === 0) { document.getElementById('departed-no-data').style.display = 'block'; return; } // Sort by departed time - uniqueDeparted.sort((a, b) => { + departed.sort((a, b) => { const aTime = a.departed_dt; const bTime = b.departed_dt; return new Date(aTime) - new Date(bTime); @@ -1657,7 +1656,7 @@ tbody.innerHTML = ''; document.getElementById('departed-table-content').style.display = 'block'; - for (const flight of uniqueDeparted) { + for (const flight of departed) { const row = document.createElement('tr'); const isLocal = flight.isLocalFlight; const isDeparture = flight.isDeparture; @@ -1745,26 +1744,15 @@ function displayParked(parked) { const tbody = document.getElementById('parked-table-body'); - // Deduplicate parked flights by ID to prevent duplicates from race conditions - const seenIds = new Set(); - const uniqueParked = parked.filter(flight => { - if (seenIds.has(flight.id)) { - console.warn(`Duplicate parked flight detected and filtered: ID ${flight.id}`); - return false; - } - seenIds.add(flight.id); - return true; - }); + document.getElementById('parked-count').textContent = parked.length; - document.getElementById('parked-count').textContent = uniqueParked.length; - - if (uniqueParked.length === 0) { + if (parked.length === 0) { document.getElementById('parked-no-data').style.display = 'block'; return; } // Sort by landed time - uniqueParked.sort((a, b) => { + parked.sort((a, b) => { if (!a.landed_dt) return 1; if (!b.landed_dt) return -1; return new Date(a.landed_dt) - new Date(b.landed_dt); @@ -1773,7 +1761,7 @@ tbody.innerHTML = ''; document.getElementById('parked-table-content').style.display = 'block'; - for (const ppr of uniqueParked) { + for (const ppr of parked) { const row = document.createElement('tr'); // All rows are PPR, so make them clickable @@ -1863,31 +1851,20 @@ function displayUpcoming(upcoming) { const tbody = document.getElementById('upcoming-table-body'); - // Deduplicate upcoming flights by ID to prevent duplicates from race conditions - const seenIds = new Set(); - const uniqueUpcoming = upcoming.filter(ppr => { - if (seenIds.has(ppr.id)) { - console.warn(`Duplicate upcoming flight detected and filtered: ID ${ppr.id}`); - return false; - } - seenIds.add(ppr.id); - return true; - }); + document.getElementById('upcoming-count').textContent = upcoming.length; - document.getElementById('upcoming-count').textContent = uniqueUpcoming.length; - - if (uniqueUpcoming.length === 0) { + if (upcoming.length === 0) { // Don't show anything if collapsed by default return; } // Sort by ETA date and time - uniqueUpcoming.sort((a, b) => new Date(a.eta) - new Date(b.eta)); + upcoming.sort((a, b) => new Date(a.eta) - new Date(b.eta)); tbody.innerHTML = ''; // Don't auto-expand, keep collapsed by default - for (const ppr of uniqueUpcoming) { + for (const ppr of upcoming) { const row = document.createElement('tr'); row.onclick = () => openPPRModal(ppr.id); row.style.cssText = 'font-size: 0.85rem !important;'; @@ -1966,25 +1943,14 @@ const tbody = document.getElementById('arrivals-table-body'); const recordCount = document.getElementById('arrivals-count'); - // Deduplicate arrivals by ID to prevent duplicates from race conditions - const seenIds = new Set(); - const uniqueArrivals = arrivals.filter(flight => { - if (seenIds.has(flight.id)) { - console.warn(`Duplicate arrival detected and filtered: ID ${flight.id}`); - return false; - } - seenIds.add(flight.id); - return true; - }); - - recordCount.textContent = uniqueArrivals.length; - if (uniqueArrivals.length === 0) { + recordCount.textContent = arrivals.length; + if (arrivals.length === 0) { document.getElementById('arrivals-no-data').style.display = 'block'; return; } // Sort arrivals by ETA/departure time (ascending) - uniqueArrivals.sort((a, b) => { + arrivals.sort((a, b) => { const aTime = a.eta || a.departure_dt; const bTime = b.eta || b.departure_dt; if (!aTime) return 1; @@ -1993,7 +1959,7 @@ }); tbody.innerHTML = ''; document.getElementById('arrivals-table-content').style.display = 'block'; - for (const flight of uniqueArrivals) { + for (const flight of arrivals) { const row = document.createElement('tr'); const isLocal = flight.isLocalFlight; const isBookedIn = flight.isBookedIn; @@ -2137,25 +2103,14 @@ const tbody = document.getElementById('departures-table-body'); const recordCount = document.getElementById('departures-count'); - // Deduplicate departures by ID to prevent duplicates from race conditions - const seenIds = new Set(); - const uniqueDepartures = departures.filter(flight => { - if (seenIds.has(flight.id)) { - console.warn(`Duplicate flight detected and filtered: ID ${flight.id}`); - return false; - } - seenIds.add(flight.id); - return true; - }); - - recordCount.textContent = uniqueDepartures.length; - if (uniqueDepartures.length === 0) { + recordCount.textContent = departures.length; + if (departures.length === 0) { document.getElementById('departures-no-data').style.display = 'block'; return; } // Sort departures by ETD (ascending), nulls last - uniqueDepartures.sort((a, b) => { + departures.sort((a, b) => { const aTime = a.etd || a.created_dt; const bTime = b.etd || b.created_dt; if (!aTime) return 1; @@ -2164,7 +2119,7 @@ }); tbody.innerHTML = ''; document.getElementById('departures-table-content').style.display = 'block'; - for (const flight of uniqueDepartures) { + for (const flight of departures) { const row = document.createElement('tr'); const isLocal = flight.isLocalFlight; const isDeparture = flight.isDeparture;