import React, { useState, useRef, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { MessageSquare, X, Send, BookOpen, AlertCircle, CheckCircle2, ChevronDown, ChevronUp, Pin, PinOff, Trash2 } from 'lucide-react'; import { askProjectQuestion, clearProjectQuestionsHistory } from '../../api/client'; import toast from 'react-hot-toast'; interface ProjectQAPanelProps { projectId: string; projectName?: string; } interface Message { id: string; role: 'user' | 'agent'; content: string; sources?: string[]; confidence?: number; recommendation?: string; created_at?: string; } const ProjectQAPanel: React.FC = ({ projectId, projectName }) => { const [isOpen, setIsOpen] = useState(false); const [isPinned, setIsPinned] = useState(false); const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(() => { const fetchHistory = async () => { try { const history = await import('../../api/client').then(m => m.getProjectQuestionsHistory(projectId)); if (history && history.length > 0) { const loadedMessages: Message[] = []; history.forEach((h: any) => { loadedMessages.push({ id: h.id + '_q', role: 'user', content: h.question, created_at: h.created_at }); loadedMessages.push({ id: h.id + '_a', role: 'agent', content: h.answer, sources: h.sources, confidence: h.confidence, recommendation: h.recommendation, created_at: h.created_at }); }); setMessages(loadedMessages); } } catch (err) { console.error("Failed to load QA history", err); } }; fetchHistory(); }, [projectId]); useEffect(() => { scrollToBottom(); }, [messages, isOpen]); useEffect(() => { const handleCmdK = (e: KeyboardEvent) => { if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setIsOpen(prev => !prev); } }; window.addEventListener('keydown', handleCmdK); return () => window.removeEventListener('keydown', handleCmdK); }, []); const handleClearHistory = async () => { if (!window.confirm("Czy na pewno chcesz trwale usunąć historię rozmów z agentem dla tego projektu?")) { return; } setIsLoading(true); try { await clearProjectQuestionsHistory(projectId); setMessages([]); toast.success("Historia została pomyślnie wyczyszczona."); } catch (error) { console.error(error); toast.error("Nie udało się usunąć historii czatu."); } finally { setIsLoading(false); } }; const handleSend = async () => { if (!input.trim() || isLoading) return; const userMsg: Message = { id: Date.now().toString(), role: 'user', content: input }; setMessages(prev => [...prev, userMsg]); setInput(''); setIsLoading(true); try { const data = await askProjectQuestion(projectId, userMsg.content); const agentMsg: Message = { id: (Date.now() + 1).toString(), role: 'agent', content: data.answer, sources: data.sources, confidence: data.confidence, recommendation: data.recommendation }; setMessages(prev => [...prev, agentMsg]); } catch (error) { console.error(error); toast.error("Nie udało się pobrać odpowiedzi. Spróbuj ponownie."); const errorMsg: Message = { id: (Date.now() + 1).toString(), role: 'agent', content: "Przepraszam, napotkałem błąd podczas analizy Twojego zapytania. Sprawdź połączenie i spróbuj ponownie." }; setMessages(prev => [...prev, errorMsg]); } finally { setIsLoading(false); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); } }; return (
{isOpen && ( {/* HEADER */}

Weryfikator (Ctrl+K)

{projectName && (
{projectName}
)}
{!isPinned && ( )}
{/* MESSAGES */}
{messages.length === 0 ? (

O co chcesz zapytać?

Agent odpowie na podstawie regulaminów i Twoich wygenerowanych sekcji wniosku.

) : ( messages.map((msg) => (
{/]*>/.test(msg.content) ? (
]*>/g, '
Sugestia:
').replace(/<\/SUGGESTION>/g, '
').replace(/\n/g, '
') }} /> ) : ( msg.content )} {/* AGENT EXTRA DETAILS */} {msg.role === 'agent' && (
{msg.sources && msg.sources.length > 0 && (
Zidentyfikowane Źródła:
    {msg.sources.map((s, i) =>
  • {s}
  • )}
)} {msg.recommendation && (
REKOMENDACJA {msg.recommendation}
)} {msg.confidence !== undefined && (
{msg.confidence > 0.8 ? : } Pewność: {Math.round(msg.confidence * 100)}%
)}
)}
)) )} {isLoading && (
)}
{/* INPUT */}