'use client'
import { useState } from 'react'
import { trpc } from '@/lib/trpc/client'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Skeleton } from '@/components/ui/skeleton'
import {
FileText,
Video,
File,
Download,
ExternalLink,
Play,
FileImage,
Loader2,
AlertCircle,
X,
} from 'lucide-react'
import { cn } from '@/lib/utils'
interface ProjectFile {
id: string
fileType: 'EXEC_SUMMARY' | 'PRESENTATION' | 'VIDEO' | 'OTHER' | 'BUSINESS_PLAN' | 'VIDEO_PITCH' | 'SUPPORTING_DOC'
fileName: string
mimeType: string
size: number
bucket: string
objectKey: string
}
interface FileViewerProps {
files: ProjectFile[]
className?: string
}
function formatFileSize(bytes: number): string {
if (bytes === 0) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
function getFileIcon(fileType: string, mimeType: string) {
if (mimeType.startsWith('video/')) return Video
if (mimeType.startsWith('image/')) return FileImage
if (mimeType === 'application/pdf') return FileText
if (fileType === 'EXEC_SUMMARY' || fileType === 'PRESENTATION') return FileText
if (fileType === 'VIDEO') return Video
return File
}
function getFileTypeLabel(fileType: string) {
switch (fileType) {
case 'EXEC_SUMMARY':
return 'Executive Summary'
case 'PRESENTATION':
return 'Presentation'
case 'VIDEO':
return 'Video'
case 'BUSINESS_PLAN':
return 'Business Plan'
case 'VIDEO_PITCH':
return 'Video Pitch'
case 'SUPPORTING_DOC':
return 'Supporting Document'
default:
return 'Attachment'
}
}
export function FileViewer({ files, className }: FileViewerProps) {
if (files.length === 0) {
return (
No files attached
This project has no files uploaded yet
)
}
// Sort files by type order
const sortOrder = ['EXEC_SUMMARY', 'BUSINESS_PLAN', 'PRESENTATION', 'VIDEO', 'VIDEO_PITCH', 'SUPPORTING_DOC', 'OTHER']
const sortedFiles = [...files].sort(
(a, b) => sortOrder.indexOf(a.fileType) - sortOrder.indexOf(b.fileType)
)
return (
Project Files
{sortedFiles.map((file) => (
))}
)
}
function FileItem({ file }: { file: ProjectFile }) {
const [showPreview, setShowPreview] = useState(false)
const Icon = getFileIcon(file.fileType, file.mimeType)
const { data: urlData, isLoading: isLoadingUrl } = trpc.file.getDownloadUrl.useQuery(
{ bucket: file.bucket, objectKey: file.objectKey },
{ enabled: showPreview }
)
const canPreview = file.mimeType.startsWith('video/') || file.mimeType === 'application/pdf'
return (
{file.fileName}
{getFileTypeLabel(file.fileType)}
{formatFileSize(file.size)}
{canPreview && (
)}
{/* Preview area */}
{showPreview && (
{isLoadingUrl ? (
) : urlData?.url ? (
) : (
)}
)}
)
}
function FileDownloadButton({ file }: { file: ProjectFile }) {
const [downloading, setDownloading] = useState(false)
const { refetch } = trpc.file.getDownloadUrl.useQuery(
{ bucket: file.bucket, objectKey: file.objectKey },
{ enabled: false }
)
const handleDownload = async () => {
setDownloading(true)
try {
const result = await refetch()
if (result.data?.url) {
// Open in new tab for download
window.open(result.data.url, '_blank')
}
} catch (error) {
console.error('Failed to get download URL:', error)
} finally {
setDownloading(false)
}
}
return (
)
}
function FilePreview({ file, url }: { file: ProjectFile; url: string }) {
if (file.mimeType.startsWith('video/')) {
return (
)
}
if (file.mimeType === 'application/pdf') {
return (
)
}
return (
Preview not available for this file type
)
}
// Compact file list for smaller views
export function FileList({ files, className }: FileViewerProps) {
if (files.length === 0) return null
return (
{files.map((file) => {
const Icon = getFileIcon(file.fileType, file.mimeType)
return (
)
})}
)
}
function CompactFileItem({ file }: { file: ProjectFile }) {
const [loading, setLoading] = useState(false)
const Icon = getFileIcon(file.fileType, file.mimeType)
const { refetch } = trpc.file.getDownloadUrl.useQuery(
{ bucket: file.bucket, objectKey: file.objectKey },
{ enabled: false }
)
const handleClick = async () => {
setLoading(true)
try {
const result = await refetch()
if (result.data?.url) {
window.open(result.data.url, '_blank')
}
} catch (error) {
console.error('Failed to get download URL:', error)
} finally {
setLoading(false)
}
}
return (
)
}
export function FileViewerSkeleton() {
return (
{[1, 2, 3].map((i) => (
))}
)
}