Public Access
feat(bootcamp): waiting-list form for another timezone or language
Three bootcamp pages (EN/DE/ES) get a small waiting-list block below the Buy button, in the Price and booking section next to the live seat count. - two required fields: email + comment; framed as "another timezone or language?" and worded around the January cohort's own schedule - posts to the same n8n CRM webhook as the site's other forms, with the footer-message payload shape copied exactly: area:'message', requirements carries the comment, no name field, wrapped in UTM.inject() - success hides the form and shows a confirmation; a failure restores the button and shows a retryable error (never stuck on "sending") - Plausible event 'Bootcamp Waitlist' on success only (cookieless); no Google Ads tag and no conversion, as on the rest of these pages - new page-local /static/bootcamp-waitlist.js carries the verbatim UTM helpers from script.js (this page does not load script.js) - buying is untouched: no markup change to the three product-17 forms Verified: exact posted body per language captured on the wire, success and error states in a real browser, 375 px no overflow, verify-html 0, JS syntax 0, competitor QC 0 new, impeccable detect byte-identical (zero new findings).
This commit is contained in:
1 parent
812571b177
commit
8f72652ada
4 files changed
+393
No files matched your search
@@ -0,0 +1,123 @@
|
||||
/* bootcamp-waitlist.js — page-local waiting-list form for the three bootcamp pages.
|
||||
*
|
||||
* The user's rule: "You want another timezone / language? Join the waiting list."
|
||||
* The form posts to the same n8n CRM webhook the site's other forms use, with the
|
||||
* site's own footer-message payload shape — area:'message', no `name` (that belongs to
|
||||
* the `area:'quote'` shape of the Custom Quote modal).
|
||||
*
|
||||
* This page does not load /script.js, so the UTM helpers are copied verbatim from it
|
||||
* (same as /static/black-friday.js does). If script.js's helpers change, change these.
|
||||
*
|
||||
* All copy — labels, placeholders, the "sending" label, success and error text — lives in
|
||||
* the page markup, in the page's own language. This file carries no strings.
|
||||
*
|
||||
* A 200 from the webhook means the workflow accepted the request, not that a CRM record
|
||||
* exists (the workflow answers before it runs) — same as the site's other forms.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* ---- UTM tracking helpers (verbatim from /script.js) ---- */
|
||||
function getCookie(name) {
|
||||
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
return match ? decodeURIComponent(match[2]) : null;
|
||||
}
|
||||
|
||||
function setCookie(name, value, days) {
|
||||
var expires = '';
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = '; expires=' + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
|
||||
}
|
||||
|
||||
function parseUTM() {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = urlParams.get('utm_' + keys[i]);
|
||||
if (val) {
|
||||
utm[keys[i]] = val;
|
||||
setCookie('utm_' + keys[i], val, 90);
|
||||
}
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
|
||||
function getStoredUTM() {
|
||||
var utm = {};
|
||||
var keys = ['source', 'medium', 'campaign'];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var val = getCookie('utm_' + keys[i]);
|
||||
if (val) utm[keys[i]] = val;
|
||||
}
|
||||
return utm;
|
||||
}
|
||||
|
||||
function injectUTM(data) {
|
||||
var stored = getStoredUTM();
|
||||
if (Object.keys(stored).length > 0) {
|
||||
data.utm_source = stored.source || null;
|
||||
data.utm_medium = stored.medium || null;
|
||||
data.utm_campaign = stored.campaign || null;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
window.UTM = { parse: parseUTM, getStored: getStoredUTM, inject: injectUTM };
|
||||
window.UTM.parse();
|
||||
|
||||
/* ---- Waiting list ---- */
|
||||
var ENDPOINT = 'https://n8n.odoo4projects.com/webhook/ODOO4projects/crm';
|
||||
|
||||
function run() {
|
||||
var form = document.getElementById('bcWaitlistForm');
|
||||
if (!form) return;
|
||||
var emailInput = document.getElementById('bcWaitlistEmail');
|
||||
var commentInput = document.getElementById('bcWaitlistComment');
|
||||
var submitBtn = form.querySelector('button[type="submit"]');
|
||||
var success = document.getElementById('bcWaitlistSuccess');
|
||||
var error = document.getElementById('bcWaitlistError');
|
||||
var label = submitBtn ? submitBtn.textContent : '';
|
||||
|
||||
/* Both fields are required, exactly as the footer form requires both. */
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var email = emailInput.value.trim();
|
||||
var comment = commentInput.value.trim();
|
||||
if (!email || !comment) return;
|
||||
|
||||
error.style.display = 'none';
|
||||
submitBtn.textContent = submitBtn.getAttribute('data-sending') || label;
|
||||
submitBtn.disabled = true;
|
||||
|
||||
fetch(ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(UTM.inject({
|
||||
email: email,
|
||||
requirements: comment,
|
||||
area: 'message'
|
||||
}))
|
||||
}).then(function (r) {
|
||||
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||
if (window.plausible) window.plausible('Bootcamp Waitlist');
|
||||
form.style.display = 'none';
|
||||
success.style.display = 'block';
|
||||
}).catch(function () {
|
||||
submitBtn.textContent = label;
|
||||
submitBtn.disabled = false;
|
||||
error.style.display = 'block';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', run);
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
})();
|
||||
Reference in new issue
Block a user