|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="UTF-8"> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | + <title>Audience SDK — Demo</title> |
| 7 | + <style> |
| 8 | + :root { |
| 9 | + --bg: #fafafa; --card: #ffffff; --border: #e4e4e7; --accent: #71717a; |
| 10 | + --text: #3f3f46; --text-strong: #18181b; --text-muted: #a1a1aa; |
| 11 | + --danger: #dc2626; --primary-bg: #18181b; --primary-text: #fafafa; |
| 12 | + --primary-hover: #3f3f46; --btn-bg: #f4f4f5; --btn-border: #d4d4d8; |
| 13 | + --btn-hover: #e4e4e7; --input-bg: #ffffff; --log-bg: #f4f4f5; |
| 14 | + --log-border: #e4e4e7; --log-time: #a1a1aa; --log-method: #18181b; |
| 15 | + } |
| 16 | + * { box-sizing: border-box; margin: 0; padding: 0; } |
| 17 | + body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); padding: 32px 24px; max-width: 960px; margin: 0 auto; } |
| 18 | + h1 { font-size: 22px; font-weight: 600; margin-bottom: 4px; color: var(--text-strong); letter-spacing: -0.3px; } |
| 19 | + .subtitle { color: var(--text-muted); font-size: 13px; margin-bottom: 28px; } |
| 20 | + .section { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 18px; margin-bottom: 14px; } |
| 21 | + .section h2 { font-size: 11px; color: var(--accent); margin-bottom: 14px; text-transform: uppercase; letter-spacing: 1.2px; font-weight: 600; } |
| 22 | + .row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; } |
| 23 | + button { background: var(--btn-bg); border: 1px solid var(--btn-border); color: var(--text); padding: 8px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; font-family: inherit; transition: all 0.15s; } |
| 24 | + button:hover { background: var(--btn-hover); border-color: var(--accent); color: var(--text-strong); } |
| 25 | + button.primary { background: var(--primary-bg); border-color: var(--primary-bg); color: var(--primary-text); font-weight: 500; } |
| 26 | + button.primary:hover { background: var(--primary-hover); } |
| 27 | + button.danger { border-color: var(--danger); color: var(--danger); } |
| 28 | + button.danger:hover { background: color-mix(in srgb, var(--danger) 10%, transparent); } |
| 29 | + input, select { background: var(--input-bg); border: 1px solid var(--btn-border); color: var(--text); padding: 8px 10px; border-radius: 6px; font-size: 13px; font-family: inherit; } |
| 30 | + input:focus, select:focus { outline: none; border-color: var(--accent); } |
| 31 | + input { width: 200px; } |
| 32 | + select { min-width: 120px; } |
| 33 | + label { font-size: 11px; color: var(--text-muted); display: block; margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.5px; } |
| 34 | + .field { display: flex; flex-direction: column; } |
| 35 | + #log { background: var(--log-bg); border: 1px solid var(--border); border-radius: 8px; padding: 12px; font-size: 12px; line-height: 1.7; max-height: 400px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace; } |
| 36 | + .log-entry { border-bottom: 1px solid var(--log-border); padding: 4px 0; } |
| 37 | + .log-time { color: var(--log-time); } |
| 38 | + .log-method { color: var(--log-method); font-weight: 600; } |
| 39 | + .log-ok { color: var(--accent); } |
| 40 | + .log-err { color: var(--danger); } |
| 41 | + .log-info { color: var(--accent); } |
| 42 | + .status-bar { display: flex; gap: 16px; font-size: 12px; padding: 10px 0; } |
| 43 | + .status-bar span { color: var(--text-muted); } |
| 44 | + .status-bar strong { color: var(--text-strong); } |
| 45 | + #consent-badge { padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; } |
| 46 | + </style> |
| 47 | + <link rel="preconnect" href="https://fonts.googleapis.com"> |
| 48 | + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet"> |
| 49 | +</head> |
| 50 | +<body> |
| 51 | + <h1>Audience SDK — Demo</h1> |
| 52 | + <p class="subtitle">End-to-end testing against dev/sandbox backend. Open DevTools Network tab to see requests.</p> |
| 53 | + |
| 54 | + <div class="status-bar"> |
| 55 | + <span>Environment: <strong id="env-display">—</strong></span> |
| 56 | + <span>Consent: <span id="consent-badge">—</span></span> |
| 57 | + <span>Anonymous ID: <strong id="anon-display">—</strong></span> |
| 58 | + <span>User ID: <strong id="user-display">none</strong></span> |
| 59 | + </div> |
| 60 | + |
| 61 | + <div class="section"> |
| 62 | + <h2>1. Initialise</h2> |
| 63 | + <div class="row"> |
| 64 | + <div class="field"> |
| 65 | + <label>Publishable Key</label> |
| 66 | + <input id="pk" type="text" placeholder="pk_imtbl_..." value=""> |
| 67 | + </div> |
| 68 | + <div class="field"> |
| 69 | + <label>Environment</label> |
| 70 | + <select id="env"> |
| 71 | + <option value="dev">dev</option> |
| 72 | + <option value="sandbox" selected>sandbox</option> |
| 73 | + <option value="production">production</option> |
| 74 | + </select> |
| 75 | + </div> |
| 76 | + <div class="field"> |
| 77 | + <label>Initial Consent</label> |
| 78 | + <select id="init-consent"> |
| 79 | + <option value="none">none</option> |
| 80 | + <option value="anonymous" selected>anonymous</option> |
| 81 | + <option value="full">full</option> |
| 82 | + </select> |
| 83 | + </div> |
| 84 | + </div> |
| 85 | + <div class="row"> |
| 86 | + <label style="display:flex;align-items:center;gap:6px;font-size:13px;color:var(--text)"> |
| 87 | + <input type="checkbox" id="debug-mode" checked> Debug mode |
| 88 | + </label> |
| 89 | + </div> |
| 90 | + <div class="row" style="margin-top:8px"> |
| 91 | + <button class="primary" onclick="initSDK()">Init SDK</button> |
| 92 | + <button class="danger" onclick="destroySDK()">Destroy</button> |
| 93 | + </div> |
| 94 | + </div> |
| 95 | + |
| 96 | + <div class="section"> |
| 97 | + <h2>2. Consent</h2> |
| 98 | + <div class="row"> |
| 99 | + <button onclick="setConsent('none')">Set: none</button> |
| 100 | + <button onclick="setConsent('anonymous')">Set: anonymous</button> |
| 101 | + <button onclick="setConsent('full')">Set: full</button> |
| 102 | + </div> |
| 103 | + </div> |
| 104 | + |
| 105 | + <div class="section"> |
| 106 | + <h2>3. Page Tracking</h2> |
| 107 | + <div class="row"> |
| 108 | + <button onclick="firePage()">page()</button> |
| 109 | + <button onclick="firePage({section:'shop',category:'weapons'})">page({section, category})</button> |
| 110 | + </div> |
| 111 | + </div> |
| 112 | + |
| 113 | + <div class="section"> |
| 114 | + <h2>4. Track Events</h2> |
| 115 | + <div class="row"> |
| 116 | + <button onclick="trackEvent('sign_up', {method:'google'})">SignUp</button> |
| 117 | + <button onclick="trackEvent('purchase', {currency:'USD',value:9.99,itemId:'sword_01'})">Purchase</button> |
| 118 | + <button onclick="trackEvent('wishlist_add', {gameId:'game_123'})">WishlistAdd</button> |
| 119 | + <button onclick="trackEvent('game_launch', {platform:'webgl'})">GameLaunch</button> |
| 120 | + </div> |
| 121 | + <div class="row" style="margin-top:8px"> |
| 122 | + <div class="field"> |
| 123 | + <label>Custom Event</label> |
| 124 | + <input id="custom-event" type="text" placeholder="event_name" value="beta_key_redeemed"> |
| 125 | + </div> |
| 126 | + <button onclick="trackCustom()" style="align-self:flex-end">Track Custom</button> |
| 127 | + </div> |
| 128 | + </div> |
| 129 | + |
| 130 | + <div class="section"> |
| 131 | + <h2>5. Identity</h2> |
| 132 | + <div class="row"> |
| 133 | + <div class="field"> |
| 134 | + <label>User ID</label> |
| 135 | + <input id="uid" type="text" placeholder="user@example.com" value="user@example.com"> |
| 136 | + </div> |
| 137 | + <button onclick="doIdentify()" style="align-self:flex-end" class="primary">identify()</button> |
| 138 | + </div> |
| 139 | + <div class="row" style="margin-top:8px"> |
| 140 | + <button onclick="doReset()" class="danger">reset()</button> |
| 141 | + </div> |
| 142 | + </div> |
| 143 | + |
| 144 | + <div class="section"> |
| 145 | + <h2>Event Log</h2> |
| 146 | + <div id="log"></div> |
| 147 | + <button onclick="document.getElementById('log').innerHTML=''" style="margin-top:8px">Clear Log</button> |
| 148 | + </div> |
| 149 | + |
| 150 | + <script src="../dist/cdn/imtbl-audience.js"></script> |
| 151 | + <script> |
| 152 | + var ImmutableAudienceSDK = window.ImmutableAudienceSDK; |
| 153 | + var sdk = null; |
| 154 | + var currentConsent = null; |
| 155 | + |
| 156 | + function log(method, detail, type) { |
| 157 | + type = type || 'info'; |
| 158 | + var el = document.getElementById('log'); |
| 159 | + var time = new Date().toISOString().slice(11, 23); |
| 160 | + var cls = type === 'ok' ? 'log-ok' : type === 'err' ? 'log-err' : 'log-info'; |
| 161 | + var detailStr = typeof detail === 'object' ? JSON.stringify(detail, null, 2) : detail; |
| 162 | + el.innerHTML += '<div class="log-entry"><span class="log-time">' + time + '</span> <span class="log-method">' + method + '</span> <span class="' + cls + '">' + detailStr + '</span></div>'; |
| 163 | + el.scrollTop = el.scrollHeight; |
| 164 | + } |
| 165 | + |
| 166 | + function updateStatus() { |
| 167 | + var anonCookie = document.cookie.match(/imtbl_anon_id=([^;]*)/); |
| 168 | + document.getElementById('anon-display').textContent = anonCookie ? anonCookie[1].slice(0, 12) + '...' : 'none'; |
| 169 | + var badge = document.getElementById('consent-badge'); |
| 170 | + badge.textContent = currentConsent || '—'; |
| 171 | + badge.style.background = currentConsent === 'full' ? '#18181b' : currentConsent === 'anonymous' ? '#888888' : currentConsent === 'none' ? '#dc2626' : '#444444'; |
| 172 | + badge.style.color = '#fff'; |
| 173 | + } |
| 174 | + |
| 175 | + window.initSDK = function() { |
| 176 | + if (sdk) { log('init', 'Already initialised — destroy first', 'err'); return; } |
| 177 | + var pk = document.getElementById('pk').value.trim(); |
| 178 | + if (!pk) { log('init', 'Enter a publishable key', 'err'); return; } |
| 179 | + var env = document.getElementById('env').value; |
| 180 | + var consent = document.getElementById('init-consent').value; |
| 181 | + var debug = document.getElementById('debug-mode').checked; |
| 182 | + |
| 183 | + sdk = new ImmutableAudienceSDK({ publishableKey: pk, environment: env, consent: consent, debug: debug }); |
| 184 | + currentConsent = consent; |
| 185 | + document.getElementById('env-display').textContent = env; |
| 186 | + log('init', { environment: env, consent: consent, debug: debug }, 'ok'); |
| 187 | + updateStatus(); |
| 188 | + }; |
| 189 | + |
| 190 | + window.destroySDK = function() { |
| 191 | + if (!sdk) { log('destroy', 'Not initialised', 'err'); return; } |
| 192 | + sdk.destroy(); |
| 193 | + sdk = null; |
| 194 | + document.getElementById('user-display').textContent = 'none'; |
| 195 | + log('destroy', 'SDK stopped', 'ok'); |
| 196 | + }; |
| 197 | + |
| 198 | + window.setConsent = function(level) { |
| 199 | + if (!sdk) { log('setConsent', 'Init SDK first', 'err'); return; } |
| 200 | + sdk.setConsent(level); |
| 201 | + currentConsent = level; |
| 202 | + log('setConsent', level, 'ok'); |
| 203 | + updateStatus(); |
| 204 | + }; |
| 205 | + |
| 206 | + window.firePage = function(props) { |
| 207 | + if (!sdk) { log('page', 'Init SDK first', 'err'); return; } |
| 208 | + sdk.page(props); |
| 209 | + log('page', props || '(no properties)', 'ok'); |
| 210 | + }; |
| 211 | + |
| 212 | + window.trackEvent = function(event, properties) { |
| 213 | + if (!sdk) { log('track', 'Init SDK first', 'err'); return; } |
| 214 | + sdk.track(event, properties); |
| 215 | + log('track', { event: event, properties: properties }, 'ok'); |
| 216 | + }; |
| 217 | + |
| 218 | + window.trackCustom = function() { |
| 219 | + var name = document.getElementById('custom-event').value.trim(); |
| 220 | + if (!sdk) { log('track', 'Init SDK first', 'err'); return; } |
| 221 | + if (!name) { log('track', 'Enter an event name', 'err'); return; } |
| 222 | + sdk.track(name, { source: 'demo' }); |
| 223 | + log('track', { event: name }, 'ok'); |
| 224 | + }; |
| 225 | + |
| 226 | + window.doIdentify = function() { |
| 227 | + if (!sdk) { log('identify', 'Init SDK first', 'err'); return; } |
| 228 | + var uid = document.getElementById('uid').value.trim(); |
| 229 | + if (!uid) { log('identify', 'Enter a user ID', 'err'); return; } |
| 230 | + sdk.identify(uid, { name: 'Demo User' }); |
| 231 | + document.getElementById('user-display').textContent = uid; |
| 232 | + log('identify', { userId: uid }, 'ok'); |
| 233 | + }; |
| 234 | + |
| 235 | + window.doReset = function() { |
| 236 | + if (!sdk) { log('reset', 'Init SDK first', 'err'); return; } |
| 237 | + sdk.reset(); |
| 238 | + document.getElementById('user-display').textContent = 'none'; |
| 239 | + log('reset', 'userId cleared', 'ok'); |
| 240 | + updateStatus(); |
| 241 | + }; |
| 242 | + |
| 243 | + updateStatus(); |
| 244 | + </script> |
| 245 | +</body> |
| 246 | +</html> |
0 commit comments