UNPKG

besper-frontend-site-dev-main

Version:

Professional B-esper Frontend Site - Site-wide integration toolkit for full website bot deployment

1,139 lines (1,005 loc) 33.9 kB
/** * Home Page Script - Bulletproof loading pattern * Welcome to our new platform experience */ class HomeNewPage { constructor(options = {}) { this.options = { containerId: 'besper-site-content', environment: 'prod', ...options, }; this.initialized = false; // BULLETPROOF: Defer all complex operations to avoid blocking class export this.authService = null; this.operatorsService = null; this.isAuthenticated = false; // Initialize auth safely in next tick to ensure class export completes first if (typeof window !== 'undefined') { setTimeout(() => { this.initializeAuth(); }, 1); } } /** * Initialize authentication safely without blocking class export */ initializeAuth() { try { this.authService = this.getAuthService(); this.operatorsService = this.getOperatorsService(); } catch (error) { console.warn('Auth initialization failed, using fallback:', error); this.authService = this.createFallbackAuthService(); this.operatorsService = this.createFallbackOperatorsService(); } } /** * Get authentication service from global scope or create simple fallback */ getAuthService() { // Try to access global token auth service if available if (typeof window !== 'undefined' && window.tokenAuthService) { return window.tokenAuthService; } return this.createFallbackAuthService(); } /** * Get operators service from global scope or create simple fallback */ getOperatorsService() { // Try to access global page operators service if available if (typeof window !== 'undefined' && window.pageOperatorsService) { return window.pageOperatorsService; } return this.createFallbackOperatorsService(); } /** * Create safe fallback auth service */ createFallbackAuthService() { return { isUserAuthenticated: () => { try { return ( typeof window !== 'undefined' && window.auth && typeof window.auth.getToken === 'function' && !!window.auth.getToken() ); } catch (error) { return false; } }, getToken: () => { try { if ( typeof window !== 'undefined' && window.auth && typeof window.auth.getToken === 'function' ) { return window.auth.getToken(); } } catch (error) { console.warn('Token access failed:', error); } return null; }, getUserPermission: key => { try { if (typeof window === 'undefined') return null; const mappings = { contactId: window.contact_id || window.user_contactid, userName: window.user_name, name: window.user_name, userEmail: window.user_email, email: window.user_email, workspaceId: window.workspace_id, accountId: window.account_id, subscriptionId: window.subscription_id, }; return mappings[key] || null; } catch (error) { console.warn('User permission access failed:', error); return null; } }, }; } /** * Create safe fallback operators service */ createFallbackOperatorsService() { return { callOperator: async () => { console.warn( 'Operators service not available, returning empty response' ); return { success: false, message: 'Service not available' }; }, }; } /** * Initialize the page - IMMEDIATE RENDERING * Shows UI instantly without waiting for authentication */ async initialize(_data = {}) { if (this.initialized) return; try { // IMMEDIATE: Show the UI without any loading delays this.renderImmediateUI(); // IMMEDIATE: Setup basic interactions this.setupInteractions(); this.initialized = true; // DEFERRED: Initialize authentication features in background this.initializeAuthenticationFeaturesInBackground(); } catch (error) { console.error('Error initializing home page:', error); this.showError(error); } } /** * Render immediate UI structure - shows content instantly */ renderImmediateUI() { const container = document.getElementById(this.options.containerId); if (!container) return; // Clear any existing loading indicators container.innerHTML = ''; // Show immediate home interface container.innerHTML = ` <div style="background: #f8f9fa; color: #022d54; font-family: Arial, sans-serif;"> <div style="max-width: 1200px; margin: 0 auto; padding: 2rem 1rem;"> <!-- Header --> <div style="margin-bottom: 2rem;"> <h1 style="color: #022d54; font-weight: 300; font-size: 28px; margin-bottom: 0.5rem;">Home</h1> <p style="color: #6c757d; font-size: 14px; margin: 0;">Welcome to our new platform experience</p> </div> <!-- Main Content Area with Skeleton Loading --> <div style="background: white; border-radius: 8px; border: 1px solid #e0e0e0; overflow: hidden;"> <div style="padding: 1rem; border-bottom: 1px solid #e0e0e0;"> <h3 style="margin: 0; color: #022d54; font-size: 16px; font-weight: 500;">Loading Content...</h3> </div> <div id="page-content-area" style="padding: 2rem;"> <!-- Skeleton Loading Animation --> <div style="height: 20px; background: #e0e0e0; border-radius: 4px; margin-bottom: 1rem; animation: pulse 1.5s ease-in-out infinite;"></div> <div style="height: 20px; background: #e0e0e0; border-radius: 4px; margin-bottom: 1rem; width: 80%; animation: pulse 1.5s ease-in-out infinite;"></div> <div style="height: 20px; background: #e0e0e0; border-radius: 4px; margin-bottom: 1rem; width: 60%; animation: pulse 1.5s ease-in-out infinite;"></div> <div style="height: 100px; background: #e0e0e0; border-radius: 4px; animation: pulse 1.5s ease-in-out infinite;"></div> </div> </div> </div> </div> <!-- Skeleton Loading Animation --> <style> @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } </style> `; } /** * Setup interactions - immediate setup without waiting */ setupInteractions() { // TODO: Add page-specific interactions here console.log('Home interactions ready'); } /** * Initialize authentication features completely in background - NO UI BLOCKING */ async initializeAuthenticationFeaturesInBackground() { // Use requestIdleCallback for true background processing const initializeAuth = () => { try { // Ensure services are ready if (!this.authService) { this.initializeAuth(); } // Check authentication status without blocking if (this.authService) { this.isAuthenticated = this.authService.isUserAuthenticated(); if (this.isAuthenticated) { // Load data in background this.loadDataInBackground(); } else { this.showUnauthenticatedView(); } } } catch (error) { console.warn( 'Background authentication features initialization failed:', error ); // Continue silently - authentication is not critical for UI display } }; // Use requestIdleCallback for non-blocking background execution if (typeof requestIdleCallback !== 'undefined') { requestIdleCallback(initializeAuth, { timeout: 5000 }); } else { // Fallback for browsers without requestIdleCallback setTimeout(initializeAuth, 50); } } /** * Load data in background */ async loadDataInBackground() { try { console.log('Loading home data in background...'); // TODO: Replace with actual data loading // Example: // const data = await this.fetchData(); // this.updateUIWithData(data); // For now, just remove skeleton loading after delay setTimeout(() => { this.updateUIWithActualContent(); }, 1000); } catch (error) { console.error('Background data loading failed:', error); } } /** * Update UI with actual content (replace skeleton loading) * Full-featured home dashboard interface based on new_home_ui.html template */ updateUIWithActualContent() { const contentArea = document.getElementById('page-content-area'); if (contentArea) { // Get user's preferred language const language = this.getCurrentLanguage(); const translations = this.getTranslations(language); contentArea.innerHTML = this.generateHomeDashboardHTML(translations); // Initialize home dashboard functionality this.initializeHomeDashboardFeatures(translations); } } /** * Get current language (German or English) */ getCurrentLanguage() { // Check URL parameter first const urlParams = new URLSearchParams(window.location.search); const langParam = urlParams.get('lang'); if (langParam && ['en', 'de'].includes(langParam)) { return langParam; } // Check localStorage const storedLang = localStorage.getItem('bsp_language'); if (storedLang && ['en', 'de'].includes(storedLang)) { return storedLang; } // Check browser language const browserLang = navigator.language.toLowerCase(); if (browserLang.startsWith('de')) { return 'de'; } // Default to English return 'en'; } /** * Get translations for the specified language */ getTranslations(language) { const translations = { en: { title: 'Welcome to B-esper', subtitle: 'Your intelligent automation platform', totalWorkspaces: 'Total Workspaces', activeBots: 'Active Bots', monthlyProcessed: 'Monthly Processed', avgResponseTime: 'Avg Response Time', workspacesManaged: 'workspaces managed', botsRunning: 'bots running', documentsProcessed: 'documents processed', responseTime: 'average response', quickActions: 'Quick Actions', createBot: 'Create New Bot', manageWorkspaces: 'Manage Workspaces', viewAnalytics: 'View Analytics', recentActivity: 'Recent Activity', systemHealth: 'System Health', noRecentActivity: 'No recent activity', viewAllActivity: 'View All Activity', cpuUsage: 'CPU Usage', memoryUsage: 'Memory Usage', apiCalls: 'API Calls Today', uptime: 'System Uptime', }, de: { title: 'Willkommen bei B-esper', subtitle: 'Ihre intelligente Automatisierungsplattform', totalWorkspaces: 'Gesamte Arbeitsbereiche', activeBots: 'Aktive Bots', monthlyProcessed: 'Monatlich verarbeitet', avgResponseTime: 'Durchschn. Antwortzeit', workspacesManaged: 'verwaltete Arbeitsbereiche', botsRunning: 'laufende Bots', documentsProcessed: 'verarbeitete Dokumente', responseTime: 'durchschnittliche Antwort', quickActions: 'Schnellaktionen', createBot: 'Neuen Bot erstellen', manageWorkspaces: 'Arbeitsbereiche verwalten', viewAnalytics: 'Analysen anzeigen', recentActivity: 'Letzte Aktivität', systemHealth: 'Systemzustand', noRecentActivity: 'Keine kürzliche Aktivität', viewAllActivity: 'Alle Aktivitäten anzeigen', cpuUsage: 'CPU-Auslastung', memoryUsage: 'Speicherauslastung', apiCalls: 'API-Aufrufe heute', uptime: 'System-Betriebszeit', }, }; return translations[language] || translations.en; } /** * Generate the complete home dashboard HTML interface */ generateHomeDashboardHTML(translations) { return ` <div class="dashboard-container"> <!-- Header --> <div class="dashboard-header"> <div class="header-left"> <h1>${translations.title}</h1> <div class="subtitle">${translations.subtitle}</div> </div> <div class="header-actions"> <select class="language-selector" onchange="window.homeNewPage.changeLanguage(this.value)"> <option value="en" ${this.getCurrentLanguage() === 'en' ? 'selected' : ''}>English</option> <option value="de" ${this.getCurrentLanguage() === 'de' ? 'selected' : ''}>Deutsch</option> </select> </div> </div> <!-- KPI Cards --> <div class="kpi-grid"> <div class="kpi-card"> <div class="kpi-label">${translations.totalWorkspaces}</div> <div class="kpi-value" id="totalWorkspaces">-</div> <div class="kpi-change positive" id="workspacesChange">+2 ${translations.workspacesManaged}</div> </div> <div class="kpi-card"> <div class="kpi-label">${translations.activeBots}</div> <div class="kpi-value" id="activeBots">-</div> <div class="kpi-change positive" id="botsChange">+5 ${translations.botsRunning}</div> </div> <div class="kpi-card"> <div class="kpi-label">${translations.monthlyProcessed}</div> <div class="kpi-value" id="monthlyProcessed">-</div> <div class="kpi-change neutral" id="processedChange">1.2k ${translations.documentsProcessed}</div> </div> <div class="kpi-card"> <div class="kpi-label">${translations.avgResponseTime}</div> <div class="kpi-value" id="avgResponseTime">-</div> <div class="kpi-change positive" id="responseTimeChange">245ms ${translations.responseTime}</div> </div> </div> <!-- Main Dashboard Grid --> <div class="dashboard-grid"> <!-- Quick Actions Card --> <div class="dashboard-card"> <div class="card-header"> <h3>${translations.quickActions}</h3> </div> <div class="card-content"> <div class="quick-actions"> <button class="action-btn primary" onclick="window.homeNewPage.createBot()"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <circle cx="12" cy="12" r="10"/> <path d="M8 14s1.5 2 4 2 4-2 4-2"/> <line x1="9" y1="9" x2="9.01" y2="9"/> <line x1="15" y1="9" x2="15.01" y2="9"/> </svg> ${translations.createBot} </button> <button class="action-btn secondary" onclick="window.homeNewPage.manageWorkspaces()"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/> <line x1="9" y1="9" x2="15" y2="9"/> <line x1="9" y1="15" x2="15" y2="15"/> </svg> ${translations.manageWorkspaces} </button> <button class="action-btn secondary" onclick="window.homeNewPage.viewAnalytics()"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M3 3v18h18"/> <path d="M18.7 8l-5.1 5.2-2.8-2.7L7 14.3"/> </svg> ${translations.viewAnalytics} </button> </div> </div> </div> <!-- Recent Activity Card --> <div class="dashboard-card"> <div class="card-header"> <h3>${translations.recentActivity}</h3> <button class="btn-link" onclick="window.homeNewPage.viewAllActivity()"> ${translations.viewAllActivity} </button> </div> <div class="card-content"> <div class="activity-list" id="activityList"> <!-- Activity items will be populated here --> </div> </div> </div> <!-- System Health Card --> <div class="dashboard-card"> <div class="card-header"> <h3>${translations.systemHealth}</h3> </div> <div class="card-content"> <div class="health-metrics"> <div class="metric-item"> <div class="metric-label">${translations.cpuUsage}</div> <div class="metric-bar"> <div class="metric-fill" style="width: 45%" data-value="45"></div> </div> <div class="metric-value">45%</div> </div> <div class="metric-item"> <div class="metric-label">${translations.memoryUsage}</div> <div class="metric-bar"> <div class="metric-fill" style="width: 68%" data-value="68"></div> </div> <div class="metric-value">68%</div> </div> <div class="metric-item"> <div class="metric-label">${translations.apiCalls}</div> <div class="metric-bar"> <div class="metric-fill" style="width: 32%" data-value="32"></div> </div> <div class="metric-value">1.2k</div> </div> <div class="metric-item"> <div class="metric-label">${translations.uptime}</div> <div class="metric-bar"> <div class="metric-fill success" style="width: 99%" data-value="99"></div> </div> <div class="metric-value">99.9%</div> </div> </div> </div> </div> </div> ${this.generateHomeDashboardCSS()} </div> `; } /** * Generate CSS styles for the home dashboard interface */ generateHomeDashboardCSS() { return ` <style> .dashboard-container { max-width: 1400px; margin: 0 auto; padding: 32px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif; background: #f8f9fa; color: #022d54; line-height: 1.6; } .dashboard-header { margin-bottom: 40px; display: flex; justify-content: space-between; align-items: center; } .dashboard-header h1 { font-size: 28px; font-weight: 300; color: #022d54; margin-bottom: 8px; letter-spacing: -0.5px; margin: 0; } .subtitle { color: #6c757d; font-size: 14px; } .header-actions { display: flex; gap: 12px; align-items: center; } .language-selector { padding: 8px 12px; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 14px; background: white; } /* KPI Cards */ .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 40px; } .kpi-card { background: white; padding: 24px; border-radius: 8px; border: 1px solid #e0e0e0; transition: all 0.2s ease; } .kpi-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.08); transform: translateY(-2px); } .kpi-label { font-size: 12px; text-transform: uppercase; color: #6c757d; letter-spacing: 0.5px; margin-bottom: 8px; } .kpi-value { font-size: 32px; font-weight: 600; color: #022d54; line-height: 1; margin-bottom: 12px; } .kpi-change { font-size: 13px; display: inline-block; padding: 4px 8px; border-radius: 4px; } .kpi-change.positive { color: #10b981; background: #d1fae5; } .kpi-change.negative { color: #f59e0b; background: #fef3c7; } .kpi-change.neutral { color: #6b7280; background: #f3f4f6; } /* Dashboard Grid */ .dashboard-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 24px; } .dashboard-card { background: white; border-radius: 8px; border: 1px solid #e0e0e0; overflow: hidden; } .card-header { padding: 20px 24px; border-bottom: 1px solid #e0e0e0; display: flex; justify-content: space-between; align-items: center; } .card-header h3 { font-size: 16px; font-weight: 500; color: #022d54; margin: 0; } .btn-link { color: #022d54; text-decoration: none; font-size: 14px; font-weight: 500; border: none; background: none; cursor: pointer; transition: color 0.2s; } .btn-link:hover { color: #011831; } .card-content { padding: 24px; } /* Quick Actions */ .quick-actions { display: flex; flex-direction: column; gap: 12px; } .action-btn { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border: none; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s; text-align: left; width: 100%; } .action-btn.primary { background: #022d54; color: white; } .action-btn.primary:hover { background: #011831; } .action-btn.secondary { background: #f8f9fa; color: #022d54; border: 1px solid #e0e0e0; } .action-btn.secondary:hover { background: #e9ecef; border-color: #6c757d; } /* Activity List */ .activity-list { max-height: 300px; overflow-y: auto; } .activity-item { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid #f0f0f0; } .activity-item:last-child { border-bottom: none; } .activity-icon { width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(135deg, #022d54 0%, #033e6b 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; } .activity-content { flex: 1; } .activity-title { font-weight: 500; color: #022d54; margin-bottom: 2px; } .activity-meta { font-size: 12px; color: #6c757d; } .activity-time { font-size: 12px; color: #6c757d; } /* Health Metrics */ .health-metrics { display: flex; flex-direction: column; gap: 16px; } .metric-item { display: flex; align-items: center; gap: 12px; } .metric-label { flex: 0 0 120px; font-size: 13px; color: #6c757d; } .metric-bar { flex: 1; height: 8px; background: #f0f0f0; border-radius: 4px; overflow: hidden; } .metric-fill { height: 100%; background: linear-gradient(90deg, #10b981 0%, #059669 100%); border-radius: 4px; transition: width 0.3s ease; } .metric-fill.success { background: linear-gradient(90deg, #10b981 0%, #059669 100%); } .metric-value { flex: 0 0 50px; text-align: right; font-size: 13px; font-weight: 500; color: #022d54; } .empty-activity { text-align: center; padding: 40px 20px; color: #6c757d; } .empty-activity svg { width: 48px; height: 48px; margin-bottom: 16px; stroke: #cbd5e0; } @media (max-width: 768px) { .dashboard-container { padding: 16px; } .dashboard-header { flex-direction: column; align-items: flex-start; gap: 16px; } .kpi-grid { grid-template-columns: 1fr; } .dashboard-grid { grid-template-columns: 1fr; } .metric-item { flex-direction: column; align-items: flex-start; gap: 8px; } .metric-label { flex: none; } .metric-bar { width: 100%; } .metric-value { flex: none; text-align: left; } } </style> `; } /** * Initialize home dashboard features */ initializeHomeDashboardFeatures(translations) { this.translations = translations; this.dashboardData = { kpis: { totalWorkspaces: 0, activeBots: 0, monthlyProcessed: 0, avgResponseTime: 0, }, activities: [], }; // Load dashboard data from APIM APIs this.loadDashboardDataFromAPIM(); } /** * Load dashboard data from APIM using operators */ async loadDashboardDataFromAPIM() { try { console.log( '[HomeDashboard] Loading dashboard data using APIM operators...' ); // Ensure authentication is available if (!this.authService?.isUserAuthenticated()) { throw new Error('Authentication required for dashboard operations'); } // Load dashboard KPIs using APIM operators const kpiResponse = await this.operatorsService.callOperator( 'dashboard', 'get_kpis', { authData: this.authService.getAuthData(), } ); // Load dashboard activity using APIM operators const activityResponse = await this.operatorsService.callOperator( 'dashboard', 'get_activity', { authData: this.authService.getAuthData(), limit: 10, } ); if (!kpiResponse.success && !activityResponse.success) { throw new Error('Failed to load dashboard data from APIM operators'); } // Process the dashboard data this.processDashboardData(kpiResponse.data, activityResponse.data); console.log( '[HomeDashboard] [SUCCESS] Successfully loaded dashboard data using APIM operators' ); } catch (error) { console.error( '[HomeDashboard] [ERROR] Failed to load dashboard data:', error ); throw error; // Re-throw error instead of falling back to sample data } } /** * Process dashboard data from APIM operators response */ processDashboardData(kpiData, activityData) { this.dashboardData = { kpis: { totalWorkspaces: kpiData?.totalWorkspaces || 0, activeBots: kpiData?.activeBots || 0, monthlyProcessed: kpiData?.monthlyProcessed || '0', avgResponseTime: kpiData?.avgResponseTime || '0ms', }, activities: activityData?.activities || [], }; this.updateKPIDisplay(); this.renderActivity(); } /** * DEPRECATED: Load sample dashboard data for demonstration * This method should never be called in production */ loadSampleDashboardData() { console.warn( '[HomeDashboard] loadSampleDashboardData is deprecated and should not be used' ); throw new Error( 'Sample dashboard data is not allowed. Use APIM operators instead.' ); } /** * Update KPI display */ updateKPIDisplay() { const kpis = this.dashboardData.kpis; const totalWorkspacesEl = document.getElementById('totalWorkspaces'); const activeBotsEl = document.getElementById('activeBots'); const monthlyProcessedEl = document.getElementById('monthlyProcessed'); const avgResponseTimeEl = document.getElementById('avgResponseTime'); if (totalWorkspacesEl) totalWorkspacesEl.textContent = kpis.totalWorkspaces; if (activeBotsEl) activeBotsEl.textContent = kpis.activeBots; if (monthlyProcessedEl) monthlyProcessedEl.textContent = kpis.monthlyProcessed; if (avgResponseTimeEl) avgResponseTimeEl.textContent = kpis.avgResponseTime; } /** * Render activity list */ renderActivity() { const activityList = document.getElementById('activityList'); if (!activityList) return; if (this.dashboardData.activities.length === 0) { activityList.innerHTML = ` <div class="empty-activity"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> </svg> <div>${this.translations.noRecentActivity}</div> </div> `; return; } activityList.innerHTML = this.dashboardData.activities .map( activity => ` <div class="activity-item"> <div class="activity-icon">${activity.icon}</div> <div class="activity-content"> <div class="activity-title">${activity.title}</div> <div class="activity-meta">${activity.meta}</div> </div> <div class="activity-time">${activity.time}</div> </div> ` ) .join(''); } /** * Change language */ changeLanguage(language) { localStorage.setItem('bsp_language', language); this.updateUIWithActualContent(); // Re-render with new language } /** * Quick action handlers */ createBot() { console.log('Create new bot'); // TODO: Navigate to bot creation page or integrate with APIM bot creation API window.location.href = '/bot-management-new'; } manageWorkspaces() { console.log('Manage workspaces'); // TODO: Navigate to workspace management page window.location.href = '/workspace-management-new'; } viewAnalytics() { console.log('View analytics'); // TODO: Navigate to analytics page window.location.href = '/analytics'; } viewAllActivity() { console.log('View all activity'); // TODO: Navigate to activity page or show detailed activity view alert('View all activity - integrate with APIM activity API'); } /** * Show unauthenticated view */ showUnauthenticatedView() { const contentArea = document.getElementById('page-content-area'); if (contentArea) { contentArea.innerHTML = ` <div style="text-align: center; padding: 2rem;"> <h2 style="color: #022d54;">Authentication Required</h2> <p style="color: #6c757d;">Please log in to access home.</p> </div> `; } } /** * Show error message */ showError(error) { const container = document.getElementById(this.options.containerId); if (container) { container.innerHTML = ` <div style="background: #f8f9fa; display: flex; align-items: center; justify-content: center;"> <div style="text-align: center; padding: 2rem; background: white; border-radius: 8px; border: 1px solid #e0e0e0; max-width: 500px;"> <h3 style="color: #d32f2f; margin-bottom: 1rem;">Error Loading Home</h3> <p style="color: #6c757d; margin-bottom: 1.5rem;">${error.message || error}</p> <button onclick="location.reload()" style="padding: 10px 20px; background: #022d54; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px;"> Try Again </button> </div> </div> `; } } } // BULLETPROOF EXPORT MECHANISM - Ensures class is always available (function () { 'use strict'; // Multiple export strategies to ensure maximum compatibility // Strategy 1: Direct window assignment (most reliable) if (typeof window !== 'undefined') { window.HomeNewPage = HomeNewPage; // Also make instance globally accessible for method calls window.homeNewPage = new HomeNewPage(); } // Strategy 2: Module exports for Node.js environments if (typeof module !== 'undefined' && module.exports) { module.exports = HomeNewPage; } // Strategy 3: Global fallback if (typeof global !== 'undefined') { global.HomeNewPage = HomeNewPage; } // Strategy 4: AMD/RequireJS support if (typeof define === 'function' && define.amd) { define([], function () { return HomeNewPage; }); } // Strategy 5: Self-executing verification setTimeout(function () { if (typeof window !== 'undefined' && !window.HomeNewPage) { console.warn('HomeNewPage export failed, retrying...'); window.HomeNewPage = HomeNewPage; } }, 10); })();