UNPKG

besper-frontend-site-dev-main

Version:

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

790 lines (698 loc) 27.3 kB
// src/index.js - B-esper Frontend Site // Site-wide implementation with comprehensive bot functionality /** * B-esper Frontend Site - Complete Package * * Main Functions: * - bsp_init_b_espersite(botId, options) - Site-wide bot integration * - bsp_manage_b_espersite(credentials, options) - Site management interface * - bsp_demo_b_espersite(botId, options) - Site demo interface * - b_esper_site_helper(options) - Public site helper bot */ // Initialize module federation compatibility for PowerPages environments if (typeof window !== 'undefined') { // Detect PowerPages environment and suppress React version conflicts early const isPowerPages = window.location.hostname.includes('powerappsportals.com') || window.location.hostname.includes('powerplatformUserVoice.com') || document.querySelector('script[src*="powerpages"]') || window.Microsoft?.PowerApps; if (isPowerPages) { // Suppress module federation React version conflicts at the package level const originalConsoleError = console.error; const originalConsoleWarn = console.warn; console.error = function (...args) { const message = args.join(' '); if ( (message.includes('Unsatisfied version') && (message.includes('react') || message.includes('react-dom')) && message.includes('shared singleton module')) || message.includes('Some icons were re-registered') || (message.includes('Refused to apply style') && message.includes('MIME type')) ) { // Suppress React version conflicts, icon warnings, and CSS MIME type errors in PowerPages console.log( `🔧 B-esper: PowerPages compatibility - suppressed: ${message.substring(0, 100)}...` ); return; } originalConsoleError.apply(console, args); }; console.warn = function (...args) { const message = args.join(' '); if ( (message.includes('react') && message.includes('version')) || message.includes('icons were re-registered') ) { // Suppress React version warnings and icon re-registration warnings return; } originalConsoleWarn.apply(console, args); }; console.log( '🔧 B-esper: PowerPages compatibility mode enabled - React version conflicts and style errors suppressed' ); } } // Import working components with CSS injection import { BesperChatWidget } from './components/chat-widget.js'; import { BesperBotManagement } from './components/b-esper-bot-management.js'; import { BesperDemoInterface } from './components/demo-interface.js'; // Import custom styling manager import { CustomStylingManager } from './components/custom-styling-manager.js'; // Import new modular site functions import { b_esper_site, b_esper_management_widget, b_esper_cleanup_page, b_esper_cleanup_all, b_esper_get_pages, b_esper_is_authenticated_page, } from './besper-site-functions.js'; // Import page loader for advanced usage import { BesperPageLoader } from './components/site/BesperPageLoader.js'; // Import all page classes to bundle them with the package import './pages/index.js'; // Import PowerPages integration utility import { initializePowerPagesIntegration, autoDetectPageIntegration, generatePowerPagesTemplate, } from './utils/powerPagesIntegration.js'; // Import optimized template loader service import TemplateLoaderService from './services/TemplateLoaderService.js'; // Import notification system components import NotificationBanner from './components/site/NotificationBanner.js'; // Import cookie-based token manager for consistent authentication import cookieTokenManager from './utils/cookieTokenManager.js'; // Import global function safety utilities import { initializeSafeGlobals } from './utils/globalFunctionSafety.js'; /** * Main initialization function for the B-esper chat widget * Creates and initializes a chat widget with dynamic styling * * @param {string} botId - The bot ID to initialize * @param {Object} options - Configuration options * @param {string} options.environment - Environment ('dev', 'int', 'prod') * @param {string} options.position - Widget position ('bottom-right', 'bottom-left', etc.) * @returns {Promise<BesperChatWidget>} - Initialized widget instance */ async function bsp_init_b_espersite(botId, options = {}) { if (!botId) { throw new Error('Bot ID is required'); } try { const widget = new BesperChatWidget(botId, options); await widget.init(); // Make widget globally available for debugging if (typeof window !== 'undefined') { window.besperWidget = widget; } console.log('[SUCCESS] B-esper chat widget initialized successfully'); return widget; } catch (error) { console.error('[ERROR] Failed to initialize B-esper chat widget:', error); throw error; } } /** * Initialize bot management interface * Creates a comprehensive management UI for bot configuration * * @param {Object} credentials - Management credentials * @param {string} credentials.botId - Bot ID * @param {string} credentials.managementId - Management ID * @param {string} credentials.managementSecret - Management secret * @param {Object} options - Configuration options * @param {string} options.environment - Environment ('dev', 'int', 'prod') * @param {string|HTMLElement} options.container - Container element or selector * @param {boolean} options.showBot - Whether to show the actual bot widget on the same page for testing * @returns {Promise<BesperBotManagement>} - Initialized management interface */ async function bsp_manage_b_espersite(credentials, options = {}) { if ( !credentials || !credentials.botId || !credentials.managementId || !credentials.managementSecret ) { throw new Error( 'Management credentials required: botId, managementId, managementSecret' ); } try { const managementInterface = new BesperBotManagement(credentials, options); await managementInterface.init(); // Make management interface globally available for debugging if (typeof window !== 'undefined') { window.besperBotManagement = managementInterface; } console.log( '[SUCCESS] B-esper Bot Management interface initialized successfully' ); return managementInterface; } catch (error) { console.error( '[ERROR] Failed to initialize B-esper Bot Management:', error ); throw error; } } // Removed duplicate b_esper_management_widget function since it's imported from besper-site-functions.js /** * Initialize demo interface * Creates a demo UI showing bot capabilities with knowledge panel * * @param {string} botId - The bot ID to initialize * @param {Object} options - Configuration options * @param {string} options.environment - Environment ('dev', 'int', 'prod') * @returns {Promise<Object|null>} - Basic demo object or null on mobile */ async function bsp_demo_b_espersite(botId, options = {}) { if (!botId) { throw new Error('Bot ID is required'); } try { // Simple demo implementation - for now just initialize a chat widget in demo mode const demoOptions = { ...options, isDemoMode: true }; const chatWidget = new BesperChatWidget(botId, demoOptions); await chatWidget.init(); // Return basic demo object const demoWidget = { chatWidget, destroy: () => chatWidget.destroy?.(), }; // Make demo widget globally available for debugging if (typeof window !== 'undefined') { window.besperDemoWidget = demoWidget; } console.log('[SUCCESS] B-esper demo widget initialized successfully'); return demoWidget; } catch (error) { console.error('[ERROR] Failed to initialize B-esper demo widget:', error); throw error; } } /** * Initialize comprehensive demo interface * Creates a full demo interface replicating tobedeveloped_demo.html functionality * * @param {string} botId - The bot ID to initialize (optional for demo) * @param {Object} options - Configuration options * @param {string} options.environment - Environment ('dev', 'int', 'prod') * @param {string|HTMLElement} options.container - Container element or selector * @returns {Promise<BesperDemoInterface|null>} - Demo interface instance or null on mobile */ async function init_demo(botId = 'demo-bot', options = {}) { try { console.log('[INIT] Initializing B-esper demo interface...'); const demoInterface = new BesperDemoInterface(botId, options); const result = await demoInterface.init(); if (!result) { console.log('📱 Demo interface hidden on mobile device'); return null; } // Make demo interface globally available for debugging if (typeof window !== 'undefined') { window.besperDemoInterface = demoInterface; } console.log('[SUCCESS] B-esper demo interface initialized successfully'); return demoInterface; } catch (error) { console.error( '[ERROR] Failed to initialize B-esper demo interface:', error ); throw error; } } /** * Get notification banner - main function requested by user * Creates and displays notification banner with count display and sidebar functionality * Integrates with CosmoDB via APIM internal endpoints using user impersonation * Uses smart token system for coordinated authentication * * @param {Object} options - Configuration options (optional) * @param {string} options.containerId - Container ID for banner placement * @param {string} options.position - Banner position (top-right, top-left, etc.) * @param {boolean} options.autoRefresh - Enable auto-refresh of counts * @param {number} options.refreshInterval - Refresh interval in milliseconds * @returns {Promise<NotificationBanner>} Notification banner instance */ async function get_notification_banner(options = {}) { try { console.log( '🔔 Initializing notification banner with cookie-based token system...' ); // Check authentication status using the cookie-based token manager const isAuthenticated = cookieTokenManager.isAuthenticated(); if (!isAuthenticated) { console.log( '[NotificationBanner] User not authenticated, skipping banner initialization' ); return null; } console.log('[NotificationBanner] [SUCCESS] User authenticated'); // Get token using cookie-based approach - no infinite loops possible const token = await cookieTokenManager.getToken('NotificationBanner'); if (!token) { console.warn( '[NotificationBanner] Authentication failed, cannot display banner' ); return null; } // Create notification banner instance const banner = new NotificationBanner(options); // Make banner globally available for debugging if (typeof window !== 'undefined') { window.notificationBanner = banner; } console.log('[SUCCESS] Notification banner initialized successfully'); return banner; } catch (error) { console.error('[ERROR] Failed to initialize notification banner:', error); return null; // Return null instead of throwing error for better UX } } /** * Initialize the public Besper helper bot * Uses the hardcoded public helper bot ID for easy integration * * @param {Object} options - Configuration options (optional) * @param {string} options.environment - Environment ('dev', 'int', 'prod') * @param {string} options.position - Widget position ('bottom-right', 'bottom-left', etc.) * @returns {Promise<BesperChatWidget>} - Initialized public helper widget instance */ async function b_esper_site_helper(options = {}) { const PUBLIC_HELPER_BOT_ID = 'public_bot_external'; try { console.log('[INIT] Initializing Besper public helper bot...'); // Use the existing bsp_init_b_espersite function with the hardcoded public bot ID const widget = await bsp_init_b_espersite(PUBLIC_HELPER_BOT_ID, options); console.log('[SUCCESS] Besper public helper bot initialized successfully'); return widget; } catch (error) { console.error( '[ERROR] Failed to initialize Besper public helper bot:', error ); throw error; } } /** * Initialize demo functionality after page render * @deprecated - Legacy function, demo is now handled by individual page scripts */ // eslint-disable-next-line no-unused-vars async function initializeDemoFunctionality(renderer, options) { try { // Initialize demo widgets in demo containers const demoContainers = document.querySelectorAll('[id*="demo"]'); for (const container of demoContainers) { if (container.id === 'besper-demo-container') { // Initialize basic demo widget await bsp_demo_b_espersite('demo_bot', { container: container.id, environment: options.environment || 'dev', }); } else if (container.id === 'besper-full-demo') { // Initialize full demo interface await bsp_demo_b_espersite('demo_bot', { container: container.id, environment: options.environment || 'dev', fullInterface: true, }); } } } catch (error) { console.warn('Failed to initialize demo functionality:', error); } } /** * Initialize page-specific functionality * @deprecated - Legacy function, page functionality is now handled by individual page scripts */ // eslint-disable-next-line no-unused-vars async function initializePageFunctionality(url, options) { try { const normalizedUrl = url.replace(/^\/+|\/+$/g, '').toLowerCase() || 'home'; // Add global window functions for page interactions if (typeof window !== 'undefined') { // Make functions globally available window.besperSite = window.besperSite || {}; // Common functions window.besperSite.navigateTo = path => { if (options.containerId) { b_esper_site(path, options); } else { window.location.href = path; } }; window.besperSite.downloadCaseStudy = caseStudyId => { const caseStudy = options.caseStudies?.find( cs => cs.id === caseStudyId ); if (caseStudy && caseStudy.downloadUrl) { window.open(caseStudy.downloadUrl, '_blank'); } }; window.besperSite.requestPitchdeckPresentation = () => { window.location.href = '/contact-us?subject=pitchdeck-presentation'; }; // Page-specific functions switch (normalizedUrl) { case 'home_auth': window.createNewBot = () => (window.location.href = '/my-bots?action=create'); window.editBot = botId => (window.location.href = `/my-bots/${botId}/edit`); window.viewBot = botId => (window.location.href = `/my-bots/${botId}`); window.deleteBot = botId => { if (confirm('Are you sure you want to delete this bot?')) { // API call to delete bot console.log('Deleting bot:', botId); } }; break; case 'pricing': window.selectPlan = planId => { window.location.href = `/subscription?plan=${planId}`; }; break; case 'contact-us': window.submitContactForm = async event => { event.preventDefault(); const formData = new FormData(event.target); // API call to submit form console.log( 'Submitting contact form:', Object.fromEntries(formData) ); alert('Thank you for your message! We will get back to you soon.'); }; break; case 'profile': window.updateProfile = async event => { event.preventDefault(); const formData = new FormData(event.target); // API call to update profile console.log('Updating profile:', Object.fromEntries(formData)); alert('Profile updated successfully!'); }; break; case 'notifications': window.markRead = notificationId => { console.log('Marking notification as read:', notificationId); }; window.markAllRead = () => { console.log('Marking all notifications as read'); }; window.deleteNotification = notificationId => { console.log('Deleting notification:', notificationId); }; break; case 'subscription': window.upgradePlan = () => (window.location.href = '/pricing'); window.addPaymentMethod = () => { console.log('Adding payment method'); }; window.removePaymentMethod = methodId => { console.log('Removing payment method:', methodId); }; break; case 'workbench': window.createProject = () => { const name = prompt('Project name:'); if (name) console.log('Creating project:', name); }; window.openProject = projectId => { console.log('Opening project:', projectId); }; window.saveProject = () => { console.log('Saving project'); }; window.runTest = () => { console.log('Running tests'); document.getElementById('test-results').textContent = 'Tests passed successfully!'; }; window.deployProject = () => { console.log('Deploying project'); }; window.loadTemplate = templateId => { console.log('Loading template:', templateId); }; break; } } } catch (error) { console.warn('Failed to initialize page functionality:', error); } } // Export all main functions and classes for ES modules and CommonJS export { // Main functions bsp_init_b_espersite, bsp_manage_b_espersite, b_esper_management_widget, bsp_demo_b_espersite, init_demo, b_esper_site_helper, b_esper_site, // New modular site functions b_esper_cleanup_page, b_esper_cleanup_all, b_esper_get_pages, b_esper_is_authenticated_page, // Notification and token management functions get_notification_banner, // PowerPages integration utilities initializePowerPagesIntegration, generatePowerPagesTemplate, // Main widget classes BesperChatWidget, BesperBotManagement, BesperDemoInterface, BesperPageLoader, // Utility classes CustomStylingManager, NotificationBanner, }; // Browser global for script tag usage if (typeof window !== 'undefined') { // Create BesperBot namespace if it doesn't exist if (!window.BesperBot) { window.BesperBot = {}; } // Assign directly to window for immediate availability window.bsp_init_b_espersite = bsp_init_b_espersite; window.bsp_manage_b_espersite = bsp_manage_b_espersite; window.b_esper_management_widget = b_esper_management_widget; window.bsp_demo_b_espersite = bsp_demo_b_espersite; window.init_demo = init_demo; window.b_esper_site_helper = b_esper_site_helper; window.b_esper_site = b_esper_site; window.b_esper_cleanup_page = b_esper_cleanup_page; window.b_esper_cleanup_all = b_esper_cleanup_all; window.b_esper_get_pages = b_esper_get_pages; window.b_esper_is_authenticated_page = b_esper_is_authenticated_page; // Notification and token management functions - requested by user window.get_notification_banner = get_notification_banner; // Ensure function is immediately available even before full initialization if (!window.get_notification_banner) { window.get_notification_banner = get_notification_banner; } // PowerPages integration utilities window.besperPageIntegration = initializePowerPagesIntegration; window.besperAutoPageIntegration = autoDetectPageIntegration; window.generateBesperTemplate = generatePowerPagesTemplate; // Initialize global function safety utilities immediately // This prevents "function is not defined" errors during page load timing issues try { // If early protection is already active, work with it if (window.__besperGlobalProtectionInitialized) { console.log( '[Index] 🛡️ Early protection detected, integrating with existing safety wrappers' ); // Replace safe wrappers with real functions where available setTimeout(() => { if ( window.besperAutoPageIntegration && window.besperAutoPageIntegration.__isSafeWrapper ) { console.log( '[Index] [LOADING] Upgrading besperAutoPageIntegration safe wrapper to real function' ); window.besperAutoPageIntegration = autoDetectPageIntegration; } // Set up pageOperatorsService properly if it only has safe wrappers if ( window.pageOperatorsService && window.pageOperatorsService.getSupportTickets && window.pageOperatorsService.getSupportTickets.__isSafeWrapper ) { console.log( '[Index] [LOADING] pageOperatorsService will be upgraded when real service loads' ); // The real pageOperatorsService will be loaded by other modules } }, 100); } else { // No early protection, initialize normally initializeSafeGlobals(); } console.log('[Index] 🛡️ Global function safety initialized'); } catch (error) { console.warn( '[Index] [WARN] Could not initialize global function safety:', error ); } window.BesperChatWidget = BesperChatWidget; window.BesperBotManagement = BesperBotManagement; window.BesperDemoInterface = BesperDemoInterface; window.BesperPageLoader = BesperPageLoader; window.CustomStylingManager = CustomStylingManager; window.TemplateLoaderService = TemplateLoaderService; window.NotificationBanner = NotificationBanner; // Also assign to the BesperSite namespace window.BesperSite = window.BesperSite || {}; Object.assign(window.BesperSite, { bsp_init_b_espersite, bsp_manage_b_espersite, b_esper_management_widget, bsp_demo_b_espersite, init_demo, b_esper_site_helper, b_esper_site, b_esper_cleanup_page, b_esper_cleanup_all, b_esper_get_pages, b_esper_is_authenticated_page, // Notification and token management functions get_notification_banner, // PowerPages integration utilities initializePowerPagesIntegration, generatePowerPagesTemplate, BesperChatWidget, BesperBotManagement, BesperDemoInterface, BesperPageLoader, CustomStylingManager, TemplateLoaderService, NotificationBanner, }); // Make a fallback assignment to ensure global availability setTimeout(() => { if (!window.bsp_init_b_espersite) { window.bsp_init_b_espersite = bsp_init_b_espersite; window.bsp_manage_b_espersite = bsp_manage_b_espersite; window.b_esper_management_widget = b_esper_management_widget; window.bsp_demo_b_espersite = bsp_demo_b_espersite; window.init_demo = init_demo; window.b_esper_site_helper = b_esper_site_helper; window.b_esper_site = b_esper_site; window.b_esper_cleanup_page = b_esper_cleanup_page; window.b_esper_cleanup_all = b_esper_cleanup_all; window.b_esper_get_pages = b_esper_get_pages; window.b_esper_is_authenticated_page = b_esper_is_authenticated_page; window.get_notification_banner = get_notification_banner; } // Ensure notification banner function is always available if (!window.get_notification_banner) { window.get_notification_banner = get_notification_banner; } }, 0); } // Export BSP Logger for PowerPages integration export { BSPLogger, initBspLogger, startBspLogger, } from './components/site/BspLogger.js'; // Auto-initialize BSP Logger if in development mode or if explicitly requested if (typeof window !== 'undefined') { // Auto-start logger on DOM ready when explicitly requested or for authenticated users const startBspLogger = () => { // Check if logger should be auto-started const explicitStart = window.location.search.includes('bsp_logger=true') || window.sessionStorage.getItem('bsp_logger_enabled') === 'true'; // Enhanced authentication detection - check multiple sources const isAuthenticated = cookieTokenManager.isAuthenticated(); const hasStoredAuth = localStorage.getItem('bsp_authenticated') === 'true'; // Check for PowerPages authentication indicators const hasPowerPagesUser = !!document.querySelector('[data-user-id]') || !!document.querySelector('#userId') || window.location.search.includes('userId=') || document.body.className.includes('authenticated'); // Check for any authentication cookies or session storage const hasAuthSession = sessionStorage.getItem('authToken') || sessionStorage.getItem('userToken') || sessionStorage.getItem('powerPagesToken') || document.cookie.includes('auth') || document.cookie.includes('user'); // Check for user-specific elements in the DOM (like user menus) const hasUserElements = !!document.querySelector('.user-menu') || !!document.querySelector('.profile-menu') || !!document.querySelector('[class*="user"]') || !!document.querySelector('#user'); const userAuthenticated = isAuthenticated || hasStoredAuth || hasPowerPagesUser || hasAuthSession || hasUserElements; // Auto-start for authenticated users or explicit requests const autoStart = explicitStart || userAuthenticated; console.log('[BSP Logger] Authentication check:', { isAuthenticated, hasStoredAuth, hasPowerPagesUser, hasAuthSession, hasUserElements, userAuthenticated, autoStart, }); if (autoStart) { import('./components/site/BspLogger.js') .then(({ startBspLogger }) => { const language = document.documentElement.lang || 'en'; window.bspLogger = startBspLogger(language, { debug: true }); console.log( '🔧 BSP Logger started', userAuthenticated ? '(authenticated user)' : '(explicit request)' ); }) .catch(error => { console.warn('Failed to auto-start BSP Logger:', error); }); } else { console.log( '🔧 BSP Logger available - add ?bsp_logger=true to URL or call window.startBspLogger() to enable' ); } }; // Start when DOM is ready - delay slightly to ensure tokenAuth is initialized if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { setTimeout(startBspLogger, 500); // Increased delay to ensure DOM is fully loaded }); } else { setTimeout(startBspLogger, 500); } // Also make available globally for manual start window.startBspLogger = () => { import('./components/site/BspLogger.js').then(({ startBspLogger }) => { const language = document.documentElement.lang || 'en'; window.bspLogger = startBspLogger(language, { debug: true }); console.log('🔧 BSP Logger manually started'); }); }; }