localStorage for booking out
This commit is contained in:
351
web/book.html
351
web/book.html
@@ -98,10 +98,17 @@
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="time"],
|
||||||
|
input[type="number"] {
|
||||||
|
padding: 12px 8px;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
input:focus, select:focus, textarea:focus {
|
input:focus, select:focus, textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #3498db;
|
border-color: #3498db;
|
||||||
@@ -119,6 +126,12 @@
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-row-3col {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-submit {
|
.btn-submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
@@ -284,6 +297,50 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recent-regs-section {
|
||||||
|
background: #f9f9f9;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-regs-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-regs-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-reg-btn {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #3498db;
|
||||||
|
color: #3498db;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-reg-btn:hover {
|
||||||
|
background: #3498db;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recent-regs-section.empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.container {
|
.container {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
@@ -294,10 +351,6 @@
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-row {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
@@ -327,11 +380,14 @@
|
|||||||
<button class="tab-btn active" onclick="switchTab(this, 'local')">Local</button>
|
<button class="tab-btn active" onclick="switchTab(this, 'local')">Local</button>
|
||||||
<button class="tab-btn" onclick="switchTab(this, 'circuits')">Circuits</button>
|
<button class="tab-btn" onclick="switchTab(this, 'circuits')">Circuits</button>
|
||||||
<button class="tab-btn" onclick="switchTab(this, 'departure')">Departure</button>
|
<button class="tab-btn" onclick="switchTab(this, 'departure')">Departure</button>
|
||||||
<button class="tab-btn" onclick="switchTab(this, 'arrival')">Arrival</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Local Flight Form -->
|
<!-- Local Flight Form -->
|
||||||
<div id="local" class="tab-content active">
|
<div id="local" class="tab-content active">
|
||||||
|
<div id="localRecentSection" class="recent-regs-section">
|
||||||
|
<div class="recent-regs-title">⏱️ Recently Used</div>
|
||||||
|
<div id="localRecent" class="recent-regs-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form id="localFlightForm" onsubmit="handleSubmit(event, 'local')">
|
<form id="localFlightForm" onsubmit="handleSubmit(event, 'local')">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -351,21 +407,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row-3col">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="localPOB">Persons on Board <span class="required">*</span></label>
|
<label for="localPOB">POB <span class="required">*</span></label>
|
||||||
<input type="number" id="localPOB" name="pob" value="1" min="1" required>
|
<input type="number" id="localPOB" name="pob" value="1" min="1" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="localDuration">Est. Duration (minutes)</label>
|
<label for="localDuration">Duration</label>
|
||||||
<input type="number" id="localDuration" name="duration" value="45" min="5">
|
<input type="number" id="localDuration" name="duration" value="45" min="5">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="localETD">Est. Takeoff Time</label>
|
<label for="localETD">ETD</label>
|
||||||
<input type="time" id="localETD" name="etd">
|
<input type="time" id="localETD" name="etd">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="localNotes">Notes</label>
|
<label for="localNotes">Notes</label>
|
||||||
@@ -378,6 +433,11 @@
|
|||||||
|
|
||||||
<!-- Circuit Form -->
|
<!-- Circuit Form -->
|
||||||
<div id="circuits" class="tab-content">
|
<div id="circuits" class="tab-content">
|
||||||
|
<div id="circuitsRecentSection" class="recent-regs-section">
|
||||||
|
<div class="recent-regs-title">⏱️ Recently Used</div>
|
||||||
|
<div id="circuitsRecent" class="recent-regs-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form id="circuitForm" onsubmit="handleSubmit(event, 'circuits')">
|
<form id="circuitForm" onsubmit="handleSubmit(event, 'circuits')">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="circuitReg">Aircraft Registration <span class="required">*</span></label>
|
<label for="circuitReg">Aircraft Registration <span class="required">*</span></label>
|
||||||
@@ -396,7 +456,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row-3col">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="circuitPOB">Persons on Board <span class="required">*</span></label>
|
<label for="circuitPOB">Persons on Board <span class="required">*</span></label>
|
||||||
<input type="number" id="circuitPOB" name="pob" value="1" min="1" required>
|
<input type="number" id="circuitPOB" name="pob" value="1" min="1" required>
|
||||||
@@ -405,12 +465,11 @@
|
|||||||
<label for="circuitDuration">Est. Duration (minutes)</label>
|
<label for="circuitDuration">Est. Duration (minutes)</label>
|
||||||
<input type="number" id="circuitDuration" name="duration" value="30" min="5">
|
<input type="number" id="circuitDuration" name="duration" value="30" min="5">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="circuitETD">Est. Takeoff Time</label>
|
<label for="circuitETD">Est. Takeoff Time</label>
|
||||||
<input type="time" id="circuitETD" name="etd">
|
<input type="time" id="circuitETD" name="etd">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="circuitNotes">Notes</label>
|
<label for="circuitNotes">Notes</label>
|
||||||
@@ -423,9 +482,11 @@
|
|||||||
|
|
||||||
<!-- Departure Form -->
|
<!-- Departure Form -->
|
||||||
<div id="departure" class="tab-content">
|
<div id="departure" class="tab-content">
|
||||||
<div class="info-box">
|
<div id="departureRecentSection" class="recent-regs-section">
|
||||||
➡️ Book a flight departing to another airport (email optional)
|
<div class="recent-regs-title">⏱️ Recently Used</div>
|
||||||
|
<div id="departureRecent" class="recent-regs-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="departureForm" onsubmit="handleSubmit(event, 'departure')">
|
<form id="departureForm" onsubmit="handleSubmit(event, 'departure')">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="depReg">Aircraft Registration <span class="required">*</span></label>
|
<label for="depReg">Aircraft Registration <span class="required">*</span></label>
|
||||||
@@ -444,7 +505,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row-3col">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="depPOB">Persons on Board <span class="required">*</span></label>
|
<label for="depPOB">Persons on Board <span class="required">*</span></label>
|
||||||
<input type="number" id="depPOB" name="pob" value="1" min="1" required>
|
<input type="number" id="depPOB" name="pob" value="1" min="1" required>
|
||||||
@@ -452,14 +513,13 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="depTo">Destination (ICAO) <span class="required">*</span></label>
|
<label for="depTo">Destination (ICAO) <span class="required">*</span></label>
|
||||||
<input type="text" id="depTo" name="out_to" placeholder="e.g., KJFK" required oninput="handleAirportLookup(this.value, 'depTo')">
|
<input type="text" id="depTo" name="out_to" placeholder="e.g., KJFK" required oninput="handleAirportLookup(this.value, 'depTo')">
|
||||||
<div id="depTo-lookup-results" class="airport-lookup-results"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="depETD">Takeoff Time</label>
|
<label for="depETD">Takeoff Time</label>
|
||||||
<input type="time" id="depETD" name="etd">
|
<input type="time" id="depETD" name="etd">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="depTo-lookup-results" class="airport-lookup-results"></div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="depNotes">Notes</label>
|
<label for="depNotes">Notes</label>
|
||||||
@@ -483,9 +543,12 @@
|
|||||||
|
|
||||||
<!-- Arrival Form -->
|
<!-- Arrival Form -->
|
||||||
<div id="arrival" class="tab-content">
|
<div id="arrival" class="tab-content">
|
||||||
<div class="info-box">
|
|
||||||
⬅️ Book an arrival from another airport (email optional)
|
<div id="arrivalRecentSection" class="recent-regs-section">
|
||||||
|
<div class="recent-regs-title">⏱️ Recently Used</div>
|
||||||
|
<div id="arrivalRecent" class="recent-regs-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="arrivalForm" onsubmit="handleSubmit(event, 'arrival')">
|
<form id="arrivalForm" onsubmit="handleSubmit(event, 'arrival')">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="arrReg">Aircraft Registration <span class="required">*</span></label>
|
<label for="arrReg">Aircraft Registration <span class="required">*</span></label>
|
||||||
@@ -504,7 +567,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row-3col">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="arrPOB">Persons on Board <span class="required">*</span></label>
|
<label for="arrPOB">Persons on Board <span class="required">*</span></label>
|
||||||
<input type="number" id="arrPOB" name="pob" value="1" min="1" required>
|
<input type="number" id="arrPOB" name="pob" value="1" min="1" required>
|
||||||
@@ -512,14 +575,13 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="arrFrom">Origin (ICAO) <span class="required">*</span></label>
|
<label for="arrFrom">Origin (ICAO) <span class="required">*</span></label>
|
||||||
<input type="text" id="arrFrom" name="in_from" placeholder="e.g., KJFK" required oninput="handleAirportLookup(this.value, 'arrFrom')">
|
<input type="text" id="arrFrom" name="in_from" placeholder="e.g., KJFK" required oninput="handleAirportLookup(this.value, 'arrFrom')">
|
||||||
<div id="arrFrom-lookup-results" class="airport-lookup-results"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="arrETA">Arrival Time</label>
|
<label for="arrETA">Arrival Time</label>
|
||||||
<input type="time" id="arrETA" name="eta">
|
<input type="time" id="arrETA" name="eta">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="arrFrom-lookup-results" class="airport-lookup-results"></div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="arrNotes">Notes</label>
|
<label for="arrNotes">Notes</label>
|
||||||
@@ -554,6 +616,164 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const API_BASE = window.location.origin + '/api/v1';
|
const API_BASE = window.location.origin + '/api/v1';
|
||||||
|
const STORAGE_RECENT_REGS_KEY = 'bookingPage_recentRegs';
|
||||||
|
const STORAGE_AIRCRAFT_TYPES_KEY = 'bookingPage_aircraftTypes';
|
||||||
|
const MAX_RECENT = 5;
|
||||||
|
|
||||||
|
// ==================== localStorage Management ====================
|
||||||
|
|
||||||
|
function getRecentRegistrations() {
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem(STORAGE_RECENT_REGS_KEY);
|
||||||
|
return stored ? JSON.parse(stored) : [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error getting recent registrations:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveRecentRegistration(registration) {
|
||||||
|
try {
|
||||||
|
if (!registration || registration.trim() === '') {
|
||||||
|
console.log('⚠️ saveRecentRegistration: empty registration');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reg = registration.toUpperCase().trim();
|
||||||
|
let recentRegs = getRecentRegistrations();
|
||||||
|
|
||||||
|
console.log('📝 Saving recent reg:', reg);
|
||||||
|
|
||||||
|
// Remove if already exists
|
||||||
|
recentRegs = recentRegs.filter(r => r !== reg);
|
||||||
|
|
||||||
|
// Add to front
|
||||||
|
recentRegs.unshift(reg);
|
||||||
|
|
||||||
|
// Keep only last MAX_RECENT
|
||||||
|
recentRegs = recentRegs.slice(0, MAX_RECENT);
|
||||||
|
|
||||||
|
localStorage.setItem(STORAGE_RECENT_REGS_KEY, JSON.stringify(recentRegs));
|
||||||
|
console.log('✅ Recent regs updated:', recentRegs);
|
||||||
|
updateAllRecentRegsUI();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error saving recent registration:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cacheAircraftType(registration, typeCode) {
|
||||||
|
try {
|
||||||
|
if (!registration || !typeCode) {
|
||||||
|
console.log('⚠️ cache skipped - registration:', registration, 'typeCode:', typeCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reg = registration.toUpperCase().trim();
|
||||||
|
const stored = localStorage.getItem(STORAGE_AIRCRAFT_TYPES_KEY);
|
||||||
|
let aircraftTypes = stored ? JSON.parse(stored) : {};
|
||||||
|
|
||||||
|
aircraftTypes[reg] = typeCode;
|
||||||
|
localStorage.setItem(STORAGE_AIRCRAFT_TYPES_KEY, JSON.stringify(aircraftTypes));
|
||||||
|
console.log('✅ Cached aircraft type:', reg, '=', typeCode);
|
||||||
|
console.log('All cached types:', aircraftTypes);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error caching aircraft type:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCachedAircraftType(registration) {
|
||||||
|
try {
|
||||||
|
const reg = registration.toUpperCase().trim();
|
||||||
|
const stored = localStorage.getItem(STORAGE_AIRCRAFT_TYPES_KEY);
|
||||||
|
if (!stored) {
|
||||||
|
console.log('⚠️ No cached types found for:', reg);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aircraftTypes = JSON.parse(stored);
|
||||||
|
const typeCode = aircraftTypes[reg] || null;
|
||||||
|
console.log('🔍 Retrieved cached type for', reg, '=', typeCode);
|
||||||
|
return typeCode;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error getting cached aircraft type:', e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRecentReg(registration, formType) {
|
||||||
|
const registerIdMap = {
|
||||||
|
'local': 'localReg',
|
||||||
|
'circuits': 'circuitReg',
|
||||||
|
'departure': 'depReg',
|
||||||
|
'arrival': 'arrReg'
|
||||||
|
};
|
||||||
|
|
||||||
|
const typeIdMap = {
|
||||||
|
'local': 'localType',
|
||||||
|
'circuits': 'circuitType',
|
||||||
|
'departure': 'depType',
|
||||||
|
'arrival': 'arrType'
|
||||||
|
};
|
||||||
|
|
||||||
|
const regId = registerIdMap[formType];
|
||||||
|
const typeId = typeIdMap[formType];
|
||||||
|
|
||||||
|
console.log('📍 applyRecentReg called - reg:', registration, 'form:', formType);
|
||||||
|
document.getElementById(regId).value = registration;
|
||||||
|
|
||||||
|
// Restore cached type if available (always overwrite)
|
||||||
|
const cachedType = getCachedAircraftType(registration);
|
||||||
|
if (cachedType) {
|
||||||
|
console.log('✔️ Applying cached type:', cachedType);
|
||||||
|
document.getElementById(typeId).value = cachedType;
|
||||||
|
} else {
|
||||||
|
console.log('ℹ️ No cached type found');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(regId).focus();
|
||||||
|
// Trigger the lookup
|
||||||
|
handleAircraftLookup(registration, formType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRecentRegsUI(formType) {
|
||||||
|
const sectionIdMap = {
|
||||||
|
'local': 'localRecentSection',
|
||||||
|
'circuits': 'circuitsRecentSection',
|
||||||
|
'departure': 'departureRecentSection',
|
||||||
|
'arrival': 'arrivalRecentSection'
|
||||||
|
};
|
||||||
|
|
||||||
|
const containerIdMap = {
|
||||||
|
'local': 'localRecent',
|
||||||
|
'circuits': 'circuitsRecent',
|
||||||
|
'departure': 'departureRecent',
|
||||||
|
'arrival': 'arrivalRecent'
|
||||||
|
};
|
||||||
|
|
||||||
|
const recentRegs = getRecentRegistrations();
|
||||||
|
const section = document.getElementById(sectionIdMap[formType]);
|
||||||
|
const container = document.getElementById(containerIdMap[formType]);
|
||||||
|
|
||||||
|
if (recentRegs.length === 0) {
|
||||||
|
section.classList.add('empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.classList.remove('empty');
|
||||||
|
container.innerHTML = recentRegs.map(reg => `
|
||||||
|
<button type="button" class="recent-reg-btn" onclick="applyRecentReg('${reg}', '${formType}')" title="Use ${reg}">
|
||||||
|
${reg}
|
||||||
|
</button>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAllRecentRegsUI() {
|
||||||
|
['local', 'circuits', 'departure', 'arrival'].forEach(formType => {
|
||||||
|
updateRecentRegsUI(formType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== End localStorage Management ====================
|
||||||
|
|
||||||
function switchTab(button, tabName) {
|
function switchTab(button, tabName) {
|
||||||
// Hide all tabs
|
// Hide all tabs
|
||||||
@@ -597,6 +817,17 @@
|
|||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
const data = Object.fromEntries(formData);
|
const data = Object.fromEntries(formData);
|
||||||
|
|
||||||
|
// Save the registration to localStorage
|
||||||
|
if (data.registration) {
|
||||||
|
saveRecentRegistration(data.registration);
|
||||||
|
|
||||||
|
// Also cache the aircraft type if provided
|
||||||
|
if (data.type) {
|
||||||
|
console.log('💾 Caching type on submit - reg:', data.registration, 'type:', data.type);
|
||||||
|
cacheAircraftType(data.registration, data.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set flight_type based on form type
|
// Set flight_type based on form type
|
||||||
if (formType === 'local' && !data.flight_type) {
|
if (formType === 'local' && !data.flight_type) {
|
||||||
data.flight_type = 'LOCAL';
|
data.flight_type = 'LOCAL';
|
||||||
@@ -665,16 +896,40 @@
|
|||||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||||
const timeValue = `${hours}:${minutes}`;
|
const timeValue = `${hours}:${minutes}`;
|
||||||
|
|
||||||
|
// ETD fields should default to 15 minutes from now
|
||||||
|
const futureTime = new Date(now.getTime() + 15 * 60000);
|
||||||
|
const futureHours = String(futureTime.getHours()).padStart(2, '0');
|
||||||
|
const futureMinutes = String(futureTime.getMinutes()).padStart(2, '0');
|
||||||
|
const futureTimeValue = `${futureHours}:${futureMinutes}`;
|
||||||
|
|
||||||
|
const etdFieldIds = ['localETD', 'circuitETD', 'depETD'];
|
||||||
|
|
||||||
document.querySelectorAll('input[type="time"]').forEach(input => {
|
document.querySelectorAll('input[type="time"]').forEach(input => {
|
||||||
if (!input.value) {
|
if (!input.value) {
|
||||||
|
if (etdFieldIds.includes(input.id)) {
|
||||||
|
input.value = futureTimeValue;
|
||||||
|
} else {
|
||||||
input.value = timeValue;
|
input.value = timeValue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aircraft lookup functionality
|
// Aircraft lookup functionality
|
||||||
let aircraftLookupTimeouts = {};
|
let aircraftLookupTimeouts = {};
|
||||||
|
|
||||||
|
function formatAircraftRegistration(input) {
|
||||||
|
const reg = input.trim().toUpperCase();
|
||||||
|
|
||||||
|
// If 5 alpha characters, add hyphen: GIVYY -> G-IVYY
|
||||||
|
if (/^[A-Z]{5}$/.test(reg)) {
|
||||||
|
return reg[0] + '-' + reg.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise just capitalize
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
async function handleAircraftLookup(registration, formType) {
|
async function handleAircraftLookup(registration, formType) {
|
||||||
if (aircraftLookupTimeouts[formType]) {
|
if (aircraftLookupTimeouts[formType]) {
|
||||||
clearTimeout(aircraftLookupTimeouts[formType]);
|
clearTimeout(aircraftLookupTimeouts[formType]);
|
||||||
@@ -703,6 +958,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('🔎 Aircraft lookup:', registration, 'formType:', formType);
|
||||||
resultsDiv.innerHTML = '<span class="lookup-searching">Searching...</span>';
|
resultsDiv.innerHTML = '<span class="lookup-searching">Searching...</span>';
|
||||||
|
|
||||||
aircraftLookupTimeouts[formType] = setTimeout(async () => {
|
aircraftLookupTimeouts[formType] = setTimeout(async () => {
|
||||||
@@ -710,19 +966,32 @@
|
|||||||
const response = await fetch(`${API_BASE}/aircraft/public/lookup/${registration.toUpperCase()}`);
|
const response = await fetch(`${API_BASE}/aircraft/public/lookup/${registration.toUpperCase()}`);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
console.log('📡 API Response:', data, 'Length:', data ? data.length : 'null');
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
if (data.length === 1) {
|
if (data.length === 1) {
|
||||||
const aircraft = data[0];
|
const aircraft = data[0];
|
||||||
document.getElementById(regId).value = aircraft.registration || registration.toUpperCase();
|
const regValue = aircraft.registration || registration.toUpperCase();
|
||||||
|
console.log('✨ Single match found:', regValue);
|
||||||
|
console.log('📋 Full aircraft object:', aircraft);
|
||||||
|
console.log('🔤 aircraft.type_code:', aircraft.type_code);
|
||||||
|
document.getElementById(regId).value = regValue;
|
||||||
|
// Cache the aircraft type
|
||||||
|
if (aircraft.type_code) {
|
||||||
|
console.log('💾 About to cache - reg:', regValue, 'type:', aircraft.type_code);
|
||||||
|
cacheAircraftType(regValue, aircraft.type_code);
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ type_code is empty or null, not caching');
|
||||||
|
}
|
||||||
resultsDiv.innerHTML = `
|
resultsDiv.innerHTML = `
|
||||||
<div class="lookup-match">
|
<div class="lookup-match">
|
||||||
${aircraft.registration || registration.toUpperCase()} - ${aircraft.type_code || 'Unknown'} ${aircraft.model ? `(${aircraft.model})` : ''}
|
${regValue} - ${aircraft.type_code || 'Unknown'} ${aircraft.model ? `(${aircraft.model})` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
if (!document.getElementById(typeId).value) {
|
if (!document.getElementById(typeId).value) {
|
||||||
document.getElementById(typeId).value = aircraft.type_code || '';
|
document.getElementById(typeId).value = aircraft.type_code || '';
|
||||||
}
|
}
|
||||||
} else if (data.length <= 10) {
|
} else if (data.length <= 10) {
|
||||||
|
console.log('🎲 Multiple matches found:', data.length);
|
||||||
resultsDiv.innerHTML = `
|
resultsDiv.innerHTML = `
|
||||||
<div class="aircraft-list">
|
<div class="aircraft-list">
|
||||||
${data.map(aircraft => `
|
${data.map(aircraft => `
|
||||||
@@ -737,9 +1006,14 @@
|
|||||||
resultsDiv.innerHTML = '<span class="lookup-no-match">Too many matches, please be more specific</span>';
|
resultsDiv.innerHTML = '<span class="lookup-no-match">Too many matches, please be more specific</span>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultsDiv.innerHTML = '<span class="lookup-no-match">No aircraft found</span>';
|
// No aircraft found - auto-format and apply the registration
|
||||||
|
const formattedReg = formatAircraftRegistration(registration);
|
||||||
|
document.getElementById(regId).value = formattedReg;
|
||||||
|
console.log('❌ No match - formatted:', registration, '→', formattedReg);
|
||||||
|
resultsDiv.innerHTML = `<span class="lookup-no-match">No match found - formatted as ${formattedReg}</span>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
console.log('⚠️ Lookup response not ok:', response.status);
|
||||||
resultsDiv.innerHTML = '';
|
resultsDiv.innerHTML = '';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -767,8 +1041,15 @@
|
|||||||
const regId = registerIdMap[formType];
|
const regId = registerIdMap[formType];
|
||||||
const typeId = typeIdMap[formType];
|
const typeId = typeIdMap[formType];
|
||||||
|
|
||||||
|
console.log('🎯 selectAircraft called:', registration, typeCode);
|
||||||
document.getElementById(regId).value = registration;
|
document.getElementById(regId).value = registration;
|
||||||
document.getElementById(typeId).value = typeCode;
|
document.getElementById(typeId).value = typeCode;
|
||||||
|
|
||||||
|
// Cache the aircraft type
|
||||||
|
if (typeCode) {
|
||||||
|
cacheAircraftType(registration, typeCode);
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById(`${regId}-lookup-results`).innerHTML = '';
|
document.getElementById(`${regId}-lookup-results`).innerHTML = '';
|
||||||
document.getElementById(regId).blur();
|
document.getElementById(regId).blur();
|
||||||
}
|
}
|
||||||
@@ -847,6 +1128,8 @@
|
|||||||
|
|
||||||
// Clear lookup results on blur
|
// Clear lookup results on blur
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
console.log('🚀 Page loaded - initializing...');
|
||||||
|
|
||||||
['localReg', 'depReg', 'arrReg', 'depTo', 'arrFrom'].forEach(fieldId => {
|
['localReg', 'depReg', 'arrReg', 'depTo', 'arrFrom'].forEach(fieldId => {
|
||||||
const field = document.getElementById(fieldId);
|
const field = document.getElementById(fieldId);
|
||||||
if (field) {
|
if (field) {
|
||||||
@@ -857,6 +1140,14 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Initialize recent registrations UI
|
||||||
|
updateAllRecentRegsUI();
|
||||||
|
console.log('✅ Recent regs UI initialized');
|
||||||
|
console.log('🗄️ Cached aircraft types:', localStorage.getItem(STORAGE_AIRCRAFT_TYPES_KEY));
|
||||||
|
|
||||||
|
// Set default times
|
||||||
|
setDefaultTimes();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize on page load
|
// Initialize on page load
|
||||||
|
|||||||
Reference in New Issue
Block a user