/** * 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 = `
${doc.name}
${doc.size} • ${doc.date}
${doc.status === 'indexed' ? 'Indexiert' : 'Verarbeitung...'}
`; documentsTable.appendChild(docRow); } function updateDocumentStatus(name, status) { const docRow = document.querySelector(`.document-row[data-name="${name}"]`); if (!docRow) return; const statusEl = docRow.querySelector('.doc-status'); if (statusEl) { statusEl.className = `doc-status ${status}`; statusEl.textContent = status === 'indexed' ? 'Indexiert' : 'Verarbeitung...'; } } function deleteDocument(name) { if (!confirm(`Möchten Sie "${name}" wirklich löschen?`)) return; const docRow = document.querySelector(`.document-row[data-name="${name}"]`); if (docRow) { docRow.remove(); updateDocCount(); showNotification('Dokument gelöscht', 'success'); } // Show empty state if no documents const documentsTable = document.getElementById('documentsTable'); if (documentsTable && documentsTable.children.length === 0) { documentsTable.innerHTML = `

Noch keine Dokumente

Laden Sie Ihr erstes PDF hoch, um zu beginnen

`; } } function updateDocCount() { const documentsTable = document.getElementById('documentsTable'); const totalDocsEl = document.getElementById('totalDocs'); const docCountEl = document.getElementById('docCount'); if (!documentsTable) return; const count = documentsTable.querySelectorAll('.document-row').length; if (totalDocsEl) totalDocsEl.textContent = `${count} Dokument${count !== 1 ? 'e' : ''}`; if (docCountEl) docCountEl.textContent = count; } // Make deleteDocument available globally window.deleteDocument = deleteDocument; // ============================================ // Chatbot // ============================================ function initChatbot() { const chatInput = document.getElementById('chatInput'); const sendBtn = document.getElementById('sendBtn'); const clearBtn = document.getElementById('clearChat'); if (!chatInput || !sendBtn) return; // Send message on button click sendBtn.addEventListener('click', () => sendMessage()); // Send message on Enter chatInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { sendMessage(); } }); // Clear chat if (clearBtn) { clearBtn.addEventListener('click', () => { const chatMessages = document.getElementById('chatMessages'); if (chatMessages) { chatMessages.innerHTML = `

Hallo! Ich bin Ihr KI-Assistent. Wie kann ich Ihnen helfen?

`; } }); } } async function sendMessage() { const chatInput = document.getElementById('chatInput'); const chatMessages = document.getElementById('chatMessages'); if (!chatInput || !chatMessages) return; const message = chatInput.value.trim(); if (!message) return; // Add user message addChatMessage(message, 'user'); chatInput.value = ''; // Show typing indicator const typingId = showTypingIndicator(); try { // Send to chat webhook (if configured) const webhookUrl = DASHBOARD_CONFIG.customerData?.chatWebhook; if (webhookUrl && webhookUrl !== 'https://sb-demo.userman.de/webhook/rag-chat-webhook/chat') { const response = await fetch(webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ chatInput: message, sessionId: getSessionId(), }), }); const data = await response.json(); removeTypingIndicator(typingId); addChatMessage(data.output || data.response || 'Keine Antwort erhalten', 'bot'); } else { // Demo response await new Promise(resolve => setTimeout(resolve, 1500)); removeTypingIndicator(typingId); const demoResponses = [ 'Das ist eine Demo-Antwort. Laden Sie Dokumente hoch, um echte Antworten zu erhalten.', 'Ich kann Ihnen helfen, sobald Sie Ihre Wissensdatenbank mit PDFs gefüllt haben.', 'Bitte laden Sie zunächst einige Dokumente hoch, damit ich Ihre Fragen beantworten kann.', ]; addChatMessage(demoResponses[Math.floor(Math.random() * demoResponses.length)], 'bot'); } } catch (error) { console.error('Chat error:', error); removeTypingIndicator(typingId); addChatMessage('Entschuldigung, es gab einen Fehler. Bitte versuchen Sie es erneut.', 'bot'); } } function addChatMessage(text, type) { const chatMessages = document.getElementById('chatMessages'); if (!chatMessages) return; const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; messageDiv.innerHTML = `

${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) return; const text = embedCode.textContent; copyToClipboard('embedCode'); // Show success message 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) return; const text = element.textContent; navigator.clipboard.writeText(text).then(() => { showNotification('In Zwischenablage kopiert', 'success'); }).catch(err => { console.error('Copy failed:', err); // Fallback const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); showNotification('In Zwischenablage kopiert', 'success'); }); } // 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);