// --- API KEYS AND CONFIG --- const TRAVELPAYOUTS_MARKER = '634425'; const AMADEUS_API_KEY = 'wnxdD8f2YGFwGBNqA7hXafKbIL4gsojf'; // 🔒 IMPORTANT: The Amadeus API Secret should NOT be stored here in production. // See the security note at the end of this guide. const AMADEUS_API_SECRET = 'NafcUGE85nx0RPVO'; let amadeusAccessToken = null; // --- 1. GOOGLE PLACES AUTOCOMPLETE --- function initAutocomplete() { const autocompleteOptions = { types: ['(cities)', 'airport'] }; // Hero Search new google.maps.places.Autocomplete(document.getElementById('from-input'), autocompleteOptions); new google.maps.places.Autocomplete(document.getElementById('to-input'), autocompleteOptions); // Tracker Search new google.maps.places.Autocomplete(document.getElementById('tracker-from-input'), autocompleteOptions); new google.maps.places.Autocomplete(document.getElementById('tracker-to-input'), autocompleteOptions); // Predictor Search new google.maps.places.Autocomplete(document.getElementById('predictor-from-input'), autocompleteOptions); new google.maps.places.Autocomplete(document.getElementById('predictor-to-input'), autocompleteOptions); // Other Searches new google.maps.places.Autocomplete(document.getElementById('hotel-location-input'), { types: ['(cities)'] }); new google.maps.places.Autocomplete(document.getElementById('hostel-location-input'), { types: ['(cities)'] }); new google.maps.places.Autocomplete(document.getElementById('car-pickup-location-input'), { types: ['(cities)', 'airport'] }); } // --- 2. AMADEUS API FLIGHT LOGIC --- async function getAmadeusToken() { // Note: This is a client-side token request for demonstration. // In production, this should be handled server-side to protect your API Secret. if (amadeusAccessToken) return amadeusAccessToken; try { const response = await fetch('https://test.api.amadeus.com/v1/security/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `grant_type=client_credentials&client_id=${AMADEUS_API_KEY}&client_secret=${AMADEUS_API_SECRET}` }); const data = await response.json(); amadeusAccessToken = data.access_token; setTimeout(() => { amadeusAccessToken = null; }, (data.expires_in - 300) * 1000); return amadeusAccessToken; } catch (error) { console.error("Amadeus Auth Error:", error); return null; } } async function getIataCode(place) { // This is a simplified function. A real implementation would use Google's Geocoding API // or a dedicated IATA code lookup service to convert the place name to a code. // For now, we will return a placeholder or extract from input if possible. console.warn("getIataCode is a placeholder. You need to implement a real IATA lookup."); return "LHR"; // Placeholder } // --- 3. DYNAMIC SEARCH FUNCTIONS --- async function searchDeals() { // This function will now power the main hero search showAudienceTab('all-travel', document.getElementById('all-travel-btn')); const fromInput = document.getElementById('from-input').value; const toInput = document.getElementById('to-input').value; const dateInput = document.getElementById('date-input').value; const dealsGrid = document.getElementById('deals-grid'); if (!fromInput || !toInput || !dateInput) { alert("Please provide an origin, destination, and departure date."); return; } dealsGrid.innerHTML = '

✈️ Searching for flights...

'; // In a real application, you would convert user-friendly names to IATA codes here. const originIata = await getIataCode(fromInput); const destinationIata = await getIataCode(toInput); const token = await getAmadeusToken(); if (!token) { dealsGrid.innerHTML = '

Could not connect to flight service. Please try again later.

'; return; } try { const url = `https://test.api.amadeus.com/v2/shopping/flight-offers?originLocationCode=${originIata}&destinationLocationCode=${destinationIata}&departureDate=${dateInput}&adults=1&nonStop=false&max=6`; const response = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` }}); if (!response.ok) throw new Error(`API Error: ${response.statusText}`); const data = await response.json(); if (data.data.length === 0) { dealsGrid.innerHTML = '

No flights found for this route. Please try another search.

'; return; } // Generate dynamic Travelpayout affiliate links const aviasalesLink = `https://www.travelpayouts.com/click?shmarker=${TRAVELPAYOUTS_MARKER}&promo_id=4047&origin_iata=${originIata}&destination_iata=${destinationIata}&trip_class=0&adults=1&with_request=true`; grid.innerHTML = data.data.map(deal => `

${deal.itineraries[0].segments[0].departure.iataCode} → ${deal.itineraries[0].segments.slice(-1)[0].arrival.iataCode}

${deal.itineraries[0].segments.length - 1} stop(s) via ${deal.validatingAirlineCodes[0]}

$${deal.price.total}

View Deal →
`).join(''); } catch (error) { console.error("Flight Search Error:", error); dealsGrid.innerHTML = '

An error occurred while searching for flights.

'; } } function searchHotels() { const location = document.getElementById('hotel-location-input').value; if (!location) { alert("Please enter a city or hotel name."); return; } const url = `https://search.hotellook.com/?marker=${TRAVELPAYOUTS_MARKER}&destination=${encodeURIComponent(location)}&language=en`; window.open(url, '_blank'); } function searchHostels() { const location = document.getElementById('hostel-location-input').value; if (!location) { alert("Please enter a city."); return; } // Hotellook is also used for hostels const url = `https://search.hotellook.com/?marker=${TRAVELPAYOUTS_MARKER}&destination=${encodeURIComponent(location)}&language=en`; window.open(url, '_blank'); } function searchCars() { const location = document.getElementById('car-pickup-location-input').value; if (!location) { alert("Please enter a pick-up location."); return; } // Using EconomyBookings.com link from Travelpayout const url = `https://www.travelpayouts.com/click?shmarker=${TRAVELPAYOUTS_MARKER}&promo_id=1415&source_type=link&type=click&trs=201555`; window.open(url, '_blank'); // Note: For a better user experience, you'd find a way to pass the 'location' to the partner site. } function setPriceAlert() { const from = document.getElementById('tracker-from-input').value; const to = document.getElementById('tracker-to-input').value; if (!from || !to) { alert("Please enter an origin and destination for the price alert."); return; } alert(`Price alert for ${from} to ${to} has been set! (This is a demo).`); // Here you would integrate with Amadeus's Flight Price Analysis API or a similar service. } function getPricePrediction() { const from = document.getElementById('predictor-from-input').value; const to = document.getElementById('predictor-to-input').value; const date = document.getElementById('predictor-date-input').value; const container = document.getElementById('prediction-result-container'); if (!from || !to || !date) { alert("Please enter all fields for a prediction."); return; } container.innerHTML = `

🔮 Analyzing historical data for ${from} to ${to}...

`; // This is where you would call your historical data API (e.g., Tefaa or Amadeus). // For this demo, we'll simulate a result. setTimeout(() => { const shouldBuy = Math.random() > 0.5; const confidence = Math.floor(Math.random() * (95 - 75 + 1) + 75); if (shouldBuy) { container.innerHTML = `

Good time to Buy!

Our analysis of historical data suggests prices are lower than average. We are ${confidence}% confident in this prediction.

`; } else { container.innerHTML = `

Consider Waiting.

Prices are currently higher than usual for this route. It may be better to track prices. We are ${confidence}% confident in this prediction.

`; } }, 2000); }

Best Europe Backpacking Trip Guide: The Value Traveler’s Bible

Summary: The ROI Reality Check The Full Value Breakdown Look, I’m about to save you from becoming another American tourist hemorrhaging money across Europe while missing everything that actually matters. After 312 nights in European hostels, 47 countries conquered, and enough spreadsheet data to make Excel cry, I’ve cracked the code on the best Europe … Read more

Cheap Countries to Travel: 30 Cheapest Destinations in 2025 – The Data-Driven Reality Check

Summary: The ROI Reality Check The Full Value Breakdown Look, I’m about to destroy every bullshit “budget travel” article you’ve ever read. You know the ones—written by trust fund kids who think $100/day is “roughing it” or bloggers who visited Thailand for two weeks and suddenly became budget experts. After tracking every cent across 47 … Read more

Digital Nomad Visa:

Digital Nomad Visa Guide 2025: Costs, Requirements & ROI Analysis Key Takeaways • Digital nomad visas range from free (Georgia) to $3,000 (Antigua) with 2-8 week payback periods • Income requirements: $3,000-$5,000/month opens 80% of viable options • Geographic arbitrage can save $50,000-70,000 annually vs. high-cost cities • Tax optimization strategies can reduce effective rates … Read more