muo
`; }
let _sharedHTML = ''; function openShare() { const name=plan.name||'My Trip Plan'; const f=plan.cities.reduce((a,c)=>a+c.items.filter(i=>i.type==='flight').length,0); const p=plan.cities.reduce((a,c)=>a+c.items.filter(i=>i.type==='place').length,0); const tot=calcPlanTotal(); $('#sh-name').textContent=name; $('#sh-meta').textContent=`${plan.cities.length} cities · ${f} flights${tot>0?' · BDT '+tot.toLocaleString():''}`; $('#sh-cities').textContent=plan.cities.length; $('#sh-flights').textContent=f; $('#sh-places').textContent=p; _sharedHTML=buildShareHTML(); $('#share-preview').textContent=_sharedHTML.substring(0,500)+'…\n[Full standalone HTML with all links]'; $('#share-modal').classList.add('open'); } ['#btn-share','#btn-share-2'].forEach(id=>{ const el=$(id); if(el) el.onclick=openShare; }); $('#share-close').onclick=()=>$('#share-modal').classList.remove('open'); $('#share-modal').onclick=e=>{ if(e.target===$('#share-modal'))$('#share-modal').classList.remove('open'); }; $('#share-dl').onclick=()=>{ const b=new Blob([_sharedHTML],{type:'text/html'}); Object.assign(document.createElement('a'),{href:URL.createObjectURL(b),download:(plan.name||'trip').replace(/\s+/g,'-')+'.html'}).click(); }; $('#share-copy-html').onclick=async()=>{ try{await navigator.clipboard.writeText(_sharedHTML);toast('HTML copied ✓');}catch{alert('Copy failed');} }; $('#share-json').onclick=async()=>{ try{await navigator.clipboard.writeText(JSON.stringify({plan,itin},null,2));toast('JSON copied ✓');}catch{alert('Copy failed');} };
// ══════════════════════════════════════ // CALC // ══════════════════════════════════════ function calcBDT(v){ return 'BDT '+(v*124*1.01).toLocaleString('en-US',{minimumFractionDigits:2}); } $('#usd-inp').oninput=e=>{ $('#calc-res').textContent=calcBDT(parseFloat(e.target.value)||0); }; $('#usd-inp2').oninput=e=>{ $('#calc-res2').textContent=calcBDT(parseFloat(e.target.value)||0); };
// ══════════════════════════════════════ // SEARCH-PAGE ITINERARY MIRROR // (same data source as main itin page) // ══════════════════════════════════════ function renderItin2() { const list = $('#itin-list2'); if(!list) return; list.innerHTML = ''; let total = 0; if (!itin.items.length) { list.innerHTML = '
'; $('#itin-total2').textContent = 'BDT 0.00'; return; } const PC = {Skyscanner:'p-sky',Gozayan:'p-goz',ShareTrip:'p-st',TripCom:'p-trip',Tripzao:'p-fnt'}; itin.items.forEach((item, idx) => { const div = document.createElement('div'); if (item.type === 'note') { div.className = 'itin-item itin-note-item'; div.innerHTML = `
`; } else { const links = buildLinks(item); const rt=item.type==='rt',mc=item.type==='mc'; const tbg=mc?'#EDE9FE':rt?'#D1FAE5':'#DBEAFE'; const tcl=mc?'#6D28D9':rt?'#065F46':'#1D4ED8'; const tlbl=mc?'Multi-City':rt?'Return':'One-Way'; const route=mc?item.segments.map(s=>`${s.from}→${s.to}`).join(' · '):`${item.from} ${rt?'↔':'→'} ${item.to}`; const dm=mc?item.segments.map(s=>s.date).join(' · '):`${item.date}${rt?' – '+item.retDate:''}`; const px=`${item.pax.adt}A${+item.pax.chd?','+item.pax.chd+'C':''}${+item.pax.inf?','+item.pax.inf+'I':''}`; const pb=Object.entries(links).map(([k,u])=>`${k} ↗`).join(''); div.className='itin-item'; div.innerHTML=`
`; total += (+item.flightPrice||0)+(+item.hotelPrice||0); } list.appendChild(div); }); $('#itin-total2').textContent = 'BDT '+total.toLocaleString('en-US',{minimumFractionDigits:2}); $$('[data-del2]').forEach(b=>b.onclick=()=>{ itin.items.splice(+b.dataset.del2,1); renderItin(); renderItin2(); }); $$('.open-all2').forEach(b=>b.onclick=()=>openAll(buildLinks(itin.items[+b.dataset.idx]))); $$('.price-inp2').forEach(i=>i.oninput=e=>{ itin.items[+e.target.dataset.idx][e.target.dataset.field]=e.target.value; let t=0; itin.items.forEach(it=>{ if(it.type!=='note') t+=(+it.flightPrice||0)+(+it.hotelPrice||0); }); $('#itin-total2').textContent='BDT '+t.toLocaleString('en-US',{minimumFractionDigits:2}); $('#itin-total').textContent='BDT '+t.toLocaleString('en-US',{minimumFractionDigits:2}); }); }
// Patch existing add buttons to also update mirror — handled in the search events block above.
$('#itin-note-btn2').onclick = ()=>{ const t=prompt('Note:'); if(t){itin.items.push({type:'note',text:t}); renderItin(); renderItin2();} }; $('#itin-save-btn2').onclick = ()=>{ const b=new Blob([JSON.stringify(itin)],{type:'application/json'}); Object.assign(document.createElement('a'),{href:URL.createObjectURL(b),download:'itinerary.json'}).click(); }; $('#itin-load2').onchange = e=>{ const f=e.target.files[0]; if(!f)return; const r=new FileReader(); r.onload=ev=>{try{itin=JSON.parse(ev.target.result); renderItin(); renderItin2();}catch{alert('Invalid JSON');}}; r.readAsText(f); }; $('#itin-clear-btn2').onclick = ()=>{ if(confirm('Clear all?')){itin.items=[]; renderItin(); renderItin2();} }; $('#itin-print-btn2').onclick = ()=>{ window.print(); };
// ══════════════════════════════════════ // B2B SECRET SYSTEM // Click logo 5× to activate B2B mode // ══════════════════════════════════════ let b2bActive = false; let b2bTaps = 0; let b2bTimer;
// B2B toggle button (hidden until activated) const b2bBtn = document.createElement('button'); b2bBtn.id = 'b2b-toggle'; b2bBtn.className = 'nav-item'; b2bBtn.innerHTML = ' B2B Mode: OFF'; b2bBtn.style.cssText = 'display:none;background:rgba(251,191,36,.1);border:1px solid rgba(251,191,36,.2);color:#FBBF24;margin-top:8px'; document.querySelector('.sb-nav').appendChild(b2bBtn);
// Secret: click the sidebar logo 5 times fast document.querySelector('.sb-logo').addEventListener('click', ()=>{ b2bTaps++; clearTimeout(b2bTimer); b2bTimer = setTimeout(()=>b2bTaps=0, 2500); if(b2bTaps >= 5) { b2bTaps = 0; b2bBtn.style.display = 'flex'; toast('🔑 B2B Panel unlocked'); } });
b2bBtn.onclick = ()=>{ b2bActive = !b2bActive; b2bBtn.innerHTML = ` B2B Mode: ${b2bActive?'ON':'OFF'}`; b2bBtn.style.background = b2bActive ? 'rgba(251,191,36,.2)' : 'rgba(251,191,36,.1)'; renderItin(); renderItin2(); toast(b2bActive ? '🟡 B2B ON — TicketLagbe & uk.trip.com active' : '⚫ B2B Mode OFF'); }; // B2B logic (uk.trip.com + TicketLagbe) is baked into buildLinks() — no override needed here.
// ══════════════════════════════════════ // VLOG TRIP PLANNER BLOCKS // ══════════════════════════════════════ // Add "Vlog Block" button to planner header actions const vlogBtn = document.createElement('button'); vlogBtn.className = 'th-btn'; vlogBtn.id = 'add-vlog-btn'; vlogBtn.innerHTML = '📝 Vlog Block'; document.querySelector('.trip-hdr-actions').appendChild(vlogBtn);
$('#add-vlog-btn').onclick = ()=>openVlogPanel();
function openVlogPanel(cityIdx) { // Close other panels first ['flight','hotel','place','note'].forEach(p=>{ const el=$(`#panel-${p}`); if(el) el.style.display='none'; }); let vp = $('#panel-vlog'); if(!vp) { vp = document.createElement('div'); vp.id = 'panel-vlog'; vp.className = 'add-panel'; vp.style.cssText = 'box-shadow:0 0 0 4px #F3E8FF,0 8px 24px rgba(0,0,0,.06)'; vp.innerHTML = `
`; // Insert before the planner-cities div const pc = $('#planner-cities'); pc.parentNode.insertBefore(vp, pc); } updateCitySels(); // Sync city select options to vb-city const opts = plan.cities.map((c,i)=>``).join(''); $('#vb-city').innerHTML = opts || ''; if(cityIdx!==undefined) $('#vb-city').value = cityIdx; vp.style.display = 'block'; vp.scrollIntoView({behavior:'smooth',block:'nearest'});
$('#vb-cancel').onclick = ()=>{ vp.style.display='none'; }; $('#vb-save').onclick = ()=>{ const ci = +$('#vb-city').value; if(!plan.cities[ci]){toast('Select a city');return;} const heading = $('#vb-heading').value.trim(); const text = $('#vb-text').value.trim(); if(!text && !heading){toast('Enter some text for the vlog block');return;} const item = { type:'vlog', heading, text, img: $('#vb-img').value.trim(), caption: $('#vb-caption').value.trim(), _id: uid() }; plan.cities[ci].items.push(item); ['#vb-heading','#vb-text','#vb-img','#vb-caption'].forEach(s=>{ const el=$(s); if(el) el.value=''; }); vp.style.display='none'; renderPlan(); toast('Vlog block added ✓'); }; }
// ══════════════════════════════════════ // BANGLA LANGUAGE TOGGLE // ══════════════════════════════════════ let currentLang = 'en'; const LANG = { 'page-search-title': { en:'Search Flights', bn:'ফ্লাইট সার্চ' }, 'page-search-sub': { en:'Compare 5 providers simultaneously', bn:'একসাথে ৫টি প্রোভাইডার তুলনা করুন' }, 'page-planner-title': { en:'Trip Planner', bn:'ট্রিপ প্ল্যানার' }, 'page-planner-sub': { en:'City-by-city plan with flights, hotels & tourist places', bn:'শহর অনুযায়ী ফ্লাইট, হোটেল ও দর্শনীয় স্থান' }, 'page-itinerary-title':{ en:'Quick Itinerary', bn:'দ্রুত ভ্রমণসূচি' }, 'page-itinerary-sub': { en:'Price comparison & cost tracking', bn:'মূল্য তুলনা ও খরচ ট্র্যাকিং' }, 'page-calc-title': { en:'Price Calculator', bn:'মূল্য ক্যালকুলেটর' }, 'page-calc-sub': { en:'USD to BDT with 1% service charge', bn:'USD থেকে BDT — ১% চার্জসহ' }, 'nav-search': { en:'Search Flights', bn:'ফ্লাইট সার্চ' }, 'nav-planner': { en:'Trip Planner', bn:'ট্রিপ প্ল্যানার' }, 'nav-itinerary': { en:'Quick Itinerary', bn:'ভ্রমণসূচি' }, 'nav-calc': { en:'Price Calculator', bn:'মূল্য ক্যালকুলেটর' }, 'tab-ow': { en:'One-Way', bn:'একমুখী' }, 'tab-rt': { en:'Return', bn:'রিটার্ন' }, 'tab-mc': { en:'Multi-City', bn:'মাল্টি-সিটি' }, 'lbl-ow-from': { en:'From (IATA)', bn:'কোথা থেকে' }, 'lbl-ow-to': { en:'To (IATA)', bn:'গন্তব্য' }, 'lbl-ow-date': { en:'Date', bn:'তারিখ' }, 'btn-ow-open': { en:'Search & Open', bn:'সার্চ ও খুলুন' }, 'btn-ow-add': { en:'+ Itinerary', bn:'+ সূচিতে যোগ' }, 'btn-ow-plan': { en:'→ Planner', bn:'→ প্ল্যানারে' }, 'notice-txt': { en:'Search & Open launches Skyscanner, Gozayan, ShareTrip, Trip.com & Tripzao at once. Use → Planner to build your full city-by-city trip plan.', bn:'সার্চ ও খুলুন বাটনে ক্লিক করলে Skyscanner, Gozayan, ShareTrip, Trip.com ও Tripzao একসাথে খুলবে। পূর্ণ ট্রিপ প্ল্যান বানাতে → প্ল্যানারে যান।' }, };
function applyLang(lang) { currentLang = lang; const btn = $('#lang-btn'); btn.textContent = lang === 'en' ? 'বাংলা' : 'English'; document.querySelectorAll('[data-lang]').forEach(el => { const key = el.dataset.lang; if (LANG[key] && LANG[key][lang] !== undefined) { el.innerHTML = LANG[key][lang]; } }); }
$('#lang-btn').onclick = () => applyLang(currentLang === 'en' ? 'bn' : 'en');
// ══════════════════════════════════════ // INIT // ══════════════════════════════════════ loadAirports(); new AC($('#ow-from'),$('#m-ow-from')); new AC($('#ow-to'),$('#m-ow-to')); new AC($('#rt-from'),$('#m-rt-from')); new AC($('#rt-to'),$('#m-rt-to')); new AC($('#pf-from'),$('#m-pf-from')); new AC($('#pf-to'),$('#m-pf-to')); addMCRow(); addMCRow(); renderItin(); renderItin2(); renderPlan(); $$('input[type=date]').forEach(d=>{ if(!d.min) d.min=today(); });