'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 && (
)}
{file.contentSnippet}
{!isPublicShare && (
Share
)}
Preview (PDFs only)
{isDownloading ? 'Cancel' : 'Download'}
{isPreviewOpen && file.fileType === 'pdf' && (
)}
{!isPublicShare && (
)}
>
);
}