{"id":55,"date":"2026-09-09T01:16:47","date_gmt":"2026-09-09T01:16:47","guid":{"rendered":"http:\/\/54.253.169.125\/?page_id=55"},"modified":"2026-09-09T01:50:53","modified_gmt":"2026-09-09T01:50:53","slug":"booking","status":"publish","type":"page","link":"https:\/\/esfamhoteltuvalu.tv\/?page_id=55","title":{"rendered":"Booking"},"content":{"rendered":"    <div id=\"esfam-booking-app\" class=\"esfam-wrap\">\n      <div class=\"esfam-hero\">\n        <h2>Book Your Stay at ESFAM Hotel<\/h2>\n        <p>Check room availability and send your booking request.<\/p>\n      <\/div>\n\n      <div class=\"esfam-card\">\n        <h3>Check availability<\/h3>\n        <div class=\"esfam-grid\">\n          <div><label for=\"esfam-ci\">Check-in<\/label><input id=\"esfam-ci\" type=\"date\"><\/div>\n          <div><label for=\"esfam-co\">Check-out<\/label><input id=\"esfam-co\" type=\"date\"><\/div>\n          <div><label for=\"esfam-guests\">Guests<\/label>\n            <select id=\"esfam-guests\">\n              <option value=\"1\">1<\/option>\n              <option value=\"2\" selected>2<\/option>\n              <option value=\"3\">3<\/option>\n            <\/select>\n          <\/div>\n          <div class=\"esfam-action\"><button id=\"esfam-check\" type=\"button\">Check Rooms<\/button><\/div>\n        <\/div>\n        <div id=\"esfam-msg1\" class=\"esfam-msg\"><\/div>\n      <\/div>\n\n      <div id=\"esfam-rooms-card\" class=\"esfam-card\" style=\"display:none\">\n        <h3>Available rooms<\/h3>\n        <div id=\"esfam-rooms\" class=\"esfam-rooms\"><\/div>\n      <\/div>\n\n      <div id=\"esfam-guest-card\" class=\"esfam-card\" style=\"display:none\">\n        <h3>Your details<\/h3>\n        <div class=\"esfam-grid\">\n          <div><label for=\"esfam-name\">Full name<\/label><input id=\"esfam-name\" type=\"text\"><\/div>\n          <div><label for=\"esfam-email\">Email<\/label><input id=\"esfam-email\" type=\"email\"><\/div>\n          <div class=\"esfam-full\"><label for=\"esfam-phone\">Phone \/ WhatsApp<\/label><input id=\"esfam-phone\" type=\"text\"><\/div>\n          <div class=\"esfam-full\"><label for=\"esfam-request\">Special request<\/label><textarea id=\"esfam-request\"><\/textarea><\/div>\n        <\/div>\n\n        <div id=\"esfam-services\" class=\"esfam-services\">\n          <h3>Additional Services <span class=\"esfam-optional\">Optional<\/span><\/h3>\n          <p class=\"esfam-help\">Add a tour or rental to your booking, or leave everything unchecked to book the room only. Service dates may be different from your hotel stay.<\/p>\n\n          <label class=\"esfam-service\"><input type=\"checkbox\" id=\"esfam-svc-boat\"> <span><b>Boat Tour to Islet<\/b><small>$300 fixed<\/small><\/span><\/label>\n          <div id=\"esfam-svc-boat-fields\" class=\"esfam-service-fields\" style=\"display:none\"><label>Preferred date<\/label><input id=\"esfam-svc-boat-date\" type=\"date\"><\/div>\n\n          <label class=\"esfam-service\"><input type=\"checkbox\" id=\"esfam-svc-island\"> <span><b>Island Tour - Mainland<\/b><small>$30 fixed<\/small><\/span><\/label>\n          <div id=\"esfam-svc-island-fields\" class=\"esfam-service-fields\" style=\"display:none\"><label>Preferred date<\/label><input id=\"esfam-svc-island-date\" type=\"date\"><\/div>\n\n          <label class=\"esfam-service\"><input type=\"checkbox\" id=\"esfam-svc-scooter\"> <span><b>Motorbike \/ Scooter Rental<\/b><small>$20 per day<\/small><\/span><\/label>\n          <div id=\"esfam-svc-scooter-fields\" class=\"esfam-service-fields esfam-grid\" style=\"display:none\"><div><label>Rental start<\/label><input id=\"esfam-svc-scooter-start\" type=\"date\"><\/div><div><label>Rental end<\/label><input id=\"esfam-svc-scooter-end\" type=\"date\"><\/div><\/div>\n\n          <label class=\"esfam-service\"><input type=\"checkbox\" id=\"esfam-svc-group\"> <span><b>Group \/ Guest Tour<\/b><small>Price on request<\/small><\/span><\/label>\n          <div id=\"esfam-svc-group-fields\" class=\"esfam-service-fields\" style=\"display:none\"><label>Preferred date<\/label><input id=\"esfam-svc-group-date\" type=\"date\"><label>Notes (optional)<\/label><input id=\"esfam-svc-group-notes\" type=\"text\" placeholder=\"Tell us about your group or tour request\"><\/div>\n        <\/div>\n\n        <div id=\"esfam-summary\" class=\"esfam-summary\"><\/div>\n        <div id=\"esfam-msg2\" class=\"esfam-msg\"><\/div>\n        <button id=\"esfam-book\" type=\"button\">Send Booking Request<\/button>\n      <\/div>\n    <\/div>\n\n    <style>\n      .esfam-wrap{max-width:960px;margin:25px auto;font-family:Arial,sans-serif;color:#17343d}\n      .esfam-hero{background:linear-gradient(135deg,#073b4c,#0b6e75);color:#fff;padding:30px 22px;border-radius:18px 18px 0 0;text-align:center}\n      .esfam-hero h2{color:#fff;margin:0 0 8px;font-size:32px}\n      .esfam-hero p{margin:0;color:#fff}\n      .esfam-card{background:#fff;padding:22px;margin:0 0 18px;border:1px solid #e3eaec;border-radius:14px;box-shadow:0 8px 26px rgba(0,0,0,.06)}\n      .esfam-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}\n      .esfam-full{grid-column:1\/-1}\n      .esfam-wrap label{display:block;font-weight:700;font-size:13px;margin-bottom:6px}\n      .esfam-wrap input,.esfam-wrap select,.esfam-wrap textarea{width:100%;padding:12px;border:1px solid #ccd8dc;border-radius:9px;font:inherit}\n      .esfam-wrap textarea{min-height:90px}\n      .esfam-wrap button{width:100%;padding:13px;border:0;border-radius:10px;background:#0b6e75;color:#fff;font-weight:700;cursor:pointer}\n      .esfam-wrap button:disabled{opacity:.55;cursor:not-allowed}\n      .esfam-action{display:flex;align-items:end}\n      .esfam-rooms{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n      .esfam-room{border:2px solid #e1e8ea;border-radius:12px;padding:16px;cursor:pointer}\n      .esfam-room.selected{border-color:#0b6e75;background:#f0fbfb}\n      .esfam-room.disabled{opacity:.5;cursor:not-allowed}\n      .esfam-price{font-size:22px;font-weight:800;margin:8px 0}\n      .esfam-pill{display:inline-block;padding:5px 8px;background:#edf7f1;border-radius:999px;font-size:12px;font-weight:700}\n      .esfam-msg{display:none;margin-top:12px;padding:11px;border-radius:9px}\n      .esfam-error{display:block;background:#fff0f0;color:#891d1d}\n      .esfam-ok{display:block;background:#edf9f1;color:#165b30}\n      .esfam-loading{display:block;background:#eef5ff;color:#234f85}\n      .esfam-summary{background:#f5f9fa;border-radius:10px;padding:14px;margin:15px 0}\n      .esfam-row{display:flex;justify-content:space-between;padding:4px 0}\n      .esfam-total{font-size:20px;font-weight:800;border-top:1px solid #dce5e8;margin-top:7px;padding-top:9px}\n      .esfam-summary-heading{font-weight:800;margin-top:10px;padding-top:10px;border-top:1px solid #dce5e8}\n      .esfam-summary-subtotal{margin-top:8px;padding-top:8px;border-top:1px solid #dce5e8}\n      .esfam-services{margin-top:20px;border-top:1px solid #e3eaec;padding-top:18px}\n      .esfam-services h3{margin:0 0 6px}.esfam-optional{font-size:11px;background:#edf7f1;padding:4px 7px;border-radius:999px}\n      .esfam-help{font-size:13px;color:#557078;margin:0 0 12px}.esfam-service{display:flex!important;align-items:center;gap:10px;padding:12px;border:1px solid #e1e8ea;border-radius:10px;margin:8px 0;cursor:pointer}\n      .esfam-service input{width:auto!important}.esfam-service span{display:flex;flex-direction:column}.esfam-service small{font-weight:400;color:#557078;margin-top:2px}\n      .esfam-service-fields{padding:4px 12px 12px}.esfam-service-fields label{margin-top:8px}\n      @media(max-width:650px){.esfam-grid,.esfam-rooms{grid-template-columns:1fr}}\n    <\/style>\n\n    <script>\n    (function() {\n      const AJAX_URL = \"https:\\\/\\\/esfamhoteltuvalu.tv\\\/wp-admin\\\/admin-ajax.php\";\n      const NONCE = \"9433d23732\";\n      let options = [];\n      let selected = null;\n      const $ = id => document.getElementById(id);\n\n      function message(id, text, cls) {\n        const e = $(id);\n        e.className = 'esfam-msg ' + cls;\n        e.textContent = text;\n        e.style.display = 'block';\n      }\n\n      function hideMessage(id) { $(id).style.display = 'none'; }\n\n      function esc(v) {\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]));\n      }\n\n      function nights() {\n        const a = new Date($('esfam-ci').value + 'T00:00:00');\n        const b = new Date($('esfam-co').value + 'T00:00:00');\n        return Math.round((b-a)\/86400000);\n      }\n\n      async function post(action, payload) {\n        const body = new URLSearchParams();\n        body.append('action', action);\n        body.append('nonce', NONCE);\n        body.append('payload', JSON.stringify(payload));\n\n        const response = await fetch(AJAX_URL, {\n          method: 'POST',\n          headers: {'Content-Type':'application\/x-www-form-urlencoded; charset=UTF-8'},\n          body: body.toString(),\n          credentials: 'same-origin'\n        });\n\n        const data = await response.json();\n        if (!data.success) {\n          throw new Error((data.data && data.data.message) ? data.data.message : 'Request failed.');\n        }\n        return data.data;\n      }\n\n      async function checkRooms() {\n        const ci = $('esfam-ci').value;\n        const co = $('esfam-co').value;\n        const guests = $('esfam-guests').value;\n\n        if (!ci || !co || co <= ci) {\n          message('esfam-msg1','Please choose valid check-in and check-out dates.','esfam-error');\n          return;\n        }\n\n        $('esfam-check').disabled = true;\n        message('esfam-msg1','Checking availability...','esfam-loading');\n\n        try {\n          options = await post('esfam_check_availability', {checkIn:ci,checkOut:co,guests:guests});\n          renderRooms();\n          hideMessage('esfam-msg1');\n        } catch (e) {\n          message('esfam-msg1',e.message,'esfam-error');\n        } finally {\n          $('esfam-check').disabled = false;\n        }\n      }\n\n      function renderRooms() {\n        const box = $('esfam-rooms');\n        box.innerHTML = '';\n        $('esfam-rooms-card').style.display = 'block';\n        $('esfam-guest-card').style.display = 'none';\n        selected = null;\n\n        if (!options.length) {\n          box.innerHTML = '<p>No room types are available for these dates.<\/p>';\n          return;\n        }\n\n        options.forEach(room => {\n          const div = document.createElement('div');\n          div.className = 'esfam-room';\n          div.dataset.key = room.code;\n          div.innerHTML =\n            '<h4>'+esc(room.type)+'<\/h4>'+\n            '<div>'+esc(room.location)+'<\/div>'+\n            '<div class=\"esfam-price\">$'+Number(room.nightlyRate).toFixed(2)+' \/ night<\/div>'+\n            '<span class=\"esfam-pill\">Available<\/span>';\n          div.addEventListener('click', () => selectRoom(room.code));\n          box.appendChild(div);\n        });\n      }\n\n      function selectRoom(key) {\n        selected = options.find(x => x.code === key);\n        document.querySelectorAll('.esfam-room').forEach(x => x.classList.toggle('selected', x.dataset.key === key));\n        $('esfam-guest-card').style.display = 'block';\n        renderSummary();\n      }\n\n      function renderSummary() {\n        if (!selected) return;\n\n        const n = nights();\n        const roomTotal = n * Number(selected.nightlyRate);\n        let servicesTotal = 0;\n        let serviceRows = '';\n        let hasServices = false;\n\n        if ($('esfam-svc-boat').checked) {\n          hasServices = true;\n          servicesTotal += 300;\n          serviceRows += '<div class=\"esfam-row\"><span>Boat Tour to Islet<\/span><b>$300.00<\/b><\/div>';\n        }\n\n        if ($('esfam-svc-island').checked) {\n          hasServices = true;\n          servicesTotal += 30;\n          serviceRows += '<div class=\"esfam-row\"><span>Island Tour - Mainland<\/span><b>$30.00<\/b><\/div>';\n        }\n\n        if ($('esfam-svc-scooter').checked) {\n          hasServices = true;\n          const a = $('esfam-svc-scooter-start').value;\n          const b = $('esfam-svc-scooter-end').value;\n          let scooterText = 'Select rental dates';\n\n          if (a && b && b >= a) {\n            const start = new Date(a + 'T00:00:00');\n            const end = new Date(b + 'T00:00:00');\n            const days = Math.floor((end - start) \/ 86400000) + 1;\n            const scooterTotal = days * 20;\n            servicesTotal += scooterTotal;\n            scooterText = days + (days === 1 ? ' day' : ' days') + ' \u00d7 $20 = $' + scooterTotal.toFixed(2);\n          }\n\n          serviceRows += '<div class=\"esfam-row\"><span>Motorbike \/ Scooter Rental<\/span><b>'+esc(scooterText)+'<\/b><\/div>';\n        }\n\n        if ($('esfam-svc-group').checked) {\n          hasServices = true;\n          serviceRows += '<div class=\"esfam-row\"><span>Group \/ Guest Tour<\/span><b>Price on request<\/b><\/div>';\n        }\n\n        let html =\n          '<div class=\"esfam-row\"><span>'+esc(selected.type)+'<\/span><b>$'+Number(selected.nightlyRate).toFixed(2)+'\/night<\/b><\/div>'+\n          '<div class=\"esfam-row\"><span>Nights<\/span><b>'+n+'<\/b><\/div>';\n\n        if (hasServices) {\n          html += '<div class=\"esfam-summary-heading\">Additional Services<\/div>' + serviceRows;\n        }\n\n        html +=\n          '<div class=\"esfam-row esfam-summary-subtotal\"><span>Room Total<\/span><b>$'+roomTotal.toFixed(2)+'<\/b><\/div>'+\n          '<div class=\"esfam-row\"><span>Services Total<\/span><b>$'+servicesTotal.toFixed(2)+'<\/b><\/div>'+\n          '<div class=\"esfam-row esfam-total\"><span>Grand Total<\/span><b>$'+(roomTotal + servicesTotal).toFixed(2)+'<\/b><\/div>';\n\n        $('esfam-summary').innerHTML = html;\n      }\n\n      function toggleService(checkId, fieldsId) {\n        const cb = $(checkId);\n        const fields = $(fieldsId);\n        fields.style.display = cb.checked ? (fields.classList.contains('esfam-grid') ? 'grid' : 'block') : 'none';\n        renderSummary();\n      }\n\n      function selectedServices() {\n        const services = [];\n        if ($('esfam-svc-boat').checked) {\n          const d = $('esfam-svc-boat-date').value;\n          if (!d) throw new Error('Please select a date for the Boat Tour to Islet.');\n          services.push({serviceId:'SERVICE-BOAT',startDate:d,endDate:'',notes:''});\n        }\n        if ($('esfam-svc-island').checked) {\n          const d = $('esfam-svc-island-date').value;\n          if (!d) throw new Error('Please select a date for the Island Tour - Mainland.');\n          services.push({serviceId:'SERVICE-ISLAND',startDate:d,endDate:'',notes:''});\n        }\n        if ($('esfam-svc-scooter').checked) {\n          const a = $('esfam-svc-scooter-start').value;\n          const b = $('esfam-svc-scooter-end').value;\n          if (!a || !b) throw new Error('Please select the scooter rental start and end dates.');\n          if (b < a) throw new Error('Scooter rental end date cannot be before the start date.');\n          services.push({serviceId:'SERVICE-SCOOTER',startDate:a,endDate:b,notes:''});\n        }\n        if ($('esfam-svc-group').checked) {\n          const d = $('esfam-svc-group-date').value;\n          if (!d) throw new Error('Please select a preferred date for the Group \/ Guest Tour.');\n          services.push({serviceId:'SERVICE-GROUP',startDate:d,endDate:'',notes:$('esfam-svc-group-notes').value.trim()});\n        }\n        return services;\n      }\n\n      async function submitBooking() {\n        if (!selected) {\n          message('esfam-msg2','Please select a room first.','esfam-error');\n          return;\n        }\n\n        let services;\n        try { services = selectedServices(); }\n        catch (e) { message('esfam-msg2',e.message,'esfam-error'); return; }\n\n        const form = {\n          guestName:$('esfam-name').value.trim(),\n          email:$('esfam-email').value.trim(),\n          phone:$('esfam-phone').value.trim(),\n          checkIn:$('esfam-ci').value,\n          checkOut:$('esfam-co').value,\n          guests:$('esfam-guests').value,\n          roomCode:selected.code,\n          specialRequest:$('esfam-request').value.trim(),\n          services:services\n        };\n\n        if (!form.guestName || !form.email || !form.phone) {\n          message('esfam-msg2','Please enter your name, email and phone number.','esfam-error');\n          return;\n        }\n\n        const btn = $('esfam-book');\n        btn.disabled = true;\n        message('esfam-msg2','Sending booking request...','esfam-loading');\n\n        try {\n          const r = await post('esfam_submit_booking', form);\n          message('esfam-msg2',\n            'Booking request received successfully. Booking ID: '+r.bookingId+\n            '. Grand Total: $'+Number(r.grandTotal != null ? r.grandTotal : r.total).toFixed(2)+\n            '. Status: '+(r.status || 'Pending')+'. ESFAM Hotel will review your request.',\n            'esfam-ok'\n          );\n          btn.style.display = 'none';\n        } catch (e) {\n          message('esfam-msg2',e.message,'esfam-error');\n          btn.disabled = false;\n        }\n      }\n\n      document.addEventListener('DOMContentLoaded', function() {\n        const today = new Date().toISOString().slice(0,10);\n        $('esfam-ci').min = today;\n        $('esfam-co').min = today;\n        $('esfam-check').addEventListener('click', checkRooms);\n        $('esfam-svc-boat').addEventListener('change', () => toggleService('esfam-svc-boat','esfam-svc-boat-fields'));\n        $('esfam-svc-island').addEventListener('change', () => toggleService('esfam-svc-island','esfam-svc-island-fields'));\n        $('esfam-svc-scooter').addEventListener('change', () => toggleService('esfam-svc-scooter','esfam-svc-scooter-fields'));\n        $('esfam-svc-group').addEventListener('change', () => toggleService('esfam-svc-group','esfam-svc-group-fields'));\n        ['esfam-svc-boat-date','esfam-svc-island-date','esfam-svc-scooter-start','esfam-svc-scooter-end','esfam-svc-group-date'].forEach(function(id) {\n          $(id).addEventListener('change', renderSummary);\n        });\n        $('esfam-book').addEventListener('click', submitBooking);\n      });\n    })();\n    <\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-55","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/pages\/55","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=55"}],"version-history":[{"count":2,"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/pages\/55\/revisions"}],"predecessor-version":[{"id":59,"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=\/wp\/v2\/pages\/55\/revisions\/59"}],"wp:attachment":[{"href":"https:\/\/esfamhoteltuvalu.tv\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}