/** * EzSepa Bank Payment Landing Page - Main JavaScript * Handles mobile navigation, smooth scrolling, and analytics */ import { initHeroScene } from './hero-scene.js'; // Mobile menu toggle const initMobileMenu = () => { const menuButton = document.getElementById('mobile-menu-button'); const mobileMenu = document.getElementById('mobile-menu'); const menuOpenIcon = menuButton?.querySelector('.menu-open'); const menuCloseIcon = menuButton?.querySelector('.menu-close'); if (!menuButton || !mobileMenu) return; menuButton.addEventListener('click', () => { const isExpanded = menuButton.getAttribute('aria-expanded') === 'true'; // Toggle menu visibility mobileMenu.classList.toggle('hidden'); // Toggle icons menuOpenIcon?.classList.toggle('hidden'); menuCloseIcon?.classList.toggle('hidden'); // Update aria-expanded menuButton.setAttribute('aria-expanded', !isExpanded); }); // Close mobile menu when clicking on a link const mobileMenuLinks = mobileMenu.querySelectorAll('a'); mobileMenuLinks.forEach(link => { link.addEventListener('click', () => { mobileMenu.classList.add('hidden'); menuOpenIcon?.classList.remove('hidden'); menuCloseIcon?.classList.add('hidden'); menuButton.setAttribute('aria-expanded', 'false'); }); }); // Close mobile menu when clicking outside document.addEventListener('click', (event) => { const isClickInsideMenu = mobileMenu.contains(event.target); const isClickOnButton = menuButton.contains(event.target); if (!isClickInsideMenu && !isClickOnButton && !mobileMenu.classList.contains('hidden')) { mobileMenu.classList.add('hidden'); menuOpenIcon?.classList.remove('hidden'); menuCloseIcon?.classList.add('hidden'); menuButton.setAttribute('aria-expanded', 'false'); } }); }; // Smooth scroll for anchor links const initSmoothScroll = () => { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { const href = this.getAttribute('href'); // Skip if href is just "#" if (href === '#') return; const targetId = href.substring(1); const targetElement = document.getElementById(targetId); if (targetElement) { e.preventDefault(); // Calculate offset for fixed header const headerOffset = 80; const elementPosition = targetElement.getBoundingClientRect().top; const offsetPosition = elementPosition + window.pageYOffset - headerOffset; window.scrollTo({ top: offsetPosition, behavior: 'smooth' }); } }); }); }; // Add shadow to nav on scroll const initNavShadow = () => { const nav = document.querySelector('nav'); if (!nav) return; const handleScroll = () => { if (window.scrollY > 10) { nav.classList.add('shadow-md'); } else { nav.classList.remove('shadow-md'); } }; window.addEventListener('scroll', handleScroll); handleScroll(); // Initial check }; // Animate elements on scroll (Intersection Observer) const initScrollAnimations = () => { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -100px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate-fade-in-up'); observer.unobserve(entry.target); } }); }, observerOptions); // Observe feature cards, pricing cards, etc. const animatedElements = document.querySelectorAll('.card, .grid > div'); animatedElements.forEach(el => observer.observe(el)); }; // Analytics stub - replace with your actual analytics implementation const initAnalytics = () => { // Placeholder for analytics tracking window._ezsepa = window._ezsepa || { track: (eventName, properties = {}) => { console.log('📊 Analytics Event:', eventName, properties); // Replace this with your actual analytics provider // Examples: // - Google Analytics: gtag('event', eventName, properties); // - Mixpanel: mixpanel.track(eventName, properties); // - Segment: analytics.track(eventName, properties); // - Plausible: plausible(eventName, { props: properties }); } }; // Track page view window._ezsepa.track('Page View', { page: window.location.pathname, referrer: document.referrer, timestamp: new Date().toISOString() }); // Track CTA clicks const ctaButtons = document.querySelectorAll('a[href*="{INSTALL_LINK}"]'); ctaButtons.forEach(button => { button.addEventListener('click', () => { window._ezsepa.track('CTA Clicked', { location: button.closest('section')?.id || 'unknown', text: button.textContent.trim(), url: button.href }); }); }); // Track demo link clicks const demoLinks = document.querySelectorAll('a[href*="{DEMO_LINK}"]'); demoLinks.forEach(link => { link.addEventListener('click', () => { window._ezsepa.track('Demo Link Clicked', { location: link.closest('section')?.id || 'unknown', text: link.textContent.trim() }); }); }); // Track section visibility const sections = document.querySelectorAll('section[id]'); const sectionObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { window._ezsepa.track('Section Viewed', { section: entry.target.id }); } }); }, { threshold: 0.5 }); sections.forEach(section => sectionObserver.observe(section)); }; // Performance monitoring const initPerformanceMonitoring = () => { if ('PerformanceObserver' in window) { // Largest Contentful Paint (LCP) const lcpObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); const lastEntry = entries[entries.length - 1]; console.log('⚡ LCP:', lastEntry.renderTime || lastEntry.loadTime); }); lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] }); // First Input Delay (FID) const fidObserver = new PerformanceObserver((list) => { list.getEntries().forEach((entry) => { console.log('⚡ FID:', entry.processingStart - entry.startTime); }); }); fidObserver.observe({ entryTypes: ['first-input'] }); // Cumulative Layout Shift (CLS) let clsValue = 0; const clsObserver = new PerformanceObserver((list) => { list.getEntries().forEach((entry) => { if (!entry.hadRecentInput) { clsValue += entry.value; console.log('⚡ CLS:', clsValue); } }); }); clsObserver.observe({ entryTypes: ['layout-shift'] }); } }; // Handle external links (open in new tab with security) const initExternalLinks = () => { const externalLinks = document.querySelectorAll('a[href^="http"]'); externalLinks.forEach(link => { const url = new URL(link.href); if (url.hostname !== window.location.hostname) { link.setAttribute('target', '_blank'); link.setAttribute('rel', 'noopener noreferrer'); } }); }; // Keyboard navigation improvements const initKeyboardNav = () => { // Add visible focus indicators for keyboard users let isUsingMouse = false; document.addEventListener('mousedown', () => { isUsingMouse = true; }); document.addEventListener('keydown', (e) => { if (e.key === 'Tab') { isUsingMouse = false; } }); document.addEventListener('focusin', () => { if (!isUsingMouse) { document.body.classList.add('using-keyboard'); } }); document.addEventListener('focusout', () => { document.body.classList.remove('using-keyboard'); }); }; // Initialize all features when DOM is ready const init = () => { initMobileMenu(); initSmoothScroll(); initNavShadow(); initScrollAnimations(); initAnalytics(); initPerformanceMonitoring(); initExternalLinks(); initKeyboardNav(); console.log('✅ EzSepa landing page initialized'); }; // Run initialization if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // Export for potential use in other scripts export { initMobileMenu, initSmoothScroll, initAnalytics };