/** * BotKonzept Dashboard JavaScript * ================================ * Handles all dashboard functionality */ // Configuration const DASHBOARD_CONFIG = { // API Endpoints - Update for production API_BASE_URL: 'https://api.botkonzept.de', CHAT_WEBHOOK_URL: '', // Will be set from customer data UPLOAD_URL: '', // Will be set from customer data // Customer data (loaded from localStorage or API) customerId: null, customerData: null, // Trial settings trialDays: 7, discountDay3: 0.30, // 30% discount discountDay5: 0.15, // 15% discount }; // ============================================ // DOM Ready // ============================================ document.addEventListener('DOMContentLoaded', () => { initDashboard(); initNavigation(); initUserMenu(); initFileUpload(); initChatbot(); initSectionNavigation(); loadCustomerData(); updateTrialStatus(); }); // ============================================ // Dashboard Initialization // ============================================ function initDashboard() { // Check if user is logged in (for demo, we'll simulate this) const isLoggedIn = localStorage.getItem('botkonzept_session') || true; // Demo mode if (!isLoggedIn) { window.location.href = 'index.html'; return; } // Load customer data from localStorage or use demo data const storedData = localStorage.getItem('botkonzept_customer'); if (storedData) { DASHBOARD_CONFIG.customerData = JSON.parse(storedData); } else { // Demo data DASHBOARD_CONFIG.customerData = { id: 'demo-' + Date.now(), firstName: 'Max', lastName: 'Mustermann', email: 'max@beispiel.de', company: 'Muster GmbH', trialStartDate: new Date().toISOString(), instanceUrl: 'https://sb-demo.userman.de', chatWebhook: 'https://sb-demo.userman.de/webhook/rag-chat-webhook/chat', uploadUrl: 'https://sb-demo.userman.de/form/rag-upload-form', }; } // Update UI with customer data updateCustomerUI(); } // ============================================ // Navigation // ============================================ function initNavigation() { // Sidebar navigation const navItems = document.querySelectorAll('.sidebar-nav .nav-item'); const sections = document.querySelectorAll('.dashboard-section'); navItems.forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); const sectionId = item.getAttribute('data-section'); // Update active states navItems.forEach(nav => nav.classList.remove('active')); item.classList.add('active'); // Show corresponding section sections.forEach(section => { section.classList.remove('active'); if (section.id === sectionId) { section.classList.add('active'); } }); // Update URL hash window.location.hash = sectionId; }); }); // Handle initial hash const hash = window.location.hash.slice(1); if (hash) { const targetNav = document.querySelector(`[data-section="${hash}"]`); if (targetNav) { targetNav.click(); } } } function initSectionNavigation() { // Quick action cards const actionCards = document.querySelectorAll('.action-card'); actionCards.forEach(card => { card.addEventListener('click', (e) => { e.preventDefault(); const sectionId = card.getAttribute('data-section'); const targetNav = document.querySelector(`[data-section="${sectionId}"]`); if (targetNav) { targetNav.click(); } }); }); } // ============================================ // User Menu // ============================================ function initUserMenu() { const userBtn = document.getElementById('userMenuBtn'); const userDropdown = document.getElementById('userDropdown'); if (!userBtn || !userDropdown) return; userBtn.addEventListener('click', () => { userDropdown.classList.toggle('active'); }); // Close on outside click document.addEventListener('click', (e) => { if (!userBtn.contains(e.target) && !userDropdown.contains(e.target)) { userDropdown.classList.remove('active'); } }); } // ============================================ // Customer Data // ============================================ function loadCustomerData() { const data = DASHBOARD_CONFIG.customerData; if (!data) return; // Update customer ID in embed code const customerIdEl = document.getElementById('customerId'); if (customerIdEl) { customerIdEl.textContent = data.id; } // Update webhook URLs const chatWebhookEl = document.getElementById('chatWebhook'); if (chatWebhookEl && data.chatWebhook) { chatWebhookEl.textContent = data.chatWebhook; } const uploadUrlEl = document.getElementById('uploadUrl'); if (uploadUrlEl && data.uploadUrl) { uploadUrlEl.textContent = data.uploadUrl; } // Update user name const userNameEl = document.getElementById('userName'); if (userNameEl) { userNameEl.textContent = `${data.firstName} ${data.lastName}`; } // Update account email const accountEmailEl = document.getElementById('accountEmail'); if (accountEmailEl) { accountEmailEl.value = data.email; } } function updateCustomerUI() { loadCustomerData(); // Update stats (demo data) updateStats({ documents: 0, messages: 0, visitors: 0, satisfaction: '-' }); } function updateStats(stats) { const docCountEl = document.getElementById('docCount'); const messageCountEl = document.getElementById('messageCount'); const visitorCountEl = document.getElementById('visitorCount'); const satisfactionEl = document.getElementById('satisfactionRate'); if (docCountEl) docCountEl.textContent = stats.documents; if (messageCountEl) messageCountEl.textContent = stats.messages; if (visitorCountEl) visitorCountEl.textContent = stats.visitors; if (satisfactionEl) satisfactionEl.textContent = stats.satisfaction; } // ============================================ // Trial Status // ============================================ function updateTrialStatus() { const data = DASHBOARD_CONFIG.customerData; if (!data || !data.trialStartDate) return; const trialStart = new Date(data.trialStartDate); const now = new Date(); const daysPassed = Math.floor((now - trialStart) / (1000 * 60 * 60 * 24)); const daysRemaining = Math.max(0, DASHBOARD_CONFIG.trialDays - daysPassed); // Update trial badge const trialDaysEl = document.getElementById('trialDays'); if (trialDaysEl) { trialDaysEl.textContent = daysRemaining; } // Update trial end date const trialEndDateEl = document.getElementById('trialEndDate'); if (trialEndDateEl) { const endDate = new Date(trialStart); endDate.setDate(endDate.getDate() + DASHBOARD_CONFIG.trialDays); trialEndDateEl.textContent = formatDate(endDate); } // Show/hide discount banner based on days const trialBanner = document.getElementById('trialBanner'); if (trialBanner) { if (daysPassed <= 3) { // Show 30% discount trialBanner.querySelector('h3').textContent = '🎉 Exklusives Angebot: 30% Frühbucher-Rabatt!'; trialBanner.querySelector('.btn').textContent = 'Jetzt für €34,30/Monat upgraden'; } else if (daysPassed <= 5) { // Show 15% discount trialBanner.querySelector('h3').textContent = '⏰ Nur noch 2 Tage: 15% Rabatt!'; trialBanner.querySelector('.btn').textContent = 'Jetzt für €41,65/Monat upgraden'; } else { // Show normal price trialBanner.querySelector('h3').textContent = '⚠️ Ihre Trial endet bald!'; trialBanner.querySelector('.btn').textContent = 'Jetzt für €49/Monat upgraden'; } } // Start countdown timer startOfferCountdown(); } function startOfferCountdown() { const countdownEl = document.getElementById('offerCountdown'); if (!countdownEl) return; // Set countdown to 48 hours from now (for demo) let timeRemaining = 48 * 60 * 60; // 48 hours in seconds const updateCountdown = () => { const hours = Math.floor(timeRemaining / 3600); const minutes = Math.floor((timeRemaining % 3600) / 60); const seconds = timeRemaining % 60; countdownEl.textContent = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; if (timeRemaining > 0) { timeRemaining--; setTimeout(updateCountdown, 1000); } }; updateCountdown(); } // ============================================ // File Upload // ============================================ function initFileUpload() { const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); if (!uploadArea || !fileInput) return; // Drag and drop uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; handleFiles(files); }); // File input change fileInput.addEventListener('change', () => { handleFiles(fileInput.files); }); } function handleFiles(files) { const validFiles = Array.from(files).filter(file => { if (file.type !== 'application/pdf') { showNotification('Nur PDF-Dateien werden unterstützt', 'error'); return false; } if (file.size > 10 * 1024 * 1024) { // 10MB showNotification(`${file.name} ist zu groß (max. 10MB)`, 'error'); return false; } return true; }); if (validFiles.length === 0) return; validFiles.forEach(file => uploadFile(file)); } async function uploadFile(file) { const uploadProgress = document.getElementById('uploadProgress'); const progressFill = document.getElementById('progressFill'); const uploadPercent = document.getElementById('uploadPercent'); // Show progress if (uploadProgress) uploadProgress.style.display = 'block'; try { // Simulate upload progress (replace with actual upload) for (let i = 0; i <= 100; i += 10) { await new Promise(resolve => setTimeout(resolve, 200)); if (progressFill) progressFill.style.width = `${i}%`; if (uploadPercent) uploadPercent.textContent = `${i}%`; } // Add document to list addDocumentToList({ name: file.name, size: formatFileSize(file.size), date: new Date().toLocaleDateString('de-DE'), status: 'processing' }); showNotification(`${file.name} wurde hochgeladen`, 'success'); // Simulate processing setTimeout(() => { updateDocumentStatus(file.name, 'indexed'); updateDocCount(); }, 3000); } catch (error) { console.error('Upload error:', error); showNotification('Fehler beim Hochladen', 'error'); } finally { // Hide progress setTimeout(() => { if (uploadProgress) uploadProgress.style.display = 'none'; if (progressFill) progressFill.style.width = '0%'; }, 500); } } function addDocumentToList(doc) { const documentsTable = document.getElementById('documentsTable'); if (!documentsTable) return; // Remove empty state if present const emptyState = documentsTable.querySelector('.empty-state'); if (emptyState) emptyState.remove(); const docRow = document.createElement('div'); docRow.className = 'document-row'; docRow.dataset.name = doc.name; docRow.innerHTML = `
Laden Sie Ihr erstes PDF hoch, um zu beginnen
${escapeHtml(text)}
`; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } function showTypingIndicator() { const chatMessages = document.getElementById('chatMessages'); if (!chatMessages) return null; const id = 'typing-' + Date.now(); const typingDiv = document.createElement('div'); typingDiv.className = 'message bot typing'; typingDiv.id = id; typingDiv.innerHTML = ` `; chatMessages.appendChild(typingDiv); chatMessages.scrollTop = chatMessages.scrollHeight; return id; } function removeTypingIndicator(id) { if (!id) return; const typingDiv = document.getElementById(id); if (typingDiv) typingDiv.remove(); } function getSessionId() { let sessionId = sessionStorage.getItem('chat_session_id'); if (!sessionId) { sessionId = 'session-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); sessionStorage.setItem('chat_session_id', sessionId); } return sessionId; } // ============================================ // Embed Code // ============================================ function copyEmbedCode() { const embedCode = document.getElementById('embedCode'); if (!embedCode) { console.error('embedCode element not found'); return; } // Get the text content and clean it up let text = embedCode.textContent || embedCode.innerText; text = text.trim(); // Use fallback method directly (more reliable) fallbackCopy(text); } function fallbackCopy(text) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; textarea.style.top = '0'; textarea.style.left = '0'; textarea.style.opacity = '0'; document.body.appendChild(textarea); textarea.focus(); textarea.select(); try { const successful = document.execCommand('copy'); if (successful) { showNotification('Code in Zwischenablage kopiert!', 'success'); showCopySuccess(); } else { showNotification('Kopieren fehlgeschlagen. Bitte manuell kopieren.', 'error'); } } catch (err) { console.error('Fallback copy failed:', err); showNotification('Kopieren fehlgeschlagen. Bitte manuell kopieren.', 'error'); } document.body.removeChild(textarea); } function showCopySuccess() { const copySuccess = document.getElementById('copySuccess'); if (copySuccess) { copySuccess.style.display = 'flex'; setTimeout(() => { copySuccess.style.display = 'none'; }, 2000); } } function copyToClipboard(elementId) { const element = document.getElementById(elementId); if (!element) { console.error('Element not found:', elementId); return; } let text = element.textContent || element.innerText; text = text.trim(); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(() => { showNotification('In Zwischenablage kopiert!', 'success'); }).catch(err => { console.error('Copy failed:', err); fallbackCopy(text); }); } else { fallbackCopy(text); } } // Make functions available globally window.copyEmbedCode = copyEmbedCode; window.copyToClipboard = copyToClipboard; // ============================================ // Settings // ============================================ function saveSettings() { const primaryColor = document.getElementById('primaryColor')?.value; const botName = document.getElementById('botName')?.value; const welcomeMessage = document.getElementById('welcomeMessage')?.value; // Save to localStorage (in production, save to API) const settings = { primaryColor, botName, welcomeMessage, }; localStorage.setItem('botkonzept_settings', JSON.stringify(settings)); showNotification('Einstellungen gespeichert', 'success'); } // Make saveSettings available globally window.saveSettings = saveSettings; // ============================================ // Utility Functions // ============================================ function showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); notification.className = `notification ${type}`; notification.innerHTML = ` ${message} `; // Add styles notification.style.cssText = ` position: fixed; bottom: 24px; right: 24px; padding: 16px 24px; background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#6366f1'}; color: white; border-radius: 8px; display: flex; align-items: center; gap: 12px; box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1); z-index: 9999; animation: slideIn 0.3s ease; `; document.body.appendChild(notification); // Remove after 3 seconds setTimeout(() => { notification.style.animation = 'slideOut 0.3s ease'; setTimeout(() => notification.remove(), 300); }, 3000); } function formatDate(date) { return new Intl.DateTimeFormat('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date); } function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Add notification animations const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } } `; document.head.appendChild(style);