Spaces:
Runtime error
Runtime error
| import { useState, useEffect } from 'react'; | |
| import FileUpload from './components/FileUpload'; | |
| import ChatWindow from './components/ChatWindow'; | |
| import DocumentList from './components/DocumentList'; | |
| import { listDocuments } from './services/api'; | |
| export default function App() { | |
| const [documents, setDocuments] = useState([]); | |
| const [isLoadingDocs, setIsLoadingDocs] = useState(true); | |
| const [sidebarOpen, setSidebarOpen] = useState(true); | |
| const fetchDocuments = async () => { | |
| try { | |
| setIsLoadingDocs(true); | |
| const result = await listDocuments(); | |
| setDocuments(result.documents || []); | |
| } catch (err) { | |
| console.error('Failed to fetch documents:', err); | |
| } finally { | |
| setIsLoadingDocs(false); | |
| } | |
| }; | |
| useEffect(() => { | |
| fetchDocuments(); | |
| }, []); | |
| const handleUploadSuccess = (doc) => { | |
| setDocuments((prev) => [...prev, doc]); | |
| }; | |
| const handleDocumentDeleted = (docId) => { | |
| setDocuments((prev) => prev.filter((d) => d.id !== docId)); | |
| }; | |
| return ( | |
| <div className="app"> | |
| {/* Sidebar */} | |
| <aside className={`sidebar ${sidebarOpen ? 'open' : 'closed'}`}> | |
| <div className="sidebar-header"> | |
| <div className="logo"> | |
| <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"> | |
| <path d="M12 2a4 4 0 0 1 4 4v2a4 4 0 0 1-8 0V6a4 4 0 0 1 4-4z" /> | |
| <path d="M6 10a6 6 0 0 0 12 0" /> | |
| <rect x="9" y="14" width="6" height="4" rx="1" /> | |
| <path d="M8 18h8v2a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2z" /> | |
| </svg> | |
| <span>RAG Assistant</span> | |
| </div> | |
| <button | |
| className="sidebar-toggle" | |
| onClick={() => setSidebarOpen(!sidebarOpen)} | |
| > | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"> | |
| {sidebarOpen ? ( | |
| <path d="M15 18l-6-6 6-6" /> | |
| ) : ( | |
| <path d="M9 18l6-6-6-6" /> | |
| )} | |
| </svg> | |
| </button> | |
| </div> | |
| <div className="sidebar-content"> | |
| <FileUpload onUploadSuccess={handleUploadSuccess} documentCount={documents.length} /> | |
| <DocumentList | |
| documents={documents} | |
| onDocumentDeleted={handleDocumentDeleted} | |
| isLoading={isLoadingDocs} | |
| /> | |
| </div> | |
| <div className="sidebar-footer"> | |
| <p>Powered by GPT-4o-mini</p> | |
| </div> | |
| </aside> | |
| {/* Mobile sidebar toggle */} | |
| {!sidebarOpen && ( | |
| <button | |
| className="mobile-sidebar-toggle" | |
| onClick={() => setSidebarOpen(true)} | |
| > | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"> | |
| <line x1="3" y1="12" x2="21" y2="12" /> | |
| <line x1="3" y1="6" x2="21" y2="6" /> | |
| <line x1="3" y1="18" x2="21" y2="18" /> | |
| </svg> | |
| </button> | |
| )} | |
| {/* Main Chat Area */} | |
| <main className="main-content"> | |
| <ChatWindow hasDocuments={documents.length > 0} /> | |
| </main> | |
| </div> | |
| ); | |
| } | |