/* App entry */ function ScrollToTop() { const [visible, setVisible] = React.useState(false); React.useEffect(() => { const onScroll = () => setVisible(window.scrollY > 400); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); return ( ); } function FritzChat() { const [open, setOpen] = React.useState(false); const [greeted, setGreeted] = React.useState(false); const [messages, setMessages] = React.useState([]); const [input, setInput] = React.useState(""); const [typing, setTyping] = React.useState(false); const endRef = React.useRef(null); const fmt = () => new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }); React.useEffect(() => { if (open && !greeted) { setGreeted(true); setTimeout(() => { setMessages([{ from: "fritz", text: "Hallo! Ich bin Fritz, dein KI-Assistent von Scality Solutions 👋 Wie kann ich dir helfen?", ts: fmt() }]); }, 400); } }, [open]); React.useEffect(() => { endRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages, typing]); const send = () => { const text = input.trim(); if (!text) return; setInput(""); setMessages(m => [...m, { from: "user", text, ts: fmt() }]); setTyping(true); const history = [...messages, { from: "user", text, ts: fmt() }]; fetch("/api-fritz.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: history }), }) .then(r => r.text()) .then(raw => { setTyping(false); try { const data = JSON.parse(raw); if (data.text) { setMessages(m => [...m, { from: "fritz", text: data.text, ts: fmt() }]); } else { setMessages(m => [...m, { from: "fritz", text: "⚠️ " + (data.error || "Unbekannter Fehler") + (data.detail ? ": " + data.detail : ""), ts: fmt() }]); } } catch { setMessages(m => [...m, { from: "fritz", text: "⚠️ Ungültige Antwort vom Server. Ist api-fritz.php hochgeladen?", ts: fmt() }]); } }) .catch(err => { setTyping(false); setMessages(m => [...m, { from: "fritz", text: "⚠️ Datei nicht erreichbar: " + err.message, ts: fmt() }]); }); }; const blue = "#15b9fa"; const bubbleBase = { maxWidth: "82%", padding: "9px 13px", borderRadius: 14, fontSize: 14, lineHeight: 1.5, wordBreak: "break-word", }; return ( <> {/* Chat window */}