function onShadowReady(root, selector, callback) { const existing = root.querySelector(selector); if (existing) return callback(existing); const observer = new MutationObserver(() => { const el = root.querySelector(selector); if (el) { observer.disconnect(); callback(el); } }); observer.observe(root, { childList: true, subtree: true }); } function jarvisGoBack() { if (!window.$shedulerShadowRoot) return; onShadowReady( window.$shedulerShadowRoot, "#app > div.flex.flex-col.flex-grow.mt-6 > form > div.z-50.flex-grow.py-6.mt-6.bg-color.shadow-2xl > div > div > div a", (backButton) => { console.log("Back button clicked by script:", backButton); backButton.click(); } ); } function isIOS() { return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; } var load_jarvis = () => { function getCommentFromURL() { // Get the full URL const url = window.location.href; // Create a URL object const urlObj = new URL(url); // Get the search parameters const searchParams = new URLSearchParams(urlObj.search); // Get the 'comment' parameter if it exists const comment = searchParams.get("comment"); // Return the decoded comment or null if not present return comment ? decodeURIComponent(comment) : null; } var LocationName = window.jarvisConfig.officeId; // Change as needed var bookingForm = document.getElementById("booking-form"); if ( LocationName === "" || LocationName === null || LocationName === undefined ) { bookingForm.style.display = "block"; var loading_icon_temp = document.getElementById("loading-spinner-tmp"); loading_icon_temp.style.display = "none"; //hide when form shows } else { bookingForm.style.display = "none"; try { /* const urlParams = new URLSearchParams(window.location.search); var commentPrefill = ""; if (urlParams.has("comment")) { = urlParams.get("comment"); }*/ // var $shedulerShadowRoot; //now window.$shedulerShadowRoot var phoneNumber; var customerFirstName; var customerLastName; var customerEmail; /* intercept XHR to get submitted phone number */ const originalXhrSend = XMLHttpRequest.prototype.send; const originalXhrOpen = XMLHttpRequest.prototype.open; // Intercept the open method to capture the URL XMLHttpRequest.prototype.open = function ( method, url, async, user, password ) { this._url = url; // Store the URL for logging return originalXhrOpen.apply(this, arguments); }; // Function to extract the mobile phone from the variables object function extractMobilePhone(variables) { return variables?.input?.mobile_phone ?? null; } // Intercept the send method to capture and log the payload XMLHttpRequest.prototype.send = function (body) { //console.log('Intercepted XHR request:'); //console.log('URL:', this._url); try { const parsedBody = JSON.parse(body); // Check if it's a GraphQL query if (!parsedBody.query) { return originalXhrSend.apply(this, arguments); // Not a GraphQL request } console.log("GraphQL Query:", parsedBody.variables); // Extract the mobile phone if present const mobilePhone = extractMobilePhone(parsedBody.variables); if (mobilePhone) { phoneNumber = mobilePhone; console.log("Extracted phone number:", phoneNumber); } } catch (e) { // Log the raw payload if it's not JSON //console.log('Payload:', body); } // Proceed with the normal submission return originalXhrSend.apply(this, arguments); }; /* end of interception */ /* Intercept fetch function */ LocationName; window.fetch = new Proxy(window.fetch, { apply: async function (target, thisArg, argumentsList) { const [url, options = {}] = argumentsList; if ( url == "https://schedule.jarvisanalytics.com/graphql" && options.body ) { try { const parsedBody = JSON.parse(options.body); const inputData = parsedBody.variables.input; if (inputData) { customerFirstName = inputData.first_name || ""; customerLastName = inputData.last_name || ""; customerEmail = inputData.email || document.getElementById("Booking-Email")?.value || ""; phoneNumber = inputData.mobile_phone || ""; console.log("Captured Submission Data:", { customerFirstName, customerLastName, customerEmail, phoneNumber }); if (phoneNumber) { console.log("Extracted phone number:", phoneNumber); const urlObj = new URL(window.location.href); urlObj.searchParams.delete("comment"); urlObj.searchParams.delete("variant"); //if(is_new_layout){ confirmation page should be the same as control and variant page urlObj.searchParams.set("confirmation", "1"); //} window.history.pushState({}, "", urlObj.toString()); //window.history.replaceState({}, '', urlObj.toString()); } } } catch (e) { // do nothing } } // You can also log the response by handling the promise const response = await target.apply(thisArg, argumentsList); //console.log('Response Status:', response.status); return response; }, }); const winShadowRoot = window.$shedulerShadowRoot; /* end of interception */ //var canUpdatePhoneNumberListener = isThreeStepForm || false; //onThreestep form, we can update the phonenumber listener at start var canObservePolicyRadio = isThreeStepForm || false; var canUpdateComment = false; var hasGoneStepTwoOnce = false; window.jarvis = new window.JarvisAnalyticsScheduler({ //now window.jarvis and window.JarvisAnalyticsScheduler token: "46138|hKPVSp7yX5m83JP4qdrNFI82ui91fp4yvJteVf3e", companyId: 3, locationId: window.jarvisConfig.officeId, }); const dataLayerPush = (event) => { window.scrollTo(0, 0); (window.dataLayer || []).push(event); try { parent.postMessage(event, "*"); setTimeout(() => { console.log("Attempting to prefill comment"); const comment = getCommentFromURL(); if ( comment && winShadowRoot ) { console.log("Comment:", comment); const textarea = winShadowRoot.querySelector("textarea"); if (textarea) { textarea.value = `Offer: ${comment}`; } } // Attach var emailInput = document .querySelector("jarvis-scheduler-v2") .shadowRoot.querySelector("#email"); if (emailInput) { console.log("Email input found"); emailInput.addEventListener("blur", function () { document.getElementById("Booking-Email").value = emailInput.value; var event = new Event("change"); document.getElementById("Booking-Email").dispatchEvent(event); }); } }, 1000); } catch (e) { window.console && window.console.log(e); } }; window.jarvis.title = ""; window.jarvis.colors.activeNavItemBackground = "#6AC64B"; window.jarvis.colors.primaryOptionColor = "#6AC64B"; window.jarvis.colors.primaryButtonBackground = "#6AC64B"; window.jarvis.colors.primaryButtonBorderColor = "#6AC64B"; window.jarvis.colors.bodyBackground = "#FBFEFF"; window.jarvis.colors.headerBackground = "#FBFEFF"; window.jarvis.colors.nearestCardSubtitleColor = "#B7BCC2"; window.jarvis.colors.inactiveNavItemBackground = "#B7BCC2"; window.jarvis.colors.samedayCardSubtitlesColor = "#B7BCC2"; window.jarvis.colors.availabilityBackground = "#FBFEFF"; window.jarvis.colors.availabilityPaginationBackground = "#EEF2F6"; window.jarvis.colors.availabilityPaginationColor = "#767F87"; window.jarvis.colors.availabilityColumnHeaderBackground = "#EEF2F6"; window.jarvis.colors.availabilityColumnHeaderColor = "#767F87"; window.jarvis.colors.nearestCardColumnHeaderBackground = "#EEF2F6"; window.jarvis.colors.nearestCardColumnHeaderColor = "#767F87"; //window.jarvis.onSubmittedhandlers.push(function () { //console.log("submitted"); //}); window.jarvis.onBookSuccesshandlers.push(function () { console.log("Booking confirmed - preparing to send webhook data"); const webhookData = { // Required parameters apikey: "HAuu1jpaWurNhCEHdRG1ZW4ZaDpB4Kr5Qs", location_id: window.jarvisConfig.officeId || "", type: "call", // Extract customer information from the scheduler first_name: customerFirstName || "", last_name: customerLastName || "", email: customerEmail || "", phone: phoneNumber || "", // Optional parameters that might be available date: new Date().toISOString().slice(0, 19).replace('T', ' '), // Current timestamp in Y-m-d H:i:s format }; // Extract first name and last name from shadow DOM try { const firstNameInput = window.$shedulerShadowRoot?.querySelector("input#first_name"); const lastNameInput = window.$shedulerShadowRoot?.querySelector("input#last_name"); if (firstNameInput) webhookData.first_name = firstNameInput.value; if (lastNameInput) webhookData.last_name = lastNameInput.value; // Extract appointment date if available const appointmentDateElements = window.$shedulerShadowRoot?.querySelectorAll("[date-picker-date]"); if (appointmentDateElements && appointmentDateElements.length > 0) { const appointmentDate = appointmentDateElements[0].getAttribute("date-picker-date"); if (appointmentDate) { webhookData.appointment_date = appointmentDate; } } // Extract middle name if available const middleNameInput = window.$shedulerShadowRoot?.querySelector("input#middle_name"); if (middleNameInput && middleNameInput.value) { webhookData.middle_name = middleNameInput.value; } // Extract comments from URL parameter if exists const comment = getCommentFromURL(); if (comment) { webhookData.comments = `Offer: ${comment}`; } // Extract UTM parameters if available in the URL const urlParams = new URLSearchParams(window.location.search); const utmParams = ['utma', 'utmb', 'utmc', 'utmv', 'utmz', 'utmx']; utmParams.forEach(param => { const value = urlParams.get(param); if (value) webhookData[param] = value; }); // Extract referrer if (document.referrer) { webhookData.referrer = document.referrer; } } catch (error) { console.error("Error extracting data from shadow DOM:", error); } // Validate required fields if (!webhookData.first_name || !webhookData.last_name || !webhookData.email) { console.error("Missing required fields for webhook:", webhookData); // For now, we'll log but continue } console.log("Sending webhook data:", webhookData); // Send the webhook to Jarvis Marketing endpoint window.fetch("https://webhooks.jarvisanalytics.com/api/v2/leads", { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify(webhookData) }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { console.log("Webhook sent successfully:", data); // Optional: Store success in dataLayer for analytics if (window.dataLayer) { window.dataLayer.push({ event: 'jarvis_webhook_success', webhookResponse: data }); } }) .catch(error => { console.error("Error sending webhook:", error); // Optional: Store error in dataLayer for analytics if (window.dataLayer) { window.dataLayer.push({ event: 'jarvis_webhook_error', error: error.message }); } // You might want to retry or notify someone // For now, we just log the error }); //console.log("booked") // run after 100ms just to be safe and the DOM is in place setTimeout(() => { const el = winShadowRoot.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.flex.flex-col.flex-grow > div > div > div" ); if (el) { el.style.visibility = "hidden"; el.style.margin = "64px 16px"; el.style.maxWidth = "396px"; el.style.width = "auto"; } window.$shedulerShadowRoot.appendChild(buttonArrowStyle); const p3 = root.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.flex.flex-col.flex-grow > div > div > div > p:nth-child(3)" ); if (p3) p3.textContent = "Confirm your appointment within the next 90 minutes to secure your spot."; const p4 = root.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.flex.flex-col.flex-grow > div > div > div > p:nth-child(4)" ); if (p4) p4.textContent = "We've sent an email and text to:"; const h3 = root.querySelector( "#app>div.flex.flex-col.flex-grow.mt-6>div.flex.flex-col.flex-grow>div>div>div>h3" ); if (h3) h3.textContent = "Last step!"; /* end update success modal text */ /* update phone number in success modal */ const phoneTarget = root.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.flex.flex-col.flex-grow > div > div > div > p.text-lg.md\\:text-2xl" ); if (phoneTarget) { phoneTarget.insertAdjacentHTML( "afterend", `

${phoneNumber}

` ); } /* end update phone number in success modal */ /* .book-an-appointment-container { padding: 0 } */ document .querySelectorAll(".book-an-appointment-container") .forEach((el) => { el.style.padding = "0px 0px 0px 0px"; }); /* hide multiple selectors */ document .querySelectorAll( ".book-an-appointement-container-mobile, .office-info-mobile, .white-bg-left.desktop" ) .forEach((el) => { el.style.display = "none"; }); /* change background color */ document .querySelectorAll( ".book-an-appointment-main, .book-an-appointement-bg-wrapper, body" ) .forEach((el) => { el.style.backgroundColor = "#6AC64B"; }); /* .book-an-appointement-bg-wrapper { padding: 0 } */ document .querySelectorAll(".book-an-appointement-bg-wrapper") .forEach((el) => { el.style.padding = "0"; }); const targetNode = document.getElementById("insurance"); if (targetNode) { const observer = new MutationObserver((mutations) => { mutations.forEach(() => { const ul = targetNode.querySelector("ul"); if (ul) { ul.style.overflow = "auto"; ul.style.height = "200px"; observer.disconnect(); // stop observing once done } }); }); observer.observe(targetNode, { childList: true, subtree: true }); } /* hide success modal container */ const container = root.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.container.mx-auto" ); if (container) container.style.display = "none"; /* .book-an-appointment-main { width: 100% } */ document .querySelectorAll(".book-an-appointment-main") .forEach((el) => { el.style.width = "100%"; }); /* make the success modal visible */ const modal = root.querySelector( "#app > div.flex.flex-col.flex-grow.mt-6 > div.flex.flex-col.flex-grow > div > div > div" ); if (modal) modal.style.visibility = "visible"; }, 100); }); window.jarvis.onloadhandlers.push(function () { //console.log("loaded"); }); window.jarvis.onNextStep(dataLayerPush); window.jarvis.onNextStephandlers.push(function (e) { //canUpdatePhoneNumberListener = true; canObservePolicyRadio = true; canUpdateComment = true; if (!hasGoneStepTwoOnce) { hasGoneStepTwoOnce = true; } }); document .querySelector("#wf-back-button-mobile") ?.setAttribute("onclick", "jarvisGoBack()"); document .querySelector("#back-button-sticky-mobile") ?.setAttribute("onclick", "jarvisGoBack()"); document .querySelector("#back-button-sticky") ?.setAttribute("onclick", "jarvisGoBack()"); document .querySelector("#next-button-sticky") ?.addEventListener("click", () => { winShadowRoot.querySelector(".continue-btn")?.click(); }); window.addEventListener("load", async function () { try { const jarvis_location = document.querySelector("#jarvis-location"); //setTimeout( function () { let $jarvisComponent = document.querySelector( "jarvis-scheduler-v2" ); window.$shedulerShadowRoot = $jarvisComponent.shadowRoot; const shadowApp = window.$shedulerShadowRoot.querySelector("#app"); if (shadowApp) { shadowApp.style.position = "relative"; } const closeButton = window.$shedulerShadowRoot.querySelector("button"); if (closeButton) { closeButton.style.display = "none"; } jarvis_location.insertAdjacentElement("afterend", $jarvisComponent); // the lengthy css was moved to a file but we can still add additional css via the style below; // If we really need to override the file content, we can change, repload on webflow and replace the link, webflow natively support only txt and image files for now that's why the style is in txt format // Create and insert a