var checks = [["street", ad.street.length >= 4, "Please enter your street address."], ["city", ad.city.length >= 2, "Please enter your city."], ["state", !!ad.state, "Please choose your state."], ["zip", /^\d{5}$/.test(ad.zip), "Please enter a 5-digit ZIP code."]]; for (var i = 0; i < checks.length; i++) { var c = checks[i]; $(c[0]).classList.toggle("rs-bad", !c[1]); if (!c[1]) { err("errAddr", c[2]); $(c[0]).focus(); return; } } if (CONFIG.zips && !CONFIG.zips[ad.zip]) { outOfArea(ad.zip, true); return; } busy = true; var btn = $("book"); btn.disabled = true; btn.textContent = "Booking your estimate\u2026"; var done = function () { busy = false; btn.disabled = false; btn.innerHTML = "Confirm my free estimate →"; }; var full = ad.street + ", " + ad.city + ", " + ad.state + " " + ad.zip; fetchSlots(true).then(function (j) { // still open? (someone else may have just taken it) var open = j.days.some(function (d) { return d.slots.indexOf(booking.start) > -1; }); if (!open) { done(); show("cal"); loadCalendar().then(function () { err("errSlot", "Sorry, that time was just taken. Please pick another."); }); return; } var appt = { calendar_id: CONFIG.calendarId, appointment_start: booking.start, appointment_end: new Date(Date.parse(booking.start) + CONFIG.durationMin * 6e4).toISOString(), appointment_time: longDay(booking.day) + " at " + fmt(booking.start) + " (" + tzLabel + ")", appointment_timezone: tzName, address1: ad.street, city: ad.city, state: ad.state, postal_code: ad.zip, full_address: full }; return bookDirect(appt).then(function (res) { if (res === "booked") { done(); thankYou(ad); return; } if (res === "taken") { done(); show("cal"); loadCalendar().then(function () { err("errSlot", "Sorry, that time was just taken. Please pick another."); }); return; } if (res === "error") { done(); err("errAddr", "We couldn't book that just now. Please try again."); return; } return hook("appointment_booked", appt) // booking function unreachable: the webhook carries the booking instead .then(function (ok) { done(); if (ok) thankYou(ad); else err("errAddr", "We couldn't book that just now. Please try again."); }); }); }).catch(function () { done(); err("errAddr", "Connection problem. Please check your signal and try again."); }); }); function bookDirect(appt) { // -> "booked" | "taken" | "error" | "unreachable" if (!CONFIG.bookFn) return Promise.resolve("unreachable"); return fetch(CONFIG.bookFn, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ slot: appt.appointment_start, first_name: lead.first_name || "", last_name: lead.last_name || "", email: lead.email || "", phone: lead.phone || "", address1: appt.address1, city: appt.city, state: appt.state, postal_code: appt.postal_code, project: a.project || "" }) }) .then(function (r) { return r.json(); }) .then(function (j) { return j && j.booked ? "booked" : j && j.error === "slot_taken" ? "taken" : "error"; }, function () { return "unreachable"; }); } function thankYou(ad) { var full = ad.street + ", " + ad.city + ", " + ad.state + " " + ad.zip; $("tyTitle").textContent = "You're booked in, " + lead.first_name + "!"; $("tyWhen").textContent = longDay(booking.day) + " at " + fmt(booking.start) + " (" + tzLabel.replace(" Time", "") + ")"; $("tyWhere").textContent = full; var ms = Date.parse(booking.start), z = function (t) { return new Date(t).toISOString().replace(/[-:]|\.\d{3}/g, ""); }; $("gcal").href = "https://calendar.google.com/calendar/render?action=TEMPLATE&text=" + encodeURIComponent("Free bathroom estimate with " + CL.name) + "&dates=" + z(ms) + "/" + z(ms + 3600000) + "&ctz=" + encodeURIComponent(tzName) + "&location=" + encodeURIComponent(full) + "&details=" + encodeURIComponent((CL.owner ? CL.owner + " from " : "") + CL.name + " comes to look at the space for your bathroom." + (CL.phone ? " Questions: " + CL.phone : "")); px("Schedule", { content_name: "Instant estimate" }, "schedule-" + leadId); show("ty"); } /* Step bar: jump to any screen with sample answers */ window.__rsDemo = function (s) { lead.first_name = lead.first_name || "Pat"; lead.last_name = lead.last_name || "Smith"; lead.email = lead.email || "
[email protected]"; lead.phone = lead.phone || "+15555550123"; if (!area.zip) area = { zip: "12345", city: "Springfield", state: CONFIG.state || "", lat: null, lng: null }; a.homeowner = a.homeowner || "Yes"; a.project = a.project || "Full bathroom remodel"; root.querySelectorAll(".rs-fn").forEach(function (x) { x.textContent = lead.first_name; }); hist = []; var withSlot = function () { return (days.length ? Promise.resolve() : loadCalendar()).then(function () { if (days.length) { booking.day = days[0]; booking.start = days[0].slots[0]; } }); }; if (s === "oa") return outOfArea("00000", false); if (s === "cal") { show("cal"); return loadCalendar(); } if (s === "addr") return withSlot().then(toAddress); if (s === "ty") return withSlot().then(function () { thankYou({ street: "123 Main Street", city: area.city, state: area.state || "TX", zip: area.zip }); }); show(s); }; // Load the open times early so the calendar is instant when they get there. fetchSlots();})();