diff --git a/api/src/routes/checkout.ts b/api/src/routes/checkout.ts index c5ae223..19e5bee 100644 --- a/api/src/routes/checkout.ts +++ b/api/src/routes/checkout.ts @@ -1240,6 +1240,32 @@ export async function handlePaymentComplete( } } + // ── Umami analytics — server-side payment event ───────────────────────── + try { + const umamiUrl = process.env.UMAMI_URL || "http://umami:3000"; + const websiteId = "55250014-ee15-44ac-a1f6-81dabad3fe0f"; + await fetch(`${umamiUrl}/api/send`, { + method: "POST", + headers: { "Content-Type": "application/json", "User-Agent": "PW-API/1.0" }, + body: JSON.stringify({ + payload: { + website: websiteId, + hostname: "performancewest.net", + url: `/checkout/complete/${order_type}`, + name: "payment-complete", + data: { + order_type, + order_id, + payment_method: paymentMethod, + total_cents: Number(order.service_fee_cents || order.total_cents || 0), + service: (order.service_slug as string) || order_type, + }, + }, + type: "event", + }), + }); + } catch { /* non-fatal */ } + // ── Advance ERPNext Sales Order workflow (CRTC) ──────────────────────── if (order_type === "canada_crtc") { const soName = (order.erpnext_sales_order as string) || null; diff --git a/site/public/js/pw-analytics.js b/site/public/js/pw-analytics.js new file mode 100644 index 0000000..e5cd8b6 --- /dev/null +++ b/site/public/js/pw-analytics.js @@ -0,0 +1,129 @@ +/** + * Performance West — Umami custom event tracking. + * Loaded after the Umami script on all pages. + * Uses umami.track() for conversion funnel events. + */ +(function() { + // Wait for umami to be available + function track(name, data) { + if (window.umami) { + window.umami.track(name, data || {}); + } + } + + // Expose globally for inline usage + window.pwTrack = track; + + // ── Auto-track common interactions ──────────────────────────────────── + + // Track all CTA button clicks with data-track attribute + document.addEventListener("click", function(e) { + var el = e.target.closest("[data-track]"); + if (el) { + track(el.getAttribute("data-track"), { + label: el.textContent.trim().slice(0, 50), + href: el.href || "", + page: location.pathname, + }); + } + }); + + // ── FCC Compliance Checker events ───────────────────────────────────── + + // Check if we're on the compliance checker page + if (location.pathname.indexOf("/tools/fcc-compliance-check") === 0) { + // Track when check starts (form submit / button click) + var checkBtn = document.querySelector("#check-btn, [onclick*='runCheck'], button[type='submit']"); + if (checkBtn) { + checkBtn.addEventListener("click", function() { + var frn = (document.querySelector("#frn-input, input[name='frn']") || {}).value || ""; + track("compliance-check-start", { frn: frn }); + }); + } + + // Track when results load (observe DOM for results container) + var observer = new MutationObserver(function(mutations) { + for (var i = 0; i < mutations.length; i++) { + var target = mutations[i].target; + if (target.id === "checks-container" || target.id === "results") { + var issues = document.querySelectorAll(".check-fail, .issue-card, [data-severity]").length; + var frn = (document.querySelector("#frn-input, input[name='frn']") || {}).value || ""; + track("compliance-check-complete", { frn: frn, issues: issues }); + observer.disconnect(); + break; + } + } + }); + var resultsEl = document.getElementById("checks-container") || document.getElementById("results"); + if (resultsEl) { + observer.observe(resultsEl, { childList: true, subtree: true }); + } + + // Track "Order" CTA clicks from results + document.addEventListener("click", function(e) { + var btn = e.target.closest("a[href*='/order/'], button[data-slug]"); + if (btn && (btn.closest("#checks-container") || btn.closest("#results") || btn.closest(".cta"))) { + var slug = btn.getAttribute("data-slug") || btn.href.split("/order/")[1] || ""; + track("order-cta-click", { + slug: slug.split("/")[0] || slug.split("?")[0], + source: "compliance-checker", + page: location.pathname, + }); + } + }); + } + + // ── Order / Checkout pages ──────────────────────────────────────────── + + if (location.pathname.indexOf("/order/") === 0) { + // Track checkout page view with service info + var slug = location.pathname.replace("/order/", "").replace(/\/$/, ""); + track("checkout-page-view", { slug: slug, referrer: document.referrer }); + + // Track payment button click + document.addEventListener("click", function(e) { + var btn = e.target.closest("#pay-btn, #submit-btn, .checkout-btn, button[type='submit']"); + if (btn && (btn.textContent.indexOf("Pay") >= 0 || btn.textContent.indexOf("Checkout") >= 0 || btn.textContent.indexOf("Place Order") >= 0)) { + track("checkout-start", { slug: slug, page: location.pathname }); + } + }); + } + + // ── eSign portal ────────────────────────────────────────────────────── + + if (location.pathname.indexOf("/portal/esign") === 0 || location.pathname.indexOf("/portal/sign") === 0) { + track("esign-opened", { page: location.pathname }); + + document.addEventListener("click", function(e) { + var btn = e.target.closest("#submit-btn, .submit-btn"); + if (btn && btn.textContent.indexOf("Submit") >= 0) { + track("esign-submitted", { page: location.pathname }); + } + }); + } + + // ── Email campaign click attribution ────────────────────────────────── + + var params = new URLSearchParams(location.search); + var utmSource = params.get("utm_source"); + var utmCampaign = params.get("utm_campaign"); + if (utmSource || utmCampaign) { + track("campaign-click", { + source: utmSource || "", + campaign: utmCampaign || "", + medium: params.get("utm_medium") || "", + page: location.pathname, + }); + } + + // ── Contact form submission ─────────────────────────────────────────── + + if (location.pathname.indexOf("/contact") === 0) { + document.addEventListener("submit", function(e) { + if (e.target.closest("form")) { + track("contact-form-submit", { page: location.pathname }); + } + }); + } + +})(); diff --git a/site/public/order/fcc-carrier-registration/index.html b/site/public/order/fcc-carrier-registration/index.html index 70b1ecc..207ef44 100644 --- a/site/public/order/fcc-carrier-registration/index.html +++ b/site/public/order/fcc-carrier-registration/index.html @@ -62,7 +62,7 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px .recommend-box strong{color:#166534} .err{color:#dc2626;font-size:.82rem;margin-top:.5rem;display:none} - +