// --- 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); }

Family Travel

Sarah’s Family Travel Guides & Tools – Endless Travel Plans
Portrait of Sarah Chen-Anderson

The Family Travel Expert

Creating Magical Memories, One Trip at a Time.

Welcome! My guides are designed to make family travel joyful and stress-free. From all-inclusive resort reviews to kid-friendly itineraries, you’ll find everything you need to plan your next great family adventure.

Sarah’s Custom Family Travel Tools

Use my interactive tools to get personalized recommendations and discover the perfect destination for your family’s next adventure.

Family Trip Planner

Get personalized recommendations for your family adventure. Tell me about your family and I’ll create the perfect itinerary.

Your Family Details

Your Family Travel Plan

Recommended Activities 12
Family-Friendly Rating 9.5/10
Estimated Budget $4,200
Personalized Recommendations

Family Destination Explorer

Discover destinations curated for multi-generational travel. Compare options to find the perfect match for your family.

Get the Best Travel Deals & Tips

Join our free newsletter for expert advice, exclusive deals, and travel inspiration delivered straight to your inbox.

EndlessTravel

Your expert guides to smarter travel.

Newsletter

Get the best deals and tips. Subscribe now.

Affiliate Disclosure: This site contains affiliate links, which means we may receive a commission if you click a link and purchase something that we have recommended. While clicking these links won’t cost you any extra money, they will help us keep this site up and running! Thank you for your support!

© 2024 Endless Travel Plans. All Rights Reserved.