console.log('RUNNING ELEVATE BOOKING'); document.addEventListener('DOMContentLoaded', () => { // --- 1. CONFIGURATION --- const airportApiUrl = 'https://tgdemo.pjsgroup.com/airports/opensearch/?format=json&limit=10&term=KTEB'; // --- 2. ELEMENT SELECTORS --- const roundTripCheckbox = document.querySelector('[booking="round-trip"]'); const fromDropdown = document.querySelector('[booking="from"]'); const toDropdown = document.querySelector('[booking="to"]'); const departureDateInput = document.querySelector('[booking="departure"]'); const returnDateInput = document.querySelector('[booking="return"]'); const guestInput = document.querySelector('[booking="guest"]'); const submitButton = document.querySelector('[booking="button"]'); const guestDecrementBtn = document.querySelector( '[booking="guest-decrease"]' ); const guestIncrementBtn = document.querySelector( '[booking="guest-increase"]' ); const errorElement = document.querySelector('[booking="error"]'); // This is a critical check. If even one of these core elements is missing, we shouldn't proceed. if (!fromDropdown || !toDropdown || !departureDateInput || !submitButton) { console.error( 'Core booking elements (from, to, departure, button) are missing from the page. Script cannot initialize.' ); return; // Stop execution if essential elements are not found } // --- 3. HELPER FUNCTIONS --- /** * Formats a Date object into 'YYYY-MM-DD' string format. */ const formatDate = date => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; /** * Displays a message in the error element. * @param {string} message The error message to display. */ const showError = message => { if (errorElement) { errorElement.textContent = message; errorElement.style.display = 'block'; } else { console.error( "Error element `[booking='error']` not found. Validation message:", message ); alert(message); // Fallback to alert } }; /** * Hides the error element. */ const hideError = () => { if (errorElement) { errorElement.style.display = 'none'; errorElement.textContent = ''; } }; /** * Hides selected option in the opposing dropdown. */ const updateDropdownFilters = () => { const fromValue = fromDropdown.dataset.selectedValue; const toValue = toDropdown.dataset.selectedValue; const fromNavList = fromDropdown.querySelector('.booking-dropdown-nav'); const toNavList = toDropdown.querySelector('.booking-dropdown-nav'); if (toNavList) { const toLinks = toNavList.querySelectorAll('.booking-dropdown-link'); toLinks.forEach(link => { link.style.display = link.dataset.value === fromValue ? 'none' : 'block'; }); } if (fromNavList) { const fromLinks = fromNavList.querySelectorAll('.booking-dropdown-link'); fromLinks.forEach(link => { link.style.display = link.dataset.value === toValue ? 'none' : 'block'; }); } }; // --- 4. SETUP AND INITIALIZATION FUNCTIONS --- /** * Sets up default values and validation for date inputs. */ const setupDateInputs = () => { // This function now only runs if both date inputs exist. const today = new Date(); const todayStr = formatDate(today); const sevenDaysFromNow = new Date(); sevenDaysFromNow.setDate(today.getDate() + 7); const sevenDaysFromNowStr = formatDate(sevenDaysFromNow); const oneYearFromNow = new Date(); oneYearFromNow.setFullYear(today.getFullYear() + 1); const oneYearFromNowStr = formatDate(oneYearFromNow); departureDateInput.value = todayStr; departureDateInput.min = todayStr; if (returnDateInput) { returnDateInput.value = sevenDaysFromNowStr; returnDateInput.min = todayStr; returnDateInput.max = oneYearFromNowStr; departureDateInput.addEventListener('change', () => { const departureDate = new Date(departureDateInput.value); const returnDate = new Date(returnDateInput.value); returnDateInput.min = departureDateInput.value; if (returnDate < departureDate) { returnDateInput.value = departureDateInput.value; } }); } }; /** * Populates a dropdown with airport data. */ const populateDropdown = (dropdownEl, data) => { const navList = dropdownEl.querySelector('.booking-dropdown-nav'); if (!navList) return; // Don't proceed if the inner structure is missing const linkTemplate = document.createElement('a'); linkTemplate.classList.add('booking-dropdown-link', 'w-dropdown-link'); linkTemplate.href = '#'; navList.innerHTML = ''; // Clear existing options data.forEach(airport => { if (!airport.value) return; const newLink = linkTemplate.cloneNode(true); newLink.textContent = airport.short_label; newLink.setAttribute('data-value', airport.value); newLink.setAttribute('data-label', airport.short_label); newLink.addEventListener('click', e => { e.preventDefault(); const labelEl = dropdownEl.querySelector('.booking-dropdown-label'); if (labelEl) { labelEl.textContent = airport.short_label; } dropdownEl.dataset.selectedValue = airport.value; dropdownEl.dataset.selectedLabel = airport.short_label; // Logic to clear the other dropdown if the same value is selected const otherDropdown = dropdownEl === fromDropdown ? toDropdown : fromDropdown; if (otherDropdown.dataset.selectedValue === airport.value) { otherDropdown.dataset.selectedValue = ''; otherDropdown.dataset.selectedLabel = ''; const otherLabelEl = otherDropdown.querySelector( '.booking-dropdown-label' ); if (otherLabelEl) { otherLabelEl.textContent = otherDropdown === toDropdown ? 'Select Destination' : 'Select Origin'; } } updateDropdownFilters(); // Manually close the dropdown const parentDropdown = dropdownEl.closest('.w-dropdown'); if (parentDropdown) { parentDropdown.classList.remove('w--open'); } }); navList.appendChild(newLink); }); }; /** * Sets up the interactive guest counter buttons and input validation. */ const setupGuestCounter = () => { const minGuests = 1; const maxGuests = 13; // Handle the decrement button click guestDecrementBtn.addEventListener('click', () => { let currentValue = parseInt(guestInput.value, 10); if (isNaN(currentValue)) currentValue = minGuests; // Handle non-numeric input if (currentValue > minGuests) { guestInput.value = currentValue - 1; } }); // Handle the increment button click guestIncrementBtn.addEventListener('click', () => { let currentValue = parseInt(guestInput.value, 10); if (isNaN(currentValue)) currentValue = minGuests; // Handle non-numeric input if (currentValue < maxGuests) { guestInput.value = currentValue + 1; } }); // Add an event listener for direct user input to enforce limits. // The 'change' event fires when the user clicks away or presses Enter. guestInput.addEventListener('change', () => { let currentValue = parseInt(guestInput.value, 10); if (isNaN(currentValue) || currentValue < minGuests) { guestInput.value = minGuests; // If invalid or too low, reset to 1 } else if (currentValue > maxGuests) { guestInput.value = maxGuests; // If too high, cap at 13 } }); }; /** * Manages the open/close behavior of all dropdowns on the page. */ const setupDropdownBehavior = () => { const allDropdownToggles = document.querySelectorAll('.w-dropdown-toggle'); allDropdownToggles.forEach(toggle => { toggle.addEventListener('click', () => { const parentDropdown = toggle.closest('.w-dropdown'); if (!parentDropdown) return; const isOpen = parentDropdown.classList.contains('w--open'); // Close all other dropdowns first document .querySelectorAll('.w-dropdown') .forEach(d => d.classList.remove('w--open')); // If it wasn't open, open it now if (!isOpen) { parentDropdown.classList.add('w--open'); } }); }); // Add a global click listener to close dropdowns when clicking outside document.addEventListener('click', e => { if (!e.target.closest('.w-dropdown')) { document .querySelectorAll('.w-dropdown') .forEach(d => d.classList.remove('w--open')); } }); }; /** * Handles the final form submission logic. * @param {Event} event The click event from the submit button. */ const handleSubmit = event => { event.preventDefault(); hideError(); const isRoundTrip = roundTripCheckbox ? roundTripCheckbox.checked : false; const fromValue = fromDropdown.dataset.selectedValue; const toValue = toDropdown.dataset.selectedValue; const departure = departureDateInput.value; const returnValue = returnDateInput ? returnDateInput.value : null; const guests = guestInput ? guestInput.value : '1'; // --- Validation --- if (!fromValue || !toValue) { showError('Please select an origin and a destination.'); return; } if (fromValue === toValue) { showError('The origin and destination cannot be the same.'); return; } // --- URL Generation --- const domain = 'https://elevatejets.com'; const path = '/dashboard'; const params = new URLSearchParams(); params.append('from_airport', fromValue); params.append('to_airport', toValue); params.append('departure_date', departure); if (isRoundTrip && returnValue) { params.append('return_date', returnValue); } params.append('passengers', guests); const finalUrl = `${domain}${path}?${params.toString()}`; console.log('Redirecting to:', finalUrl); alert(`The application would now redirect to:\n${finalUrl}`); }; // --- 5. EXECUTION --- // Initialize components only if their corresponding elements exist if (departureDateInput) { setupDateInputs(); } else { console.error( 'Element with [booking="departure"] not found. Date inputs not initialized.' ); } if (guestInput && guestDecrementBtn && guestIncrementBtn) { setupGuestCounter(); } else { console.warn('Guest counter elements not found. Counter not initialized.'); } // if (roundTripCheckbox && returnDateInput) { // const returnDateField = returnDateInput.closest('.form_field-item'); // if (returnDateField) { // roundTripCheckbox.checked = true; // returnDateField.style.display = 'flex'; // Initial state // roundTripCheckbox.addEventListener('change', () => { // returnDateField.style.display = roundTripCheckbox.checked // ? 'flex' // : 'none'; // }); // } // } else { // console.warn( // 'Round trip checkbox or return date input not found. Round trip functionality disabled.' // ); // } // These are safe to run as they query within the function setupDropdownBehavior(); // Add the submit handler submitButton.addEventListener('click', handleSubmit); // Fetch airport data and populate dropdowns fetch(airportApiUrl) .then(response => { if (!response.ok) { throw new Error(`Network response was not ok: ${response.statusText}`); } return response.json(); }) .then(airportData => { populateDropdown(fromDropdown, airportData); populateDropdown(toDropdown, airportData); // Set default "From" airport const defaultFromAirport = airportData.find(a => a.value === 'KTEB'); if (defaultFromAirport) { const fromLabel = fromDropdown.querySelector('.booking-dropdown-label'); if (fromLabel) { fromLabel.textContent = defaultFromAirport.short_label; } fromDropdown.dataset.selectedValue = defaultFromAirport.value; fromDropdown.dataset.selectedLabel = defaultFromAirport.short_label; } updateDropdownFilters(); }) .catch(error => { console.error('Error fetching or processing airport data:', error); showError('Failed to load airport information. Please try again later.'); }); });