Skip to main content
Booking

Plan Your Maldives Experience

Tell us what you'd love to do — we'll handle the rest

1
Your Trip
2
Your Details
3
Confirm
travel_explore

Your Trip

When are you coming and what would you like to do?

calendar_today
Arrival Select date
arrow_forward
Departure Select date
1 (max 8)

Select all that apply.

person

Your Details

We'll use this to confirm your booking and stay in touch.

receipt_long

Review & Confirm

Our team will confirm within 24 hours.

Request Sent!

Our team will contact you within 24 hours to confirm your booking.

Reference
Dates
Guests
Contact
Summary
shopping_cartYour Booking
Fill in the form to see your summary
const B = (() => { 'use strict'; const ACT_LABELS = { 'fun-dive': 'Fun Dives', 'course': 'PADI Course', 'snorkeling':'Snorkeling', 'dive-stay': 'Dive & Stay Package', 'unsure': 'Not Sure Yet', }; let S = { arrDate:null, depDate:null, gc:1, acts:[], step:1 }; let calDate = new Date(); let toastTimer = null; let lastHoverDs = null; const $ = id => document.getElementById(id); const fmt = d => { if(!d)return''; const dt=new Date(d+'T12:00:00'); return dt.toLocaleDateString('en-US',{weekday:'short',month:'short',day:'numeric'}); }; const fmtL = d => { if(!d)return''; const dt=new Date(d+'T12:00:00'); return dt.toLocaleDateString('en-US',{weekday:'long',month:'long',day:'numeric',year:'numeric'}); }; const diff = (a,b) => { if(!a||!b)return 0; return Math.round((new Date(b)-new Date(a))/86400000); }; const esc = s => String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); function toast(msg, type='err') { const t=$('toast'); if(!t)return; t.textContent=msg; t.style.display='block'; t.style.background=type==='ok'?'#059669':type==='info'?'#0369a1':'#dc2626'; clearTimeout(toastTimer); toastTimer=setTimeout(()=>{t.style.display='none';},3500); } function setGC(n) { n=Math.max(1,Math.min(8,n)); S.gc=n; $('gNum').textContent=n; updateSummary(); } function openCal() { if(S.arrDate) calDate=new Date(S.arrDate+'T12:00:00'); else calDate=new Date(); calDate.setDate(1); $('calPop').classList.add('on'); renderCal(); } function renderMonth(gridId, y, m, previewEnd) { const g=$(gridId); g.innerHTML=''; const first=new Date(y,m,1).getDay(), dim=new Date(y,m+1,0).getDate(); const today=new Date(); today.setHours(0,0,0,0); for(let i=0;i${d}`; if(dtS.arrDate&&dsS.arrDate&&dsARR`; } if(ds===S.depDate){ e.classList.add('dep'); num.innerHTML+=`DEP`; } if(ds===previewEnd&&!S.depDate) e.classList.add('dep'); e.onclick=(ev)=>{ev.stopPropagation();pickDay(ds);}; } e.appendChild(num); g.appendChild(e); } } function renderCal(hoverDs) { const MONTHS=['January','February','March','April','May','June','July','August','September','October','November','December']; const y1=calDate.getFullYear(), m1=calDate.getMonth(); const d2=new Date(y1,m1+1,1), y2=d2.getFullYear(), m2=d2.getMonth(); $('calTitle1').textContent=`${MONTHS[m1]} ${y1}`; $('calTitle2').textContent=`${MONTHS[m2]} ${y2}`; const previewEnd=(!S.depDate&&S.arrDate&&hoverDs&&hoverDs>S.arrDate)?hoverDs:null; $('calPop').classList.toggle('has-rng',!!(S.arrDate&&(S.depDate||previewEnd))); const st=$('calState'); if(!S.arrDate) st.textContent='Select your arrival date'; else if(!S.depDate) st.textContent='Now select your departure date'; else st.textContent=`${fmt(S.arrDate)} → ${fmt(S.depDate)}`; renderMonth('calGrid1',y1,m1,previewEnd); renderMonth('calGrid2',y2,m2,previewEnd); const now=new Date(); now.setDate(1); now.setHours(0,0,0,0); $('calPrev').disabled=(calDate<=now); } function pickDay(ds) { lastHoverDs=null; if(!S.arrDate || S.depDate) { S.arrDate=ds; S.depDate=null; const t=$('arrTxt'); t.textContent=fmtL(ds); t.className='slot-val'; const dt=$('depTxt'); dt.textContent='Select date'; dt.className='slot-val ph'; renderCal(); } else { if(ds<=S.arrDate){ toast('Departure must be after arrival.'); return; } S.depDate=ds; const t=$('depTxt'); t.textContent=fmtL(ds); t.className='slot-val'; renderCal(); $('calPop').classList.remove('on'); } updateStaySummary(); updateSummary(); } function updateStaySummary() { if(!S.arrDate||!S.depDate){ $('staySum').style.display='none'; return; } const n=diff(S.arrDate,S.depDate); $('staySumTxt').innerHTML=`${n} night${n>1?'s':''} stay — ${fmt(S.arrDate)} → ${fmt(S.depDate)}`; $('staySum').style.display='block'; } function goStep(n) { document.querySelectorAll('.step').forEach(s=>s.classList.remove('on')); document.querySelectorAll('.pstep').forEach((s,i)=>{ s.classList.remove('on','done'); if(i+1ACT_LABELS[k]||k).join(', '); $('revContent').innerHTML=`
Arrival${fmtL(S.arrDate)}
Departure${fmtL(S.depDate)}
Stay${n} night${n>1?'s':''}
Guests${S.gc} ${S.gc===1?'person':'people'}
Activities${acts||'—'}
Name${esc($('fName').value.trim())} ${esc($('lName').value.trim())}
Email${esc($('email').value.trim())}
Phone${esc($('phone').value.trim())}
Country${esc($('country').value)}
${$('notes').value.trim()?`
Notes${esc($('notes').value.trim())}
`:''}
`; } function updateSummary() { const hasAny=S.gc>1||S.arrDate||S.acts.length; $('sumEmpty').style.display=hasAny?'none':'block'; $('sumBody').style.display=hasAny?'block':'none'; $('sGuests').textContent=`${S.gc} ${S.gc===1?'person':'people'}`; if(S.arrDate&&S.depDate){ const n=diff(S.arrDate,S.depDate); $('sArr').textContent=fmt(S.arrDate); $('sDep').textContent=fmt(S.depDate); $('sNights').textContent=`${n} night${n>1?'s':''}`; $('sDates').style.display='block'; } else { $('sDates').style.display='none'; } if(S.acts.length){ $('sActList').innerHTML=S.acts.map(k=>`
${ACT_LABELS[k]||k}
`).join(''); $('sActSec').style.display='block'; } else { $('sActSec').style.display='none'; } } function submit() { if(!$('termsCb').checked){ $('termsErr').style.display='flex'; return; } $('termsErr').style.display='none'; const ref='RK-'+Date.now().toString(36).toUpperCase(); const fn=$('fName').value.trim(), ln=$('lName').value.trim(); $('sucRef').textContent=ref; $('sucDates').textContent=`${fmt(S.arrDate)} - ${fmt(S.depDate)}`; $('sucGuests').textContent=`${S.gc} ${S.gc===1?'person':'people'}`; $('sucName').textContent=`${fn} ${ln}`; goStep(4); } function init() { $('gMinus').onclick=()=>setGC(S.gc-1); $('gPlus').onclick=()=>setGC(S.gc+1); $('calPrev').onclick=()=>{calDate.setMonth(calDate.getMonth()-1);renderCal();}; $('calNext').onclick=()=>{calDate.setMonth(calDate.getMonth()+1);renderCal();}; ['calGrid1','calGrid2'].forEach(id=>{ $(id).addEventListener('mouseover', e=>{ if(!S.arrDate||S.depDate) return; const day=e.target.closest('.cday[data-ds]'); if(day&&day.dataset.ds!==lastHoverDs){ lastHoverDs=day.dataset.ds; renderCal(lastHoverDs); } }); $(id).addEventListener('mouseleave', ()=>{ if(lastHoverDs){ lastHoverDs=null; if(S.arrDate&&!S.depDate) renderCal(); } }); }); document.querySelectorAll('.act-pill').forEach(btn=>{ btn.onclick=()=>{ const k=btn.dataset.act; const idx=S.acts.indexOf(k); if(idx>=0) S.acts.splice(idx,1); else S.acts.push(k); btn.classList.toggle('on', S.acts.includes(k)); if(S.acts.length) $('actErr').style.display='none'; updateSummary(); }; }); $('s1Next').onclick=()=>{ if(validate1()) goStep(2); }; $('s2Next').onclick=()=>{ if(validate2()){ buildReview(); goStep(3); } }; $('submitBtn').onclick=submit; document.addEventListener('click', e=>{ const pop=$('calPop'); if(pop&&pop.classList.contains('on')&&!pop.contains(e.target)&&!e.target.closest('.date-range-bar')) pop.classList.remove('on'); }); updateSummary(); } return { init, openCal, goStep }; })(); document.addEventListener('DOMContentLoaded', ()=>B.init());