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
JavaScript
// 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');
});
};
}