import React, { useState, useEffect } from 'react'; import { X, Loader, AlertCircle, CheckCircle, Upload as UploadIcon, Download, FileText, Trash2 } from 'lucide-react'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; export default function KnowledgeBaseModal({ onClose, onUpdate }) { const [phase, setPhase] = useState('idle'); // idle, uploading, success, error const [selectedFile, setSelectedFile] = useState(null); const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [category, setCategory] = useState('General'); const [result, setResult] = useState(null); const [existingArticles, setExistingArticles] = useState([]); const [error, setError] = useState(''); // Fetch existing articles on mount useEffect(() => { fetchExistingArticles(); }, []); const fetchExistingArticles = async () => { try { const response = await fetch(`${API_BASE}/knowledge-base`, { credentials: 'include' }); if (!response.ok) throw new Error('Failed to fetch articles'); const data = await response.json(); setExistingArticles(data); } catch (err) { console.error('Error fetching articles:', err); } }; const handleFileSelect = (e) => { const file = e.target.files[0]; if (file) { // Validate file type const allowedExtensions = ['.pdf', '.md', '.txt', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.html', '.json', '.yaml', '.yml']; const ext = '.' + file.name.split('.').pop().toLowerCase(); if (!allowedExtensions.includes(ext)) { setError('File type not allowed. Please upload: PDF, Markdown, Text, Office docs, or HTML files.'); return; } setSelectedFile(file); setError(''); // Auto-populate title from filename if empty if (!title) { const filename = file.name.replace(/\.[^/.]+$/, ''); // Remove extension setTitle(filename); } } }; const handleUpload = async () => { if (!selectedFile || !title.trim()) { setError('Please provide both a title and file'); return; } setPhase('uploading'); const formData = new FormData(); formData.append('file', selectedFile); formData.append('title', title.trim()); formData.append('description', description.trim()); formData.append('category', category); try { const response = await fetch(`${API_BASE}/knowledge-base/upload`, { method: 'POST', body: formData, credentials: 'include' }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Upload failed'); } const data = await response.json(); setResult(data); setPhase('success'); // Refresh the list of existing articles await fetchExistingArticles(); // Notify parent to refresh if (onUpdate) onUpdate(); } catch (err) { setError(err.message); setPhase('error'); } }; const handleDownload = async (id, filename) => { try { const response = await fetch(`${API_BASE}/knowledge-base/${id}/download`, { credentials: 'include' }); if (!response.ok) throw new Error('Download failed'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error('Error downloading file:', err); setError('Failed to download file'); } }; const handleDelete = async (id, articleTitle) => { if (!window.confirm(`Are you sure you want to delete "${articleTitle}"?`)) { return; } try { const response = await fetch(`${API_BASE}/knowledge-base/${id}`, { method: 'DELETE', credentials: 'include' }); if (!response.ok) throw new Error('Delete failed'); // Refresh the list await fetchExistingArticles(); // Notify parent to refresh if (onUpdate) onUpdate(); } catch (err) { console.error('Error deleting article:', err); setError('Failed to delete article'); } }; const resetForm = () => { setPhase('idle'); setSelectedFile(null); setTitle(''); setDescription(''); setCategory('General'); setResult(null); setError(''); }; const formatFileSize = (bytes) => { if (!bytes) return 'Unknown size'; if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; }; const formatDate = (dateString) => { return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); }; const getCategoryColor = (cat) => { const colors = { 'General': '#94A3B8', 'Policy': '#0EA5E9', 'Procedure': '#10B981', 'Guide': '#F59E0B', 'Reference': '#8B5CF6' }; return colors[cat] || '#94A3B8'; }; return (
Selected: {selectedFile.name} ({formatFileSize(selectedFile.size)})
)}{error}
Uploading document...
Upload Successful!
{result.title} has been added to the knowledge base.
Upload Failed
{error}
{article.title}
{article.description}
)}