// ───────────────────────────────────────────────────────────── // NOTIFICATIONS CONFIG // ───────────────────────────────────────────────────────────── const SLACK_WEBHOOK = 'YOUR_SLACK_WEBHOOK_URL'; // already working const SHEETS_WEBHOOK = 'YOUR_APPS_SCRIPT_URL'; // paste after deploying // ───────────────────────────────────────────────────────────── // SEND LOGIN NOTIFICATION → Slack + Google Sheets // ───────────────────────────────────────────────────────────── async function sendLoginNotification(profile) { // 1. Detect device & browser const ua = navigator.userAgent; const device = /iPhone/.test(ua) ? 'iPhone' : /iPad/.test(ua) ? 'iPad' : /Android/.test(ua)? 'Android' : /Mac/.test(ua) ? 'Mac' : /Windows/.test(ua)? 'Windows' : 'Unknown'; const browser = /CriOS/.test(ua) ? 'Chrome iOS' : /FxiOS/.test(ua) ? 'Firefox iOS' : /EdgA/.test(ua) ? 'Edge Android' : /OPR/.test(ua) ? 'Opera' : /Edg/.test(ua) ? 'Edge' : /Chrome/.test(ua) ? 'Chrome' : /Firefox/.test(ua) ? 'Firefox' : /Safari/.test(ua) ? 'Safari' : 'Unknown'; const deviceIcon = /iPhone|iPad/.test(ua) ? '📱' : /Android/.test(ua) ? '📱' : /Mac/.test(ua) ? '💻' : /Windows/.test(ua) ? '🖥️' : '🌐'; // 2. Get location from IP geolocation let ip = '—', city = '—', region = '—', country = '—', flag = '🌍'; try { const geo = await fetch('https://ipapi.co/json/'); if (geo.ok) { const g = await geo.json(); ip = g.ip || '—'; city = g.city || '—'; region = g.region || '—'; country = g.country_name || '—'; // Country code to emoji flag if (g.country_code) { flag = g.country_code.toUpperCase().replace(/./g, c => String.fromCodePoint(0x1F1E6 + c.charCodeAt(0) - 65)); } } } catch(e) {} const location = [city, region, country].filter(s => s !== '—').join(', ') || '—'; const now = new Date().toLocaleString('en-US', { timeZone: 'America/Chicago', month: 'short', day: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: true }); // ── A) LOG TO GOOGLE SHEETS ────────────────────────────── if (SHEETS_WEBHOOK && SHEETS_WEBHOOK !== 'YOUR_APPS_SCRIPT_URL') { fetch(SHEETS_WEBHOOK, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: profile.name, email: profile.email, city, region, country, ip, device, browser, picture: profile.picture || '' }) }).catch(e => console.warn('Sheets log failed:', e)); } // ── B) NOTIFY SLACK ────────────────────────────────────── if (SLACK_WEBHOOK && SLACK_WEBHOOK !== 'YOUR_SLACK_WEBHOOK_URL') { const slackBody = { text: '🧘 New Mesa Meditation Login', blocks: [ { type: 'header', text: { type: 'plain_text', text: '🧘 New Login — Mesa Meditation', emoji: true } }, { type: 'section', fields: [ { type: 'mrkdwn', text: `*Name:*\n${profile.name}` }, { type: 'mrkdwn', text: `*Email:*\n${profile.email}` }, { type: 'mrkdwn', text: `*Location:*\n${flag} ${location}` }, { type: 'mrkdwn', text: `*IP:*\n\`${ip}\`` }, { type: 'mrkdwn', text: `*Device:*\n${deviceIcon} ${device} · ${browser}` }, { type: 'mrkdwn', text: `*Time:*\n${now} CT` } ] }, { type: 'divider' } ] }; fetch(SLACK_WEBHOOK, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(slackBody) }).catch(e => console.warn('Slack notification failed:', e)); } } // (stars, storage, OAuth, UI helpers all handled in the module above)