const SELFBOOK_BASE_URL="https://sdk.selfbook.com",SELFBOOK_BASE_URL_V3="https://sdk-v3.selfbook.com",SELFBOOK_BASE_URL_LAYERS="%REACT_APP_SELFBOOK_BASE_URL_LAYERS%";let SELFBOOK_BACKEND_URL="https://api.selfbook.com/api/v2",SELFBOOK_BACKEND_URL_V3="https://api.selfbook.com/api/v3";const STATSIG_CLIENT_KEY="client-PV01TCjBc3a7zunh9brJUh2fIaLwbXaH7aQH2dFpSGW",STATSIG_EXPERIMENT="ddn",STATSIGN_SIGNAL_BOX_EXPERIMENT="ddn_signal_box";let SELFBOOK_APP_VERSION="v2",SELFBOOK_APP_BASE_URL=SELFBOOK_BASE_URL;const SELFBOOK_SCRIPT_ID="selfbook_jssdk",SELFBOOK_HOTEL_ID_PROP="hotelId",SELFBOOK_API_KEY_PROP="apiKey",SELFBOOK_WIDGET_ELEMENT_ID="selfbook_sdkwidget",SELFBOOK_WIDGET_WRAPPER_ELEMENT_ID="selfbook_sdkwidget_wrapper",SELFBOOK_WIDGET_LOADING_ELEMENT="selfbook-loading",IS_LANDING_PAGE_FLAG_ID="ddnLandingPage",BOOTSTRAP_ACTION="WIDGET/BOOTSTRAP",SELFBOOK_HOTEL_GROUP_INFO="selfbook_hotel_group_info",SELFBOOK_HOTEL_INFO="selfbook_hotel_info";window.selfbookStatsigClient=null;const BLACK_SQUARE_THEME_HOTELS=["6739"],THE_LINE_HOTELS=["68711","71661","2427"],COMPLETE_BOOKING_BTN_CLICK="Complete your reservation button click",ROUTE_PATHS={app:{confirmation:"/confirmation",wallet:"/wallet",account:"/account",settings:"/settings",reservations:"/reservations",reservationDetail:"/reservation-detail",editBooking:"/edit-booking",bookingConfirmed:"/booking-confirmed"}},INITIAL_PERSISTED_DATA={isExpired:!0,all:null,booking:null,core:null,router:null},GUEST_TYPE={ADULT:"adult",CHILD:"child",INFANT:"infants"};let initialV35AvailabilityStartEndDates={},initialCalendarResponse=null;function setOverflowHidden(e){const t=e?"hidden":"";document.body.style.overflow=t,document.documentElement.style.overflow=t}function getStatsigValue(e,t){if(window.selfbookStatsigClient){const n=window.selfbookStatsigClient.getExperiment(e);return n&&n.value&&n.value[t]}return null}const SUPPORTED_LOCALES=["en","fr","pt","da","de","de-DE","es-MX","it","ja","ko","nl","ro","ru","sq","sv","vi","zh","zh-CN","zh-TW","es"];function parseLocaleFromUrl(){try{const{pathname:e}=new URL(window.location.href),t=e.split("/").filter(Boolean),n=t[0]?.toLowerCase();if(!n)return null;if(!/^[a-z]{2}(-[a-z]{2})?$/i.test(n))return null;const o=n.replace(/^([a-z]{2})(-[a-z]{2})?$/i,(e,t,n)=>n?`${t.toLowerCase()}-${n.slice(1).toUpperCase()}`:t.toLowerCase());return SUPPORTED_LOCALES.includes(o)?o:"en"}catch{return null}}function appendWidgetScript({src:e,callback:t,type:n="text/javascript"}){const o=document.createElement("script");o.type=n,o.src=e,document.body.appendChild(o),t&&"function"==typeof t&&(o.onload=function(){t()})}function initFloatingSearchbar({apiKey:e,hotelId:t}={}){appendWidgetScript({src:`${SELFBOOK_BASE_URL_V3}/widgets/floating-search-bar.js`,type:"module",callback:function(){const n=SELFBOOK_BACKEND_URL.replace(/\/v[123]/,"");window.renderWidget(null,{backendURL:n,hotelId:t,apiKey:e})}})}function initDDNSignalBox({signalPartner:e,apiKey:t,hotelId:n}={}){e&&"none"!==e&&appendWidgetScript({src:`${SELFBOOK_BASE_URL_V3}/widgets/ddn-signal-box.js`,callback:function(){const o=SELFBOOK_BACKEND_URL.replace(/\/v[123]/,"");window.renderSBSignalBox({backendURL:o,hotelId:n,apiKey:t,ddn_signal_partner:e,experiment:"ddn_signal_box",locale:parseLocaleFromUrl()})}})}function initWidgets({apiKey:e,hotelId:t,hotelData:n}){if(n?.enable_direct_distribution_network&&(n?.enable_paypal_partner&&n?.enable_paypal||n?.enable_perplexity_partner)){initDDNSignalBox({signalPartner:getStatsigValue("ddn_signal_box","ddn_signal_partner"),apiKey:e,hotelId:t})}}function initSDKBus(){const e={},t={};window.sb_sdkBus={emit(n,o){t[n]||(t[n]=[]),t[n].push(o),e[n]?.length&&e[n].forEach(e=>e(o))},on(t,n){e[t]||(e[t]=[]),e[t].push(n)},off(t,n){e[t]&&(e[t]=e[t].filter(e=>e!==n))},pull(e){const n=t[e]||[];return t[e]=[],n}}}function checkStatus(e){if(e.status>=200&&e.status<300)return e;const t=new Error(e.statusText);throw t.response=e,t}async function parseJSON(e){try{const t=await e.text();if(!t)return;return JSON.parse(t)}catch(e){console.error("parseJSON: err: ",e)}}function intervalWrapper(e,t){const n=setInterval(e,t);return function(){clearInterval(n)}}function getHotelBasicData(e){try{const t=getFromSessionStorage(SELFBOOK_HOTEL_GROUP_INFO).hotels?.filter(t=>t.id==e),n=t?.[0]||{};return getIsEnableV35(n)&&(n.app_version="v3",n.enable_v3_new_ui_version=!0),n}catch(e){return console.error("getHotelBasicData: err: ",e),{}}}function getFromSessionStorage(e){try{return JSON.parse(sessionStorage.getItem(e))}catch(e){return console.error("getFromSessionStorage: err: ",{e:e}),{}}}function getPersistedData(e){try{const t=JSON.parse(e.getItem("persist:root"));if(!t)return INITIAL_PERSISTED_DATA;const n=JSON.parse(t.booking||"{}"),o=JSON.parse(t.core||"{}"),a=JSON.parse(t?.router||"{}"),{expireTime:r}=o,s=(Date.now()-new Date(o.interactionTime))/1e3;return{isExpired:s>r,all:t,booking:n,core:o,router:a}}catch(e){return console.error("getPersistedData: err: ",e),INITIAL_PERSISTED_DATA}}function fillGuestsFields(e=[],t){const n=t.default_adult_occupancy?t.default_adult_occupancy:2;return e?.map(e=>e.type===GUEST_TYPE.ADULT?{type:GUEST_TYPE.ADULT,count:parseInt(e.count)||n}:e.type===GUEST_TYPE.CHILD&&parseInt(e.count)>0?{type:GUEST_TYPE.CHILD,count:parseInt(e.count),age:parseInt(e.age)||1,special_request:e.special_request||""}:e.type===GUEST_TYPE.INFANT&&parseInt(e.count)>0?{type:GUEST_TYPE.INFANT,count:parseInt(e.count)||1,age:parseInt(e.age)||1,special_request:e.special_request||""}:void 0).filter(Boolean)}function buildRoomsGuests(e,t){const n=t.default_adult_occupancy?t.default_adult_occupancy:2,o=()=>Math.random().toString(36).slice(2),a=["adult","child","childAges","room2Adult","room3Adult","room4Adult"].some(t=>!!e[t]);if(e.guests?.length&&!a)return Array.from({length:4},(t,a)=>{const r=0===a?"guests":`guestsRoom${a+1}`;if(!e[r])return null;const s=e[r]?.map(e=>{const t=e?.type===GUEST_TYPE.ADULT?e?.count||n:e?.count,a=e?.type===GUEST_TYPE.CHILD&&"number"==typeof e?.age;return{type:e?.type,count:Number(t),guest_details:a?[{key:o(),age:Number(e?.age)}]:void 0}});return{key:0===a?"room1":o(),data:s}}).filter(Boolean);const r=t=>Number(e[t]||0),[s,i,l,c]=["roomCount","adult","child","infants"].map(r);if(s>1&&!r("room2Adult")){const e=i||n,t=Math.floor(e/s);let a=e%s;return Array.from({length:s},(e,n)=>{const r=a>=n+1?1:0;return{key:0===n?"room1":o(),data:[{type:GUEST_TYPE.ADULT,count:t+r}]}})}const d=[];return Array.from({length:4}).forEach((t,a)=>{const s=a+1,u=0===a?i||n:r(`room${s}Adult`);if(u){const t=[{type:GUEST_TYPE.ADULT,count:u}],n=0===a?l:r(`room${s}Child`),i=e[0===a?"childAges":`room${s}ChildAges`];i?i.split(",").forEach(e=>{t.push({type:GUEST_TYPE.CHILD,count:1,guest_details:[{key:o(),age:Number(e)}]})}):n&&t.push({type:GUEST_TYPE.CHILD,count:n}),0===a&&c>0&&t.push({type:GUEST_TYPE.INFANT,count:c}),d.push({key:0===a?"room1":o(),data:t})}}),d}function buildRedirectSynxisLink(e,t){let n=`https://be.synxis.com/?hotel=${t.id}&theme=${t.synxis_theme}&config=${t.synxis_config}`;try{if(e){const{startDate:t,endDate:o,promoCode:a,groupCode:r,guests:s,iataNumber:i,couponCode:l,destinationId:c,nights:d,rate:u,hotelId:p,roomCategory:_}=e;d&&(n+=`&nights=${d}`),t&&(n+=`&arrive=${t}`),o&&(n+=`&depart=${o}`),a&&(n+=`&promo=${a}`),r&&(n+=`&group=${r}`),i&&(n+=`&iataNumber=${i}`),l&&(n+=`&couponCode=${l}`),u&&(n+=`&rate=${u}`),c&&(n+=`&destinationId=${c}`),Array.isArray(_)?n+=`&roomCategory=${_.map(e=>e).join(",")}`:_&&(n+=`&roomCategory=${_}`),s&&s.length>0?("adult"===s[0].type&&(n+=`&adult=${s[0].count}`),s[1]&&"child"===s[1].type&&(n+=`&child=${s[1].count}`)):n+="&adult=1"}}catch(e){console.error("buildRedirectSynxisLink: err: ",e)}return n}function selectShowWidgetButtonCopies(e){return e.core.showWidgetButtonCopies||{}}function selectRoute(e){return e?.router?.location?e.router.location.pathname:ROUTE_PATHS.app.editBooking}function isObjectEqual(e,t){return JSON.stringify(e)===JSON.stringify(t)}function isTemplateDomainMatch(e,t){return e?.booking_template_domain&&t?.target?.href?.includes(e.booking_template_domain)}function getElementById(e){return document?.getElementById(e)}function getIsEnableV35(e){return!!SELFBOOK_APP_VERSION.match(/^v3/i)||(e?.enable_v3_new_ui_version||!1)}function getIsLayers(e){return"layers"===e?.app_version||!!SELFBOOK_APP_VERSION.match(/^layers/i)}function runDirectApplication(){console.info("(!) selfbook: widget initialization started");let e,t,n,o=!1,a=!1,r=!1,s=!1,i=!1,l=!1,c=!1;function d(e){try{const t=document.createElement("script");if(t.innerHTML='\n !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","identify","reset","group","track","ready","alias","debug","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;ee.destination_id?.toLowerCase()===o.destinationId.toLowerCase());e&&(o.hotelId=e.id)}else o.hotelId=o?.hotelId||a?.id;if(a?.enable_direct_distribution_network&&"signalBox"!==o.userStartingPoint&&(a?.enable_paypal_partner&&a?.enable_paypal||a?.enable_perplexity_partner)){const e=getStatsigValue("ddn_signal_box","ddn_signal_partner");if("paypal"===e){const t=function(){const e=g();if(e)return"authenticated"===e?.state?.step&&!!e?.state?.identifier}();l=c?{}:{partner:e,signalBoxUserVerified:!!t,paypalData:t?y():null,shouldExecuteRegularFlow:(!t||!a?.is_default_date_logic_enabled||"single"!==i?.structure)&&s}}}}setOverflowHidden(!0),window.toggleShowSBSignalBox?.(!1);const u=getElementById("selfbook_sdkwidget"),p=getElementById("selfbook_sdkwidget_wrapper");window.selfbookWidgetStore||(p.appendChild(function(){const e=document.createElement("div");return e.id="selfbook-loading",e.style.color="white",e.style.marginRight="-50%",e.style.position="absolute",e.style.top="50%",e.style.left="50%",e.style.fontFamily="sans-serif",e.style.transform="translate(-50%, -50%)",e.innerHTML='',e}()),p.style.zIndex=2147483646,p.style.height="100%",p.style.background="v2"===SELFBOOK_APP_VERSION?"rgba(0, 0, 0, .74)":"rgba(39, 39, 39, 0.74)",setOverflowHidden(!0)),function(e){if(!0===r)return;n&&n.length>0&&n.forEach(e=>{if(e.includes(".js")){const t=document.createElement("script");t.type="text/javascript",t.src=`${SELFBOOK_APP_BASE_URL}/${e}`,document.body.appendChild(t)}});e?.enable_direct_distribution_network||d(e);r=!0}(a);const _=setInterval(()=>{if(window.selfbookWidgetStore){const n=getIsLayers(a),r={hotelInfo:{...!n&&{hotelIdAsArg:!!o.hotelId},...n&&{hotelResponse:getFromSessionStorage(SELFBOOK_HOTEL_INFO)},apiKey:o.apiKey||t,hotelId:o.hotelId||e},bookingData:{...o,...l},...!n&&{hotelGroupInfo:getFromSessionStorage(SELFBOOK_HOTEL_GROUP_INFO)},roomsGuests:o.roomsGuests||void 0,shouldExecuteRegularFlow:!1===l?.shouldExecuteRegularFlow?l?.shouldExecuteRegularFlow:s,userIP:o.userIP?.country_code?o.userIP:void 0,version:o.version,isDdnLandingPageSource:c};!function(){const e=document.getElementById("selfbook-loading");e&&getElementById("selfbook_sdkwidget_wrapper").removeChild(e)}(),clearInterval(_),window.selfbookWidgetStore.dispatch({type:BOOTSTRAP_ACTION,payload:r}),"none"===u.style.display&&(p.style.zIndex=2147483646,p.style.height="100%",p.style.background="v2"===SELFBOOK_APP_VERSION?"rgba(0, 0, 0, .74)":"rgba(39, 39, 39, 0.74)",setOverflowHidden(!0)),setTimeout(()=>{u.style.display="block",u.setAttribute("class","slide-in")},20),setTimeout(()=>{const e=p.querySelector('[aria-modal="true"]');e&&e.focus()},250)}},100)}function _(){try{const{isExpired:e,core:t,booking:n}=getPersistedData(localStorage);if(e||!t?.hotel?.data?.id)return void function(){try{localStorage.removeItem("persist:root")}catch(e){console.error("removePersistedData: err",e)}}();const o=t.bootstrapArgs;f({...o,startDate:n.bookingForm.start_date.slice(0,10),endDate:n.bookingForm.end_date?.slice(0,10)||null,guests:n.bookingForm.guests,propertyId:n.bookingForm.property_id,persistActive:!0,hotelId:t.hotel.data.id})}catch(e){console.error("openPersistWidget: err",e)}}const m=async()=>await fetch(`${SELFBOOK_APP_BASE_URL}/asset-manifest.json`,{headers:{"content-type":"application/json"}}).then(e=>e.json()).then(e=>function(e){n=e.entrypoints}(e));function g(){try{return JSON.parse(localStorage.getItem("selfbook_ddn-signal-box_auth"))}catch(e){console.error("Unable to extract Signal box from local storage.")}}function y(){const e=g();if(e)return e?.state?.user?.paypal_data}async function f(n={}){try{if(o)return;n.currencyCode&&(n.currency=n.currencyCode,delete n.currencyCode),n.locale||(n.locale=function(){const e=location.pathname.match(/^\/([a-z]{2}(?:-[A-Z]{2})?)(\/|$)/)?.[1],t=new URLSearchParams(location.search),n=t.get("lang")||t.get("locale"),o=document.documentElement.lang,a=navigator.language||navigator.languages?.[0];return function(e){if(!e)return"en";const[t,n]=e.split(/[-_]/);return n?`${t.toLowerCase()}-${n.toUpperCase()}`:t.toLowerCase()}(e||n||o||a||"en")}());let a=n.shouldExecuteRegularFlow||!1;n.apiKey&&await k(n.apiKey,n.hotelId);const r=getHotelBasicData(n.hotelId||e);getIsLayers(r)&&await async function(e,t){try{l=!0;const n=await u({url:`${SELFBOOK_BACKEND_URL_V3}/hotels/${e}`,headers:{"content-type":"application/json","API-Key":t}});sessionStorage.setItem(SELFBOOK_HOTEL_INFO,JSON.stringify(n)),l=!1}catch(e){console.log(e)}}(n.hotelId||e,n.apiKey||t),console.log("args",n);const s=getIsEnableV35(r),c=getFromSessionStorage(SELFBOOK_HOTEL_GROUP_INFO),d="group"===c?.structure,_="single"===c?.structure,m=function(e,t=[]){if(!e||"object"!=typeof e||Array.isArray(e))return!1;for(const n in e){if(t.includes(n))continue;const o=e[n];if(null!=o&&!("string"==typeof o&&""===o.trim()||Array.isArray(o)&&0===o.length||"object"==typeof o&&!Array.isArray(o)&&0===Object.keys(o).length))return!0}return!1}(n,["version","selfbook","hotelId","destinationId"]);if(s&&!1!==n.shouldExecuteRegularFlow&&((/*!initialAPIsCallsExecuted && */_&&m||d&&!i)&&(a=!0),r?.is_default_date_logic_enabled?n.startDate&&n.endDate&&(_||d&&n.hotelId)&&(a=!0):a=!0),n.guests?n.guests=fillGuestsFields(n.guests,r):n.guests=[{type:GUEST_TYPE.ADULT,count:r.default_adult_occupancy?r.default_adult_occupancy:2}],r.redirect_to_synxis){const e=buildRedirectSynxisLink(n,r);return void window.open(e,"_blank").focus()}getIsEnableV35(r)&&(n.roomsGuests=buildRoomsGuests(n,r)),p(n,r,a),document.getElementsByTagName("html")[0].setAttribute("translate","no")}catch(e){console.error("bookNow: err: ",e)}}function h(){const e="\n #selfbook_sdkwidget {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0px;\n right: 0px;\n }\n\n .dismiss-btn-slide-in {\n -webkit-transition: 500ms;\n -moz-transition: 500ms;\n transition: 500ms;\n transform: translateX(0)!important\n }\n\n .dismiss-btn-slide-out {\n -webkit-transition: 500ms;\n -moz-transition: 500ms;\n transition: 500ms;\n transform: translateX(300px)!important\n }\n\n .dismiss-btn-slide-out span {\n display: none;\n }\n\n .payment-summary-wrapper {\n overflow: scroll!important;\n -ms-overflow-style: none!important;\n scrollbar-width: none!important;\n }\n .payment-summary-wrapper::-webkit-scrollbar {\n display: none!important;\n }\n\n .dismiss-btn-resize-in {\n width: 46px!important;\n height: 46px!important;\n transition: 500ms;\n right: 30px!important;\n }\n\n .dismiss-btn-resize-in span {\n display: none;\n }\n\n .dismiss-btn-resize-in:hover {\n width: 217px!important;\n height: 46px!important;\n transition: all 300ms linear;\n cursor: pointer;\n }\n\n .dismiss-btn-resize-in:hover span {\n display: inline;\n height: 20px!important;\n overflow: hidden;\n }\n\n .dismiss-btn-resize-out {\n width: 46px!important;\n height: 46px!important;\n transition: 500ms;\n right: -100px!important;\n }\n\n .slide-in {\n transform: translateX(100%);\n -webkit-transform: translateX(100%);\n animation: slide-in 0.8s forwards !important;\n -webkit-animation: slide-in 0.8s forwards !important;\n z-index: 2147483646;\n }\n\n .slide-out {\n transform: translateX(100%);\n -webkit-transform: translateX(100%);\n animation: slide-out 1s forwards !important;\n -webkit-animation: slide-out 1s forwards !important;\n z-index: -2147483646;\n }\n\n @media screen and (max-width:495px) {\n .slide-in {\n transform: translateY(100%);\n -webkit-transform: translateY(100%);\n animation: slide-up 0.8s forwards !important;\n -webkit-animation: slide-up 0.8s forwards !important;\n z-index: 2147483646;\n }\n .slide-out {\n transform: translateY(100%);\n -webkit-transform: translateY(100%);\n animation: slide-down 0.5s forwards !important;\n -webkit-animation: slide-down 1s forwards !important;\n z-index: -2147483646;\n }\n }\n\n @keyframes slide-in {\n 100% {\n transform: translateX(0%);\n }\n }\n\n @-webkit-keyframes slide-in {\n 100% {\n -webkit-transform: translateX(0%);\n }\n }\n\n @keyframes slide-up {\n 100% {\n transform: translateY(0%);\n }\n }\n\n @-webkit-keyframes slide-up {\n 100% {\n -webkit-transform: translateY(0%);\n }\n }\n\n @keyframes slide-out {\n 0% {\n transform: translateX(0%);\n }\n 100% {\n transform: translateX(100%);\n }\n }\n\n @-webkit-keyframes slide-out {\n 0% {\n -webkit-transform: translateX(0%);\n }\n 100% {\n -webkit-transform: translateX(100%);\n }\n }\n\n @keyframes slide-down {\n 0% {\n transform: translateY(0%);\n }\n 100% {\n transform: translateY(100%);\n }\n }\n\n @-webkit-keyframes slide-down {\n 0% {\n -webkit-transform: translateY(0%);\n }\n 100% {\n -webkit-transform: translateY(100%);\n }\n }\n ",t=document.createElement("style");t.textContent=e,document.head.append(t),function(e){const t=document.createElement("style");t.textContent=e,document.head.append(t)}(e)}function S(e){const t={startdate:"startDate",enddate:"endDate",rateplancode:"ratePlanCode",rate:"rate",roomid:"roomId",propertyid:"propertyId",destinationid:"destinationId",room:"room",room_count:"roomCount",adult:"adult",child:"child",child_ages:"childAges",infants:"infants",room2_adult:"room2Adult",room2_child:"room2Child",room2_child_ages:"room2ChildAges",room3_adult:"room3Adult",room3_child:"room3Child",room3_child_ages:"room3ChildAges",room4_adult:"room4Adult",room4_child:"room4Child",room4_child_ages:"room4ChildAges",currency:"currency",group:"group",locale:"locale",hotel:"hotel",promo:"promo",promocode:"promocode",selfbook:"selfbook",iatanumber:"iataNumber",couponcode:"couponCode",nights:"nights",reservationid:"reservationId",lastname:"lastName",search:"search",sbsearch:"sbsearch",threeDsContinueId:"three_ds_continue_id",status:"status",roomcategory:"roomCategory",properties:"properties",source:"source",include_inclusive_fees:"includeInclusiveFees",hotelid:"hotelId",version:"version",loyaltyuseremail:"loyaltyUserEmail",loyaltyeventname:"loyaltyEventname",loyaltysignupform:"loyaltySignupForm"};return Array.from(e.entries()).reduce((e,[n,o])=>({...e,[t[n.toLowerCase()]]:o}),{})}function E(){setTimeout(()=>{const t=setInterval(()=>{if(o||l)return;clearInterval(t);const n=S(new URLSearchParams(window.location.search));if("true"!==n.selfbook)return;const a=getHotelBasicData(n.hotel||n.hotelId||e),r=n.version?.toLowerCase?.();SELFBOOK_APP_VERSION=r||a?.app_version||"v2",w(n,a)},100)},500)}function w(e,t={}){const n=parseInt(t?.default_adult_occupancy)||2,o=[{type:"adult",count:e.adult||n},{type:"child",count:e.child||0},{type:"infants",count:e.infants||0}];f({...e,guests:o,groupCode:e.group,currency:e.currency||e.currencyCode,promoCode:e.promo||e.promocode,hotelId:e.hotel||e.hotelId||void 0,roomCategory:"string"==typeof e.roomCategory?e.roomCategory.split(",").map(e=>e.trim()):void 0})}async function b(){!function(){const e=document.createElement("div"),t=document.createElement("div");e.setAttribute("id","selfbook_sdkwidget"),e.style.display="none",t.setAttribute("id","selfbook_sdkwidget_wrapper"),t.style.background="rgba(0, 0, 0, 0)",t.style.position="fixed",t.style.top="0",t.style.right="0",t.style.width="100%",t.style.transition="background .5s ease-out",t.appendChild(e),document.body.appendChild(t)}(),await m(),function(){if(!0!==s){if(n&&n.length>0){const e=document.getElementsByTagName("head")[0];n.forEach(t=>{if(t.includes(".css")){const n=document.createElement("link");n.rel="stylesheet",n.type="text/css",n.media="all",n.href=`${SELFBOOK_APP_BASE_URL}/${t}`,e.appendChild(n)}})}s=!0}}(),_(),document?.querySelectorAll("a").forEach(t=>{t.addEventListener("click",t=>{try{"A"!==t.target.tagName&&"A"===t.target.parentNode?.tagName&&(t.target.href=t.target.parentNode.href);const n=t.target.href||"";if(-1===n.indexOf("?"))return;const o=S(new URLSearchParams(n.substring(n.indexOf("?")))),a=getHotelBasicData(o.hotelId||o.hotel||e);if(SELFBOOK_APP_VERSION=o.version?.toLowerCase?.()||a?.app_version||"v2",a?.mobile_display_only&&window.innerWidth>=768)return;(isTemplateDomainMatch(a,t)||"true"===o.selfbook)&&(t.preventDefault(),w(o,a))}catch(e){console.error("a-element: err: ",e)}})}),"complete"===document?.readyState?E():window?.addEventListener("load",E)}function O(e){return e.toISOString()}function I(){return new Promise(e=>{const t=document.createElement("script");t.src=`https://cdn.jsdelivr.net/npm/@statsig/js-client@3/build/statsig-js-client.min.js?apikey=${STATSIG_CLIENT_KEY}`,t.defer=!0,t.onload=async()=>{try{await async function(){const e={userID:L()};let t=new window.Statsig.StatsigClient(STATSIG_CLIENT_KEY,e);await t.initializeAsync(),window.selfbookStatsigClient=t}()}catch(e){console.log("Unable to initialize Statsig client",e)}e(t)},t.onerror=t=>{console.log("Failed to load Statsig script",t),e()},document.head.appendChild(t)})}function L(){const e="selfbook_statsig_anonymous_id";let t=localStorage.getItem(e);return t||(t=crypto.randomUUID?crypto.randomUUID():Math.random().toString(36).substring(2,15),localStorage.setItem(e,t)),t}async function k(n,r){try{o=!0;const s=r?`?id=${r}`:"",l=await u({url:`${SELFBOOK_BACKEND_URL}/hotels/info${s}`,headers:{"content-type":"application/json","API-Key":n}});sessionStorage.setItem(SELFBOOK_HOTEL_GROUP_INFO,JSON.stringify(l));const p={...l},_=getHotelBasicData(r);(function(e){const t=getFromSessionStorage(SELFBOOK_HOTEL_GROUP_INFO);return!("single"!==t?.structure||!(e?.enable_direct_distribution_network||e?.enable_flex_cancellation||e?.enable_priority_upgrade))||!("group"!==t?.structure||!t?.hotels.some(e=>e.enable_direct_distribution_network||e.enable_flex_cancellation||e.enable_priority_upgrade))||!("multiple_properties"!==t?.structure||!t?.hotels.some(e=>e.enable_direct_distribution_network||e.enable_flex_cancellation||e.enable_priority_upgrade))})(_)&&await I(),d(_);const m=getIsLayers(_);!_?.enable_direct_distribution_network||m||c||"none"===_?.ddn_box_device||initWidgets({apiKey:t,hotelId:e,hotelData:_}),m||initFloatingSearchbar({apiKey:t,hotelId:e});const g=S(new URLSearchParams(window.location.search));if(SELFBOOK_APP_VERSION=g.version?.toLowerCase?.()||_?.app_version||"v2",m?SELFBOOK_APP_BASE_URL=SELFBOOK_BASE_URL_LAYERS:SELFBOOK_APP_VERSION.match(/^v3/i)?(SELFBOOK_APP_BASE_URL=SELFBOOK_BASE_URL_V3,p.hotels=p?.hotels?.map(e=>({...e,enable_v3_new_ui_version:!0}))):SELFBOOK_APP_BASE_URL=SELFBOOK_BASE_URL,sessionStorage.setItem(SELFBOOK_HOTEL_GROUP_INFO,JSON.stringify(p)),!i&&getIsEnableV35(_)&&_?.is_default_date_logic_enabled&&"group"!==p?.structure)try{const t=await async function(t,n,o){try{const a=function(){const e=new Date,t=new Date(e.getFullYear(),e.getMonth(),1),n=new Date(e.getFullYear(),e.getMonth()+2,0);return{startDate:A(t),endDate:A(n)}}(),r={start_date:a.startDate,end_date:a.endDate,currency_code:o?.currency_code||"USD",guests:[{type:"adult",count:o?.default_adult_occupancy||2}]};window.sb_sdkBus.emit("sdk-calendar-status",{type:"loading",payload:r});const s=await u({url:`${"v2"===SELFBOOK_APP_VERSION?SELFBOOK_BACKEND_URL:SELFBOOK_BACKEND_URL.replace("v2","v3")}/hotels/${n||e}/calendar`,headers:{"content-type":"application/json","API-Key":t},data:JSON.stringify(r),method:"POST"});return initialCalendarResponse=s,window.sb_sdkBus.emit("sdk-calendar-status",{type:"success",payload:s}),s.data}catch(e){window.sb_sdkBus.emit("sdk-calendar-status",{type:"error",error:e.message}),console.log(e)}}(n,r,_),o=function(e){const t=new Date,n=t.getUTCFullYear(),o=t.getUTCMonth(),a=t.getUTCDate(),r=new Date(Date.UTC(n,o,a+14));let s=e.filter(e=>function(e){const[t,n,o]=e.split("-").map(Number);return new Date(Date.UTC(t,n-1,o))}(e.date)>r&&null!=e.price);0===s.length&&(s=e.filter(e=>null!=e.price));return 0===s.length?null:s.reduce((e,t)=>t.price`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`;const B=document?.getElementById("selfbook_jssdk");if(B){const n=new URL(B.getAttribute("src"));if(e=n.searchParams.get("hotelId"),t=n.searchParams.get("apiKey"),c="true"===n.searchParams.get("ddnLandingPage"),"?11howard"===window.location.search&&window.location.href.includes("staging")&&(e="66350",t="x9GTqyGB8Pboi5Tkk3fuQUrQ8qAecxzxNY0"),!t||!e)throw new Error("(!) selfbook: ApiKey and HotelId are required.");window.isSelfbookSDKActive=!0,initSDKBus(),k(t,e).then(e=>{getIsLayers(e)||h()})}window&&(window.sbApiLogger=function(n,o={},a){const r=`${"v2"===SELFBOOK_APP_VERSION?SELFBOOK_BACKEND_URL:SELFBOOK_BACKEND_URL.replace("v2","v3")}/hotels/${a||e}/events`;try{const e={generated_at:(new Date).toISOString(),event_source:"SDK",event_name:n,body:JSON.stringify(o)};fetch(r,{method:"POST",headers:{"Content-Type":"application/json","API-Key":t},body:JSON.stringify(e)})}catch(e){console.error("sbApiLogger error:",e)}},window.book=function(e,t,n,o,a,r,s,i,l,c,d="fr",u,p,_){f({startDate:e,endDate:t,guests:n,propertyId:o,currency:a,roomId:r,ratePlanCode:s,rate:i,promoCode:l,groupCode:c,locale:d,destinationId:p,hotelId:u,roomCategory:_})},window.bookNow=f,window.closeSelfbookWidget=function(){const e=getElementById("selfbook_sdkwidget"),t=getElementById("selfbook_sdkwidget_wrapper");setOverflowHidden(!1),e.setAttribute("class","slide-out"),t.style.background="rgba(0, 0, 0, 0)",window.selfbookWidgetStore.dispatch({type:"WIDGET/SELFBOOK_WIDGET_CLOSED"}),window.selfbookWidgetStore.dispatch({type:"ANALYTICS/TRACK_EVENT",payload:{eventType:"widget closed"}}),window.toggleShowSBSignalBox?.(!0),setTimeout(()=>{e.style.display="none",t.style.zIndex=-2147483646},800)})}runDirectApplication(); /* Mews integration, Wilmina hotel group SDK Wilmina Hotel -> https://wilmina.com/de/zimmer/ Carlotta Apartments -> https://carlotta-apartments.com/ */ if (window.location.href.includes("selfbook-staging") || localStorage.getItem("selfbook-staging") === "true" ) { localStorage.setItem("selfbook-staging", "true"); console.log( '%cCustom script has been initialized', 'background: green; color: white;', ); (() => { const customStyles = document.createElement('style'); customStyles.innerText = ` #selfbook_sdkwidget [lang*="en"] [data-testid="properties-list"] [alt="Carlotta"] + div:after { font-size: 14px !important; font-weight: 300 !important; letter-spacing: 0px !important; line-height: 20px !important; font-family: var(--sb-font-family-main); position: relative !important; top: 10px !important; margin-bottom: 10px !important; padding-bottom: 10px !important; display: block !important; white-space: initial !important; content: "Luxurious apartments with plenty of space for retreat and togetherness for up to four people. Lush gardens connect the building directly to the historic Wilmina building complex." !important; } #selfbook_sdkwidget [lang="de"] [data-testid="properties-list"] [alt="Carlotta"] + div:after { font-size: 14px !important; font-weight: 300 !important; letter-spacing: 0px !important; line-height: 20px !important; font-family: var(--sb-font-family-main); position: relative !important; top: 10px !important; margin-bottom: 10px !important; padding-bottom: 10px !important; display: block !important; white-space: initial !important; content: "Die Carlotta Apartments bieten moderne, ruhige und hochwertig ausgestattete Apartments für einen längeren Aufenthalt in Berlin. Sie befinden sich in der zentral gelegenen Pestalozzistraße in Charlottenburg. Die großzügig geschnittenen Wohneinheiten haben eine Größe von 32 bis 246 qm und sind lichtdurchflutet durch ihre großen, bodentiefen Fenster. Einige der Apartments verfügen über große Loggien, die einen herrlichen Blick bieten auf den ruhigen grünen Innenhof. Die Apartments wurden entworfen und ausgestattet von dem preisgekrönten Berliner Büro Grüntuch-Ernst Architekten. Im Erdgeschoss des Gebäudes befindet sich die Tagesbar LOTTA. Hier kann täglich ein kleines Frühstück eingenommen werden." !important; } #selfbook_sdkwidget [lang*="en"] [data-testid="properties-list"] [alt="Wilmina Hotel"] + div:after { font-size: 14px !important; font-weight: 300 !important; letter-spacing: 0px !important; line-height: 20px !important; font-family: var(--sb-font-family-main); position: relative !important; top: 10px !important; margin-bottom: 10px !important; padding-bottom: 10px !important; display: block !important; white-space: initial !important; content: "Bright, modern rooms in a historic building for up to two people." !important; } #selfbook_sdkwidget [lang="de"] [data-testid="properties-list"] [alt="Wilmina Hotel"] + div:after { font-size: 14px !important; font-weight: 300 !important; letter-spacing: 0px !important; line-height: 20px !important; font-family: var(--sb-font-family-main); position: relative !important; top: 10px !important; margin-bottom: 10px !important; padding-bottom: 10px !important; display: block !important; white-space: initial !important; content: "Das Hotel Wilmina befindet sich im ehemaligen Charlottenburger Frauengefängnis und ist Teil eines denkmalgeschützten Ensembles aus dem 19. Jahrhundert. Hinter ineinanderfließenden Höfen und üppigen Gärten verborgen, wurde das Gebäude von Grüntuch-Ernst Architekten im sensiblen Dialog mit den vorhandenen Räumen und Spuren früherer Nutzung in einen kontemplativen Rückzugsort mitten in Berlin transformiert. Das familiengeführte Hotel verfügt über 44 Zimmer und Suiten sowie 22 Apartments, eine Dachterrasse über dem neuen Penthouse, eine Bibliothek, eine Bar, einen Spa-Bereich und ein Fitnessstudio. Es bietet seinen Gästen ein hohes Maß an Ruhe und Komfort. Zum Wilmina gehören das renommierte Fine-Dining Restaurant & Bar Lovis, die LOTTA Tagesbar mit hausgemachten Spezialitäten und die hauseigene Bäckerei Wilmina Brot." !important; } `; document.head.appendChild(customStyles); })(); function modifyExistingSbLinks() { const links = document.querySelectorAll(`a[href*='selfbook=true']`); for (const link of links) { const href = link.getAttribute('href'); if (href) { const updatedHref = href.toString(); const linkObj = hrefToObj(updatedHref); const finalParams = assignObjectVals(linkObj) // link.setAttribute('href', window.location.href); link.addEventListener("click", (e) => { e.preventDefault(); e.stopImmediatePropagation(); bookNow(finalParams); console.log('modifyExistingSbLinks()', finalParams) }); } } } function setLocale(locale) { const localeList = { "fr-FR": "fr", "fr-fr": "fr", "fr": "fr", /* French */ "de-DE": "de", "de-de": "de", "de": "de", /* German */ "it-IT": "it", "it-it": "it", "it": "it", /* Italian */ "es-ES": "es", "es-es": "es", "es": "es", /* Spanish (Spain) */ "es-MX": "es-MX", "es-mx": "es-MX", /* Spanish (Mexico) */ "pt-PT": "pt-PT", "pt-pt": "pt-PT", "pt": "pt-PT", /* Portuguese */ "zh-CN": "zh-CN", "zh-cn": "zh-CN", /* Simplified Chinese */ "zh-TW": "zh-TW", "zh-tw": "zh-TW", /* Traditional Chinese */ "ja-JP": "ja", "ja-jp": "ja", /* Japan */ } return localeList[locale] || localeList[document.documentElement.lang] || "en"; }; // Checks the format of the inputted date and puts it in the correct order format (YYYY-MM-DD) function convertDate(date) { try { const inputDate = new Date(date); const year = inputDate.getFullYear(); const month = (inputDate.getMonth() + 1).toString().padStart(2, '0'); const day = inputDate.getDate().toString().padStart(2, '0'); return [year, month, day].join('-'); } catch (error) { console.log(error, 'convertDate'); } }; // Validates date format is 'YYYY-MM-DD' function checkDateIsISOformat(inputString) { try { const regexPattern = /^\d{4}-\d{2}-\d{2}$/; return regexPattern.test(inputString); } catch (error) { console.log(error, 'checkDateIsISOformat'); } } /* Verifies these date formats: 'DD MONTH YYYY', 'YYYY-MM-DD', 'YYYY/MM/DD', 'MM/DD/YYYY' */ function verifyFutureDate(date) { try { if (date) { if (checkDateIsISOformat(date)) { const inputDate = new Date(date); const today = new Date(); today.setHours(0, 0, 0, 0); if (inputDate >= today) { const formattedDate = inputDate.toISOString().split('T')[0]; return formattedDate; } } else { const inputDate = new Date(date); const today = new Date(); today.setHours(0, 0, 0, 0); if (inputDate >= today) { return convertDate(inputDate); } } } return ''; } catch (error) { console.log(error, 'verifyFutureDate'); } } // arrival > departure, return new departure function compareDates(arrive, depart) { try { let arrivalDate = new Date(arrive); let departureDate = new Date(depart); arrivalDate.setHours(0, 0, 0, 0); departureDate.setHours(0, 0, 0, 0); if (arrivalDate > departureDate) { arrivalDate.setDate(arrivalDate.getDate() + 1); departureDate = arrivalDate; } return departureDate.toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit' }); } catch (error) { console.log(error, 'compareDates'); } } /* This function flattens the array / object within guests */ function pruneGuests(object) { try { const pruneObject = object; if (pruneObject.guests && Array.isArray(pruneObject.guests)) { const guests = pruneObject.guests; for (const guest of guests) { if (guest.type === 'adult' && guest.count > 0) { pruneObject.adult = guest.count; } else if (guest.type === 'child' && guest.count > 0) { pruneObject.child = guest.count; } // else if (guest.type === 'infants' && guest.count > 0) { // pruneObject.infants = guest.count; // } } delete pruneObject.guests; } // console.log('pruneObject', pruneObject); return pruneObject; } catch (error) { console.log(error, 'pruneGuests'); } } /* Fix for Currency Case Bug */ function upperCaseCurrency(currency) { try { if (!currency) { return null; } const currencyCode = currency.toUpperCase(); return currencyCode; } catch (error) { console.log(error, 'upperCaseCurrency'); } }; /* This function defines the bookNow() Object and assigns the values */ function assignObjectVals(param) { try { /* mewsStart mewsEnd mewsVoucherCode mewsRoom mewsAdultCount mewsChildCount language currency */ const urlData = param; const updatedLocale = setLocale(urlData.language || urlData.locale); const updatedCurrency = upperCaseCurrency(urlData.currency); const adult = urlData.mewsadultcount || urlData.adult; const child = urlData.mewschildcount || urlData.child; delete urlData.locale; delete urlData.currency; const arrive = urlData.mewsstart || urlData.startdate; const depart = urlData.mewsend || urlData.enddate; const bookNowParams = { startDate: verifyFutureDate(arrive), endDate: verifyFutureDate(depart), guests: [ { type: 'adult', count: (!adult ? null : parseInt(adult, 10)), }, { type: 'child', count: (!child ? null : parseInt(child, 10)), } ], propertyId: urlData.propertyId, currency: updatedCurrency, roomId: urlData.mewsroom || urlData.roomid, ratePlanCode: urlData.rate || urlData.rateplancode, promoCode: urlData.mewsvouchercode || urlData.promocode, groupCode: urlData.group, locale: updatedLocale, hotel: urlData.hotel || urlData.hotelid, hotelId: urlData.hotel || urlData.hotelid, iataNumber: urlData.agencyid, ...urlData }; // Remove any properties with null or undefined values Object.keys(bookNowParams).forEach((key) => { if (bookNowParams[key] === null || bookNowParams[key] === undefined || bookNowParams[key] === "") { delete bookNowParams[key]; } }); return bookNowParams; } catch (error) { console.log(error, 'assignObjectVals'); } }; // Create a function that parses the URL and returns an object with the params function hrefToObj(url) { try { let href = url.replace(/%20/g, ''); const parsedUrl = new URL(href); const rawParams = Object.fromEntries(parsedUrl.searchParams.entries()); const params = {}; for (const [key, value] of Object.entries(rawParams)) { params[key] = value; } return params; } catch (error) { console.log(error, 'hrefToObj'); } } // Create a direct link function objToSBlinks(params) { try { let siteUrl = `${window.location.pathname}?selfbook=true`; let sbObj = assignObjectVals(params); let prunedSBobj = pruneGuests(sbObj); let urlParams = decodeURIComponent( new URLSearchParams(prunedSBobj), ).toString(); return `${siteUrl}&${urlParams}`; } catch (error) { console.log(error, 'objToSBlinks'); } } /* Find booking links with specific keywords, then point them to Selfbook */ function linkReplacer() { const allMewsLinks = document.querySelectorAll(`a[href*='app.mews.com']`); // const allMewsLinks = document.querySelectorAll(`a[href*='reservations'], a[href*='app.mews.com']`); if (allMewsLinks.length > 0) { for (let i = 0; i < allMewsLinks.length; i++) { // 3 ways to check class on a CTA // if (allMewsLinks[i].classList.contains("hero__booking_cta")) { // // Class 'active' exists console.log("Class 'active' is present."); // } // if (allMewsLinks[i].className.startsWith("hero__booking_cta")) { // // do something // } // for (let cls of allMewsLinks[i].classList) { // if (cls.startsWith("hero__booking_cta")) { // link.style.backgroundColor = "black"; // break; // Stop checking once a match is found // } // } allMewsLinks[i].removeAttribute('target'); const link = allMewsLinks[i].href.toString(); const linkObj = hrefToObj(link); // const sbLink = objToSBlinks(linkObj); if (link.indexOf("signin") === -1) { let finalParams = assignObjectVals(linkObj); // allMewsLinks[i].href = sbLink; // allMewsLinks[i].href = "?book-now"; allMewsLinks[i].addEventListener('click', (e) => { e.preventDefault(); e.stopImmediatePropagation(); bookNow(finalParams); }); } else { allMewsLinks[i].href = `/?selfbook=true&sbsearch=true&hotel=${linkObj.hotel}`; allMewsLinks[i].addEventListener('click', (e) => { e.preventDefault(); }) } } } }; linkReplacer(); modifyExistingSbLinks(); setInterval(linkReplacer, 1000); /* Hide Bed Count from Rooms + Room Details screen Hide PAYMENT & CANCELLATION Policies from Price Breakdown + Summary + Checkout screens (policies are not explicitly outlined in Mews, they're found in rate descriptions) Hide Selfbook Account from Menu + Checkout + Confirmation Hide Due Now */ const customStyles = document.createElement("style"); customStyles.innerText = ` #selfbook-loading { max-width: 150px !important; } #sb-pay { align-items: center !important; justify-content: center !important; } #sb-pay > span { display: none !important; } /* Hide login section on post booking */ #sb-post-booking-auth { display: none !important; } /* Text wrapping issue on room list and room detail screens */ #room-detail-description > div > button > div > div, li.sb-room-item button div { white-space: initial !important; word-wrap: break-word !imporant; } /* hide loading image */ #selfbook-loading { display: none !important; } /* hide calendar default text */ #sb-cal-prices-msg { display: none !important; } `; document.head.appendChild(customStyles); const trackRoomScreens = { "cs-CZ": { "room_list":"Vyberte pokoj", "room_detail": "Tarifs et packages", "room_modal_cancellation_policy":"Platební a storno podmínky", "menu_sign_in_sign_up":"Přihlásit se / Registrovat" }, "de": { "room_list":"Zimmer auswählen", "room_detail":"Zimmerdetails", "room_modal_cancellation_policy":"Zahlungs- und Stornierungsbedingungen", "menu_sign_in_sign_up":"Anmelden / Registrieren" }, "es": { "room_list":"Seleccionar habitación", "room_detail":"Detalles de la habitación", "room_modal_cancellation_policy":"Políticas de pago y cancelación", "menu_sign_in_sign_up":"Iniciar sesión / Registrarse" }, "fr": { "room_list":"Choisir une chambre", "room_detail": "Détails de la chambre", "room_modal_cancellation_policy":"Politiques de paiement et d'annulation", "menu_sign_in_sign_up":"Se connecter / S'inscrire" }, "it": { "room_list":"Seleziona la stanza", "room_detail":"Dettagli della camera", "room_modal_cancellation_policy":"Politiche di pagamento e cancellazione", "menu_sign_in_sign_up":"Accedi / Registrati" }, "ja": { "room_list":"部屋を選択", "room_detail":"部屋の詳細", "room_modal_cancellation_policy":"支払いおよびキャンセルポリシー", "menu_sign_in_sign_up":"サインイン/サインアップ" }, "lv-LV": { "room_list":"Izvēlieties istabu", "room_detail":"Istabas informācija", "room_modal_cancellation_policy":"Maksājumu un atcelšanas politika", "menu_sign_in_sign_up":"Pierakstīties / Reģistrēties" }, "nl": { "room_list":"Selecteer kamer", "room_detail":"Kamerdetails", "room_modal_cancellation_policy":"Betalings- en annuleringsbeleid", "menu_sign_in_sign_up":"Aanmelden / Registreren" }, "pt-PT": { "room_list":"Selecione o quarto", "room_detail":"Detalhes do quarto", "room_modal_cancellation_policy":"Políticas de Pagamento e Cancelamento", "menu_sign_in_sign_up":"Entrar / Cadastrar-se" }, "ru": { "room_list":"Выбрать комнату", "room_detail":"Подробности о номере", "room_modal_cancellation_policy":"Правила оплаты и отмены", "menu_sign_in_sign_up":"Войти / Зарегистрироваться" }, "tr": { "room_list":"Oda seç", "room_detail":"Oda detayları", "room_modal_cancellation_policy":"Ödeme ve İptal Politikaları", "menu_sign_in_sign_up":"Giriş Yap / Kaydol" }, "zh-CN": { "room_list":"选择房间", "room_detail":"客房详情", "room_modal_cancellation_policy":"付款和取消政策", "menu_sign_in_sign_up":"登录/注册" }, "en-US": { "room_list":"Select room", "room_detail": "Room details", "room_modal_cancellation_policy":"Payment and Cancellation Policies", "menu_sign_in_sign_up":"Sign In / Sign Up" }, "en-GB": { "room_list":"Select room", "room_detail": "Room details", "room_modal_cancellation_policy":"Payment and Cancellation Policies", "menu_sign_in_sign_up":"Sign In / Sign Up" }, "en": { "room_list":"Select room", "room_detail": "Room details", "room_modal_cancellation_policy":"Payment and Cancellation Policies", "menu_sign_in_sign_up":"Sign In / Sign Up" } }; // selfbookTranslations['fr']['rooms.title'] // room list // selfbookTranslations['fr']['roomDetail.title] // room detail function removeBedTypeFromRoomDetails(lang,screenName) { if (document.querySelector('#widget-inner-wrapper [aria-label]') && document.querySelector('#selfbook_sdkwidget [lang]')) { let lang = document.querySelector('#selfbook_sdkwidget [lang]').getAttribute('lang').toString(); let screenName = document.querySelector('#widget-inner-wrapper [aria-label]').getAttribute('aria-label').toString(); if(trackRoomScreens[lang] && trackRoomScreens[lang].room_detail === screenName){ // console.log('room_detail',trackRoomScreens[lang]); if (document.querySelector(`[aria-label="${screenName}"] svg[title="bed"]`) && document.querySelector(`[aria-label="${screenName}"] svg[title="number-of-people"]`)) { // Select the parent element const parentElement = document.querySelector(`[aria-label="${screenName}"] svg[title="number-of-people"]`).parentElement.parentElement; // Select the child element to be removed const childElement = parentElement.querySelector('svg[title="bed"]').parentElement; // Remove the child element from the parent if (childElement) { parentElement.removeChild(childElement); } } } // if(trackRoomScreens[lang] && trackRoomScreens[lang].room_list === screenName){ // console.log('room_list',trackRoomScreens[lang]); // } // else if(trackRoomScreens[lang] && trackRoomScreens[lang].room_detail === screenName){ // console.log('room_detail',trackRoomScreens[lang]); // } } } function removeBedTypeFromRoomList(lang,screenName) { if (document.querySelector('ul[data-testid="rooms-list"] .sb-room-item svg[title="bed"]')) { document.querySelectorAll('ul[data-testid="rooms-list"] .sb-room-item svg[title="bed"] + div, ul[data-testid="rooms-list"] .sb-room-item svg[title="bed"]').forEach(div => div.remove()); } } function removePaymentAndCancellationPolicies(lang,screenName) { // let lang = document.querySelector('#selfbook_sdkwidget [lang]').getAttribute('lang').toString(); // let screenName = document.querySelector('#widget-inner-wrapper [aria-label]').getAttribute('aria-label').toString(); if (document.querySelector('[data-testid="sb-room-price-modal"]') && document.querySelector('[data-testid="sb-room-price-modal"] h5')) { let text = document.querySelector('[data-testid="sb-room-price-modal"] h5').textContent; if (text === trackRoomScreens[lang].room_modal_cancellation_policy) { document.querySelector('[data-testid="sb-room-price-modal"] h5 + p[role="presentation"]').remove(); document.querySelector('[data-testid="sb-room-price-modal"] h5').remove(); } } } function removeCancellationLinkOnPaymentScreen(lang,screenName) { if (document.querySelector('[aria-label="Checkout"] [data-testid="sb-payments-msg"]')) { document.querySelector('[aria-label="Checkout"] [data-testid="sb-payments-msg"]').remove(); } } function removeCancellationTextOnSummaryScreen(lang,screenName) { if (document.querySelector('[aria-label="Summary"] .payment-summary-wrapper p')) { let text = document.querySelector('[aria-label="Summary"] .payment-summary-wrapper p').textContent; if (text.includes("arrival")) { document.querySelector('[aria-label="Summary"] .payment-summary-wrapper p').remove(); } } } function removeLogin(lang,screenName) { // menu.loginRegister for sign-up/sign-in button if (document.querySelector('[aria-label="Selfbook Main Menu"] ul li button') && !document.querySelector('[aria-label="Selfbook Main Menu"] ul li button[data-sb-updated]')) { document.querySelector('[aria-label="Selfbook Main Menu"] ul li button').setAttribute("data-sb-updated", "true"); document.querySelectorAll('[aria-label="Selfbook Main Menu"] ul li button').forEach((button) => { if (button.textContent === trackRoomScreens[lang].menu_sign_in_sign_up) { button.remove(); } }) } if (document.querySelector('#sb-screen #have-an-account') && !document.querySelector('#sb-screen #have-an-account[data-sb-updated]')) { document.querySelector('#sb-screen #have-an-account').setAttribute("data-sb-updated", "true"); document.querySelector('#sb-screen #have-an-account').style = "visibility: hidden !important;"; document.querySelector('#sb-screen #have-an-account + button').style = "visibility: hidden !important;"; } } function removeCancelPolicyFromConfirmationScreen(lang,screenName) { if (document.querySelector('[aria-label="Cancellation description"]')) { document.querySelector(`[aria-label="Cancellation description"]`).parentElement.remove(); } } function removeMewsIframe(){ if(document.querySelector('iframe.mews-distributor')){ document.querySelector('iframe.mews-distributor').remove(); } } setInterval(() => { removeMewsIframe(); if (document.querySelector('#widget-inner-wrapper [aria-label]') && document.querySelector('#selfbook_sdkwidget [lang]')) { let lang = document.querySelector('#selfbook_sdkwidget [lang]').getAttribute('lang').toString(); let screenName = document.querySelector('#widget-inner-wrapper [aria-label]').getAttribute('aria-label').toString(); removeLogin(lang,screenName); removeBedTypeFromRoomList(lang,screenName); removeBedTypeFromRoomDetails(lang,screenName); removePaymentAndCancellationPolicies(lang,screenName); removeCancellationTextOnSummaryScreen(lang,screenName); removeCancellationLinkOnPaymentScreen(lang,screenName); removeCancelPolicyFromConfirmationScreen(lang,screenName); } }, 500); document.addEventListener('click', (e) => { const linkEl = e.target.closest("a[href*='#']"); if (!linkEl) return; // Confirm button text const text = linkEl.textContent.trim().toLowerCase(); if (text !== 'book now') return; const href = linkEl.href; if (href.includes('signin')) { e.preventDefault(); return; } e.preventDefault(); e.stopImmediatePropagation(); const linkObj = hrefToObj(href); const finalParams = assignObjectVals(linkObj); bookNow(finalParams); }); /* // if a form element does not have a name attribute, the selected value is not included in the form data, i.e. when FormData(form) is used. function serializeBookingForm(form) { const formData = new FormData(form); const params = new URLSearchParams(); // Manually add select value if missing a name attribute const resortSelect = form.querySelector('#bookstay-select-resort'); if (resortSelect && resortSelect.value) { params.append('resortId', resortSelect.value); // Or use any desired key } for (const [key, value] of formData.entries()) { params.append(key, value); } return params.toString(); } function dateStringToISO(date) { // converts '07/28/2025' to '2025-07-28' if (!date) return null; let [month, day, year] = date.split('/'); return [year, month, day].join('-'); } function mapFormObjToSB(obj) { let adults = parseInt(obj.adults || obj.Adults); // let children = obj.Children || obj.children; let rooms = parseInt(obj.rooms); let bookingParms = { startDate: dateStringToISO(obj.arrival), endDate: dateStringToISO(obj.departure), locale: document.documentElement.lang } if (rooms) { console.log('rooms', rooms, 'adults', adults); if (adults === 1 && rooms === 1) { bookingParms.guests = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 2 && rooms === 1) { bookingParms.guests = [{ type: 'adult', count: 2 }]; return bookingParms; } else if (adults === 2 && rooms === 2) { bookingParms.guests = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 2 && rooms > 2) { bookingParms.guests = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 3 && rooms === 1 || adults === 3 && rooms === 2) { bookingParms.guests = [{ type: 'adult', count: 2 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 3 && rooms >= 3) { bookingParms.guests = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom3 = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 4 && rooms === 2 || adults === 4 && rooms === 1) { bookingParms.guests = [{ type: 'adult', count: 2 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 2 }]; return bookingParms; } else if (adults === 4 && rooms === 3) { bookingParms.guests = [{ type: 'adult', count: 2 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom3 = [{ type: 'adult', count: 1 }]; return bookingParms; } else if (adults === 4 && rooms === 4 || adults === 4 && rooms === 1) { bookingParms.guests = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom2 = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom3 = [{ type: 'adult', count: 1 }]; bookingParms.guestsRoom4 = [{ type: 'adult', count: 1 }]; return bookingParms; } } return bookingParms; } document.querySelector('#hotelresform li.last-child-btn') .addEventListener("click", (e) => { e.preventDefault(); e.stopImmediatePropagation(); let form = document.querySelector("#hotelresform"); let serializedData = serializeBookingForm(form); let result = queryStringToObj(serializedData); let finalParams = mapFormObjToSB(result, 99914); bookNow(finalParams) console.log("Custom click intercepted. Preventing form submission.", 'serializedData', serializedData, 'finalParams', finalParams); // Prevent reservation_validation1 from executing return false; }, true); // Use capture phase to intercept before inline handler } if(document.querySelector('#bookingForm')){ document.getElementById("bookingForm").addEventListener("submit", function (e) { e.preventDefault(); e.stopImmediatePropagation(); const form = e.target; const serializedData = serializeBookingForm(form); console.log(serializedData); }); } // Clone a CTA function bookNowCloner(selector) { const bookNowButton = document.querySelector(selector); if (bookNowButton !== null) { const bookNowButtonClone = bookNowButton.cloneNode(true); bookNowButton.parentNode.replaceChild(bookNowButtonClone, bookNowButton); bookNowButtonClone.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); // eslint-disable-next-line no-undef bookNow(); }); } } bookNowCloner('my-selector'); // Example usage of assignObjectVals(obj), leverages existing validation if (document.querySelector('body > form > input[type=submit]')) { document.querySelector('body > form > input[type=submit]') .addEventListener('click', function (e) { try { e.preventDefault(); e.stopImmediatePropagation(); let obj = {}; // Create an obj with SynXis booking properties obj.adult = document.querySelector('#adults').value; obj.arrive = document.querySelector('#checkin').value; obj.depart = document.querySelector('#checkout').value; obj.depart = compareDates(obj.arrive, obj.depart); let finalParams = assignObjectVals(obj); bookNow(finalParams); } catch (error) { console.log(error, "formInputs"); } }); } */ } else { console.log("SB not loaded"); } // Save a reference to the original bookNow() function // let originalBookNow = bookNow; // Custom function that tracks bookNow() // function sbBookNowTracker(args) { // if (args && typeof args === 'object') { // if (window.location.href.includes("birdwoodmansion")) { // // www.birdwoodmansion.com // args.roomId = birdwoodRoomsList; // args.startDate = "2026-04-02"; // } // else { // // must be www.boarsheadresort.com/ // args.roomId = boarsheadRoomsList; // } // console.log("arguments: myArgs", args); // } else { // if (window.location.href.includes("birdwoodmansion")) { // args = { // roomId: birdwoodRoomsList, // startDate: "2026-04-02" // }; // } // else { // // https://www.boarsheadresort.com/ // args = { roomId: boarsheadRoomsList }; // } // console.log("no arguments, using default:", args); // } // return args; // } // Override Selfbook's bookNow() function with new custom function // Override Selfbook's bookNow() function // function newCustomBookNow(args) { // let updatedArgs = sbBookNowTracker(args); // return originalBookNow.call(this, updatedArgs); // } // Assign override function to bookNow(); // bookNow = newCustomBookNow; /* Client would like to exclude these rooms from Carlotta on this URL. Studio 32: 16208f33-84d4-492b-a455-b00d00838f34 Studio 40: 428ab6e7-7fbd-4fab-a4e6-b00d00838f34 Studio 52: f08f218f-1351-41d2-ab71-b00d00838f35 */ let roomList = { CarlottaExcludedRoomsList: ["16208f33-84d4-492b-a455-b00d00838f34", "428ab6e7-7fbd-4fab-a4e6-b00d00838f34", "f08f218f-1351-41d2-ab71-b00d00838f35"] }; function removeRooms() { if (typeof selfbookWidgetStore !== 'undefined' && selfbookWidgetStore?.getState()?.core?.hotel?.data?.id) { let hotelId = selfbookWidgetStore?.getState()?.core?.hotel?.data?.id; let url = window.location.href; if (hotelId && hotelId === '698244f5-d2c4-4d09-9693-b00d00838413' && url.includes('wilmina.com/')) { if (document.querySelector('ul[data-testid="rooms-list"] li.sb-room-item')) { document.querySelectorAll('ul[data-testid="rooms-list"] li.sb-room-item').forEach(room => { let roomId = room.getAttribute('data-roomid'); if (roomList.CarlottaExcludedRoomsList.includes(roomId)) { // console.log(roomId, roomList.CarlottaExcludedRoomsList.includes(roomId)) // room.style.display = "none !important;"; room.setAttribute("style", "display:none;"); } }); } } } } setInterval( () => { removeRooms(); }, 1000);