const SELFBOOK_BASE_URL="https://sdk.selfbook.com",SELFBOOK_BACKEND_URL="https://api.selfbook.com/api/v2",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",SELFBOOK_WIDGET_RESUME="selfbook-sdkwidget-resume",SELFBOOK_WIDGET_RESUME_TEXT="selfbook-sdkwidget-resume-text",BOOTSTRAP_ACTION="WIDGET/BOOTSTRAP",SELFBOOK_HOTEL_GROUP_INFO="selfbook_hotel_group_info",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"};function checkStatus(t){if(t.status>=200&&t.status<300)return t;const e=new Error(t.statusText);throw e.response=t,e}async function parseJSON(t){try{const e=await t.text();if(!e)return;return JSON.parse(e)}catch(t){console.error("parseJSON: err: ",t)}}function intervalWrapper(t,e){const n=setInterval(t,e);return function(){clearInterval(n)}}function getHotelBasicData(t,e){try{const n=getFromLocalStorage(t,SELFBOOK_HOTEL_GROUP_INFO).hotels?.filter((t=>t.id==e));return n?.[0]||{}}catch(t){return console.error("getHotelBasicData: err: ",t),{}}}function getFromLocalStorage(t,e){try{return JSON.parse(t.getItem(e))}catch(t){return console.error("getFromLocalStorage: err: ",{e:t}),{}}}function getPersistedData(t){try{const e=JSON.parse(t.getItem("persist:root"));if(!e)return INITIAL_PERSISTED_DATA;const n=JSON.parse(e.booking||"{}"),o=JSON.parse(e.core||"{}"),r=JSON.parse(e?.router||"{}"),{expireTime:a}=o,i=(Date.now()-new Date(o.interactionTime))/1e3;return{isExpired:i>a,all:e,booking:n,core:o,router:r}}catch(t){return console.error("getPersistedData: err: ",t),INITIAL_PERSISTED_DATA}}function fillGuestsFields(t=[],e){const n=e.default_adult_occupancy?e.default_adult_occupancy:2;return t.map((t=>t.type===GUEST_TYPE.ADULT?{type:GUEST_TYPE.ADULT,count:parseInt(t.count)||n}:t.type===GUEST_TYPE.CHILD&&parseInt(t.count)>0?{type:GUEST_TYPE.CHILD,count:parseInt(t.count),age:parseInt(t.age)||1,special_request:t.special_request||""}:t.type===GUEST_TYPE.INFANT&&parseInt(t.count)>0?{type:GUEST_TYPE.INFANT,count:parseInt(t.count)||1,age:parseInt(t.age)||1,special_request:t.special_request||""}:void 0)).filter(Boolean)}function buildRedirectSynxisLink(t,e){let n=`https://be.synxis.com/?hotel=${e.id}&theme=${e.synxis_theme}&config=${e.synxis_config}`;try{if(t){const{startDate:e,endDate:o,promoCode:r,groupCode:a,guests:i,iataNumber:s,couponCode:l,destinationId:d,nights:c,rate:p,hotelId:u,roomCategory:m}=t;c&&(n+=`&nights=${c}`),e&&(n+=`&arrive=${e}`),o&&(n+=`&depart=${o}`),r&&(n+=`&promo=${r}`),a&&(n+=`&group=${a}`),s&&(n+=`&iataNumber=${s}`),l&&(n+=`&couponCode=${l}`),p&&(n+=`&rate=${p}`),d&&(n+=`&destinationId=${d}`),Array.isArray(m)?n+=`&roomCategory=${m.map((t=>t)).join(",")}`:m&&(n+=`&roomCategory=${m}`),i&&i.length>0?("adult"===i[0].type&&(n+=`&adult=${i[0].count}`),i[1]&&"child"===i[1].type&&(n+=`&child=${i[1].count}`)):n+="&adult=1"}}catch(t){console.error("buildRedirectSynxisLink: err: ",t)}return n}function selectShowWidgetButtonCopies(t){return t.core.showWidgetButtonCopies||{}}function selectRoute(t){return t?.router?.location?t.router.location.pathname:ROUTE_PATHS.app.editBooking}function isObjectEqual(t,e){return JSON.stringify(t)===JSON.stringify(e)}function isTemplateDomainMatch(t,e){return t?.booking_template_domain&&e?.target?.href?.includes(t.booking_template_domain)}function getElementById(t){return document?.getElementById(t)}function runDirectApplication(){console.info("(!) selfbook: widget initialization started");let t,e,n,o,r,a=!1,i=!1,s=!1,l=!1;function d({url:t,method:e,data:n,headers:o,callback:r}){fetch(t,{method:e,body:n,headers:o}).then(checkStatus).then(parseJSON).then(r).catch((t=>{console.debug("requestWrapper: Request failed",t)}))}function c(){try{const t=n||{},e=o||ROUTE_PATHS.app.editBooking;n=selectShowWidgetButtonCopies(window.selfbookWidgetStore.getState()),o=selectRoute(window.selfbookWidgetStore.getState());const r=getElementById(SELFBOOK_WIDGET_RESUME_TEXT);let a=t.COMPLETE_BOOKING;isObjectEqual(t,n)&&o===e||(a=o===ROUTE_PATHS.app.reservations?n.VIEW_RESERVATIONS:o===ROUTE_PATHS.app.confirmation||o===ROUTE_PATHS.app.reservationDetail?n.VIEW_RESERVATION:o===ROUTE_PATHS.app.account?n.VIEW_ACCOUNT:o===ROUTE_PATHS.app.wallet?n.VIEW_WALLET:o===ROUTE_PATHS.app.bookingConfirmed?n.RETURN_BOOKING:n.COMPLETE_BOOKING,r&&(r.innerHTML=a))}catch(t){console.error("handleStoreChange: err: ",t)}}function p(){return THE_LINE_HOTELS.includes(t)?"Lydian BT":"Main"}function u(e){const n=e?.colors||{},o=`\n position: fixed;\n overflow: hidden;\n cursor: pointer;\n display: flex;\n justify-content: space-evenly;\n align-items: center;\n width: 217px;\n height: 46px;\n box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.25), 0px 4px 4px rgba(0, 0, 0, 0.1);\n right: 30px;\n z-index: 100000000000;\n bottom: 40px;\n font-family: ${p()}!important;\n font-size: 14px;\n line-height: 142%;\n letter-spacing: 0.02em;\n text-transform: capitalize!important;\n border: none;\n transform: translateX(300px);\n `,r="\n background: #343A40;\n color: #FFFFFF;\n ",a=`\n ${r}\n border-radius: 23px;\n `,i=`\n background: ${n.primary_color||n.primary};\n color: ${n.secondary_color||n.secondary}!important;\n `;return s=e?.id||t,BLACK_SQUARE_THEME_HOTELS.includes(s)?`${o}${r}`:n.primary_color&&n.secondary_color||n.primary&&n.secondary?`${o}${i}`:`${o}${a}`;var s}function m(t){const e=document.createElement("style");e.textContent=t,document.head.append(e)}function f(n,o){if(!r)return;m(`#${SELFBOOK_WIDGET_RESUME} {\n ${u(o)}\n }`),document.body.style.overflow="hidden";const a=getElementById("selfbook_sdkwidget"),i=getElementById("selfbook_sdkwidget_wrapper"),l=getElementById(SELFBOOK_WIDGET_RESUME),d=l?l.getAttribute("class"):null;d&&d.includes("dismiss-btn")&&(l.removeAttribute("class"),l.setAttribute("class","dismiss-btn-slide-out")),window.selfbookWidgetStore||(i.appendChild(function(){const t=document.createElement("div");return t.id="selfbook-loading",t.style.color="white",t.style.marginRight="-50%",t.style.position="absolute",t.style.top="50%",t.style.left="50%",t.style.fontFamily="sans-serif",t.style.transform="translate(-50%, -50%)",t.innerHTML='',t}()),i.style.zIndex=1e11,i.style.height="100%",i.style.background="rgba(0, 0, 0, .74)",document.body.style.overflow="hidden"),function(){if(!0===s)return;r&&r.length>0&&r.forEach((t=>{if(t.includes(".js")){const e=document.createElement("script");e.type="text/javascript",e.src=`${SELFBOOK_BASE_URL}/${t}`,document.body.appendChild(e)}}));(function(){try{const t=document.createElement("script");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;e{if(window.selfbookWidgetStore){window.selfbookWidgetStore.subscribe(c);!function(){const t=document.getElementById("selfbook-loading");t&&getElementById("selfbook_sdkwidget_wrapper").removeChild(t)}(),clearInterval(p),window.selfbookWidgetStore.dispatch({type:BOOTSTRAP_ACTION,payload:{hotelInfo:{apiKey:n.apiKey||e,hotelId:n.hotelId||t},bookingData:n,hotelGroupInfo:getFromLocalStorage(localStorage,SELFBOOK_HOTEL_GROUP_INFO)}}),"none"===a.style.display&&(i.style.zIndex=1e11,i.style.height="100%",i.style.background="rgba(0, 0, 0, .4)",document.body.style.overflow="hidden"),setTimeout((()=>{a.style.display="block",a.setAttribute("class","slide-in")}),20),setTimeout((()=>{const t=i.querySelector('[aria-modal="true"]');t&&t.focus()}),250),function(){const t=getElementById("selfbook_sdkwidget"),e=getElementById("selfbook_sdkwidget_wrapper"),n=getElementById(SELFBOOK_WIDGET_RESUME);n.addEventListener("click",(o=>{try{if(n){const o=n?n.getAttribute("class"):null;o&&o.includes("dismiss-btn")&&(n.removeAttribute("class"),n.setAttribute("class","dismiss-btn-slide-out")),document.body.style.overflow="hidden",e.style.zIndex=1e11,e.style.height="100%",e.style.background="rgba(0, 0, 0, .5)",t.style.display="block",t.setAttribute("class","slide-in"),window.selfbookWidgetStore.dispatch({type:"ANALYTICS/TRACK_EVENT",payload:{eventType:COMPLETE_BOOKING_BTN_CLICK,eventPayload:null}}),setTimeout((()=>{const t=e.querySelector('[aria-modal="true"]');t&&t.focus()}),500)}}catch(t){console.error("handleWidgetCloseListeneres: err: ",t)}}))}()}}),100)}function y(){try{const{isExpired:t,core:e,booking:n}=getPersistedData(localStorage),o=!!e?.hotel?.data?.feature_flags?.persist_state;if(t||!e?.hotel?.data?.id||!o)return void function(){try{localStorage.removeItem("persist:root")}catch(t){console.error("removePersistedData: err",t)}}();const r=e.bootstrapArgs;E({...r,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:e.hotel.data.id})}catch(t){console.error("openPersistWidget: err",t)}}const g=async()=>await fetch(`${SELFBOOK_BASE_URL}/asset-manifest.json`,{headers:{"content-type":"application/json"}}).then((t=>t.json())).then((t=>function(t){r=t.entrypoints}(t)));function E(e={}){try{e.apiKey&&w(e.apiKey,e.hotelId);const n=getHotelBasicData(localStorage,e.hotelId||t);if(e.guests?e.guests=fillGuestsFields(e.guests,n):e.guests=[{type:GUEST_TYPE.ADULT,count:n.default_adult_occupancy?n.default_adult_occupancy:2}],console.log(e),n.redirect_to_synxis){const t=buildRedirectSynxisLink(e,n);return void window.open(t,"_blank").focus()}f(e,n),document.getElementsByTagName("html")[0].setAttribute("translate","no")}catch(t){console.error("bookNow: err: ",t)}}function h(t){const e={startdate:"startDate",enddate:"endDate",rateplancode:"ratePlanCode",rate:"rate",roomid:"roomId",propertyid:"propertyId",destinationid:"destinationId",room:"room",adult:"adult",child:"child",infants:"infants",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"};return Array.from(t.entries()).reduce(((t,[n,o])=>({...t,[e[n.toLowerCase()]]:o})),{})}function _(){setTimeout((()=>{const e=setInterval((()=>{if(a)return;clearInterval(e);const n=h(new URLSearchParams(window.location.search));"true"===n.selfbook&&b(n,getHotelBasicData(localStorage,n.hotel||t))}),100)}),500)}function b(t,e={}){const n=parseInt(e?.default_adult_occupancy)||2,o=[{type:"adult",count:t.adult||n},{type:"child",count:t.child||0},{type:"infants",count:t.infants||0}];E({...t,guests:o,groupCode:t.group,promoCode:t.promo||t.promocode,hotelId:t.hotel||void 0,roomCategory:"string"==typeof t.roomCategory?t.roomCategory.split(",").map((t=>t.trim())):void 0})}async function k(){!function(){const t=document.createElement("div"),e=document.createElement("div"),n=document.createElement("button"),o=document.createElement("span"),r=document.createElement("img");n.id=SELFBOOK_WIDGET_RESUME,n.style.cursor="pointer",r.src="https://sdk.selfbook.com/assets/resume-icon-black.png",r.alt="Resume booking",r.width="16",r.height="16",o.innerHTML="Complete your booking",o.id=SELFBOOK_WIDGET_RESUME_TEXT,n.appendChild(o),n.appendChild(r),t.setAttribute("id","selfbook_sdkwidget"),t.style.display="none",e.setAttribute("id","selfbook_sdkwidget_wrapper"),e.style.background="rgba(0, 0, 0, 0)",e.style.position="fixed",e.style.top="0",e.style.right="0",e.style.width="100%",e.style.transition="background .5s ease-out",e.appendChild(t),document.body.appendChild(e),document.body.appendChild(n)}(),await g(),function(){if(!0!==l){if(r&&r.length>0){const t=document.getElementsByTagName("head")[0];r.forEach((e=>{if(e.includes(".css")){const n=document.createElement("link");n.rel="stylesheet",n.type="text/css",n.media="all",n.href=`${SELFBOOK_BASE_URL}/${e}`,t.appendChild(n)}}))}l=!0}}(),y(),document?.querySelectorAll("a").forEach((e=>{e.addEventListener("click",(e=>{try{"A"!==e.target.tagName&&"A"===e.target.parentNode?.tagName&&(e.target.href=e.target.parentNode.href);const n=e.target.href||"";if(-1===n.indexOf("?"))return;const o=h(new URLSearchParams(n.substring(n.indexOf("?")))),r=getHotelBasicData(localStorage,o.hotel||t);if(r?.mobile_display_only&&window.innerWidth>=768)return;(isTemplateDomainMatch(r,e)||"true"===o.selfbook)&&(e.preventDefault(),b(o,r))}catch(t){console.error("a-element: err: ",t)}}))})),"complete"===document?.readyState?_():window?.addEventListener("load",_)}function w(t,e){a=!0;d({url:`${SELFBOOK_BACKEND_URL}/hotels/info${e?`?id=${e}`:""}`,headers:{"content-type":"application/json","API-Key":t},callback(t){localStorage.setItem(SELFBOOK_HOTEL_GROUP_INFO,JSON.stringify(t)),i||k(),i=!0,a=!1}})}const S=document?.getElementById("selfbook_jssdk");if(S){const n=new URL(S.getAttribute("src"));if(t=n.searchParams.get("hotelId"),e=n.searchParams.get("apiKey"),!e||!t)throw new Error("(!) selfbook: ApiKey and HotelId are required.");window.isSelfbookSDKActive=!0,w(e,t),intervalWrapper((()=>{w(e,t)}),3e5),function(){const t=`\n #selfbook_sdkwidget {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0px;\n right: 0px;\n }\n\n #${SELFBOOK_WIDGET_RESUME} {\n ${u()}\n }\n\n #${SELFBOOK_WIDGET_RESUME_TEXT} {\n display: block!important;\n font-family: ${p()}!important;\n font-size: 14px!important;\n font-weight: 400!important;\n color: #ffffff!important;\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: 1000000000000;\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: -1000000000000;\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: 1000000000000;\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: -1000000000000;\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 `,e=document.createElement("style");e.textContent=t,document.head.append(e),m(t)}()}window&&(window.sbApiLogger=function(n){try{d({url:`${SELFBOOK_BACKEND_URL}/hotels/${t}/events`,method:"POST",headers:{"content-type":"application/json","API-Key":e},data:JSON.stringify({generated_at:(new Date).toISOString(),event_source:"SDK",body:n})})}catch(t){console.log(t)}},window.book=function(t,e,n,o,r,a,i,s,l,d,c="fr",p,u,m){E({startDate:t,endDate:e,guests:n,propertyId:o,currency:r,roomId:a,ratePlanCode:i,rate:s,promoCode:l,groupCode:d,locale:c,destinationId:u,hotelId:p,roomCategory:m})},window.bookNow=E,window.closeSelfbookWidget=function(){const t=getElementById("selfbook_sdkwidget"),e=getElementById("selfbook_sdkwidget_wrapper"),n=getElementById(SELFBOOK_WIDGET_RESUME);document.body.style.overflow="initial",t.setAttribute("class","slide-out"),e.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"}}),setTimeout((()=>{t.style.display="none",e.style.zIndex=-1e11;const o=getFromLocalStorage(localStorage,SELFBOOK_HOTEL_GROUP_INFO);o&&(o.maintenance_mode||(n.setAttribute("class","dismiss-btn-slide-in"),n.focus()))}),800)})}runDirectApplication(); /* ---------------------------------- Custom integration script for Club Quarters: https://clubquartershotels.com https://cqstaging.wpengine.com/ Chain code: 14601 ---------------------------------- */ /* This script works for both Desktop and Mobile but is running only for Mobile */ let htmlContainer = ""; let stylesForSBcta = '.sbCTAcontainer{\n position: relative;\n z-index:999;\n background-color:orange;\n}\n\n.sbCTApositionContainer{\n position: fixed;\n right:50px;\n bottom:50px;\n}\n\n#sbSlideInSection {\n margin-right:-400px;\n font-family: "CircularXXWeb-Bold-1", sans-serif, sans-serif;\n}\n\n.sbSlideInNav {\n background-color: #00263E;\n padding-left:30px;\n height: 100%;\n width: 350px;\n position: fixed;\n z-index: 100;\n top: 0;\n right: 0;\n padding-top: 60px;\n overflow-x: hidden;\n transition: 0.5s;\n}\n\n.sbSlideInNav a {\n display: block;\n color: #FFF;\n padding: 8px 8px 8px 32px;\n text-decoration: none;\n font-size: 16px;\n transition: 0.3s;\n font-weight:500 !important;\n}\n\n.sbSlideInNav a:hover {\n color: #e9a45e;\n}\n\n.sbSlideInNav .closeSbSlider {\n position: absolute;\n top: 10px;\n color:#FFF;\n font-weight:900;\n right: 25px;\n font-size: 40px;\n margin-left: 50px;\n}\n\n@media screen and (max-height: 450px) {\n .sbSlideInNav {padding-top: 15px;}\n .sbSlideInNav a {font-size: 18px;}\n}.sb-hotel-dest-group, .sb-section-header { font-family:"CircularXXWeb-Bold-1", sans-serif } .sb-section-header{ font-size: 1.65rem; margin-bottom:10px;color:#FFF; } .sb-hotel-destination{ font-size:18px; color:#e9a45e;} .sb-hotel-destination:hover {cursor:pointer;color:#fff;}.sb-hotel-dest-group a{ color:#000; text-decoration: none; font-size: 1.125rem; display: block; margin-left:15px; padding:5px; } .sb-muted-text{ color:#bdbdbd; font-size: 1.0rem; margin-left:10px; };'; let sbStyles = document.createElement("style"); sbStyles.textContent = stylesForSBcta; document.head.appendChild(sbStyles); let sbCTAcontainer = document.createElement("div"); sbCTAcontainer.setAttribute("class", "sbCTAcontainer"); sbCTAcontainer.setAttribute("id", "sbCTAcontainer"); document.body.appendChild(sbCTAcontainer); let sbCTApositionContainer = document.createElement("div"); sbCTApositionContainer.setAttribute("class", "sbCTApositionContainer"); sbCTAcontainer.appendChild(sbCTApositionContainer); let sbSlideInSection = document.createElement("div"); sbSlideInSection.setAttribute("class", "sbSlideInNav"); sbSlideInSection.setAttribute("id", "sbSlideInSection"); sbSlideInSection.innerHTML = '
Loading ...pre-view mode
'; sbCTApositionContainer.appendChild(sbSlideInSection); function openSBslideNav() { if (document.getElementById("sbSlideInSection")) { document.getElementById("sbSlideInSection").style.marginRight = "0"; } } document .querySelector(".closeSbSlider") .addEventListener("click", function (e) { e.preventDefault(); if (document.getElementById("sbSlideInSection")) { document.getElementById("sbSlideInSection").style.marginRight = "-400px"; } }); /* ---------------------------------- The data below is used to build the modal for the offers pages ---------------------------------- */ const hotels = [ { name: "Boston", code: 58311, destination: ["CQMBR", "BOS", "BRKFST", "", "Boston"] }, { name: "Wacker at Michigan", code: 58315, destination: ["CQMBR", "CQ CHI", "REWESC", "BRKFST", "Chicago"], }, { name: "Central Loop", code: 58314, destination: ["CQMBR", "CQ CHI", "REWESC", "BRKFST", "Chicago"], }, { name: "Downtown Houston", code: 58316, destination: ["CQMBR", "HOU", "REWESC", "BRKFST", "Houston"], }, { name: "Covent Garden Holborn", code: 58335, destination: ["CQMBR", "UKCQ", "BRKFST", "LON", "London"], }, { name: "St. Paul's", code: 58319, destination: ["CQMBR", "UKCQ", "BRKFST", "LON", "London"], }, { name: "Trafalgar Square", code: 58322, destination: ["CQMBR", "UKCQ", "BRKFST", "LON", "London"], }, { name: "London City", code: 58318, destination: ["CQMBR", "UKCQ", "BRKFST", "LON", "London"], }, { name: "Times Square - Midtown", code: 58308, destination: ["CQMBR", "CQ NYC", "", "", "New York City"], }, { name: "The Jewel, Opposite Rockefeller Center", code: 58324, destination: ["CQMBR", "CQ NYC", "", "", "New York City"], }, { name: "Grand Central", code: 59166, destination: ["CQMBR", "CQ NYC", "", "", "New York City"], }, { name: "World Trade Center", code: 58309, destination: ["CQMBR", "CQ NYC", "", "", "New York City"], }, { name: "Rittenhouse Square", code: 58313, destination: ["CQMBR", "PHL", "REWESC", "", "Philadelphia"], }, { name: "San Francisco", code: 58312, destination: ["CQMBR", "SF", "REWESC", "BRKFST", "San Francisco"], }, { name: "Washington, D.C.", code: 58310, destination: ["CQMBR", "DC", "", "", "Washington, DC"], }, ]; /* ---------------------------------- Start of the core mobile code Code contained in this block only executes when its a mobile device. ---------------------------------- */ let isMobile = false; let browserNavUserAgent = navigator.userAgent; if ( /(tablet|ipad|playbook|silk)|(android(?!.*mobi))|Mobile|iP(hone|od)|iPad|iPhone|Android|BlackBerry|IEMobile|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/i.test( browserNavUserAgent ) ) { isMobile = true; } if (navigator.maxTouchPoints >= 0 && isMobile) { console.log( "%cMobile script has been initialized", "background: green; color: white;" ); console.time('check'); const API_KEY_BUGSNAG = '6cb771be223c608f92775d1516dce6e2'; const CLIENT_URL = window.location.href; const sendErrorToBugsnag = async (error, func, obj) => { const apiKey = API_KEY_BUGSNAG; const apiUrl = 'https://notify.bugsnag.com'; const payload = { apiKey: apiKey, notifier: { name: 'Custom Notifier', version: '1.0', url: CLIENT_URL, }, events: [ { payloadVersion: '5', exceptions: [ { errorClass: 'SbIntegration', message: `${error.name ? error.name : ""}. Message: ${error.message}.`, stacktrace: [ { file: CLIENT_URL, method: " (" + func + " Error) ", code: { 1: `${error.name ? error.name : ""}. Message: ${error.message}.`, 2: "Browser: " + navigator.userAgent, 3: "Language: " + navigator.language, 4: `Mobile form data: ${obj ? JSON.stringify(obj) : ""}` }, } ], } ], severity: 'error', context: CLIENT_URL, } ] }; const headers = new Headers({ 'Content-Type': 'application/json', 'Bugsnag-Api-Key': apiKey, 'Bugsnag-Payload-Version': '5', 'Bugsnag-Sent-At': new Date().toISOString() }); const requestOptions = { method: 'POST', headers: headers, body: JSON.stringify(payload) }; try { const response = await fetch(apiUrl, requestOptions); if (response.ok) { console.log('Error report sent to Bugsnag successfully'); } else { console.error('Failed to send error report to Bugsnag'); } } catch (error) { console.error('Error sending error report to Bugsnag:', error); } }; const handleError = (error, func, obj) => { console.error(`${func} error occurred:`, error); sendErrorToBugsnag(error, func, obj); // Forward the error to Bugsnag reporting }; let replacedLinks = 0; /* Checks the format of the inputted date and puts it in the correct order format (YYYY-MM-DD) */ function convertDate(date) { try { let inputDate = new Date(date); let year = inputDate.getFullYear(); let month = (inputDate.getMonth() + 1).toString().padStart(2, '0'); let day = inputDate.getDate().toString().padStart(2, '0'); return [year, month, day].join('-'); } catch (error) { handleError(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) { handleError(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)) { let inputDate = new Date(date) let today = new Date(); today.setHours(0, 0, 0, 0); if (inputDate => today) { let formattedDate = inputDate.toISOString().split("T")[0] return formattedDate; } } else { let inputDate = new Date(date); let today = new Date(); today.setHours(0, 0, 0, 0); if (inputDate => today) { return convertDate(inputDate); } } } return ""; } catch (error) { handleError(error, "verifyFutureDate"); } } /* This function filters the initial parameters and returns the ones that are null of undefined, it also flattens the array / object within guests */ function pruneObjectKeys(object) { try { const pruneObject = object; Object.keys(pruneObject).forEach((key) => { if (key === 'guests') { if (pruneObject[key][0] !== null && pruneObject[key][0].count > 0) { const adultCount = pruneObject[key][0].count; pruneObject.adult = adultCount; if ( pruneObject[key][1] !== null && pruneObject[key][1].count > 0) { const childCount = pruneObject[key][1].count; pruneObject.child = childCount; } } if ( pruneObject[key] !== null && pruneObject[key][1].count !== null) { const childCount = pruneObject[key][1].count; pruneObject.child = childCount; } else { delete pruneObject[key]; } } if (!pruneObject[key]) { // console.log(pruneObject[key]); delete pruneObject[key]; } return pruneObject; }); return pruneObject; } catch (error) { handleError(error, "pruneObjectKeys"); } }; /* Fix for Currency Case Bug */ function upperCaseCurrency(currency) { try { if (!currency) { return null; } const currencyCode = currency.toUpperCase(); return currencyCode; } catch (error) { handleError(error, "upperCaseCurrency"); } }; /* This function defines the bookNow() Object and assigns the values after running it through pruneObjectKeys(). */ function assignObjectVals(param) { try { const urlData = param; // console.log(param); const bookNowParams = { startDate: verifyFutureDate(urlData.arrive), endDate: (verifyFutureDate(urlData.arrive) !== "") ? verifyFutureDate(urlData.depart) : "", guests: [ { type: 'adult', count: (!urlData.adult ? null : parseInt(urlData.adult, 10)), }, { type: 'child', count: (!urlData.child ? null : parseInt(urlData.child, 10)), }, ], propertyId: urlData.propertyId, currency: upperCaseCurrency(urlData.currency), roomId: urlData.room, ratePlanCode: urlData.rate, promoCode: urlData.promo, groupCode: urlData.group, locale: urlData.locale, hotelId: urlData.hotel, dest: urlData.dest }; // console.log('assignObjectVals, bookNowParams', bookNowParams) return pruneObjectKeys(bookNowParams); } catch (error) { handleError(error, "assignObjectVals"); } }; // Create a function that parses the URL and returns an object with the params function parseURL(url) { try { const params = {}; let urlInput = url.replace(/%20/g, ''); urlInput = urlInput.split('?'); const urlParams = urlInput[1].split('&'); for (let i = 0; i < urlParams.length; i++) { const param = urlParams[i].split('='); params[param[0]] = param[1]; } const searchParams = decodeURIComponent( new URLSearchParams(assignObjectVals(params)), ).toString(); // eslint-disable-next-line max-len const domain = `https://${window.location.hostname}?selfbook=true&${searchParams}`; const dest = params.dest; return [domain, params, dest]; } catch (error) { handleError(error, "parseURL"); } }; /* .hotel-list-section > button:before, .hotel-list-section > button:after, .hotel-list-section > button { background-color: transparent !important; display: block !important; text-align: left !important; color: #D6D1CA !important; } */ function modalBuilder(hotelsByDest, bookingCTAdata) { try { console.log('bookingCTAdata', bookingCTAdata) htmlContainer = ``; let infoIcon = `ⓘ Promo code has been applied.`; let offerName = (bookingCTAdata?.promoCode || bookingCTAdata?.ratePlanCode) ? infoIcon : ""; let offerDesc = bookingCTAdata?.promoCode ? `Promo code: ${bookingCTAdata?.promoCode}
` : ""; offerDesc += bookingCTAdata?.ratePlanCode ? `Rate code: ${bookingCTAdata?.ratePlanCode}` : ""; // document.querySelector(".sb-section-header").innerHTML = offerName; htmlContainer += `
Select Hotel To Continue
`; htmlContainer += `
${offerName}
`; htmlContainer += `

`; for (let destination in hotelsByDest) { htmlContainer += `
${destination}
`; hotelsByDest[destination].forEach(function (obj, index) { htmlContainer += ``; }); } return htmlContainer; } catch (error) { handleError(error, "modalBuilder"); } } /* this finds all tags and checks that thier hrefs contain a parameter then runs a loop that replaces that href and adds an event listener for the bookNow() */ function linkReplacer() { try { const allSynxisLinks = document.querySelectorAll(`a[href*='synxis'], a[href*='reservations.clubquartershotels.com']`); for (let i = 0; i < allSynxisLinks.length; i++) { const link = allSynxisLinks[i].href.toString().toLowerCase(); // Only target SynXis booking links if (link.includes("signin")) { return; } else { allSynxisLinks[i].removeAttribute("target"); let atag = allSynxisLinks[i]; let parsedLink = parseURL(link); let finalParams = assignObjectVals(parsedLink[1]); // atag.href = parseURL(link)[0]; // console.log('parseURL(link)[0]', parseURL(link)[0]); // console.log('finalParams', finalParams) atag.href = '#book'; if (link.indexOf("hotel=") < 0) { // attach params to CTAs within Modal // console.log(parsedLink[1].dest, link) // filter only for specific destination value let filteredHotels = filterHotelsByDestination(hotels, parsedLink[1].dest.toUpperCase()); let hotelsByDest = groupHotelsByDestination(filteredHotels, 4) allSynxisLinks[i].addEventListener("click", (e) => { e.preventDefault(); htmlContainer = modalBuilder(hotelsByDest, finalParams); document.querySelector(".hotel-list-section").innerHTML = htmlContainer; // console.log('openSBslideNav() finalParams', finalParams) openSBslideNav(); }); } else { // normal logic atag.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); bookNow(finalParams); }); } replacedLinks += 1; } } } catch (error) { handleError(error, "linkReplacer"); } }; linkReplacer(); console.log('Replaced Links', replacedLinks); console.timeEnd('check'); // filter array of hotels and group by destination function groupHotelsByDestination(hotels, ind) { try { return hotels.reduce((acc, hotel) => { const destination = hotel.destination[ind]; if (!acc[destination]) { acc[destination] = []; } acc[destination].push(hotel); return acc; }, {}); } catch (error) { handleError(error, "groupHotelsByDestination"); } } // filter and group hotels that match a specific destination value function filterHotelsByDestination(hotels, destination) { try { return hotels.filter((hotel) => hotel.destination.includes(destination)); } catch (error) { handleError(error, "filterHotelsByDestination"); } } function checkHotelSelectionFail(targetElm) { try { // Creates a visual cue that the hotel/dest selection failed let oldBgColor = targetElm.style.backgroundColor; targetElm.style.backgroundColor = "#ea6e84"; targetElm.style.transition = "background 2s"; setTimeout(missingDestSelection, 1500); function missingDestSelection() { targetElm.style.backgroundColor = oldBgColor; } } catch (error) { handleError(error, "checkHotelSelectionFail"); } }; /* When mobile booking form is submitted, the code below runs */ if (document.querySelector(".mobile-booking-mask.theme--navy.has-bg")) { document.querySelector(".mobile-booking-mask.theme--navy.has-bg") .addEventListener("submit", mobileForm); } function mobileForm(e) { let obj = {}; try { let mobileBookingMask = document.querySelector( ".mobile-booking-mask.theme--navy.has-bg" ); let bookingForm = mobileBookingMask.querySelector("form"); if (bookingForm.elements.namedItem("hotel").selectedIndex == 0) { checkHotelSelectionFail( document.querySelector(".mobile-booking-mask.theme--navy.has-bg div.dropdown") ); e.preventDefault(); return; } /* ---------------------------------- bookNow() is called. parameters being passed in are values from the mobile booking form ---------------------------------- */ obj.arrive = bookingForm.elements.namedItem("arrive").value; // check if depart is '' if (bookingForm.elements.namedItem("depart").value == "") { let tempDate = new Date(obj.arrive); let updatedDate = tempDate.setDate(tempDate.getDate() + 1); obj.depart = new Date(updatedDate).toISOString().split("T")[0]; } else { obj.depart = bookingForm.elements.namedItem("depart").value; } obj.adult = bookingForm.elements.namedItem("adult").value; obj.child = bookingForm.elements.namedItem("child").value; obj.promo = bookingForm.elements.namedItem("promo").value; obj.groupCode = bookingForm.querySelectorAll('input[placeholder="Company code or work email"') ? (bookingForm.querySelectorAll('input[placeholder="Company code or work email"')[0] ? bookingForm.querySelectorAll('input[placeholder="Company code or work email"')[0].value : "") : ""; obj.hotel = document.querySelector(".mobile-booking-mask.theme--navy.has-bg div.dropdown") ? bookingForm.elements.namedItem("hotel").querySelectorAll("option:checked")[0].value : document.querySelector("body > div.mobile-booking-mask.theme--navy.has-bg.active > form > input[name='hotel']").value console.log('Mobile form data', obj) bookNow(assignObjectVals(obj)) e.preventDefault(); document .querySelector(".mobile-booking-mask.theme--navy.has-bg") .classList.remove("active"); } catch (err) { handleError(err, "mobileForm", obj) } }; // For dynamic elements document.addEventListener("click", function (e) { try { if (e.target && e.target.nodeName == "A") { let hlink = e.target.href.toString().toLowerCase(); if ( (hlink.includes("synxis") || hlink.includes("reservations.clubquartershotels")) && !hlink.includes("/signin")) { e.preventDefault(); e.stopPropagation(); e.target.removeAttribute("target"); let parsedLink = parseURL(hlink); if (parsedLink[2] != undefined && (parsedLink[1]["hotel"] === "" || parsedLink[1]["hotel"] === undefined)) { let linkDest = (parsedLink[2] === "" || parsedLink[2] === "undefined" || parsedLink[2] === undefined) ? "CQMBR" : parsedLink[2]; let hotelListData = filterHotelsByDestination(hotels, linkDest.toUpperCase()); // console.log('hotelListData', hotelListData) // console.log('linkDest.toUpperCase()', linkDest.toUpperCase(), 'parsedLink[2].toString().toUpperCase()', parsedLink[2].toString().toUpperCase()) let hotelsByDest = groupHotelsByDestination(hotelListData, 4) htmlContainer = modalBuilder(hotelsByDest, assignObjectVals(parsedLink[1])) document.querySelector(".hotel-list-section").innerHTML = htmlContainer; openSBslideNav(); } else { bookNow(assignObjectVals(parsedLink[1])) } } } } catch (error) { handleError(error, "clickEventListener"); } }); let customStyle = document.createElement("style"); customStyle.textContent = ` .hotel-list-section > button:before, .hotel-list-section > button:after, .hotel-list-section > button { background-color: transparent !important; display: block !important; text-align: left !important; color: #D6D1CA !important; font-weight: 500 !important; margin-top: 10px; margin-bottom: 5px; margin-left: 1rem; margin-right: 0.5rem; } .sb-hotel-destination { text-transform: uppercase !important; } `; document.head.appendChild(customStyle); // Global error capture // window.onerror = (a, b, c, d, e) => { // // filter away(remove) known errors // if (a.toString().toLowerCase().includes("resizeobserver") // || b.toString().toLowerCase().includes("clubquarters") // || b.toString().toLowerCase().includes("hotelsnetwork") // || (a.toString().toLowerCase().includes("script error.") // && b.toString().toLowerCase().includes("") // && e.toString().toLowerCase().includes("null.")) // ) { // return false; // } else { // let customError = {}; // let errorName = a.toString().split(":") // ? a.toString().split(":")[0] // : a.toString().split(" ")[0] // customError.name = errorName // customError.message = ` // [MESSAGE]: ${a}. // [SOURCE]: ${b}. // [STACK]: ${e.stack ? e.stack : ""}. // [LINENO]: ${c}. // [COLNO]: ${d}. // [ERROR]: ${e}.`; // handleError(customError, errorName); // return false; // } // }; }