import React, { useState, useEffect, useRef } from 'react'; import { UploadCloud, File, Trash2, ShieldAlert, CheckCircle, Loader, Eye, FileText } from 'lucide-react'; import { getProjectDocuments, uploadProjectDocument, deleteProjectDocument } from '../../api/client'; interface ResourcePanelProps { projectId: string; } const ProjectResourcesPanel: React.FC = ({ projectId }) => { const [documents, setDocuments] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isUploading, setIsUploading] = useState(false); const [dragActive, setDragActive] = useState(false); const [toastMsg, setToastMsg] = useState(""); const [expandedDoc, setExpandedDoc] = useState(null); const inputRef = useRef(null); const fetchDocuments = async () => { try { setIsLoading(true); const data = await getProjectDocuments(projectId); setDocuments(data || []); } catch (err) { console.error("Error fetching documents:", err); } finally { setIsLoading(false); } }; useEffect(() => { if (projectId) { fetchDocuments(); } }, [projectId]); const showToast = (msg: string) => { setToastMsg(msg); setTimeout(() => setToastMsg(""), 3000); }; const handleUpload = async (file: File) => { if (file.size > 10 * 1024 * 1024) { alert("Plik przekracza rozmiar 10MB"); return; } const validTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/msword', 'text/plain']; // Quick extension check as fallback const ext = file.name.split('.').pop()?.toLowerCase(); if (!validTypes.includes(file.type) && !['pdf', 'docx', 'doc', 'txt'].includes(ext || '')) { alert("Nieobsługiwany format. Użyj PDF, DOCX, DOC lub TXT."); return; } try { setIsUploading(true); await uploadProjectDocument(projectId, file); showToast("Dokument wgrany i dodany do wiedzy projektu"); await fetchDocuments(); } catch (err: any) { console.error(err); alert("Błąd podczas wgrywania dokumentu: " + (err.response?.data?.detail || err.message)); } finally { setIsUploading(false); if (inputRef.current) inputRef.current.value = ""; } }; const handleDrag = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); if (e.type === "dragenter" || e.type === "dragover") { setDragActive(true); } else if (e.type === "dragleave") { setDragActive(false); } }; const handleDrop = async (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); if (e.dataTransfer.files && e.dataTransfer.files[0]) { handleUpload(e.dataTransfer.files[0]); } }; const handleDelete = async (filename: string) => { if (!window.confirm(`Czy na pewno chcesz usunąć plik ${filename}? Zostanie on usunięty z wiedzy RAG.`)) return; try { await deleteProjectDocument(projectId, filename); showToast("Plik został usunięty"); await fetchDocuments(); } catch (err) { alert("Błąd podczas usuwania pliku."); } }; return (

Zasoby

Tutaj możesz dodać umowy, oferty, biznesplany – pomogą AI lepiej zrozumieć Twój projekt.

{toastMsg && (
{toastMsg}
)} {/* UPLOADER */}
inputRef.current?.click()} > { if (e.target.files && e.target.files[0]) handleUpload(e.target.files[0]); }} /> {isUploading ? (

Analizowanie dokumentu...

Trwa ekstrakcja tekstu i wektoryzacja w Pinecone

) : (

{dragActive ? 'Upuść plik tutaj' : 'Kliknij lub przeciągnij plik tutaj'}

Obsługiwane formaty: PDF, DOCX, TXT. Maksymalny rozmiar: 10 MB.

)}
{/* LISTA DOKUMENTÓW */}

Wgrane dokumenty ({documents?.length || 0} / 5 dla Free)

{isLoading ? (
Ładowanie...
) : documents?.length === 0 ? (
Brak dołączonych plików do tego projektu.
Tutaj możesz dodać umowy, oferty, biznesplany – pomogą AI lepiej zrozumieć Twój projekt.
) : (
{documents.map((doc, idx) => (
{doc.filename}
Wgrano: {new Date(doc.uploaded_at).toLocaleString('pl-PL', { day: 'numeric', month: 'long', year: 'numeric' })} Rozmiar: {((doc.size_bytes || doc.size || 0) / 1024 / 1024).toFixed(2)} MB
{expandedDoc === doc.id && (

Wyciągnięty tekst (podgląd):

{doc.extracted_text ? doc.extracted_text : 'Brak wyciągniętego tekstu.'}
)}
))}
)}
); }; export default ProjectResourcesPanel;