(function() { 'use strict'; // Read config set by the inline script (MemberSpace-style) var preConfig = window.MemberGate || {}; var MG = window.MemberGate = preConfig; // Configuration (use pre-set appId if available, fallback to baked-in) MG.appId = MG.appId || '697d10ec870ca6ca241e4463'; MG.appUrl = 'https://' + MG.appId + '.base44.app'; MG.settings = {"showFloatingButton":true,"postLoginRedirectMode":"returnToRequestedPage","brandColor":"#2563eb","loginButtonPosition":"bottom-right","postLoginFixedUrl":null,"siteName":"My Website","loginButtonLabel":"Login","unauthorizedRedirectUrl":"/login","postLogoutRedirectUrl":"/","id":"697d13c2c667d4dce44a9253","created_date":"2026-01-30T20:25:38.390000","updated_date":"2026-01-30T20:25:38.390000","created_by_id":"697d10ec870ca6ca241e4464","created_by":"rudy@onlineculture.co","is_sample":false}; MG.routes = [{"pattern":"/entertainment","redirect":""}]; MG.tokenKey = 'mg_auth_token'; MG.nextUrlKey = 'mg_next_url'; // State MG.isAuthenticated = false; MG.user = null; MG.onProtectedPage = false; // Styles var brandColor = MG.settings.brandColor || '#2563eb'; var styles = ` .mg-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 999999; display: flex; align-items: center; justify-content: center; padding: 16px; box-sizing: border-box; opacity: 0; transition: opacity 0.2s ease; } .mg-overlay.mg-visible { opacity: 1; } .mg-modal { background: white; border-radius: 16px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); width: 100%; max-width: 400px; transform: translateY(20px); transition: transform 0.2s ease; } .mg-overlay.mg-visible .mg-modal { transform: translateY(0); } .mg-modal-header { padding: 24px 24px 0; text-align: center; } .mg-modal-title { font-size: 24px; font-weight: 600; color: #1e293b; margin: 0 0 8px; font-family: system-ui, -apple-system, sans-serif; } .mg-modal-subtitle { font-size: 14px; color: #64748b; margin: 0; font-family: system-ui, -apple-system, sans-serif; } .mg-modal-body { padding: 24px; } .mg-form-group { margin-bottom: 16px; } .mg-label { display: block; font-size: 14px; font-weight: 500; color: #374151; margin-bottom: 6px; font-family: system-ui, -apple-system, sans-serif; } .mg-input { width: 100%; padding: 12px 16px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 16px; transition: border-color 0.15s, box-shadow 0.15s; box-sizing: border-box; font-family: system-ui, -apple-system, sans-serif; } .mg-input:focus { outline: none; border-color: ` + brandColor + `; box-shadow: 0 0 0 3px ` + brandColor + `20; } .mg-btn { width: 100%; padding: 12px 24px; border: none; border-radius: 8px; font-size: 16px; font-weight: 500; cursor: pointer; transition: all 0.15s; font-family: system-ui, -apple-system, sans-serif; } .mg-btn-primary { background: ` + brandColor + `; color: white; } .mg-btn-primary:hover { filter: brightness(1.1); } .mg-btn-primary:disabled { opacity: 0.6; cursor: not-allowed; } .mg-error { background: #fef2f2; color: #dc2626; padding: 12px; border-radius: 8px; font-size: 14px; margin-bottom: 16px; font-family: system-ui, -apple-system, sans-serif; } .mg-link { color: ` + brandColor + `; text-decoration: none; font-size: 14px; cursor: pointer; font-family: system-ui, -apple-system, sans-serif; } .mg-link:hover { text-decoration: underline; } .mg-footer { padding: 16px 24px; border-top: 1px solid #f1f5f9; text-align: center; } .mg-float-btn { position: fixed; z-index: 999998; padding: 12px 20px; background: ` + brandColor + `; color: white; border: none; border-radius: 50px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.15); transition: all 0.2s; font-family: system-ui, -apple-system, sans-serif; display: flex; align-items: center; gap: 8px; } .mg-float-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,0.2); } .mg-float-btn.mg-bottom-right { bottom: 24px; right: 24px; } .mg-float-btn.mg-bottom-left { bottom: 24px; left: 24px; } .mg-float-btn.mg-top-right { top: 24px; right: 24px; } .mg-float-btn.mg-top-left { top: 24px; left: 24px; } .mg-user-menu { position: fixed; z-index: 999997; background: white; border-radius: 12px; box-shadow: 0 10px 40px rgba(0,0,0,0.15); min-width: 200px; opacity: 0; visibility: hidden; transform: translateY(10px); transition: all 0.2s; } .mg-user-menu.mg-visible { opacity: 1; visibility: visible; transform: translateY(0); } .mg-user-menu.mg-bottom-right { bottom: 80px; right: 24px; } .mg-user-menu.mg-bottom-left { bottom: 80px; left: 24px; } .mg-user-menu.mg-top-right { top: 80px; right: 24px; } .mg-user-menu.mg-top-left { top: 80px; left: 24px; } .mg-user-info { padding: 16px; border-bottom: 1px solid #f1f5f9; } .mg-user-name { font-weight: 600; color: #1e293b; font-size: 14px; margin: 0 0 4px; font-family: system-ui, -apple-system, sans-serif; } .mg-user-email { font-size: 12px; color: #64748b; margin: 0; font-family: system-ui, -apple-system, sans-serif; } .mg-menu-item { display: block; width: 100%; padding: 12px 16px; text-align: left; border: none; background: none; color: #374151; font-size: 14px; cursor: pointer; transition: background 0.15s; font-family: system-ui, -apple-system, sans-serif; box-sizing: border-box; } .mg-menu-item:hover { background: #f8fafc; } .mg-menu-item.mg-logout { color: #dc2626; } .mg-block-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.01); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); z-index: 999990; } `; // Inject styles function injectStyles() { var style = document.createElement('style'); style.textContent = styles; document.head.appendChild(style); } // Check if path matches pattern function pathMatches(path, pattern) { if (pattern.endsWith('/*')) { var base = pattern.slice(0, -2); return path.startsWith(base + '/'); } return path === pattern; } // Check if current path is protected function isProtectedPath() { var path = window.location.pathname; for (var i = 0; i < MG.routes.length; i++) { if (pathMatches(path, MG.routes[i].pattern)) { return MG.routes[i]; } } return null; } // API calls async function apiCall(endpoint, options) { var token = localStorage.getItem(MG.tokenKey); var headers = { 'Content-Type': 'application/json' }; if (token) { headers['Authorization'] = 'Bearer ' + token; } var response = await fetch(MG.appUrl + '/api/' + endpoint, { ...options, headers: { ...headers, ...(options && options.headers ? options.headers : {}) } }); return response; } // Check authentication async function checkAuth() { var token = localStorage.getItem(MG.tokenKey); if (!token) { MG.isAuthenticated = false; MG.user = null; return false; } try { var appId = MG.appId; var response = await fetch('https://api.base44.app/api/apps/' + appId + '/functions/authCheck', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({}) }); if (response.ok) { var data = await response.json(); if (data.authenticated && data.memberActive) { MG.isAuthenticated = true; MG.user = data.user; return true; } } } catch (e) { console.error('Auth check failed:', e); } localStorage.removeItem(MG.tokenKey); MG.isAuthenticated = false; MG.user = null; return false; } // Login via backend function (member check + token in one call) async function login(email, password) { var appId = MG.appId; var response = await fetch('https://api.base44.app/api/apps/' + appId + '/functions/loginMember', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: password }) }); var data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Invalid email or password'); } if (data.token) { localStorage.setItem(MG.tokenKey, data.token); MG.isAuthenticated = true; MG.user = data.user; return data; } throw new Error('Login failed - no token received'); } // Logout function logout() { localStorage.removeItem(MG.tokenKey); MG.isAuthenticated = false; MG.user = null; var redirectUrl = MG.settings.postLogoutRedirectUrl || '/'; window.location.href = redirectUrl; } // Block page content function blockPage() { // Remove early CSS blocker var early = document.getElementById('mg-early-block'); if (early) early.remove(); var blocker = document.createElement('div'); blocker.className = 'mg-block-overlay'; blocker.id = 'mg-blocker'; // Insert as first child so it's behind the modal overlay document.body.insertBefore(blocker, document.body.firstChild); } function unblockPage() { var early = document.getElementById('mg-early-block'); if (early) early.remove(); var blocker = document.getElementById('mg-blocker'); if (blocker) blocker.remove(); // Also remove any extra security overlay var extraOverlay = document.getElementById('mg-overlay'); if (extraOverlay) extraOverlay.remove(); } // Create modal function createModal() { var overlay = document.createElement('div'); overlay.className = 'mg-overlay'; overlay.id = 'mg-login-overlay'; overlay.innerHTML = `

` + (MG.settings.siteName || 'Members Area') + `

Sign in to access this content

`; // Click outside to close (only if not on a protected page) overlay.addEventListener('click', function(e) { if (e.target === overlay && !MG.onProtectedPage) { hideModal(); } }); document.body.appendChild(overlay); // Bind events document.getElementById('mg-login-form').addEventListener('submit', async function(e) { e.preventDefault(); var email = document.getElementById('mg-email').value; var password = document.getElementById('mg-password').value; var errorEl = document.getElementById('mg-error'); var submitBtn = document.getElementById('mg-submit'); submitBtn.disabled = true; submitBtn.textContent = 'Signing in...'; errorEl.style.display = 'none'; try { await login(email, password); hideModal(); unblockPage(); // Dispatch access granted event for extra security overlay window.dispatchEvent(new Event('mg-access-granted')); // Handle redirect var nextUrl = localStorage.getItem(MG.nextUrlKey); localStorage.removeItem(MG.nextUrlKey); if (MG.settings.postLoginRedirectMode === 'fixedUrl' && MG.settings.postLoginFixedUrl) { window.location.href = MG.settings.postLoginFixedUrl; } else if (nextUrl && nextUrl !== window.location.href) { window.location.href = nextUrl; } else { window.location.reload(); } } catch (err) { errorEl.textContent = err.message; errorEl.style.display = 'block'; submitBtn.disabled = false; submitBtn.textContent = 'Sign In'; } }); document.getElementById('mg-forgot').addEventListener('click', function() { window.open(MG.appUrl + '/forgot-password', '_blank'); }); return overlay; } // Show/hide modal function showModal() { var overlay = document.getElementById('mg-login-overlay') || createModal(); setTimeout(function() { overlay.classList.add('mg-visible'); }, 10); } function hideModal() { var overlay = document.getElementById('mg-login-overlay'); if (overlay) { overlay.classList.remove('mg-visible'); } } // Create floating button function createFloatingButton() { if (MG.settings.showFloatingButton === false) return; var position = MG.settings.loginButtonPosition || 'bottom-right'; var btn = document.createElement('button'); btn.className = 'mg-float-btn mg-' + position; btn.id = 'mg-float-btn'; updateFloatingButton(btn); document.body.appendChild(btn); // Create user menu var menu = document.createElement('div'); menu.className = 'mg-user-menu mg-' + position; menu.id = 'mg-user-menu'; document.body.appendChild(menu); btn.addEventListener('click', function() { if (MG.isAuthenticated) { var menu = document.getElementById('mg-user-menu'); menu.classList.toggle('mg-visible'); } else { showModal(); } }); // Close menu when clicking outside document.addEventListener('click', function(e) { if (!e.target.closest('#mg-float-btn') && !e.target.closest('#mg-user-menu')) { var menu = document.getElementById('mg-user-menu'); if (menu) menu.classList.remove('mg-visible'); } }); } function updateFloatingButton(btn) { btn = btn || document.getElementById('mg-float-btn'); if (!btn) return; if (MG.isAuthenticated && MG.user) { btn.innerHTML = ' Account'; var menu = document.getElementById('mg-user-menu'); if (menu) { menu.innerHTML = '

' + (MG.user.full_name || 'Member') + '

' + MG.user.email + '

'; document.getElementById('mg-logout-btn').addEventListener('click', logout); } } else { btn.innerHTML = ' ' + (MG.settings.loginButtonLabel || 'Login'); } } // Initialize async function init() { try { console.log('[MemberGate] Initializing widget...', { appUrl: MG.appUrl, appId: MG.appId }); injectStyles(); var protectedRoute = isProtectedPath(); if (protectedRoute) { // Block page immediately while checking auth blockPage(); } var isAuthenticated = await checkAuth(); if (protectedRoute && !isAuthenticated) { // Save current URL for redirect after login localStorage.setItem(MG.nextUrlKey, window.location.href); // Show modal showModal(); } else { // Remove blocker and grant access unblockPage(); window.dispatchEvent(new Event('mg-access-granted')); } createFloatingButton(); updateFloatingButton(); console.log('[MemberGate] Widget initialized successfully'); } catch (error) { console.error('[MemberGate] Initialization failed:', error); } } // Block page IMMEDIATELY (before DOM ready) on protected paths (function() { var path = window.location.pathname; for (var i = 0; i < MG.routes.length; i++) { var pattern = MG.routes[i].pattern; var matches = pattern.endsWith('/*') ? path.startsWith(pattern.slice(0, -2) + '/') : path === pattern; if (matches) { MG.onProtectedPage = true; // Inject blocker style immediately via a style tag var s = document.createElement('style'); s.id = 'mg-early-block'; s.textContent = 'body > *:not(#mg-login-overlay):not(#mg-blocker) { filter: blur(12px); pointer-events: none; } body { overflow: hidden; }'; (document.head || document.documentElement).appendChild(s); break; } } })(); // Wait for DOM if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();