feat: Add complete BotKonzept SaaS platform
- Landing page with registration form (HTML/CSS/JS) - n8n workflows for customer registration and trial management - PostgreSQL schema for customer/instance/payment management - Automated email system (Day 3, 5, 7 with discounts) - Setup script and deployment checklist - Comprehensive documentation Features: - Automatic LXC instance creation per customer - 7-day trial with automated upgrade offers - Discount system: 30% → 15% → regular price - Supabase integration for customer management - Email automation via Postfix/SES - GDPR compliant (data in Germany) - Stripe/PayPal payment integration ready Components: - botkonzept-website/ - Landing page and registration - BotKonzept-Customer-Registration-Workflow.json - n8n registration workflow - BotKonzept-Trial-Management-Workflow.json - n8n trial management workflow - sql/botkonzept_schema.sql - Complete database schema - setup_botkonzept.sh - Automated setup script - BOTKONZEPT_README.md - Full documentation - DEPLOYMENT_CHECKLIST.md - Deployment guide
This commit is contained in:
@@ -0,0 +1,388 @@
|
||||
// BotKonzept Website - Main JavaScript
|
||||
// =====================================
|
||||
|
||||
// Configuration
|
||||
const CONFIG = {
|
||||
// n8n Webhook URL für Registrierung (wird später konfiguriert)
|
||||
WEBHOOK_URL: 'https://n8n.userman.de/webhook/botkonzept-registration',
|
||||
// Supabase URL (lokale Instanz)
|
||||
SUPABASE_URL: 'http://192.168.45.3:3000',
|
||||
SUPABASE_ANON_KEY: 'your-anon-key-here'
|
||||
};
|
||||
|
||||
// =====================================
|
||||
// Mobile Menu Toggle
|
||||
// =====================================
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
|
||||
const navMenu = document.querySelector('.nav-menu');
|
||||
|
||||
if (mobileMenuToggle) {
|
||||
mobileMenuToggle.addEventListener('click', function() {
|
||||
navMenu.classList.toggle('active');
|
||||
this.classList.toggle('active');
|
||||
});
|
||||
}
|
||||
|
||||
// Close mobile menu when clicking on a link
|
||||
const navLinks = document.querySelectorAll('.nav-menu a');
|
||||
navLinks.forEach(link => {
|
||||
link.addEventListener('click', function() {
|
||||
navMenu.classList.remove('active');
|
||||
mobileMenuToggle.classList.remove('active');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// Smooth Scroll for Anchor Links
|
||||
// =====================================
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
const offset = 80; // Navbar height
|
||||
const targetPosition = target.offsetTop - offset;
|
||||
window.scrollTo({
|
||||
top: targetPosition,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// Trial Registration Form
|
||||
// =====================================
|
||||
const trialForm = document.getElementById('trialForm');
|
||||
const successMessage = document.getElementById('successMessage');
|
||||
|
||||
if (trialForm) {
|
||||
trialForm.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Get form data
|
||||
const formData = {
|
||||
firstName: document.getElementById('firstName').value.trim(),
|
||||
lastName: document.getElementById('lastName').value.trim(),
|
||||
email: document.getElementById('email').value.trim().toLowerCase(),
|
||||
company: document.getElementById('company').value.trim() || null,
|
||||
terms: document.getElementById('terms').checked,
|
||||
registeredAt: new Date().toISOString(),
|
||||
source: 'website',
|
||||
utmSource: getUrlParameter('utm_source') || null,
|
||||
utmMedium: getUrlParameter('utm_medium') || null,
|
||||
utmCampaign: getUrlParameter('utm_campaign') || null
|
||||
};
|
||||
|
||||
// Validate
|
||||
if (!formData.firstName || !formData.lastName || !formData.email) {
|
||||
showError('Bitte füllen Sie alle Pflichtfelder aus.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateEmail(formData.email)) {
|
||||
showError('Bitte geben Sie eine gültige E-Mail-Adresse ein.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.terms) {
|
||||
showError('Bitte akzeptieren Sie die AGB und Datenschutzerklärung.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
const submitButton = trialForm.querySelector('button[type="submit"]');
|
||||
const btnText = submitButton.querySelector('.btn-text');
|
||||
const btnLoading = submitButton.querySelector('.btn-loading');
|
||||
|
||||
submitButton.disabled = true;
|
||||
btnText.style.display = 'none';
|
||||
btnLoading.style.display = 'flex';
|
||||
|
||||
try {
|
||||
// Send to n8n webhook
|
||||
const response = await fetch(CONFIG.WEBHOOK_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Registrierung fehlgeschlagen');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// Show success message
|
||||
trialForm.style.display = 'none';
|
||||
successMessage.style.display = 'block';
|
||||
|
||||
// Track conversion (Google Analytics, Facebook Pixel, etc.)
|
||||
trackConversion('trial_registration', formData);
|
||||
|
||||
// Scroll to success message
|
||||
successMessage.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Registration error:', error);
|
||||
showError('Ein Fehler ist aufgetreten. Bitte versuchen Sie es später erneut oder kontaktieren Sie uns direkt.');
|
||||
|
||||
// Reset button state
|
||||
submitButton.disabled = false;
|
||||
btnText.style.display = 'inline';
|
||||
btnLoading.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Helper Functions
|
||||
// =====================================
|
||||
|
||||
function validateEmail(email) {
|
||||
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
// Create or update error message
|
||||
let errorDiv = document.querySelector('.form-error');
|
||||
|
||||
if (!errorDiv) {
|
||||
errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'form-error';
|
||||
errorDiv.style.cssText = `
|
||||
background: #fee2e2;
|
||||
border: 1px solid #ef4444;
|
||||
color: #991b1b;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.95rem;
|
||||
`;
|
||||
trialForm.insertBefore(errorDiv, trialForm.firstChild);
|
||||
}
|
||||
|
||||
errorDiv.textContent = message;
|
||||
errorDiv.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
|
||||
// Remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
errorDiv.remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function getUrlParameter(name) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get(name);
|
||||
}
|
||||
|
||||
function trackConversion(eventName, data) {
|
||||
// Google Analytics
|
||||
if (typeof gtag !== 'undefined') {
|
||||
gtag('event', eventName, {
|
||||
'event_category': 'registration',
|
||||
'event_label': 'trial',
|
||||
'value': 0
|
||||
});
|
||||
}
|
||||
|
||||
// Facebook Pixel
|
||||
if (typeof fbq !== 'undefined') {
|
||||
fbq('track', 'Lead', {
|
||||
content_name: 'Trial Registration',
|
||||
content_category: 'Registration'
|
||||
});
|
||||
}
|
||||
|
||||
// Custom tracking
|
||||
console.log('Conversion tracked:', eventName, data);
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Scroll Animations
|
||||
// =====================================
|
||||
const observerOptions = {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('animate-in');
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
// Observe elements for animation
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const animateElements = document.querySelectorAll('.feature-card, .step, .pricing-card, .faq-item');
|
||||
animateElements.forEach(el => {
|
||||
el.style.opacity = '0';
|
||||
el.style.transform = 'translateY(20px)';
|
||||
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||
observer.observe(el);
|
||||
});
|
||||
});
|
||||
|
||||
// Add CSS for animation
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.animate-in {
|
||||
opacity: 1 !important;
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// =====================================
|
||||
// Pricing Calculator (Optional)
|
||||
// =====================================
|
||||
function calculatePricing(plan, discount = 0) {
|
||||
const prices = {
|
||||
trial: 0,
|
||||
starter: 49,
|
||||
business: 149
|
||||
};
|
||||
|
||||
const basePrice = prices[plan] || 0;
|
||||
const discountedPrice = basePrice * (1 - discount / 100);
|
||||
|
||||
return {
|
||||
basePrice,
|
||||
discount,
|
||||
discountedPrice,
|
||||
savings: basePrice - discountedPrice
|
||||
};
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// FAQ Accordion (Optional Enhancement)
|
||||
// =====================================
|
||||
document.querySelectorAll('.faq-item').forEach(item => {
|
||||
item.addEventListener('click', function() {
|
||||
this.classList.toggle('active');
|
||||
});
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// Newsletter Subscription (Optional)
|
||||
// =====================================
|
||||
function subscribeNewsletter(email) {
|
||||
// Integration mit Sendy.co
|
||||
const sendyUrl = 'https://sendy.userman.de/subscribe';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('email', email);
|
||||
formData.append('list', 'your-list-id');
|
||||
formData.append('boolean', 'true');
|
||||
|
||||
return fetch(sendyUrl, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Live Chat Widget Integration (Optional)
|
||||
// =====================================
|
||||
function initializeChatWidget() {
|
||||
// Hier kann später der eigene BotKonzept-Chatbot integriert werden
|
||||
console.log('Chat widget initialized');
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// A/B Testing Helper (Optional)
|
||||
// =====================================
|
||||
function getABTestVariant() {
|
||||
const variants = ['A', 'B'];
|
||||
const stored = localStorage.getItem('ab_variant');
|
||||
|
||||
if (stored) {
|
||||
return stored;
|
||||
}
|
||||
|
||||
const variant = variants[Math.floor(Math.random() * variants.length)];
|
||||
localStorage.setItem('ab_variant', variant);
|
||||
return variant;
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Cookie Consent (DSGVO)
|
||||
// =====================================
|
||||
function showCookieConsent() {
|
||||
const consent = localStorage.getItem('cookie_consent');
|
||||
|
||||
if (!consent) {
|
||||
const banner = document.createElement('div');
|
||||
banner.className = 'cookie-banner';
|
||||
banner.innerHTML = `
|
||||
<div class="cookie-content">
|
||||
<p>Wir verwenden Cookies, um Ihre Erfahrung zu verbessern.
|
||||
<a href="privacy.html">Mehr erfahren</a></p>
|
||||
<button onclick="acceptCookies()" class="btn-primary">Akzeptieren</button>
|
||||
</div>
|
||||
`;
|
||||
banner.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #1f2937;
|
||||
color: white;
|
||||
padding: 1.5rem;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 -4px 6px rgba(0,0,0,0.1);
|
||||
`;
|
||||
document.body.appendChild(banner);
|
||||
}
|
||||
}
|
||||
|
||||
function acceptCookies() {
|
||||
localStorage.setItem('cookie_consent', 'true');
|
||||
document.querySelector('.cookie-banner').remove();
|
||||
}
|
||||
|
||||
// Show cookie consent on page load
|
||||
document.addEventListener('DOMContentLoaded', showCookieConsent);
|
||||
|
||||
// =====================================
|
||||
// Performance Monitoring
|
||||
// =====================================
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
console.log('Performance:', entry.name, entry.duration);
|
||||
}
|
||||
});
|
||||
observer.observe({ entryTypes: ['measure', 'navigation'] });
|
||||
}
|
||||
|
||||
// =====================================
|
||||
// Error Tracking
|
||||
// =====================================
|
||||
window.addEventListener('error', function(e) {
|
||||
console.error('Global error:', e.error);
|
||||
// Hier könnte Sentry oder ähnliches integriert werden
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', function(e) {
|
||||
console.error('Unhandled promise rejection:', e.reason);
|
||||
});
|
||||
|
||||
// =====================================
|
||||
// Export for testing
|
||||
// =====================================
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
validateEmail,
|
||||
calculatePricing,
|
||||
getUrlParameter
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user