'use client'; import * as React from 'react'; import ReactDOM from 'react-dom'; import { FileText, Download, X, Eye, Loader2, File as FileIcon, Presentation, Share2 } from 'lucide-react'; import { TableRow, TableCell } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import type { File as FileType } from '@/app/api/files/route'; import { useToast } from "@/hooks/use-toast" import { Progress } from './ui/progress'; import { cn } from '@/lib/utils'; import dynamic from 'next/dynamic'; import { Badge } from './ui/badge'; import { Checkbox } from './ui/checkbox'; import { ShareDialog } from './share-dialog'; const PdfThumbnail = dynamic(() => import('./pdf-thumbnail').then(mod => mod.PdfThumbnail), { ssr: false, loading: () =>
}); function PdfLoader() { const [isMounted, setIsMounted] = React.useState(false); React.useEffect(() => { setIsMounted(true); return () => setIsMounted(false); }, []); if (!isMounted) { return null; } return ReactDOM.createPortal(
, document.body ); } const PdfViewer = dynamic(() => import('./pdf-viewer').then(mod => mod.PdfViewer), { ssr: false, loading: () => , }); interface FileItemProps extends React.HTMLAttributes { file: FileType; isSelected: boolean; onSelectItem: (id: string, isSelected: boolean) => void; isSelectionActive: boolean; isPublicShare?: boolean; } const fileTypeConfig = { pdf: { icon: FileText, color: 'destructive' as const, label: 'PDF', }, docx: { icon: FileText, color: 'default' as const, label: 'DOCX', }, pptx: { icon: Presentation, color: 'secondary' as const, label: 'PPTX', }, other: { icon: FileIcon, color: 'outline' as const, label: 'File' } } export function FileItem({ file, className, isSelected, onSelectItem, isSelectionActive, isPublicShare, ...props }: FileItemProps) { const [downloadProgress, setDownloadProgress] = React.useState(null); const [isDownloading, setIsDownloading] = React.useState(false); const downloadAbortController = React.useRef(null); const [isPreviewOpen, setIsPreviewOpen] = React.useState(false); const [isShareOpen, setIsShareOpen] = React.useState(false); const { toast } = useToast(); const handleRowClick = (e: React.MouseEvent) => { if ((e.target as HTMLElement).closest('[role="checkbox"]') || (e.target as HTMLElement).closest('button')) { return; } if (isSelectionActive) { onSelectItem(file.id, !isSelected); } else if (file.fileType === 'pdf') { setIsPreviewOpen(true); } } const handleDownload = async () => { if (isDownloading) { if (downloadAbortController.current) { downloadAbortController.current.abort(); } return; } setIsDownloading(true); setDownloadProgress(0); const controller = new AbortController(); downloadAbortController.current = controller; try { const response = await fetch(file.path, { signal: controller.signal, }); if (!response.ok) { throw new Error('Network response was not ok'); } if (!response.body) { throw new Error('Response body is null'); } const contentLength = response.headers.get('content-length'); const totalSize = contentLength ? parseInt(contentLength, 10) : 0; let loaded = 0; const reader = response.body.getReader(); const chunks: Uint8Array[] = []; while (true) { const { done, value } = await reader.read(); if (done) { break; } chunks.push(value); loaded += value.length; if (totalSize > 0) { const progress = Math.round((loaded / totalSize) * 100); setDownloadProgress(progress); } } const blob = new Blob(chunks); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = file.name; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); setDownloadProgress(100); } catch (error: any) { if (error.name === 'AbortError') { console.log('Download was aborted.'); } else { toast({ variant: "destructive", title: "Download Error", description: "There was a problem downloading the file.", }); console.error('Download error:', error); } } finally { setIsDownloading(false); setDownloadProgress(null); downloadAbortController.current = null; } }; const config = fileTypeConfig[file.fileType] ?? fileTypeConfig.other; const Icon = config.icon; const FileNameDisplay = ( {e.stopPropagation(); if (file.fileType === 'pdf' && !isSelectionActive) setIsPreviewOpen(true);}}>{file.name} ) const handleShareClick = (e: React.MouseEvent) => { e.stopPropagation(); setIsShareOpen(true); } return ( <> e.stopPropagation()}> onSelectItem(file.id, Boolean(checked))} aria-label={`Select file ${file.name}`} />
{file.fileType === 'pdf' ? ( {FileNameDisplay} ) : FileNameDisplay } {config.label}
{isDownloading && downloadProgress !== null && (
{downloadProgress}%
)}

{file.contentSnippet}

{!isPublicShare && (

Share

)}

Preview (PDFs only)

{isDownloading ? 'Cancel' : 'Download'}

{isPreviewOpen && file.fileType === 'pdf' && ( )} {!isPublicShare && ( )} ); }