✈️
Flights
One way
Return
Multi-city
Date Flexibility
Exact dates only
± 1 Day
± 2 Days
± 3 Days
± 5 Days
Cabin class
Economy
Premium Economy
Business
First
+ Add Flight Leg
Search Flights
// ========================================================
// SHONAPAY FLIGHT SYSTEM ENGINE (DYNAMIC MULTI-CITY & LIVE INTERFACE)
// ========================================================
// Internal array to keep track of currently active flight legs
window.shona_flight_legs = [];
// Clean initialisation executor
document.addEventListener('DOMContentLoaded', () => {
const tOneway = document.getElementById('flightTabOneway');
const tReturn = document.getElementById('flightTabReturn');
const tMulti = document.getElementById('flightTabMulti');
const legsWrapper = document.getElementById('flightLegsWrapper');
const actionRow = document.getElementById('multiCityActionRow');
const addLegBtn = document.getElementById('addMultiCityLegBtn');
if (!legsWrapper) return;
// Default configuration: Render Return layout on load
setTripTypeMode('return');
// Tab Event listeners
if (tOneway) tOneway.addEventListener('click', () => setTripTypeMode('one-way'));
if (tReturn) tReturn.addEventListener('click', () => setTripTypeMode('return'));
if (tMulti) tMulti.addEventListener('click', () => setTripTypeMode('multi-city'));
if (addLegBtn) {
addLegBtn.addEventListener('click', () => {
if (window.shona_flight_legs.length < 5) { // Cap at a maximum of 5 legs for stability
appendNewFlightLegRow(window.shona_flight_legs.length, true);
}
});
}
function setTripTypeMode(type) {
window.shona_current_trip_mode = type;
legsWrapper.innerHTML = '';
window.shona_flight_legs = [];
// Tab highlight synchronisation
[tOneway, tReturn, tMulti].forEach(tab => {
if (tab) {
tab.classList.remove('active');
tab.style.background = 'transparent';
tab.style.color = 'var(--gray)';
}
});
if (type === 'one-way') {
tOneway.classList.add('active');
tOneway.style.background = 'var(--white)';
tOneway.style.color = 'var(--dark)';
actionRow.style.display = 'none';
appendNewFlightLegRow(0, false);
} else if (type === 'return') {
tReturn.classList.add('active');
tReturn.style.background = 'var(--white)';
tReturn.style.color = 'var(--dark)';
actionRow.style.display = 'none';
appendNewFlightLegRow(0, true);
} else if (type === 'multi-city') {
tMulti.classList.add('active');
tMulti.style.background = 'var(--white)';
tMulti.style.color = 'var(--dark)';
actionRow.style.display = 'block';
appendNewFlightLegRow(0, false);
appendNewFlightLegRow(1, false); // Multi-city requires at least two rows to start
}
}
// Dynamic Element Injection Worker
function appendNewFlightLegRow(index, includeReturnDate = false) {
const legId = `leg_${Date.now()}_${index}`;
const rowHTML = `
${index > 0 ? `
✕ Remove ` : ''}
Flight Leg ${index + 1}
`;
legsWrapper.insertAdjacentHTML('beforeend', rowHTML);
// Register newly appended records into state tracking data arrays
const legRecord = { id: legId, originIata: '', destIata: '' };
window.shona_flight_legs.push(legRecord);
// Bind Live Autocomplete listeners dynamically
setupLiveSearchListeners(legId, 'origin', legRecord);
setupLiveSearchListeners(legId, 'dest', legRecord);
// Date Initializer defaults
const today = new Date().toISOString().split('T')[0];
document.getElementById(`date_depart_${legId}`).value = today;
if (includeReturnDate) {
document.getElementById(`date_return_${legId}`).value = today;
}
// Row removal trigger configuration
if (index > 0) {
const rowElement = document.getElementById(legId);
rowElement.querySelector('.remove-leg-btn').addEventListener('click', () => {
window.shona_flight_legs = window.shona_flight_legs.filter(l => l.id !== legId);
rowElement.remove();
renumberMultiCityLabels();
});
}
}
function renumberMultiCityLabels() {
// Keeps index counts accurate after row removals
const children = legsWrapper.children;
for (let i = 0; i < children.length; i++) {
const label = children[i].querySelector('div');
if (label && window.shona_current_trip_mode === 'multi-city') {
label.textContent = `Flight Leg ${i + 1}`;
}
}
}
// Dynamic Real-time Live Discovery Lookup API Proxy
function setupLiveSearchListeners(legId, type, legRecord) {
const input = document.getElementById(`${type}_${legId}`);
// Replace the alert block inside your Passenger Form "submit" listener with this live injection engine:
const resultsWrapper = document.getElementById('flight-results-injector');
if (resultsWrapper) {
// Reveal the container and show a sleek metasearch loader message
resultsWrapper.style.display = 'flex';
resultsWrapper.innerHTML = '
Searching live airline inventories via Duffel API...
';
// Call your local backend API proxy securely
const origin = manifest.legs[0].originIata || 'LHR';
const dest = manifest.legs[0].destIata || 'JFK';
const cabin = manifest.cabinClass || 'economy';
fetch(`/api/search-flights?origin=${origin}&destination=${dest}&cabin_class=${cabin}`)
.then(res => res.json())
.then(payload => {
resultsWrapper.innerHTML = ''; // Wipe loader text
if (!payload.data || payload.data.length === 0) {
resultsWrapper.innerHTML = '
No matching flights found.
';
return;
}
// Loop through Duffel responses and render KAYAK-mode itinerary cards directly under the form
payload.data.forEach(flight => {
const card = document.createElement('div');
// Apply elite KAYAK-inspired inline styling matching ShonaPay variables
card.style.cssText = 'background: var(--white); border: 1px solid var(--border); border-radius: 14px; padding: 14px; display: flex; flex-direction: column; gap: 10px; text-align: left; box-sizing: border-box; width: 100%;';
card.innerHTML = `
${flight.airline}
$${flight.price}
${flight.departure_time || '08:45'}
${origin}
${flight.duration || '7h 45m'}
Direct
${flight.arrival_time || '16:30'}
${dest}
Select Journey
`;
resultsWrapper.appendChild(card);
});
})
.catch(err => {
console.error("Duffel Search Pipeline Error: ", err);
resultsWrapper.innerHTML = '
Unable to fetch inventories. Try again later.
';
});
}
// 3. SHONAPAY MANIFEST MODAL & FORM INTERCEPT LOGIC
document.addEventListener('DOMContentLoaded', () => {
const searchFlightsBtn = document.getElementById('searchFlightsBtn');
const modalContainer = document.getElementById('shonaBookingModal');
const closeModalBtn = document.getElementById('closeShonaModalBtn');
const passengerForm = document.getElementById('shonaPassengerForm');
const summaryInput = document.getElementById('flightTravellerSummary');
const popupDropdown = document.getElementById('flightTravellerDropdown');
const textAdults = document.getElementById('countAdults');
const textChildren = document.getElementById('countChildren');
if (summaryInput && popupDropdown) {
summaryInput.addEventListener('click', (e) => { e.stopPropagation(); popupDropdown.style.display = 'block'; });
function updateSummary() {
const total = (parseInt(textAdults.value) || 1) + (parseInt(textChildren.value) || 0);
summaryInput.value = total === 1 ? "1 Traveller" : `${total} Travellers`;
window.shonapay_passenger_manifest = { adults: parseInt(textAdults.value)||1, children: parseInt(textChildren.value)||0 };
}
[textAdults, textChildren].forEach(el => { el.addEventListener('change', updateSummary); el.addEventListener('input', updateSummary); });
document.addEventListener('click', (e) => { if (!summaryInput.contains(e.target) && !popupDropdown.contains(e.target)) popupDropdown.style.display = 'none'; });
}
if (!searchFlightsBtn || !modalContainer || !closeModalBtn || !passengerForm) return;
searchFlightsBtn.addEventListener('click', (e) => {
e.preventDefault();
if (!window.shona_flight_legs || window.shona_flight_legs.length === 0) return;
let isValid = true;
window.shona_flight_legs.forEach(leg => {
const o = document.getElementById(`origin_${leg.id}`), d = document.getElementById(`dest_${leg.id}`);
if ((o && !o.value) || (d && !d.value)) isValid = false;
});
if (!isValid) { alert('Please select valid Origin and Destination details before proceeding.'); return; }
modalContainer.style.display = 'flex';
});
closeModalBtn.addEventListener('click', () => modalContainer.style.display = 'none');
modalContainer.addEventListener('click', (e) => { if (e.target === modalContainer) modalContainer.style.display = 'none'; });
passengerForm.addEventListener('submit', (e) => {
e.preventDefault();
const manifest = {
givenNames: document.getElementById('passGivenName').value,
surname: document.getElementById('passSurname').value,
dob: document.getElementById('passDob').value,
gender: document.getElementById('passGender').value,
passport: document.getElementById('passPassportNumber').value,
nationality: document.getElementById('passNationality').value.toUpperCase(),
baggage: document.getElementById('passBaggage').value,
cabinClass: document.getElementById('flightCabinClass').value,
flexibility: document.getElementById('flightDateFlexibility').value,
travellers: window.shonapay_passenger_manifest || { adults: 1, children: 0 },
legs: window.shona_flight_legs
};
window.shonapay_secured_booking = manifest;
modalContainer.style.display = 'none';
alert(`Success! Passenger manifest caught by ShonaPay ecosystem.\n\nLead Passenger: ${manifest.givenNames} ${manifest.surname}\nTotal Flight Legs: ${manifest.legs.length}\nDate Flexibility: ${manifest.flexibility === 'exact' ? 'Exact dates' : '±' + manifest.flexibility + ' days'}`);
});
});
Mobile Connect
📱 Top-up
🎁 Gift cards
Select Airtime / Data Bundle
Start top-up
Travel Data
Where do you need data?
🔍
Popular locations
🇬🇧 United Kingdom
🇺🇸 United States
🇫🇷 France
🇹🇭 Thailand
Regional eSIMs
Africa
Asia
Europe
Global Plan
Finding active data networks...
Select Plan
Medical Care
✓ English & Multi-lingual support
✓ Over 150 countries covered
✓ 24/7 Urgent assistance desk
Where do you need care?
United States
France
Thailand
Other Destination
Get Policy
Find Doctor