From 5ac64b437b901d77f3156bf27ec0333d26c75def Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Fri, 16 Jan 2026 16:15:02 +0100 Subject: [PATCH] fix: AI chat loading indicator and auto-refresh tasks - Add animated typing indicator (bouncing dots) when AI is processing - Show "Thinking..." status in chat header while processing - Add translations for AI chat (en/de): title, welcome, placeholder, thinking, error - Auto-refresh tasks, labels, and user data after AI response - Disable input field while AI is processing - Fix translation keys to use ai.chat.* namespace --- client/src/components/AiChat.tsx | 38 +++++++++++++++++++++++++------- client/src/i18n/locales/de.json | 7 ++++++ client/src/i18n/locales/en.json | 7 ++++++ client/src/pages/AiChatPage.tsx | 12 ++++------ 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/client/src/components/AiChat.tsx b/client/src/components/AiChat.tsx index 3aff916..9fda0e7 100644 --- a/client/src/components/AiChat.tsx +++ b/client/src/components/AiChat.tsx @@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardFooter, CardHeader } from '@/components/ui/card'; -import { Bot, X, Send, Sparkles, Loader2 } from 'lucide-react'; +import { Bot, X, Send, Sparkles } from 'lucide-react'; import { apiRequest } from '@/lib/queryClient'; import { cn } from '@/lib/utils'; @@ -13,8 +13,20 @@ interface Message { content: string; } +// Typing indicator with animated dots +function TypingIndicator() { + return ( +
+
+
+
+
+ ); +} + export function AiChat() { const { t } = useTranslation(); + const queryClient = useQueryClient(); const [isOpen, setIsOpen] = useState(false); const [input, setInput] = useState(''); const [messages, setMessages] = useState([]); @@ -31,9 +43,13 @@ export function AiChat() { }, onSuccess: (data) => { setMessages(prev => [...prev, data]); + // Refresh tasks and labels in case AI created/modified them + queryClient.invalidateQueries({ queryKey: ['/api/tasks'] }); + queryClient.invalidateQueries({ queryKey: ['/api/labels'] }); + queryClient.invalidateQueries({ queryKey: ['/api/user'] }); }, onError: (err: Error) => { - setMessages(prev => [...prev, { role: 'assistant', content: t('ai.error') + ": " + err.message }]); + setMessages(prev => [...prev, { role: 'assistant', content: t('ai.chat.error', 'Something went wrong') + ": " + err.message }]); } }); @@ -70,7 +86,12 @@ export function AiChat() {
- {t('ai.title')} + {t('ai.chat.title', 'AI Assistant')} + {mutation.isPending && ( + + {t('ai.chat.thinking', 'Thinking')}... + + )}