feat(pitch-deck): Waiting-Indicator im Investor Agent Chat
All checks were successful
CI / test-go-consent (push) Successful in 27s
CI / test-bqas (push) Successful in 29s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-python-voice (push) Successful in 31s

Drei animierte Punkte (iMessage-Style) erscheinen sofort nach dem
Absenden und verschwinden wenn der erste Token eintrifft.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-06 09:16:22 +01:00
parent 9f0e8328e5
commit 806d3e0b56

View File

@@ -15,6 +15,7 @@ export default function ChatInterface({ lang }: ChatInterfaceProps) {
const [messages, setMessages] = useState<ChatMessage[]>([])
const [input, setInput] = useState('')
const [isStreaming, setIsStreaming] = useState(false)
const [isWaiting, setIsWaiting] = useState(false)
const messagesEndRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
@@ -29,6 +30,7 @@ export default function ChatInterface({ lang }: ChatInterfaceProps) {
setInput('')
setMessages(prev => [...prev, { role: 'user', content: message }])
setIsStreaming(true)
setIsWaiting(true)
try {
const res = await fetch('/api/chat', {
@@ -47,21 +49,28 @@ export default function ChatInterface({ lang }: ChatInterfaceProps) {
const decoder = new TextDecoder()
let content = ''
setMessages(prev => [...prev, { role: 'assistant', content: '' }])
while (true) {
const { done, value } = await reader.read()
if (done) break
content += decoder.decode(value, { stream: true })
setMessages(prev => {
const updated = [...prev]
updated[updated.length - 1] = { role: 'assistant', content }
return updated
})
const chunk = decoder.decode(value, { stream: true })
content += chunk
if (isWaiting || content.length === chunk.length) {
// First chunk arrived — replace waiting indicator with real content
setIsWaiting(false)
setMessages(prev => [...prev, { role: 'assistant', content }])
} else {
setMessages(prev => {
const updated = [...prev]
updated[updated.length - 1] = { role: 'assistant', content }
return updated
})
}
}
} catch (err) {
console.error('Chat error:', err)
setIsWaiting(false)
setMessages(prev => [
...prev,
{ role: 'assistant', content: lang === 'de'
@@ -71,6 +80,7 @@ export default function ChatInterface({ lang }: ChatInterfaceProps) {
])
} finally {
setIsStreaming(false)
setIsWaiting(false)
}
}
@@ -135,6 +145,33 @@ export default function ChatInterface({ lang }: ChatInterfaceProps) {
</motion.div>
))}
</AnimatePresence>
{/* Waiting indicator — shown between send and first token */}
<AnimatePresence>
{isWaiting && (
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -4 }}
className="flex gap-3"
>
<div className="w-8 h-8 rounded-full bg-indigo-500/20 flex items-center justify-center shrink-0">
<Bot className="w-4 h-4 text-indigo-400" />
</div>
<div className="bg-white/[0.06] rounded-2xl px-4 py-3 flex items-center gap-1">
{[0, 1, 2].map(i => (
<motion.span
key={i}
className="block w-2 h-2 rounded-full bg-indigo-400/70"
animate={{ opacity: [0.3, 1, 0.3], y: [0, -4, 0] }}
transition={{ duration: 0.8, repeat: Infinity, delay: i * 0.18 }}
/>
))}
</div>
</motion.div>
)}
</AnimatePresence>
<div ref={messagesEndRef} />
</div>