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();
/* eslint-disable no-undef */
/*
----------------------------------
Custom integration script for Dorchester Collection.
https://www.dorchestercollection.com/
Chain code: 5310
----------------------------------
*/
// https://bugsnagerrorreportingapi.docs.apiary.io/#
const API_KEY_BUGSNAG = '6cb771be223c608f92775d1516dce6e2';
const CLIENT_URL = window.location.href;
async function sendErrorToBugsnag(error, func, sb_int_queue) {
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,
},
},
],
},
],
severity: 'error',
context: CLIENT_URL,
app: {
releaseStage: sb_int_queue ? sb_int_queue : '',
},
},
],
};
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 successfully');
} else {
console.error('Failed to send error report');
}
} catch (error) {
console.error('Error sending error report:', error);
}
};
function handleError(error, func, sb_int) {
console.error(`${func} error occurred:`, error);
sendErrorToBugsnag(error, func, sb_int); // Forward the error to Bugsnag reporting
};
console.log(
'%cCustom script has been initialized',
'background: green; color: white;',
);
(() => {
const theLanaCustomStyles = document.createElement('style');
theLanaCustomStyles.innerText = `
[data-testid="properties-list"] [alt="The Lana"] + 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: 15px !important;
padding-bottom: 10px !important;
display: block !important;
content: "Striking a new pose on Dubai’s impressive skyline, The Lana is a celebration of the city’s vibrancy, captivating vistas and glorious sunsets." !important;
}
`;
document.head.appendChild(theLanaCustomStyles);
})();
const stylesForSBcta = `.synxis-best-rate{cursor:pointer;} .sbCTAcontainer{ position: relative; z-index:1000; background-color:orange;}.sbCTApositionContainer{ position: fixed; right:50px; bottom:50px;}#sbSlideInSection { margin-right:-350px; font-family: acumin-pro,Arial,sans-serif;}.sbSlideInNav { background-color: #fff; padding-left:30px; height: 100%; width: 350px; position: fixed; z-index: 100; top: 0; right: 0; padding-top: 60px; overflow-x: hidden; transition: 0.5s;}
.sbSlideInNav a { display: block; font-weight: 300; color: #000; padding: 8px 8px 8px 32px; text-decoration: none; font-size: 25px; transition: 0.3s;}.sbSlideInNav a:hover { color: #cc9f27;}.sbSlideInNav .closeSbSlider { position: absolute; top: 7px; color:#000; font-weight:900; right: 25px; font-size: 40px; margin-left: 50px;}@media screen and (max-height: 450px) { .sbSlideInNav {padding-top: 15px;}
.sbSlideInNav a {font-size: 18px;}} .sb-hotel-dest-group, .sb-section-header { font-family:acumin-pro,Arial,sans-serif; font-weight: 300;} .sb-section-header{ font-size: 1.65rem; margin-bottom:10px; } .sb-hotel-destination{ color:#b58504; } .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; font-weight: 400;};
#sbCTAcontainer #sbSlideInSection { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); padding-top: 2rem; padding-left: 2rem; } #sbCTAcontainer #sbSlideInSection .sbSlideInNav .closeSbSlider { margin-left: 0; } #sbCTAcontainer #sbSlideInSection .sb-section-header { font-size: 1.25rem; line-height: 1.75rem; margin-bottom: 1rem; line-height: 2rem; } #sbCTAcontainer #sbSlideInSection .sb-hotel-dest-group { margin-bottom: 1rem; }
#sbCTAcontainer #sbSlideInSection .sb-hotel-dest-group .sb-hotel-destination { --text-opacity: 1; color: #D9B77B; color: rgba(217, 183, 123, var(--text-opacity)); font-weight: 700; font-size: 0.75rem; line-height: 1rem; text-transform: uppercase; line-height: 1; margin-bottom: 0.5rem; } #sbCTAcontainer #sbSlideInSection .sb-hotel-dest-group a { margin-left: 0; }
#sbCTAcontainer #sbSlideInSection .sb-hotel-dest-group a .sb-muted-text { --text-opacity: 1; color: #bdbdbd; color: rgba(189, 189, 189, var(--text-opacity)); font-weight: 400;}
#selfbook-loading { display: none!important; }`;
const sbStyles = document.createElement('style');
sbStyles.textContent = stylesForSBcta;
document.head.appendChild(sbStyles);
const sbCTAcontainer = document.createElement('div');
sbCTAcontainer.setAttribute('class', 'sbCTAcontainer');
sbCTAcontainer.setAttribute('id', 'sbCTAcontainer');
document.body.appendChild(sbCTAcontainer);
const sbCTApositionContainer = document.createElement('div');
sbCTApositionContainer.setAttribute('class', 'sbCTApositionContainer');
sbCTAcontainer.appendChild(sbCTApositionContainer);
const sbSlideInSection = document.createElement('div');
sbSlideInSection.setAttribute('class', 'sbSlideInNav');
sbSlideInSection.setAttribute('id', 'sbSlideInSection');
sbSlideInSection.innerHTML = `✕
`;
sbCTApositionContainer.appendChild(sbSlideInSection);
function openSBslideNav() {
if (document.getElementById('sbSlideInSection')) {
document.getElementById('sbSlideInSection').style.marginRight = '0';
}
}
// eslint-disable-next-line no-unused-vars
function closeSBslideNav() {
if (document.getElementById('sbSlideInSection')) {
document.getElementById('sbSlideInSection').style.marginRight = '-350px';
}
}
function unSelectOpenDate() {
let counter = 0;
const undoStartDateInterval = setInterval(function() {
counter++;
if (document.querySelector('button[data-testid="sb-calendar-day-Thu Feb 01 2024"][aria-current="true"]')) {
console.log(`Took ${counter} loops to remove overflow hidden`);
document.querySelector('button[data-testid="sb-calendar-day-Thu Feb 01 2024"][aria-current="true"]').click();
clearInterval(undoStartDateInterval);
}
}, 500);
}
function theLanaOpenDate() {
bookNow({hotelId: '42380', startDate: '2024-02-01'});
closeSBslideNav();
unSelectOpenDate();
}
/* 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) {
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)) {
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) {
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 */
const 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 */
const 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(). */
const assignObjectVals = (param) => {
try {
const urlData = param;
// console.log(param);
const bookNowParams = {
startDate: verifyFutureDate(urlData.arrive),
endDate: 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,
};
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 = {};
const siteUrl = `${window.location.pathname}?selfbook=true`;
let urlInput = url.replace(/%20/g, '');
if (urlInput.toLowerCase().includes('?')) {
urlInput = urlInput.toLowerCase().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 = `${siteUrl}&${searchParams}`;
return [domain, params, searchParams];
}
return [siteUrl, '', ''];
} catch (error) {
handleError(error, 'parseURL');
}
};
/* 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() */
const linkReplacer = () => {
try {
const allSynxisLinks = document.querySelectorAll(`a[href*='synxis']`);
// const allSynxisLinks = document.querySelectorAll(`a[href*='reservations'], a[href*='synxis']`);
for (let i = 0; i < allSynxisLinks.length; i++) {
const atag = allSynxisLinks[i];
const link = allSynxisLinks[i].href.toString().toLowerCase();
const parsedLink = parseURL(link);
const finalParams = assignObjectVals(parsedLink[1]);
// console.log('parseURL(link)[0]', parseURL(link)[0]);
// console.log('finalParams', finalParams);
// atag.href = '#';
if (link.indexOf('hotel=') === -1 && !link.includes('sb-skip=true')) {
allSynxisLinks[i].removeAttribute('target');
atag.href = '#' + parseURL(link)[2];
atag.addEventListener('click', (e) => {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
openSBslideNav();
});
} else if (!link.includes('sb-skip=true')) {
atag.href = '#' + parseURL(link)[2];
allSynxisLinks[i].removeAttribute('target');
atag.addEventListener('click', (e) => {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
bookNow(finalParams);
});
}
}
} catch (error) {
handleError(error, 'linkReplacer');
}
};
linkReplacer();
(() => {
let customStyles = document.createElement('style');
customStyles.innerText = `
#selfbook_sdkwidget .payment-summary-wrapper div > span > p {
margin-top: 10px !important;
width: 100% !important;
text-align: left !important;
}
#selfbook_sdkwidget .payment-summary-wrapper div > span > p > a {
color: #495057 !important;
font-weight: 400 !important;
text-decoration: underline !important;
}
#selfbook_sdkwidget .payment-summary-wrapper div > span > p > a:hover {
cursor: pointer !important;
}
`;
document.head.appendChild(customStyles);
})();
const sbLegalTextEng = `By continuing to checkout, you agree all the booking terms including booking and cancellation policies. You can object at anytime to the use of your data by writing at privacy.DCL@dorchestercollection.com. For more information on the processing of your personal data, please consult our Privacy Policy. For our French hotels, you can object to telephone prospecting by registering on the Bloctel opposition list`;
const sbLegalTextFR = `En poursuivant, vous accepter toutes les conditions y compris les politiques de réservations et d’annulation.
Vous pouvez à tout moment vous opposer à l’utilisation de vos données en écrivant à privacy.DCL@dorchestercollection.com. Pour plus d’informations sur le traitement de vos données à caractère personnel, merci de consulter notre Politique de Confidentialité.
Pour nos hôtels français, vous pouvez vous opposer au démarchage téléphonique en vous inscrivant sur la liste d’opposition Bloctel`;
setInterval(() => {
linkReplacer();
if (document.querySelector('#selfbook_sdkwidget [lang="en"] .payment-summary-wrapper div > span > p')) {
document.querySelector('#selfbook_sdkwidget [lang="en"] .payment-summary-wrapper div > span > p').innerHTML = sbLegalTextEng;
}
if (document.querySelector('#selfbook_sdkwidget [lang="fr"] .payment-summary-wrapper div > span > p')) {
document.querySelector('#selfbook_sdkwidget [lang="fr"] .payment-summary-wrapper div > span > p').innerHTML = sbLegalTextFR;
}
}, 1000);
// Function to calculate distance from top of screen
// Add click event listener to the document
/* for single page apps, use this code to grab anchor tags and add event listeners */
document.addEventListener('click', function(e) {
if (e.target && e.target.nodeName == 'A') {
try {
const hlink = e.target.href.toString().toLowerCase();
if (hlink.includes('synxis') && !hlink.includes('sb-skip=true')) {
e.target.removeAttribute('target');
e.preventDefault();
e.stopPropagation();
if (hlink.indexOf('hotel=') === -1) {
openSBslideNav();
} else {
const parsedLink = parseURL(hlink);
bookNow(assignObjectVals(parsedLink[1]));
}
}
} catch (error) {
handleError(error, 'document.AddEventListener');
}
}
});
function customHideUpgrades(params) {
new MutationObserver(() => {
const el = document.querySelector(params.element);
if (el && !document.getElementById('customHideUpgrades') && (el.value === 'DIAMONDCLUB' || el.value === 'diamondclub')) {
console.log('found diamond club upgrade');
const style = document.createElement('style');
style.id = 'customHideUpgrades';
style.textContent = `
#sb-screen #sb-upgrade-container {
display: none !important;
}`;
document.querySelector('body').appendChild(style);
}
if (el && (el.value !== 'DIAMONDCLUB' && el.value !== 'diamondclub') && document.getElementById('customHideUpgrades') !== null) {
console.log('removing diamond club upgrade hide');
document.getElementById('customHideUpgrades').remove();
}
}).observe(params.parent || document, {
subtree: true,
childList: true,
});
}
customHideUpgrades({
hidden: '#sb-screen div.css-1xjhl1u',
element: '#special-rate-promo-code',
parent: document.getElementById('widget-inner-wrapper'),
recursive: false,
});
function customPostBookingAddonText() {
const dineText = document.querySelector('[data-testid=\'sb-screen-content\'] > div:first-child > div:nth-child(4) > div:first-child > div:first-child > section > div > div:first-child > div');
dineText.innerHTML = 'Book dining, drinks and more';
}
function customPostBookingAddonText2() {
const dineText = document.querySelector('[data-testid=\'sb-screen-content\'] > div:first-child > div:first-child > div:first-child > div:first-child > section > div > div:first-child > div');
dineText.innerHTML = 'Book dining, drinks and more';
}
function customPostBookingAddonText3() {
const dineText = document.querySelector('[data-testid=\'sb-screen-content\'] > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child > div');
dineText.innerHTML = 'Book dining, drinks and more';
}
function postBookingObserver(params) {
new MutationObserver(() => {
const el = document.querySelector(params.id);
if (el && el.innerHTML === 'Add experience and amenities.') {
console.log('element found');
customPostBookingAddonText();
}
}).observe(params.parent || document, {
subtree: true,
childList: true,
});
}
function reservationCheckObserver(params) {
new MutationObserver(() => {
const el = document.querySelector(params.id);
if (el && el.innerHTML === 'Add experience and amenities.') {
console.log('element found2');
customPostBookingAddonText2();
}
}).observe(params.parent || document, {
subtree: true,
childList: true,
});
}
function reservationCheckObserver2(params) {
new MutationObserver(() => {
const el = document.querySelector(params.id);
if (el && el.innerHTML === 'Add experience and amenities.') {
console.log('element found3');
customPostBookingAddonText3();
}
}).observe(params.parent || document, {
subtree: true,
childList: true,
});
}
postBookingObserver({
id: '[data-testid=\'sb-screen-content\'] > div:first-child > div:nth-child(4) > div:first-child > div:first-child > section > div > div:first-child > div',
parent: document.getElementById('widget-inner-wrapper'),
recursive: false,
});
reservationCheckObserver({
id: '[data-testid=\'sb-screen-content\'] > div:first-child > div:first-child > div:first-child > div:first-child > section > div > div:first-child > div',
parent: document.getElementById('widget-inner-wrapper'),
recursive: false,
});
reservationCheckObserver2({
id: '[data-testid=\'sb-screen-content\'] > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child > div',
parent: document.getElementById('widget-inner-wrapper'),
recursive: false,
});
// Global error capture
window.onerror = (message, source, lineno, colno, error) => {
// Returning true prevents the default browser error handling. Skip staging sites
if (!window.location.href.includes('uat.dorchestercollection') || !window.location.href.includes('uat-cms.dorchestercollection')) {
if (message && !message?.toString().toLowerCase().includes('resizeobserver') &&
!source?.toString().toLowerCase().includes('guestbook') &&
!source?.toString().toLowerCase().includes('dorchester')) {
const customError = {
name: message?.toString().split(' ')[0],
message: `
message: ${message}.
source: ${source}.
lineno: ${lineno}.
colno: ${colno}.
error: ${error}.`,
};
if (
source &&
(
source.toString().includes('react') ||
source.toString().includes('saga.js') ||
source.toString().includes('affirm.js')
)
) {
handleError(customError, 'selfbook-crash', 'sb_integrations');
return true;
}
}
}
};
// Maintenance Mode Function for Coworth Park
// function coworthParkMaintenance() {
// const propertySelect = document.querySelector('#sb-property-select');
// if (propertySelect && propertySelect.innerHTML.includes('Coworth')) {
// const editBookingSection = document.querySelector('[data-testid="sb-edit-booking"]');
// const footer = document.querySelector('[data-testid="sb-screen-body"] div[data-testid="sb-screen-footer"]');
// editBookingSection.innerHTML = `
// We Apologize
//
//
// Please note that online bookings are temporarily unavailable due to system maintenance.
// For Coworth Park reservations please contact +44 (0)1344 838 160. We apologize for any inconvenience.
// `;
// if (footer) {
// footer.remove();
// }
// }
// }
// setInterval(coworthParkMaintenance, 1000);