import React, { useState, useEffect } from 'react'; import { ProjectDocument, DocumentCategory, ModuleType, BOQItem, ExtractedBill } from '../types'; import { FileText, Image, File, Search, UploadCloud, Download, X, FileSpreadsheet, Paperclip, Loader2, CheckCircle2, Sparkles, Zap, Tag } from 'lucide-react'; import { analyzeDocumentContent, suggestDocumentMetadata, extractBillData } from '../services/localAnalysisService'; interface DocumentManagerProps { documents: ProjectDocument[]; onAddDocument: (doc: ProjectDocument) => void; onAnalyzeDocument?: (docId: string, suggestions: any[]) => void; onSelectDocument?: (docId: string | null) => void; onBillUploaded?: (data: ExtractedBill) => void; boqItems?: BOQItem[]; filterModule?: ModuleType; compact?: boolean; allowUpload?: boolean; } const DocumentManager: React.FC = ({ documents, onAddDocument, onAnalyzeDocument, onBillUploaded, boqItems = [], filterModule, compact = false, allowUpload = true }) => { const [searchTerm, setSearchTerm] = useState(''); const [selectedCategory, setSelectedCategory] = useState('ALL'); const [selectedModule, setSelectedModule] = useState('ALL'); const [dateFrom, setDateFrom] = useState(''); const [dateTo, setDateTo] = useState(''); const [isUploadModalOpen, setIsUploadModalOpen] = useState(false); const [analyzingDocId, setAnalyzingDocId] = useState(null); // Upload Form State const [selectedFile, setSelectedFile] = useState(null); const [newDocName, setNewDocName] = useState(''); const [newDocType, setNewDocType] = useState('PDF'); const [newDocCategory, setNewDocCategory] = useState('REPORT'); const [newDocModule, setNewDocModule] = useState(filterModule || 'GENERAL'); const [isUploading, setIsUploading] = useState(false); const [isSuggestingMetadata, setIsSuggestingMetadata] = useState(false); const [isAnalyzingBill, setIsAnalyzingBill] = useState(false); const [hasAiSuggested, setHasAiSuggested] = useState(false); const [newDocTags, setNewDocTags] = useState(''); const filteredDocs = documents.filter(doc => { const matchesSearch = doc.name.toLowerCase().includes(searchTerm.toLowerCase()) || (doc.tags && doc.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase()))); const matchesCategory = selectedCategory === 'ALL' || doc.category === selectedCategory; const matchesModule = filterModule ? doc.module === filterModule : (selectedModule === 'ALL' || doc.module === selectedModule); const matchesDate = (!dateFrom || doc.uploadDate >= dateFrom) && (!dateTo || doc.uploadDate <= dateTo); return matchesSearch && matchesCategory && matchesModule && matchesDate; }); const handleDeepScan = async (doc: ProjectDocument) => { if (!onAnalyzeDocument) return; setAnalyzingDocId(doc.id); let mimeType = 'application/pdf'; if (doc.type === 'JPG' || doc.type === 'PNG') mimeType = 'image/jpeg'; const suggestions = await analyzeDocumentContent(doc.name, doc.category, boqItems, doc.content, mimeType); onAnalyzeDocument(doc.id, suggestions); setAnalyzingDocId(null); }; const readFileAsBase64 = (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const result = reader.result as string; // Remove data URL prefix const base64 = result.split(',')[1]; resolve(base64); }; reader.onerror = reject; reader.readAsDataURL(file); }); }; const handleFileChange = async (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; setSelectedFile(file); setNewDocName(file.name); setHasAiSuggested(false); const ext = file.name.split('.').pop()?.toLowerCase(); if (ext === 'pdf') setNewDocType('PDF'); else if (['jpg', 'jpeg', 'png', 'gif'].includes(ext || '')) setNewDocType('JPG'); else if (['xlsx', 'xls', 'csv'].includes(ext || '')) setNewDocType('XLSX'); else if (['docx', 'doc'].includes(ext || '')) setNewDocType('DOCX'); else if (['dwg', 'dxf'].includes(ext || '')) setNewDocType('DWG'); else setNewDocType('PDF'); // AI Meta Suggestion setIsSuggestingMetadata(true); const suggestion = await suggestDocumentMetadata(file.name, "USER_ROLE"); // Pass role if available setIsSuggestingMetadata(false); if (suggestion) { if (suggestion.category) setNewDocCategory(suggestion.category as DocumentCategory); if (suggestion.module) setNewDocModule(suggestion.module as ModuleType); setHasAiSuggested(true); } } }; const handleUpload = async (e: React.FormEvent) => { e.preventDefault(); setIsUploading(true); // Simulate upload delay await new Promise(resolve => setTimeout(resolve, 800)); let fileSize = '0.0 MB'; let fileUrl = undefined; let base64Content: string | undefined = undefined; if (selectedFile) { fileSize = `${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB`; fileUrl = URL.createObjectURL(selectedFile); try { base64Content = await readFileAsBase64(selectedFile); } catch (err) { console.error("Failed to read file", err); } } else { fileSize = `${(Math.random() * 5 + 0.5).toFixed(1)} MB`; } const newDoc: ProjectDocument = { id: `D${Date.now()}`, name: newDocName, type: newDocType, category: newDocCategory, module: newDocModule, uploadDate: new Date().toISOString().split('T')[0], size: fileSize, url: fileUrl, content: base64Content, isAnalyzed: false, tags: newDocTags.split(',').map(t => t.trim()).filter(t => t !== '') }; onAddDocument(newDoc); // Auto-Extraction for Bills if (newDocCategory === 'BILL' && onBillUploaded) { setIsAnalyzingBill(true); try { let mimeType = 'application/pdf'; if (newDocType === 'JPG' || newDocType === 'PNG') mimeType = 'image/jpeg'; const extracted = await extractBillData(newDocName, base64Content, mimeType); if (extracted) { onBillUploaded(extracted); } } catch (err) { console.error("Bill extraction failed", err); } setIsAnalyzingBill(false); } setIsUploading(false); setIsUploadModalOpen(false); setNewDocName(''); setNewDocTags(''); setSelectedFile(null); setHasAiSuggested(false); }; const getIcon = (type: string) => { if (type.includes('PDF')) return ; if (type.includes('JPG') || type.includes('PNG')) return ; if (type.includes('XLS')) return ; if (type.includes('DOC')) return ; if (type.includes('DWG')) return ; return ; }; return (

{compact ? 'Related Documents' : 'Document Management'}

{!compact &&

Central repository for all project files

}
{allowUpload && ( )}
setSearchTerm(e.target.value)} className="w-full pl-9 pr-4 py-2 text-sm border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none" />
{filteredDocs.length > 0 ? ( {filteredDocs.map((doc) => ( ))}
Name Category Date AI Scan Action
{getIcon(doc.type)}

{doc.name}

{doc.tags && doc.tags.length > 0 && (
{doc.tags.map((tag, i) => ( {tag} ))}
)}
{doc.category} {doc.uploadDate} {analyzingDocId === doc.id ? (
Reading...
) : doc.isAnalyzed ? (
Synced
) : ( )}
) : (

No documents found

)}
{isUploadModalOpen && (

Upload & Analyze

{isSuggestingMetadata && !isAnalyzingBill && (
AI Analyzing Name...
)} {isAnalyzingBill && (
Extracting Bill Data...
)}
{selectedFile ? : }

{selectedFile ? selectedFile.name : "Choose file"}

{hasAiSuggested && ( AI Sug )}
{hasAiSuggested && ( AI Sug )}
setNewDocTags(e.target.value)} className="w-full pl-9 pr-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 outline-none text-sm transition-all" />
)}
); }; export default DocumentManager;