/** * ChatbotConversationsView * * Chatbot interface with chat history sidebar and messages view. * Similar to trustee views but hardcoded for chatbot feature. */ import React, { useState, useCallback } from 'react'; import { useChatbot } from '../../../hooks/useChatbot'; import { useConfirm } from '../../../hooks/useConfirm'; import { TextField } from '../../../components/UiComponents/TextField'; import { Button } from '../../../components/UiComponents/Button'; import { AutoScroll } from '../../../components/UiComponents/AutoScroll'; import { ChatMessage } from '../../../components/UiComponents/Messages/ChatMessages/ChatMessage'; import { formatUnixTimestamp } from '../../../utils/time'; import { IoMdSend } from 'react-icons/io'; import { MdStop } from 'react-icons/md'; import { LuMessageSquare, LuTrash2 } from 'react-icons/lu'; import messagesStyles from '../../../components/UiComponents/Messages/Messages.module.css'; import styles from './ChatbotViews.module.css'; export const ChatbotConversationsView: React.FC = () => { const { threads, selectedThreadId, loadingThreads, error, messages, loadingMessages, isStreaming, streamingStatus, currentWorkflowId, selectThread, createNewThread, sendMessage, stopStreaming, deleteThread, refreshThreads, inputValue, setInputValue } = useChatbot(); const [deletingId, setDeletingId] = useState(null); const { confirm, ConfirmDialog } = useConfirm(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!inputValue.trim() || isStreaming) return; await sendMessage(inputValue); }; const handleKeyDown = (e: React.KeyboardEvent) => { // Enter ohne Shift sendet die Nachricht if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (!inputValue.trim() || isStreaming) return; sendMessage(inputValue); } }; const handleStop = async () => { console.log('Stop button clicked', { isStreaming, currentWorkflowId, selectedThreadId, hasMessages: messages.length > 0 }); if (isStreaming) { console.log('Calling stopStreaming...'); try { await stopStreaming(); console.log('stopStreaming completed'); } catch (error) { console.error('Error in stopStreaming:', error); } } else { console.warn('Stop button clicked but not streaming'); } }; const handleDeleteThread = useCallback(async (e: React.MouseEvent, workflowId: string) => { e.stopPropagation(); const ok = await confirm('Möchten Sie diese Konversation wirklich löschen?', { title: 'Konversation löschen', confirmLabel: 'Löschen', variant: 'danger', }); if (!ok) return; setDeletingId(workflowId); try { await deleteThread(workflowId); } finally { setDeletingId(null); } }, [confirm, deleteThread]); const formatDate = (timestamp?: number) => { if (!timestamp) return ''; // Convert Unix timestamp (seconds) to milliseconds using the time utility logic const milliseconds = timestamp * 1000; const date = new Date(milliseconds); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Gerade eben'; if (diffMins < 60) return `Vor ${diffMins} Min`; if (diffHours < 24) return `Vor ${diffHours} Std`; if (diffDays < 7) return `Vor ${diffDays} Tagen`; // For older dates, use the formatUnixTimestamp utility for consistent formatting const { time } = formatUnixTimestamp(timestamp, 'de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); return time; }; const getThreadTitle = (thread: any) => { if (thread.name) return thread.name; // Try to get first message content as title return 'Neue Konversation'; }; return (
{/* Chat History Sidebar */} {/* Main Chat Area */}
{/* Messages Area */}
{loadingMessages && messages.length === 0 ? (
Lade Nachrichten...
) : messages.length === 0 ? (
Noch keine Nachrichten. Starte eine Konversation!
) : (
{messages.map((message) => ( ))} {isStreaming && (
{streamingStatus ? (
{streamingStatus}
) : (
)}
)}
)}
{/* Input Form */}
{isStreaming ? ( ) : ( )}
); }; export default ChatbotConversationsView;