'use client' import { useState, useRef, useCallback } from 'react' import { Camera, Upload, X, FileImage } from 'lucide-react' interface FileUploadProps { onFileSelect: (file: File) => void onFileRemove?: () => void selectedFile?: File | null accept?: string maxSize?: number // in bytes className?: string disabled?: boolean tripId: number expenseId?: number } interface UploadResponse { success: boolean file_url: string thumbnail_url: string metadata: { filename: string file_size: number original_size?: [number, number] resized?: boolean new_size?: [number, number] format: string } } export default function FileUpload({ onFileSelect, onFileRemove, selectedFile, accept = 'image/*', maxSize = 5 * 1024 * 1024, // 5MB className = '', disabled = false, tripId, expenseId }: FileUploadProps) { const [dragActive, setDragActive] = useState(false) const [uploading, setUploading] = useState(false) const [uploadError, setUploadError] = useState(null) const [uploadedUrl, setUploadedUrl] = useState(null) const [thumbnailUrl, setThumbnailUrl] = useState(null) const [preview, setPreview] = useState(null) const fileInputRef = useRef(null) // Create preview when file is selected const createPreview = useCallback((file: File) => { if (file && file.type.startsWith('image/')) { const reader = new FileReader() reader.onloadend = () => { setPreview(reader.result as string) } reader.readAsDataURL(file) } else { setPreview(null) } }, []) // Validate file const validateFile = useCallback((file: File): string | null => { if (file.size > maxSize) { return `File size too large. Maximum is ${maxSize / (1024 * 1024)}MB` } if (accept && !file.type.match(accept.replace('*', '.*'))) { return `File type not allowed. Accepted types: ${accept}` } return null }, [maxSize, accept]) // Handle file selection const handleFileSelect = useCallback(async (file: File) => { setUploadError(null) const validationError = validateFile(file) if (validationError) { setUploadError(validationError) return } createPreview(file) onFileSelect(file) }, [validateFile, createPreview, onFileSelect]) // Handle file input change const handleInputChange = useCallback((e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { handleFileSelect(file) } }, [handleFileSelect]) // Handle drag events const handleDrag = useCallback((e: React.DragEvent) => { e.preventDefault() e.stopPropagation() if (e.type === 'dragenter' || e.type === 'dragover') { setDragActive(true) } else if (e.type === 'dragleave') { setDragActive(false) } }, []) // Handle drop const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setDragActive(false) if (disabled) return const file = e.dataTransfer.files?.[0] if (file) { handleFileSelect(file) } }, [disabled, handleFileSelect]) // Handle camera capture const handleCameraCapture = useCallback(() => { if (disabled) return const input = document.createElement('input') input.type = 'file' input.accept = 'image/*' input.capture = 'environment' // Use back camera by default input.onchange = (e) => { const file = (e.target as HTMLInputElement).files?.[0] if (file) { handleFileSelect(file) } } input.click() }, [disabled, handleFileSelect]) // Remove file const handleRemove = useCallback(() => { setPreview(null) setUploadError(null) setUploadedUrl(null) setThumbnailUrl(null) onFileRemove?.() }, [onFileRemove]) // Click to upload const handleClick = useCallback(() => { if (disabled || uploading) return fileInputRef.current?.click() }, [disabled, uploading]) // Format file size const formatFileSize = useCallback((bytes: number) => { 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] }, []) return (
{!preview ? ( // Upload area
{uploading ? (
) : ( )}
{uploading ? (

Uploading receipt...

) : ( <>

Drag and drop receipt image here, or click to select

Supports: JPG, PNG, WebP (max {formatFileSize(maxSize)})

)}
{/* Camera button for mobile */} {!uploading && !disabled && ( )}
{uploadError && (
{uploadError}
)}
) : ( // Preview area
Receipt preview {/* Remove button */} {/* File info overlay */}
{selectedFile && (
{selectedFile.name} ({formatFileSize(selectedFile.size)})
)}
{/* Upload status */} {uploading && (

Uploading receipt image...

)} {/* Upload error */} {uploadError && (

{uploadError}

)} {/* Re-upload option */} {!uploading && !disabled && (
)}
)}
) }