diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 46030c0..0252a70 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -10,6 +10,7 @@ import Dashboard from './components/Dashboard/Dashboard';
import UploadPage from './pages/UploadPage';
import DocumentsPage from './pages/DocumentsPage';
import SearchPage from './pages/SearchPage';
+import DocumentDetailsPage from './pages/DocumentDetailsPage';
function App() {
const { user, loading } = useAuth();
@@ -59,6 +60,7 @@ function App() {
} />
} />
} />
+ } />
} />
Watch Folder Page - Coming Soon} />
Settings Page - Coming Soon} />
diff --git a/frontend/src/pages/DocumentDetailsPage.jsx b/frontend/src/pages/DocumentDetailsPage.jsx
new file mode 100644
index 0000000..a59755c
--- /dev/null
+++ b/frontend/src/pages/DocumentDetailsPage.jsx
@@ -0,0 +1,412 @@
+import React, { useState, useEffect } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import {
+ Box,
+ Typography,
+ Card,
+ CardContent,
+ Button,
+ Chip,
+ Stack,
+ Grid,
+ Divider,
+ IconButton,
+ Paper,
+ Alert,
+ CircularProgress,
+ Tooltip,
+ Dialog,
+ DialogContent,
+ DialogTitle,
+ DialogActions,
+} from '@mui/material';
+import {
+ ArrowBack as BackIcon,
+ Download as DownloadIcon,
+ PictureAsPdf as PdfIcon,
+ Image as ImageIcon,
+ Description as DocIcon,
+ TextSnippet as TextIcon,
+ CalendarToday as DateIcon,
+ Storage as SizeIcon,
+ Tag as TagIcon,
+ Visibility as ViewIcon,
+ Search as SearchIcon,
+ Edit as EditIcon,
+} from '@mui/icons-material';
+import { documentService } from '../services/api';
+
+const DocumentDetailsPage = () => {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const [document, setDocument] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [ocrText, setOcrText] = useState('');
+ const [showOcrDialog, setShowOcrDialog] = useState(false);
+
+ useEffect(() => {
+ if (id) {
+ fetchDocumentDetails();
+ }
+ }, [id]);
+
+ const fetchDocumentDetails = async () => {
+ try {
+ setLoading(true);
+ setError(null);
+
+ // Since we don't have a direct document details endpoint,
+ // we'll fetch the document from the list and find the matching one
+ const response = await documentService.list(1000, 0);
+ const foundDoc = response.data.find(doc => doc.id === id);
+
+ if (foundDoc) {
+ setDocument(foundDoc);
+ // If the document has OCR text, we could fetch it here
+ // For now, we'll show a placeholder
+ if (foundDoc.has_ocr_text) {
+ setOcrText('OCR text extraction feature would be available here. The document has been processed and text content is available for search.');
+ }
+ } else {
+ setError('Document not found');
+ }
+ } catch (err) {
+ setError('Failed to load document details');
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleDownload = async () => {
+ try {
+ const response = await documentService.download(document.id);
+ const url = window.URL.createObjectURL(new Blob([response.data]));
+ const link = document.createElement('a');
+ link.href = url;
+ link.setAttribute('download', document.original_filename);
+ document.body.appendChild(link);
+ link.click();
+ link.remove();
+ window.URL.revokeObjectURL(url);
+ } catch (err) {
+ console.error('Download failed:', err);
+ }
+ };
+
+ const getFileIcon = (mimeType) => {
+ if (mimeType?.includes('pdf')) return ;
+ if (mimeType?.includes('image')) return ;
+ if (mimeType?.includes('text')) return ;
+ return ;
+ };
+
+ const formatFileSize = (bytes) => {
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+ if (bytes === 0) return '0 Bytes';
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
+ return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
+ };
+
+ const formatDate = (dateString) => {
+ return new Date(dateString).toLocaleString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ };
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error || !document) {
+ return (
+
+ }
+ onClick={() => navigate('/documents')}
+ sx={{ mb: 3 }}
+ >
+ Back to Documents
+
+
+ {error || 'Document not found'}
+
+
+ );
+ }
+
+ return (
+
+ {/* Header */}
+
+ }
+ onClick={() => navigate('/documents')}
+ sx={{ mb: 2 }}
+ >
+ Back to Documents
+
+
+
+ Document Details
+
+
+ View and manage document information
+
+
+
+
+ {/* Document Preview */}
+
+
+
+
+ {getFileIcon(document.mime_type)}
+
+
+
+ {document.original_filename}
+
+
+
+ }
+ onClick={handleDownload}
+ sx={{ borderRadius: 2 }}
+ >
+ Download
+
+ {document.has_ocr_text && (
+ }
+ onClick={() => setShowOcrDialog(true)}
+ sx={{ borderRadius: 2 }}
+ >
+ View OCR
+
+ )}
+
+
+ {document.has_ocr_text && (
+ }
+ />
+ )}
+
+
+
+
+ {/* Document Information */}
+
+
+
+
+ Document Information
+
+
+
+
+
+
+
+
+ Filename
+
+
+
+ {document.original_filename}
+
+
+
+
+
+
+
+
+
+ File Size
+
+
+
+ {formatFileSize(document.file_size)}
+
+
+
+
+
+
+
+
+
+ Upload Date
+
+
+
+ {formatDate(document.created_at)}
+
+
+
+
+
+
+
+
+
+ File Type
+
+
+
+ {document.mime_type}
+
+
+
+
+ {document.tags && document.tags.length > 0 && (
+
+
+
+
+
+ Tags
+
+
+
+ {document.tags.map((tag, index) => (
+
+ ))}
+
+
+
+ )}
+
+
+
+
+
+ Processing Status
+
+
+
+
+
+
+
+ Document uploaded successfully
+
+
+
+
+
+
+
+ {document.has_ocr_text ? 'OCR processing completed' : 'OCR processing pending'}
+
+
+
+
+
+
+
+
+
+ {/* OCR Text Dialog */}
+
+
+ );
+};
+
+export default DocumentDetailsPage;
\ No newline at end of file
diff --git a/frontend/src/pages/DocumentsPage.jsx b/frontend/src/pages/DocumentsPage.jsx
index 9050bfb..72d856f 100644
--- a/frontend/src/pages/DocumentsPage.jsx
+++ b/frontend/src/pages/DocumentsPage.jsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
import {
Box,
Typography,
@@ -41,6 +42,7 @@ import {
import { documentService } from '../services/api';
const DocumentsPage = () => {
+ const navigate = useNavigate();
const [documents, setDocuments] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -263,7 +265,10 @@ const DocumentsPage = () => {
Download
-