Files
customer-frontend/js/main.js
root b3224ed296 feat: BotKonzept Frontend erstellt
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
2026-01-28 22:31:54 +01:00

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
};
}