// Initialize everything when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Initialize AOS (Animate On Scroll)
if (typeof AOS !== 'undefined') {
AOS.init({
duration: 800,
easing: 'ease-out-cubic',
once: true,
offset: 100,
delay: 200
});
}
// Initialize all features
initNavigation();
initAnimatedCounters();
initScrollEffects();
initFormHandling();
initMobileMenu();
// Start counter animations after a short delay
setTimeout(animateCounters, 1000);
});
// Navigation scroll effects
function initNavigation() {
const navbar = document.getElementById('navbar');
const fixedCta = document.getElementById('fixedCta');
let lastScrollTop = 0;
window.addEventListener('scroll', function() {
const currentScroll = window.pageYOffset || document.documentElement.scrollTop;
// Navbar scroll effects
if (currentScroll > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
// Show/hide fixed CTA based on scroll position
if (currentScroll > window.innerHeight && currentScroll > lastScrollTop) {
// Scrolling down and past hero section
if (fixedCta) {
fixedCta.classList.add('show');
}
} else if (currentScroll < window.innerHeight / 2) {
// Near top of page
if (fixedCta) {
fixedCta.classList.remove('show');
}
}
lastScrollTop = currentScroll <= 0 ? 0 : currentScroll;
});
}
// Mobile menu functionality
function initMobileMenu() {
const hamburger = document.getElementById('hamburger');
const navMenu = document.querySelector('.nav-menu');
if (hamburger && navMenu) {
hamburger.addEventListener('click', function() {
hamburger.classList.toggle('active');
navMenu.classList.toggle('active');
document.body.classList.toggle('menu-open');
});
// Close menu when clicking nav links
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('click', function() {
hamburger.classList.remove('active');
navMenu.classList.remove('active');
document.body.classList.remove('menu-open');
});
});
// Close menu when clicking outside
document.addEventListener('click', function(e) {
if (!hamburger.contains(e.target) && !navMenu.contains(e.target)) {
hamburger.classList.remove('active');
navMenu.classList.remove('active');
document.body.classList.remove('menu-open');
}
});
}
}
// Animated counter functionality
function initAnimatedCounters() {
const counters = document.querySelectorAll('.stat-number');
const observerOptions = {
threshold: 0.5,
rootMargin: '0px 0px -100px 0px'
};
const counterObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !entry.target.classList.contains('counted')) {
entry.target.classList.add('counted');
animateCounter(entry.target);
}
});
}, observerOptions);
counters.forEach(counter => {
counterObserver.observe(counter);
});
}
function animateCounter(element) {
const target = parseInt(element.getAttribute('data-target'));
const duration = 2000; // 2 seconds
const increment = target / (duration / 16); // 60fps
let current = 0;
const timer = setInterval(() => {
current += increment;
if (current >= target) {
current = target;
clearInterval(timer);
}
// Format number with appropriate suffix
let displayValue = Math.floor(current);
if (target >= 1000) {
displayValue = Math.floor(current / 1000) + 'K';
}
element.textContent = displayValue;
}, 16);
}
// Call this function directly for immediate animation
function animateCounters() {
const counters = document.querySelectorAll('.stat-number');
counters.forEach(counter => {
if (!counter.classList.contains('counted')) {
counter.classList.add('counted');
animateCounter(counter);
}
});
}
// Scroll effects and animations
function initScrollEffects() {
// Smooth scroll for internal links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
const offsetTop = target.offsetTop - 80; // Account for fixed navbar
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}
});
});
// Parallax effect for hero background
const heroBackground = document.querySelector('.hero-background');
if (heroBackground) {
window.addEventListener('scroll', function() {
const scrolled = window.pageYOffset;
const parallax = scrolled * 0.5;
heroBackground.style.transform = `translateY(${parallax}px)`;
});
}
// Add scroll-triggered animations
const animatedElements = document.querySelectorAll('[data-aos]');
const scrollObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('aos-animate');
}
});
}, {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
});
animatedElements.forEach(el => {
scrollObserver.observe(el);
});
}
// Form handling
function initFormHandling() {
const consultationForm = document.getElementById('consultationForm');
if (consultationForm) {
consultationForm.addEventListener('submit', function(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this);
const formObject = {};
// Convert FormData to object
for (let [key, value] of formData.entries()) {
if (formObject[key]) {
// Handle multiple values (like checkboxes)
if (Array.isArray(formObject[key])) {
formObject[key].push(value);
} else {
formObject[key] = [formObject[key], value];
}
} else {
formObject[key] = value;
}
}
// Validate required fields
if (validateForm(formObject)) {
// Show loading state
const submitBtn = this.querySelector('.btn-submit');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = 'Processing...';
submitBtn.disabled = true;
// Simulate form submission (replace with actual submission logic)
setTimeout(() => {
// Success message
showFormMessage('success', 'Thank you! Your consultation request has been submitted. We\'ll contact you within 24 hours.');
// Reset form
consultationForm.reset();
// Reset button
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
// Optional: redirect or track conversion
if (typeof gtag !== 'undefined') {
gtag('event', 'form_submit', {
event_category: 'engagement',
event_label: 'consultation_form'
});
}
}, 2000);
}
});
// Real-time form validation
const inputs = consultationForm.querySelectorAll('input, select');
inputs.forEach(input => {
input.addEventListener('blur', function() {
validateField(this);
});
input.addEventListener('input', function() {
clearFieldError(this);
});
});
// Phone number formatting
const phoneInput = document.getElementById('phone');
if (phoneInput) {
phoneInput.addEventListener('input', function(e) {
let value = e.target.value.replace(/\D/g, '');
// Add Nigerian country code if not present
if (value.length > 0 && !value.startsWith('234')) {
if (value.startsWith('0')) {
value = '234' + value.substring(1);
} else if (value.length === 10) {
value = '234' + value;
}
}
// Format number
if (value.length >= 3) {
value = '+' + value.substring(0, 3) + ' ' + value.substring(3);
}
e.target.value = value;
});
}
}
}
// Form validation functions
function validateForm(formData) {
let isValid = true;
const requiredFields = ['firmName', 'contactName', 'position', 'phone', 'location', 'email'];
requiredFields.forEach(field => {
const input = document.getElementById(field);
if (!formData[field] || formData[field].trim() === '') {
showFieldError(input, 'This field is required');
isValid = false;
}
});
// Email validation
const emailInput = document.getElementById('email');
if (formData.email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
showFieldError(emailInput, 'Please enter a valid email address');
isValid = false;
}
}
// Phone validation (Nigerian numbers)
const phoneInput = document.getElementById('phone');
if (formData.phone) {
const phoneRegex = /^\+?234[0-9]{10}$/;
const cleanPhone = formData.phone.replace(/\s/g, '');
if (!phoneRegex.test(cleanPhone)) {
showFieldError(phoneInput, 'Please enter a valid Nigerian phone number');
isValid = false;
}
}
return isValid;
}
function validateField(input) {
const value = input.value.trim();
if (input.hasAttribute('required') && !value) {
showFieldError(input, 'This field is required');
return false;
}
if (input.type === 'email' && value) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
showFieldError(input, 'Please enter a valid email address');
return false;
}
}
if (input.type === 'tel' && value) {
const phoneRegex = /^\+?234[0-9]{10}$/;
const cleanPhone = value.replace(/\s/g, '');
if (!phoneRegex.test(cleanPhone)) {
showFieldError(input, 'Please enter a valid Nigerian phone number');
return false;
}
}
clearFieldError(input);
return true;
}
function showFieldError(input, message) {
clearFieldError(input);
const errorDiv = document.createElement('div');
errorDiv.className = 'field-error';
errorDiv.style.color = '#E53E3E';
errorDiv.style.fontSize = '0.875rem';
errorDiv.style.marginTop = '0.25rem';
errorDiv.textContent = message;
input.style.borderColor = '#E53E3E';
input.parentNode.appendChild(errorDiv);
}
function clearFieldError(input) {
const existingError = input.parentNode.querySelector('.field-error');
if (existingError) {
existingError.remove();
}
input.style.borderColor = '#e2e8f0';
}
function showFormMessage(type, message) {
// Remove existing messages
const existingMessages = document.querySelectorAll('.form-message');
existingMessages.forEach(msg => msg.remove());
const messageDiv = document.createElement('div');
messageDiv.className = `form-message ${type}`;
messageDiv.style.padding = '1rem';
messageDiv.style.marginBottom = '1rem';
messageDiv.style.borderRadius = '8px';
messageDiv.style.textAlign = 'center';
messageDiv.style.fontWeight = '600';
if (type === 'success') {
messageDiv.style.backgroundColor = '#F0FFF4';
messageDiv.style.color = '#2F855A';
messageDiv.style.border = '1px solid #9AE6B4';
} else {
messageDiv.style.backgroundColor = '#FED7D7';
messageDiv.style.color = '#C53030';
messageDiv.style.border = '1px solid #FCA5A5';
}
messageDiv.textContent = message;
const form = document.getElementById('consultationForm');
form.insertBefore(messageDiv, form.firstChild);
// Auto-remove after 5 seconds
setTimeout(() => {
messageDiv.remove();
}, 5000);
}
// Package selection functionality
function selectPackage(packageName) {
const preferredPackageSelect = document.getElementById('preferredPackage');
if (preferredPackageSelect) {
preferredPackageSelect.value = packageName;
}
// Scroll to contact form
scrollToSection('contact');
// Highlight the form briefly
const form = document.getElementById('consultationForm');
if (form) {
form.style.boxShadow = '0 0 20px rgba(45, 105, 255, 0.3)';
setTimeout(() => {
form.style.boxShadow = '';
}, 2000);
}
}
// Utility function for smooth scrolling
function scrollToSection(sectionId) {
const element = document.getElementById(sectionId);
if (element) {
const offsetTop = element.offsetTop - 80; // Account for fixed navbar
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}
}
// Business hours detection (West Africa Time)
function checkBusinessHours() {
const now = new Date();
const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
const wat = new Date(utc + (1 * 3600000)); // WAT is UTC+1
const hour = wat.getHours();
const day = wat.getDay(); // 0 = Sunday, 6 = Saturday
// Business hours: Monday-Friday, 9 AM - 6 PM WAT
const isBusinessHours = (day >= 1 && day <= 5) && (hour >= 9 && hour < 18);
// Update urgency timer if outside business hours
const urgencyTimer = document.querySelector('.urgency-timer span');
if (urgencyTimer && !isBusinessHours) {
if (day === 0 || day === 6) {
urgencyTimer.textContent = 'We\'ll respond on Monday!';
} else if (hour < 9) {
urgencyTimer.textContent = 'We\'ll respond when office opens!';
} else {
urgencyTimer.textContent = 'We\'ll respond tomorrow!';
}
}
}
// Performance optimizations
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Optimize scroll events
const debouncedScroll = debounce(() => {
// Any heavy scroll operations can go here
}, 16); // ~60fps
window.addEventListener('scroll', debouncedScroll);
// Lazy loading for images (if needed)
function initLazyLoading() {
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
}
// Error handling for external dependencies
window.addEventListener('error', function(e) {
console.warn('Script error:', e.message);
// Fallback for AOS if it fails to load
if (e.message.includes('AOS')) {
console.log('AOS failed to load, using fallback animations');
// Add basic CSS animations as fallback
document.querySelectorAll('[data-aos]').forEach(el => {
el.style.opacity = '1';
el.style.transform = 'none';
});
}
});
// Initialize business hours check
document.addEventListener('DOMContentLoaded', checkBusinessHours);
// Refresh business hours status every hour
setInterval(checkBusinessHours, 3600000);
// Export functions for global access
window.scrollToSection = scrollToSection;
window.selectPackage = selectPackage;
window.animateCounters = animateCounters;