import React, { useState, useRef, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { useAuth } from '../../context/AuthContext'; import aiService from '../../services/aiService'; import { marked } from 'marked'; marked.use({ breaks: true, gfm: true }); const renderMd = (text) => { try { const html = marked.parse(String(text || ''), { async: false }); return { __html: typeof html === 'string' ? html : String(html) }; } catch { return { __html: String(text || '').replace(/\n/g, '
') }; } }; const STAFF_ROLES = ['super_admin', 'admin', 'support', 'bearbeiter']; const WELCOME_MSG = { role: 'assistant', content: 'Hallo! Ich bin dein KI-Assistent für IT-Support. Wie kann ich dir helfen?\n\nDu kannst mich z.B. nach Troubleshooting-Schritten, Lösungen für bekannte Probleme oder Ticket-Einschätzungen fragen.', }; export default function AiChatWidget() { const { user } = useAuth(); const location = useLocation(); const [open, setOpen] = useState(false); const [messages, setMessages] = useState([WELCOME_MSG]); const [input, setInput] = useState(''); const [loading, setLoading] = useState(false); const [configured, setConfigured] = useState(true); const bottomRef = useRef(null); const inputRef = useRef(null); const isStaff = user && STAFF_ROLES.includes(user.role_name); const isPublicPage = ['/health', '/defect', '/login', '/tv'].some(p => location.pathname.startsWith(p)); // Status prüfen (immer, auch wenn nicht Staff) useEffect(() => { if (!isStaff) return; aiService.getStatus() .then(s => setConfigured(s.configured)) .catch(() => setConfigured(false)); }, [isStaff]); useEffect(() => { if (open) { setTimeout(() => inputRef.current?.focus(), 100); } }, [open]); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); // Nur für Staff-Rollen und nicht auf öffentlichen Seiten anzeigen if (!isStaff || isPublicPage) return null; async function sendMessage() { const text = input.trim(); if (!text || loading) return; const userMsg = { role: 'user', content: text }; const newMessages = [...messages, userMsg]; setMessages(newMessages); setInput(''); setLoading(true); try { // Nur die letzten 20 Nachrichten als Kontext senden (ohne Welcome-Msg) const contextMsgs = newMessages .filter(m => m !== WELCOME_MSG) .slice(-20); const reply = await aiService.chat(contextMsgs); setMessages(prev => [...prev, { role: 'assistant', content: reply }]); } catch (err) { setMessages(prev => [...prev, { role: 'assistant', content: `Fehler: ${err.response?.data?.message || err.message || 'Unbekannter Fehler'}`, isError: true, }]); } finally { setLoading(false); setTimeout(() => inputRef.current?.focus(), 50); } } function handleKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } } function clearChat() { setMessages([WELCOME_MSG]); } return ( <> {/* Floating Button */} {/* Chat Panel */} {open && (
{/* Header */}
🤖
KI-Assistent
{configured ? 'Claude claude-sonnet-4-6 · IT Support' : 'Nicht konfiguriert'}
{!configured && (
⚠️ ANTHROPIC_API_KEY nicht konfiguriert
)} {/* Messages */}
{messages.map((msg, i) => (
{msg.role === 'assistant' ?
: msg.content}
))} {loading && (
)}
{/* Input */}