Menu
Public repository / 4c387744dbc385b16c78993fca9f753400aead4b
AkurAI-Platform / frontend/contact.js
Latest change f0014e563961e05e2913923cda58289ad20d27a7 - feat: persist acquisition attribution with durable CRM handoff (AKURAI-PLATFORM-25) by Ólafur Búi Ólafsson
// contact.js — Contact/demo/waitlist inquiry form with attribution capture
const modal = document.getElementById("contact-modal");
const dialog = modal?.querySelector("[role=dialog]");
const form = document.getElementById("contact-form");
const submit = document.getElementById("contact-submit");
const consent = document.getElementById("contact-consent");
const confirmation = document.getElementById("contact-confirmation");
const locale = document.documentElement.lang || "en";
function isIcelandic() {
return locale.startsWith("is");
}
function captureAttribution() {
const params = new URLSearchParams(location.search);
const attr = {};
const utmKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
for (const key of utmKeys) {
const val = params.get(key);
if (val) attr[key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = val;
}
const ref = document.referrer;
if (ref && !ref.startsWith(location.origin)) attr.referrer = ref;
attr.landingPage = location.pathname + location.search;
return attr;
}
function openModal() {
if (!modal || !dialog) return;
modal.hidden = false;
if (confirmation) confirmation.hidden = true;
if (submit) { submit.disabled = false; submit.textContent = isIcelandic() ? "Senda" : "Send inquiry"; }
if (form) form.reset();
if (consent) consent.setAttribute("aria-checked", "false");
const firstInput = form?.querySelector("input[name=name]");
if (firstInput instanceof HTMLInputElement) firstInput.focus();
}
function closeModal() {
if (!modal) return;
modal.hidden = true;
}
function showConfirmation(msg) {
if (!confirmation) return;
confirmation.textContent = msg;
confirmation.hidden = false;
if (submit) submit.hidden = true;
}
// Wire trigger buttons
document.querySelectorAll("[data-contact-trigger]").forEach((btn) => {
btn.addEventListener("click", openModal);
});
// Wire close buttons
if (modal) {
modal.querySelectorAll("[data-contact-close]").forEach((btn) => {
btn.addEventListener("click", closeModal);
});
modal.addEventListener("keydown", (event) => {
if (event.key === "Escape") closeModal();
});
// Prevent backdrop click from closing during active state
modal.addEventListener("click", (event) => {
if (event.target === modal) closeModal();
});
}
// Consent toggle
if (consent) {
consent.addEventListener("click", () => {
const checked = consent.getAttribute("aria-checked") !== "true";
consent.setAttribute("aria-checked", String(checked));
});
}
// Form submission
if (form) {
form.addEventListener("submit", async (event) => {
event.preventDefault();
const name = form.elements.name.value.trim();
const email = form.elements.email.value.trim();
const outcome = form.elements.outcome?.value || "contact";
const company = form.elements.company?.value?.trim() || "";
const intent = form.elements.intent?.value?.trim() || "";
if (!name || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
if (!name) form.elements.name.focus();
else form.elements.email.focus();
return;
}
if (consent && consent.getAttribute("aria-checked") !== "true") {
consent.focus();
return;
}
const originalLabel = submit.textContent;
submit.disabled = true;
submit.textContent = isIcelandic() ? "Sendi…" : "Sending…";
try {
const attribution = captureAttribution();
const response = await fetch("/api/contact", {
method: "POST",
headers: { "content-type": "application/json", accept: "application/json" },
body: JSON.stringify({
name, email, company, outcome, intent,
locale,
productIds: [],
consent: {
noticeVersion: "v1",
grants: ["contact"],
explicit: true,
},
...attribution,
}),
});
if (!response.ok) throw new Error("contact_failed");
const data = await response.json();
showConfirmation(data.message || (
isIcelandic() ? "Skráning móttekin. Við höfum samband innan skamms."
: "Your inquiry has been received. We will be in touch shortly."
));
} catch {
submit.disabled = false;
submit.textContent = originalLabel;
}
});
}