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
745 lines
24 KiB
JavaScript
745 lines
24 KiB
JavaScript
/**
|
|
* 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 = `
|
|
<div class="doc-icon">
|
|
<i class="fas fa-file-pdf"></i>
|
|
</div>
|
|
<div class="doc-info">
|
|
<div class="doc-name">${doc.name}</div>
|
|
<div class="doc-meta">${doc.size} • ${doc.date}</div>
|
|
</div>
|
|
<span class="doc-status ${doc.status}">${doc.status === 'indexed' ? 'Indexiert' : 'Verarbeitung...'}</span>
|
|
<div class="doc-actions">
|
|
<button title="Herunterladen"><i class="fas fa-download"></i></button>
|
|
<button class="delete" title="Löschen" onclick="deleteDocument('${doc.name}')"><i class="fas fa-trash"></i></button>
|
|
</div>
|
|
`;
|
|
|
|
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 = `
|
|
<div class="empty-state">
|
|
<i class="fas fa-folder-open"></i>
|
|
<h3>Noch keine Dokumente</h3>
|
|
<p>Laden Sie Ihr erstes PDF hoch, um zu beginnen</p>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
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 = `
|
|
<div class="message bot">
|
|
<p>Hallo! Ich bin Ihr KI-Assistent. Wie kann ich Ihnen helfen?</p>
|
|
</div>
|
|
`;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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 = `<p>${escapeHtml(text)}</p>`;
|
|
|
|
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 = `
|
|
<span class="typing-indicator">
|
|
<span></span><span></span><span></span>
|
|
</span>
|
|
`;
|
|
|
|
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 = `
|
|
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
|
|
<span>${message}</span>
|
|
`;
|
|
|
|
// 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);
|