Neue Dateien: - index.html: Landing Page mit Registrierung - dashboard.html: Kunden-Dashboard - css/style.css: Haupt-Stylesheet (1500+ Zeilen) - css/dashboard.css: Dashboard-Styles (800+ Zeilen) - js/main.js: Landing Page JavaScript - js/dashboard.js: Dashboard JavaScript - logo/20250119_Logo_Botkozept.svg: Logo Features: - Modernes, responsives Design - Hero-Section mit Chat-Preview Animation - Feature-Übersicht und Pricing-Tabelle - Registrierungsformular mit Validierung - FAQ-Akkordeon - Dashboard mit PDF-Upload (Drag & Drop) - Chatbot-Test-Interface - Embed-Code Generator - Trial-Status und Upgrade-Banner - Mobile-optimiert
469 lines
14 KiB
JavaScript
469 lines
14 KiB
JavaScript
/**
|
|
* BotKonzept - Main JavaScript
|
|
* ============================
|
|
* Handles all interactive functionality for the BotKonzept website
|
|
*/
|
|
|
|
// Configuration
|
|
const CONFIG = {
|
|
// API Endpoints - Update these for production
|
|
WEBHOOK_URL: 'https://n8n.userman.de/webhook/botkonzept-registration',
|
|
API_BASE_URL: 'https://api.botkonzept.de',
|
|
|
|
// Validation
|
|
MIN_NAME_LENGTH: 2,
|
|
MAX_NAME_LENGTH: 50,
|
|
|
|
// Animation
|
|
SCROLL_OFFSET: 100,
|
|
ANIMATION_DELAY: 100,
|
|
};
|
|
|
|
// ============================================
|
|
// DOM Ready
|
|
// ============================================
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initNavigation();
|
|
initMobileMenu();
|
|
initSmoothScroll();
|
|
initFAQ();
|
|
initRegistrationForm();
|
|
initScrollAnimations();
|
|
initTypingAnimation();
|
|
});
|
|
|
|
// ============================================
|
|
// Navigation
|
|
// ============================================
|
|
function initNavigation() {
|
|
const navbar = document.getElementById('navbar');
|
|
let lastScroll = 0;
|
|
|
|
window.addEventListener('scroll', () => {
|
|
const currentScroll = window.pageYOffset;
|
|
|
|
// Add shadow on scroll
|
|
if (currentScroll > 50) {
|
|
navbar.style.boxShadow = '0 4px 6px -1px rgb(0 0 0 / 0.1)';
|
|
} else {
|
|
navbar.style.boxShadow = 'none';
|
|
}
|
|
|
|
// Hide/show navbar on scroll (optional)
|
|
// if (currentScroll > lastScroll && currentScroll > 200) {
|
|
// navbar.style.transform = 'translateY(-100%)';
|
|
// } else {
|
|
// navbar.style.transform = 'translateY(0)';
|
|
// }
|
|
|
|
lastScroll = currentScroll;
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// Mobile Menu
|
|
// ============================================
|
|
function initMobileMenu() {
|
|
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
|
|
const navLinks = document.getElementById('navLinks');
|
|
|
|
if (!mobileMenuBtn || !navLinks) return;
|
|
|
|
mobileMenuBtn.addEventListener('click', () => {
|
|
navLinks.classList.toggle('active');
|
|
|
|
// Toggle icon
|
|
const icon = mobileMenuBtn.querySelector('i');
|
|
if (navLinks.classList.contains('active')) {
|
|
icon.classList.remove('fa-bars');
|
|
icon.classList.add('fa-times');
|
|
} else {
|
|
icon.classList.remove('fa-times');
|
|
icon.classList.add('fa-bars');
|
|
}
|
|
});
|
|
|
|
// Close menu when clicking a link
|
|
navLinks.querySelectorAll('a').forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
navLinks.classList.remove('active');
|
|
const icon = mobileMenuBtn.querySelector('i');
|
|
icon.classList.remove('fa-times');
|
|
icon.classList.add('fa-bars');
|
|
});
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// Smooth Scroll
|
|
// ============================================
|
|
function initSmoothScroll() {
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const targetId = this.getAttribute('href');
|
|
|
|
if (targetId === '#') return;
|
|
|
|
const targetElement = document.querySelector(targetId);
|
|
if (targetElement) {
|
|
const navbarHeight = document.getElementById('navbar').offsetHeight;
|
|
const targetPosition = targetElement.offsetTop - navbarHeight - 20;
|
|
|
|
window.scrollTo({
|
|
top: targetPosition,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// FAQ Accordion
|
|
// ============================================
|
|
function initFAQ() {
|
|
const faqItems = document.querySelectorAll('.faq-item');
|
|
|
|
faqItems.forEach(item => {
|
|
const question = item.querySelector('.faq-question');
|
|
|
|
question.addEventListener('click', () => {
|
|
// Close other items
|
|
faqItems.forEach(otherItem => {
|
|
if (otherItem !== item && otherItem.classList.contains('active')) {
|
|
otherItem.classList.remove('active');
|
|
}
|
|
});
|
|
|
|
// Toggle current item
|
|
item.classList.toggle('active');
|
|
});
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// Registration Form
|
|
// ============================================
|
|
function initRegistrationForm() {
|
|
const form = document.getElementById('registerForm');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const formSuccess = document.getElementById('formSuccess');
|
|
const formError = document.getElementById('formError');
|
|
|
|
if (!form) return;
|
|
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
// Validate form
|
|
if (!validateForm(form)) {
|
|
return;
|
|
}
|
|
|
|
// Show loading state
|
|
setLoadingState(submitBtn, true);
|
|
|
|
// Collect form data
|
|
const formData = {
|
|
firstName: form.firstName.value.trim(),
|
|
lastName: form.lastName.value.trim(),
|
|
email: form.email.value.trim(),
|
|
company: form.company.value.trim() || null,
|
|
website: form.website.value.trim() || null,
|
|
newsletter: form.newsletter.checked,
|
|
timestamp: new Date().toISOString(),
|
|
source: 'website',
|
|
userAgent: navigator.userAgent,
|
|
language: navigator.language,
|
|
};
|
|
|
|
try {
|
|
// Send registration request
|
|
const response = await fetch(CONFIG.WEBHOOK_URL, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
// Show success message
|
|
form.style.display = 'none';
|
|
formSuccess.style.display = 'block';
|
|
|
|
// Track conversion (if analytics is set up)
|
|
trackConversion('registration_complete', formData);
|
|
|
|
} catch (error) {
|
|
console.error('Registration error:', error);
|
|
|
|
// Show error message
|
|
form.style.display = 'none';
|
|
formError.style.display = 'block';
|
|
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
if (errorMessage) {
|
|
errorMessage.textContent = getErrorMessage(error);
|
|
}
|
|
} finally {
|
|
setLoadingState(submitBtn, false);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Form validation
|
|
function validateForm(form) {
|
|
let isValid = true;
|
|
|
|
// Clear previous errors
|
|
form.querySelectorAll('.error').forEach(el => el.classList.remove('error'));
|
|
form.querySelectorAll('.error-message').forEach(el => el.remove());
|
|
|
|
// Validate first name
|
|
const firstName = form.firstName.value.trim();
|
|
if (firstName.length < CONFIG.MIN_NAME_LENGTH) {
|
|
showFieldError(form.firstName, 'Bitte geben Sie Ihren Vornamen ein');
|
|
isValid = false;
|
|
}
|
|
|
|
// Validate last name
|
|
const lastName = form.lastName.value.trim();
|
|
if (lastName.length < CONFIG.MIN_NAME_LENGTH) {
|
|
showFieldError(form.lastName, 'Bitte geben Sie Ihren Nachnamen ein');
|
|
isValid = false;
|
|
}
|
|
|
|
// Validate email
|
|
const email = form.email.value.trim();
|
|
if (!isValidEmail(email)) {
|
|
showFieldError(form.email, 'Bitte geben Sie eine gültige E-Mail-Adresse ein');
|
|
isValid = false;
|
|
}
|
|
|
|
// Validate website (if provided)
|
|
const website = form.website.value.trim();
|
|
if (website && !isValidURL(website)) {
|
|
showFieldError(form.website, 'Bitte geben Sie eine gültige URL ein (z.B. https://beispiel.de)');
|
|
isValid = false;
|
|
}
|
|
|
|
// Validate privacy checkbox
|
|
if (!form.privacy.checked) {
|
|
showFieldError(form.privacy, 'Bitte akzeptieren Sie die Datenschutzerklärung');
|
|
isValid = false;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
// Show field error
|
|
function showFieldError(field, message) {
|
|
field.classList.add('error');
|
|
field.style.borderColor = '#ef4444';
|
|
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'error-message';
|
|
errorDiv.style.color = '#ef4444';
|
|
errorDiv.style.fontSize = '0.75rem';
|
|
errorDiv.style.marginTop = '4px';
|
|
errorDiv.textContent = message;
|
|
|
|
field.parentNode.appendChild(errorDiv);
|
|
}
|
|
|
|
// Email validation
|
|
function isValidEmail(email) {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
}
|
|
|
|
// URL validation
|
|
function isValidURL(url) {
|
|
try {
|
|
new URL(url);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Set loading state
|
|
function setLoadingState(button, isLoading) {
|
|
const btnText = button.querySelector('.btn-text');
|
|
const btnLoading = button.querySelector('.btn-loading');
|
|
|
|
if (isLoading) {
|
|
button.disabled = true;
|
|
if (btnText) btnText.style.display = 'none';
|
|
if (btnLoading) btnLoading.style.display = 'inline-flex';
|
|
} else {
|
|
button.disabled = false;
|
|
if (btnText) btnText.style.display = 'inline';
|
|
if (btnLoading) btnLoading.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// Get user-friendly error message
|
|
function getErrorMessage(error) {
|
|
if (error.message.includes('Failed to fetch')) {
|
|
return 'Verbindungsfehler. Bitte überprüfen Sie Ihre Internetverbindung.';
|
|
}
|
|
if (error.message.includes('500')) {
|
|
return 'Serverfehler. Bitte versuchen Sie es später erneut.';
|
|
}
|
|
if (error.message.includes('400')) {
|
|
return 'Ungültige Eingabe. Bitte überprüfen Sie Ihre Daten.';
|
|
}
|
|
return 'Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.';
|
|
}
|
|
|
|
// Reset form
|
|
function resetForm() {
|
|
const form = document.getElementById('registerForm');
|
|
const formSuccess = document.getElementById('formSuccess');
|
|
const formError = document.getElementById('formError');
|
|
|
|
if (form) {
|
|
form.reset();
|
|
form.style.display = 'flex';
|
|
}
|
|
if (formSuccess) formSuccess.style.display = 'none';
|
|
if (formError) formError.style.display = 'none';
|
|
}
|
|
|
|
// Make resetForm available globally
|
|
window.resetForm = resetForm;
|
|
|
|
// ============================================
|
|
// Scroll Animations
|
|
// ============================================
|
|
function initScrollAnimations() {
|
|
const animatedElements = document.querySelectorAll('.feature-card, .step, .pricing-card, .faq-item');
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry, index) => {
|
|
if (entry.isIntersecting) {
|
|
setTimeout(() => {
|
|
entry.target.classList.add('visible');
|
|
entry.target.style.opacity = '1';
|
|
entry.target.style.transform = 'translateY(0)';
|
|
}, index * CONFIG.ANIMATION_DELAY);
|
|
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
});
|
|
|
|
animatedElements.forEach(el => {
|
|
el.style.opacity = '0';
|
|
el.style.transform = 'translateY(20px)';
|
|
el.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
|
|
observer.observe(el);
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// Typing Animation (Chat Preview)
|
|
// ============================================
|
|
function initTypingAnimation() {
|
|
const typingMessage = document.querySelector('.message.typing');
|
|
if (!typingMessage) return;
|
|
|
|
// Simulate typing response
|
|
setTimeout(() => {
|
|
typingMessage.innerHTML = '<p>Sie können Ihre Bestellung ganz einfach über unser Online-Formular aufgeben. Alternativ können Sie uns auch telefonisch unter 0800-123456 erreichen.</p>';
|
|
typingMessage.classList.remove('typing');
|
|
}, 3000);
|
|
}
|
|
|
|
// ============================================
|
|
// Analytics & Tracking
|
|
// ============================================
|
|
function trackConversion(eventName, data = {}) {
|
|
// Google Analytics 4
|
|
if (typeof gtag !== 'undefined') {
|
|
gtag('event', eventName, {
|
|
'event_category': 'conversion',
|
|
'event_label': 'registration',
|
|
...data
|
|
});
|
|
}
|
|
|
|
// Facebook Pixel
|
|
if (typeof fbq !== 'undefined') {
|
|
fbq('track', 'Lead', data);
|
|
}
|
|
|
|
// Console log for debugging
|
|
console.log('Conversion tracked:', eventName, data);
|
|
}
|
|
|
|
// ============================================
|
|
// Utility Functions
|
|
// ============================================
|
|
|
|
// Debounce function
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// Throttle function
|
|
function throttle(func, limit) {
|
|
let inThrottle;
|
|
return function(...args) {
|
|
if (!inThrottle) {
|
|
func.apply(this, args);
|
|
inThrottle = true;
|
|
setTimeout(() => inThrottle = false, limit);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Format currency
|
|
function formatCurrency(amount, currency = 'EUR') {
|
|
return new Intl.NumberFormat('de-DE', {
|
|
style: 'currency',
|
|
currency: currency
|
|
}).format(amount);
|
|
}
|
|
|
|
// Format date
|
|
function formatDate(date) {
|
|
return new Intl.DateTimeFormat('de-DE', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
}).format(new Date(date));
|
|
}
|
|
|
|
// ============================================
|
|
// Export for testing
|
|
// ============================================
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = {
|
|
validateForm,
|
|
isValidEmail,
|
|
isValidURL,
|
|
formatCurrency,
|
|
formatDate
|
|
};
|
|
}
|