1/** 2 * Thank-you trip handler. 3 * 4 * Two jobs: 5 * 1. On property page load: if URL has `?trip=<hash>&slot=<slot>`, stash to sessionStorage so the 6 * context survives the Guesty checkout redirect (which drops our query params). 7 * 2. On any page load: if sessionStorage has a pending trip context AND the current page looks 8 * like a post-booking success state, POST to the trip REST endpoint to mark the listing booked. 9 * 10 * Depends on global `hrckTripThankYou` localized from TripBuilderTool. 11 */ 12(function () { 13 'use strict'; 14 15 if (typeof hrckTripThankYou === 'undefined') { 16 return; 17 } 18 19 var STORAGE_KEY = 'hrck_trip_context'; 20 21 function getUrlParam(name) { 22 var search = window.location.search || ''; 23 var match = new RegExp('[?&]' + name + '=([^&]+)').exec(search); 24 return match ? decodeURIComponent(match[1]) : null; 25 } 26 27 function stashIfPresent() { 28 var hash = getUrlParam('trip'); 29 var slot = getUrlParam('slot'); 30 var token = getUrlParam('t'); 31 if (hash && slot && /^[A-Za-z0-9_-]{16}$/.test(hash)) { 32 try { 33 sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ hash: hash, slot: parseInt(slot, 10), token: token || '' })); 34 } catch (e) { /* storage blocked */ } 35 } 36 } 37 38 function readStash() { 39 try { 40 var raw = sessionStorage.getItem(STORAGE_KEY); 41 if (!raw) { return null; } 42 var parsed = JSON.parse(raw); 43 if (parsed && parsed.hash && parsed.slot) { return parsed; } 44 } catch (e) { /* noop */ } 45 return null; 46 } 47 48 function clearStash() { 49 try { sessionStorage.removeItem(STORAGE_KEY); } catch (e) { /* noop */ } 50 } 51 52 function urlReservationId() { 53 // The HR plugin's confirmation page arrives as ?reservation=<uuid>&hash=<bcrypt> â 54 // the exact Central reservation id its [homerunner-confirmation] shortcode resolves. 55 // This is the one attachment point every standard HR checkout actually provides. 56 var id = getUrlParam('reservation') || getUrlParam('reservation_id'); 57 if (id && /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(id)) { 58 return id; 59 } 60 return null; 61 } 62 63 function looksLikeSuccess() { 64 // The HR confirmation page carries the reservation id + verification hash in the URL â 65 // the strongest success signal available, and present on every standard HR checkout. 66 if (urlReservationId() && getUrlParam('hash')) { 67 return true; 68 } 69 // Conservative fallbacks: HomeRunner's thank-you page commonly contains a .reservation-confirmation 70 // block or a body class of `page-thank-you`. Match either. 71 if (document.body && document.body.className) { 72 if (/thank-?you|booking-success|reservation-confirmed/i.test(document.body.className)) { 73 return true; 74 } 75 } 76 if (document.querySelector('.reservation-confirmation, .booking-confirmed, [data-reservation-id]')) { 77 return true; 78 } 79 // Also allow an explicit window flag the HR plugin can set when it renders confirmation. 80 if (typeof window.hrckBookingCompleted !== 'undefined' && window.hrckBookingCompleted) { 81 return true; 82 } 83 return false; 84 } 85 86 function extractReservationId() { 87 // URL param first: it is the Central reservation id verbatim (UUID-validated above). 88 var fromUrl = urlReservationId(); 89 if (fromUrl) { return fromUrl; } 90 // Theme/site-specific attachment points; return null if not found â acceptable, the 91 // listing is still marked booked and revenue falls back to the search-time estimate. 92 var el = document.querySelector('[data-reservation-id]'); 93 if (el) { 94 var id = el.getAttribute('data-reservation-id'); 95 if (id) { return id; } 96 } 97 if (window.hrckReservationId) { 98 return String(window.hrckReservationId); 99 } 100 return null; 101 } 102 103 function postBooked(context, reservationId) { 104 var url = hrckTripThankYou.restBase + '/' + encodeURIComponent(context.hash) 105 + '/listing/' + encodeURIComponent(String(context.slot)) + '/booked'; 106 107 var payload = { token: context.token || '' }; 108 if (reservationId) { payload.reservation_id = reservationId; } 109 110 fetch(url, { 111 method: 'POST', 112 headers: { 113 'Content-Type': 'application/json', 114 'X-WP-Nonce': hrckTripThankYou.nonce 115 }, 116 body: JSON.stringify(payload) 117 }) 118 .then(function (res) { 119 if (res.ok) { 120 clearStash(); 121 showNotice(context.hash); 122 } 123 }) 124 .catch(function () { /* silent; reservation sync is the backstop in v1.1 */ }); 125 } 126 127 function showNotice(hash) { 128 var wrap = document.createElement('div'); 129 wrap.className = 'hrck-trip-thank-you-notice'; 130 wrap.setAttribute('role', 'status'); 131 wrap.innerHTML = 'This listing is booked for your group trip. ' 132 + '<a href="/trip/' + encodeURIComponent(hash) + '">Back to your trip →</a>'; 133 document.body.appendChild(wrap); 134 } 135 136 // Job 1: stash trip context on every page (no harm if URL doesn't have the params) 137 stashIfPresent(); 138 139 // Job 2: if we look like a success page and have stash, mark booked. 140 if (document.readyState === 'loading') { 141 document.addEventListener('DOMContentLoaded', maybeMarkBooked); 142 } else { 143 maybeMarkBooked(); 144 } 145 146 function maybeMarkBooked() { 147 var context = readStash(); 148 if (!context) { return; } 149 // Give the thank-you page a moment to hydrate (Guesty checkout can be slow to settle). 150 setTimeout(function () { 151 if (!looksLikeSuccess()) { return; } 152 postBooked(context, extractReservationId()); 153 }, 600); 154 } 155})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.