/* PURA — Página de Captura * Meta Pixel + CAPI: PageView / ViewContent / Lead * Pixel ID: 1587694082922255 * Reportana: data-rptn-form="87550" */ const { useState, useEffect, useRef } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "copper", "glow": 60, "layout": "split", "showManifesto": true, "eventDate": "25.07.26", "eventTime": "__H — __H", "eventLocation": "CHAPECÓ - SC" }/*EDITMODE-END*/; // ═══════════════════════════════════════════════════════════ // PIXEL + CAPI // ═══════════════════════════════════════════════════════════ const PIXEL_ID = '1587694082922255'; const CAPI_URL = 'capi.php'; function uuidv4() { return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); } async function sha256(str) { if (!str) return null; const clean = String(str).toLowerCase().trim(); if (!clean) return null; const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(clean)); return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join(''); } function getFbp() { const m = document.cookie.match(/_fbp=([^;]+)/); return m ? m[1] : null; } function getFbc() { const m = document.cookie.match(/_fbc=([^;]+)/); if (m) return m[1]; const p = new URLSearchParams(location.search).get('fbclid'); return p ? `fb.1.${Date.now()}.${p}` : null; } // Busca geo (ipapi.co) e gender (genderize.io) em paralelo // firstName opcional — se vazio, só retorna geo async function getGeoGender(firstName) { const [geoRes, genRes] = await Promise.allSettled([ fetch('https://ipapi.co/json/', { signal: AbortSignal.timeout(4000) }).then(r => r.json()), firstName ? fetch(`https://api.genderize.io/?name=${encodeURIComponent(firstName)}&country_id=BR`, { signal: AbortSignal.timeout(4000) }).then(r => r.json()) : Promise.resolve(null), ]); const geo = geoRes.status === 'fulfilled' ? (geoRes.value || {}) : {}; const gen = genRes.status === 'fulfilled' ? genRes.value : null; let ge = null; if (gen && gen.gender && (gen.probability || 0) >= 0.8) { ge = await sha256(gen.gender === 'male' ? 'm' : 'f'); } return { ip : geo.ip || null, city : (geo.city || '').toLowerCase(), region : (geo.region || '').toLowerCase(), country : (geo.country_code || 'BR').toLowerCase(), postal : geo.postal || null, ge, }; } // Cache do geo para não buscar 3x (PageView, ViewContent, Lead) let _geoCache = null; async function getGeoCached(firstName) { if (!_geoCache) _geoCache = getGeoGender(firstName || ''); return _geoCache; } // ── Pixel browser ──────────────────────────────────────────────────────────── function pixelTrack(event, params, options) { try { if (typeof window.fbq === 'function') window.fbq('track', event, params || {}, options || {}); } catch(e) {} } // ── CAPI server-side ───────────────────────────────────────────────────────── // userData: { em, ph, fn, ln, ct, st, country, zp, ge } — todos já hasheados // geo: { ip, city, region, country, postal, ge } — raw, o PHP faz o resto async function capiSend({ eventName, eventId, userData = {}, geo = {} }) { const payload = { event_name : eventName, event_id : eventId, event_time : Math.floor(Date.now() / 1000), source_url : location.href, user_agent : navigator.userAgent, client_ip : geo.ip || '', fbp : getFbp(), fbc : getFbc(), // PII hasheado (sha256 feito aqui no cliente) em : userData.em || null, ph : userData.ph || null, fn : userData.fn || null, ln : userData.ln || null, ct : userData.ct || null, st : userData.st || null, country : userData.country || null, zp : userData.zp || null, ge : userData.ge || null, }; const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' }); try { navigator.sendBeacon ? navigator.sendBeacon(CAPI_URL, blob) : fetch(CAPI_URL, { method: 'POST', body: blob, keepalive: true }).catch(()=>{}); } catch(e) {} } // ── Helpers de hash de geo ─────────────────────────────────────────────────── async function hashGeo(geo) { const [ct, st, country, zp] = await Promise.all([ sha256(geo.city), sha256(geo.region), sha256(geo.country), geo.postal ? sha256(geo.postal) : Promise.resolve(null), ]); return { ct, st, country, zp, ge: geo.ge }; } // ───────────────────────────────────────────────────────────────────────────── // PageView CAPI — dispara assim que o módulo carrega (antes do React montar) // Geo sem firstName; sem PII de usuário (async () => { try { const pvId = uuidv4(); // Pixel já disparou no ; aqui só o CAPI const geo = await getGeoCached(''); const geoH = await hashGeo(geo); await capiSend({ eventName: 'PageView', eventId: pvId, geo, userData: geoH }); } catch(e) {} })(); // ═══════════════════════════════════════════════════════════ // COMPONENTES // ═══════════════════════════════════════════════════════════ function RingMark({ size = 56, stroke = 1.1, color = "currentColor", style }) { return ( ); } function PuraLogo({ width = 200, className = "" }) { return ( PURA — A State of Feeling ); } function AtmosphereStage({ glow, palette }) { const accent = palette === "olive" ? "#4D5B46" : "#8A6A52"; return (