Flow improvements
This commit is contained in:
+94
-36
@@ -49,11 +49,11 @@
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- Local Flights Table -->
|
||||
<!-- Local Traffic Table -->
|
||||
<div class="ppr-table">
|
||||
<div class="table-header">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span>🛩️ Today's Local Flights - <span id="local-flights-count">0</span></span>
|
||||
<span>🛩️ Local Traffic - <span id="local-flights-count">0</span></span>
|
||||
<span class="info-icon" onclick="showTableHelp('local-flights')" title="What is this?">ℹ️</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,7 +84,7 @@
|
||||
</div>
|
||||
|
||||
<div id="local-flights-no-data" class="no-data" style="display: none;">
|
||||
<h3>No Local Flights</h3>
|
||||
<h3>No Local Traffic</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -447,12 +447,11 @@
|
||||
document.getElementById('departures-no-data').style.display = 'none';
|
||||
|
||||
try {
|
||||
// Load PPR departures and airport departures simultaneously
|
||||
const [pprResponse, depBookedOutResponse, depOutGroundResponse, depLocalResponse] = await Promise.all([
|
||||
// Load PPR departures and airport departures that are still pending departure
|
||||
const [pprResponse, depBookedOutResponse, depOutGroundResponse] = await Promise.all([
|
||||
authenticatedFetch('/api/v1/pprs/?limit=1000'),
|
||||
authenticatedFetch('/api/v1/departures/?status=BOOKED_OUT&limit=1000'),
|
||||
authenticatedFetch('/api/v1/departures/?status=GROUND&limit=1000'),
|
||||
authenticatedFetch('/api/v1/departures/?status=LOCAL&limit=1000')
|
||||
authenticatedFetch('/api/v1/departures/?status=GROUND&limit=1000')
|
||||
]);
|
||||
|
||||
if (!pprResponse.ok) {
|
||||
@@ -462,10 +461,9 @@
|
||||
const allPPRs = await pprResponse.json();
|
||||
const depBookedOut = depBookedOutResponse.ok ? await depBookedOutResponse.json() : [];
|
||||
const depOutGround = depOutGroundResponse.ok ? await depOutGroundResponse.json() : [];
|
||||
const depLocal = depLocalResponse.ok ? await depLocalResponse.json() : [];
|
||||
|
||||
// Combine departures
|
||||
const allDepartures = [...depBookedOut, ...depOutGround, ...depLocal];
|
||||
const allDepartures = [...depBookedOut, ...depOutGround];
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
|
||||
// Filter for PPR departures with ETD today and LANDED status only
|
||||
@@ -478,7 +476,7 @@
|
||||
return etdDate === today;
|
||||
});
|
||||
|
||||
// Add departures to other airports (BOOKED_OUT, GROUND, and LOCAL status)
|
||||
// Add departures to other airports that are not yet airborne locally
|
||||
const depDepartures = allDepartures.map(flight => ({
|
||||
...flight,
|
||||
isDeparture: true // Flag to distinguish from PPR
|
||||
@@ -502,19 +500,41 @@
|
||||
document.getElementById('local-flights-no-data').style.display = 'none';
|
||||
|
||||
try {
|
||||
const response = await authenticatedFetch('/api/v1/local-flights/?limit=1000');
|
||||
const [localResponse, pprResponse, depResponse] = await Promise.all([
|
||||
authenticatedFetch('/api/v1/local-flights/?limit=1000'),
|
||||
authenticatedFetch('/api/v1/pprs/?status=LOCAL&limit=1000'),
|
||||
authenticatedFetch('/api/v1/departures/?status=LOCAL&limit=1000')
|
||||
]);
|
||||
|
||||
if (!response.ok) {
|
||||
if (!localResponse.ok || !pprResponse.ok || !depResponse.ok) {
|
||||
throw new Error('Failed to fetch local flights');
|
||||
}
|
||||
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const localFlights = (await response.json()).filter(flight => {
|
||||
const localFlights = (await localResponse.json()).filter(flight => {
|
||||
if (!flight.created_dt || ['CANCELLED', 'LANDED'].includes(flight.status)) return false;
|
||||
return flight.created_dt.split('T')[0] === today;
|
||||
});
|
||||
const pprLocalTraffic = (await pprResponse.json())
|
||||
.filter(ppr => {
|
||||
const dateFields = [ppr.etd, ppr.landed_dt, ppr.submitted_dt];
|
||||
return dateFields.some(value => value && value.split('T')[0] === today);
|
||||
})
|
||||
.map(ppr => ({
|
||||
...ppr,
|
||||
isPPRLocalTraffic: true
|
||||
}));
|
||||
const departureLocalTraffic = (await depResponse.json())
|
||||
.filter(departure => {
|
||||
const dateFields = [departure.created_dt, departure.etd, departure.takeoff_dt, departure.departed_dt];
|
||||
return dateFields.some(value => value && value.split('T')[0] === today);
|
||||
})
|
||||
.map(departure => ({
|
||||
...departure,
|
||||
isDepartureLocalTraffic: true
|
||||
}));
|
||||
|
||||
displayLocalFlights(localFlights);
|
||||
displayLocalFlights([...localFlights, ...pprLocalTraffic, ...departureLocalTraffic]);
|
||||
} catch (error) {
|
||||
console.error('Error loading local flights:', error);
|
||||
if (error.message !== 'Session expired. Please log in again.') {
|
||||
@@ -610,7 +630,7 @@
|
||||
}
|
||||
|
||||
|
||||
// Load departed aircraft (DEPARTED status with departed_dt today)
|
||||
// Load departed aircraft (DEPARTED status with QSY/departed time today)
|
||||
async function loadDeparted() {
|
||||
document.getElementById('departed-loading').style.display = 'block';
|
||||
document.getElementById('departed-table-content').style.display = 'none';
|
||||
@@ -631,10 +651,10 @@
|
||||
|
||||
// Filter for PPRs departed today (only PPR'd departures, exclude local/circuits)
|
||||
const departed = allPPRs.filter(ppr => {
|
||||
if (!ppr.departed_dt || ppr.status !== 'DEPARTED') {
|
||||
if (!ppr.qsy_dt || ppr.status !== 'DEPARTED') {
|
||||
return false;
|
||||
}
|
||||
const departedDate = ppr.departed_dt.split('T')[0];
|
||||
const departedDate = ppr.qsy_dt.split('T')[0];
|
||||
return departedDate === today;
|
||||
});
|
||||
|
||||
@@ -675,8 +695,8 @@
|
||||
|
||||
// Sort by departed time
|
||||
departed.sort((a, b) => {
|
||||
const aTime = a.departed_dt;
|
||||
const bTime = b.departed_dt;
|
||||
const aTime = a.isDeparture ? a.departed_dt : a.qsy_dt;
|
||||
const bTime = b.isDeparture ? b.departed_dt : b.qsy_dt;
|
||||
return parseUtcDate(aTime) - parseUtcDate(bTime);
|
||||
});
|
||||
|
||||
@@ -721,7 +741,7 @@
|
||||
<td style="padding: 0.3rem 0.4rem !important; font-size: 0.85rem !important; text-align: center; width: 30px;"><span style="color: #032cfc; font-weight: bold;" title="From PPR">P</span></td>
|
||||
<td style="padding: 0.3rem 0.4rem !important; font-size: 0.85rem !important;">${flight.ac_call || '-'}</td>
|
||||
<td style="padding: 0.3rem 0.4rem !important; font-size: 0.85rem !important;">${flight.out_to || '-'}</td>
|
||||
<td style="padding: 0.3rem 0.4rem !important; font-size: 0.85rem !important;">${formatTimeOnly(flight.departed_dt)}</td>
|
||||
<td style="padding: 0.3rem 0.4rem !important; font-size: 0.85rem !important;">${formatTimeOnly(flight.qsy_dt)}</td>
|
||||
`;
|
||||
}
|
||||
tbody.appendChild(row);
|
||||
@@ -1200,24 +1220,52 @@
|
||||
tbody.innerHTML = '';
|
||||
document.getElementById('local-flights-table-content').style.display = 'block';
|
||||
|
||||
const circuitCounts = await loadLocalFlightCircuitCounts(localFlights);
|
||||
const circuitCounts = await loadLocalFlightCircuitCounts(localFlights.filter(flight => !flight.isPPRLocalTraffic && !flight.isDepartureLocalTraffic));
|
||||
|
||||
for (const flight of localFlights) {
|
||||
const row = document.createElement('tr');
|
||||
row.onclick = () => openLocalFlightEditModal(flight.id);
|
||||
const isPPR = flight.isPPRLocalTraffic;
|
||||
const isDeparture = flight.isDepartureLocalTraffic;
|
||||
row.onclick = () => isPPR ? openPPRModal(flight.id) : (isDeparture ? openDepartureEditModal(flight.id) : openLocalFlightEditModal(flight.id));
|
||||
|
||||
const aircraftDisplay = flight.callsign && flight.callsign.trim()
|
||||
? `<strong>${flight.callsign}</strong><br><span style="font-size: 0.8em; color: #666; font-style: italic;">${flight.registration}</span>`
|
||||
: `<strong>${flight.registration}</strong>`;
|
||||
const typeIcon = flight.submitted_via === 'PUBLIC'
|
||||
const aircraftDisplay = isPPR
|
||||
? (flight.ac_call && flight.ac_call.trim()
|
||||
? `<strong>${flight.ac_call}</strong><br><span style="font-size: 0.8em; color: #666; font-style: italic;">${flight.ac_reg}</span>`
|
||||
: `<strong>${flight.ac_reg}</strong>`)
|
||||
: isDeparture
|
||||
? (flight.callsign && flight.callsign.trim()
|
||||
? `<strong>${flight.callsign}</strong><br><span style="font-size: 0.8em; color: #666; font-style: italic;">${flight.registration}</span>`
|
||||
: `<strong>${flight.registration}</strong>`)
|
||||
: (flight.callsign && flight.callsign.trim()
|
||||
? `<strong>${flight.callsign}</strong><br><span style="font-size: 0.8em; color: #666; font-style: italic;">${flight.registration}</span>`
|
||||
: `<strong>${flight.registration}</strong>`);
|
||||
const typeIcon = isPPR
|
||||
? '<span style="color: #032cfc; font-weight: bold; font-size: 0.9em;" title="From PPR">P</span>'
|
||||
: isDeparture
|
||||
? (flight.submitted_via === 'PUBLIC'
|
||||
? '<span style="color: #b8860b; font-weight: bold; font-size: 0.9em;" title="Submitted by Pilot Online">O</span>'
|
||||
: '<span style="color: #6f42c1; font-weight: bold; font-size: 0.9em;" title="Airport departure">D</span>')
|
||||
: flight.submitted_via === 'PUBLIC'
|
||||
? '<span style="color: #b8860b; font-weight: bold; font-size: 0.9em;" title="Submitted by Pilot Online">O</span>'
|
||||
: '<span style="color: #228b22; font-weight: bold; font-size: 0.9em;" title="Local flight">L</span>';
|
||||
const flightType = flight.flight_type === 'CIRCUITS' ? 'Circuits' : flight.flight_type === 'LOCAL' ? 'Local' : 'Departure';
|
||||
const flightType = isPPR ? (flight.out_to ? `To ${flight.out_to}` : 'PPR Departure') : isDeparture ? (flight.out_to ? `To ${flight.out_to}` : 'Departure') : flight.flight_type === 'CIRCUITS' ? 'Circuits' : flight.flight_type === 'LOCAL' ? 'Local' : 'Departure';
|
||||
const etd = flight.etd ? formatTimeOnly(flight.etd) : (flight.created_dt ? formatTimeOnly(flight.created_dt) : '-');
|
||||
const circuits = circuitCounts[flight.id] ?? flight.circuits ?? 0;
|
||||
const circuits = (isPPR || isDeparture) ? '-' : circuitCounts[flight.id] ?? flight.circuits ?? 0;
|
||||
|
||||
let actionButtons = '';
|
||||
if (flight.status === 'BOOKED_OUT') {
|
||||
if (isPPR) {
|
||||
actionButtons = `
|
||||
<button class="btn btn-success btn-icon" onclick="event.stopPropagation(); showTimestampModal('DEPARTED', ${flight.id})" title="Mark as Departed">
|
||||
QSY
|
||||
</button>
|
||||
`;
|
||||
} else if (isDeparture) {
|
||||
actionButtons = `
|
||||
<button class="btn btn-success btn-icon" onclick="event.stopPropagation(); currentDepartureId = ${flight.id}; showTimestampModal('DEPARTED', ${flight.id}, false, true)" title="Mark as Departed">
|
||||
QSY
|
||||
</button>
|
||||
`;
|
||||
} else if (flight.status === 'BOOKED_OUT') {
|
||||
actionButtons = `
|
||||
<button class="btn btn-warning btn-icon" onclick="event.stopPropagation(); currentLocalFlightId = ${flight.id}; showTimestampModal('GROUND', ${flight.id}, true)" title="Contact Pilot">
|
||||
CONTACT
|
||||
@@ -1246,10 +1294,10 @@
|
||||
row.innerHTML = `
|
||||
<td>${aircraftDisplay}</td>
|
||||
<td style="text-align: center; width: 30px;">${typeIcon}</td>
|
||||
<td>${flight.type || '-'}</td>
|
||||
<td>${isPPR ? flight.ac_type || '-' : flight.type || '-'}</td>
|
||||
<td>${flightType}</td>
|
||||
<td>${etd}</td>
|
||||
<td>${flight.pob || '-'}</td>
|
||||
<td>${isPPR ? (flight.pob_out || flight.pob_in || '-') : (flight.pob || '-')}</td>
|
||||
<td>${localFlightStatusBadge(flight.status)}</td>
|
||||
<td>${circuits}</td>
|
||||
<td style="white-space: nowrap;">${actionButtons}</td>
|
||||
@@ -1495,11 +1543,21 @@
|
||||
fuel = flight.fuel || '-';
|
||||
landedDt = flight.landed_dt ? formatTimeOnly(flight.landed_dt) : '-';
|
||||
|
||||
actionButtons = `
|
||||
<button class="btn btn-primary btn-icon" onclick="event.stopPropagation(); showTimestampModal('DEPARTED', ${flight.id})" title="Mark as Departed">
|
||||
TAKE OFF
|
||||
</button>
|
||||
`;
|
||||
if (flight.status === 'LANDED') {
|
||||
actionButtons = `
|
||||
<button class="btn btn-primary btn-icon" onclick="event.stopPropagation(); showTimestampModal('LOCAL', ${flight.id})" title="Mark as Local">
|
||||
TAKE OFF
|
||||
</button>
|
||||
`;
|
||||
} else if (flight.status === 'LOCAL') {
|
||||
actionButtons = `
|
||||
<button class="btn btn-success btn-icon" onclick="event.stopPropagation(); showTimestampModal('DEPARTED', ${flight.id})" title="Mark as Departed">
|
||||
QSY
|
||||
</button>
|
||||
`;
|
||||
} else {
|
||||
actionButtons = '<span style="color: #999;">-</span>';
|
||||
}
|
||||
}
|
||||
|
||||
row.innerHTML = `
|
||||
|
||||
Reference in New Issue
Block a user