"use client" import { useCallback, useRef, useState, useEffect } from "react" import { FileUp, X, FileText, FileImage, FileSpreadsheet, File } from "lucide-react" import type { BaseFieldControlProps } from "../types" import { cn } from "@/shared/lib/utils" export type DocumentInputFieldProps = BaseFieldControlProps & { accept?: string } const IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"] function getFileIcon(file: File) { if (IMAGE_TYPES.includes(file.type)) return FileImage if (file.type === "application/pdf") return FileText if ( file.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || file.type === "application/vnd.ms-excel" || file.type === "text/csv" ) return FileSpreadsheet return File } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / (1024 * 1024)).toFixed(1)} MB` } export function DocumentInputField({ value, onChange, onBlur, name, disabled, invalid, accept = "image/*,.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt", }: DocumentInputFieldProps) { const inputRef = useRef(null) const [preview, setPreview] = useState(null) const [isDragging, setIsDragging] = useState(false) const isImage = value && IMAGE_TYPES.includes(value.type) useEffect(() => { if (!value || !isImage) { setPreview(null) return } const url = URL.createObjectURL(value) setPreview(url) return () => URL.revokeObjectURL(url) }, [value, isImage]) const handleFile = useCallback( (file: File | null) => { onChange(file) }, [onChange], ) const handleDrop = useCallback( (e: React.DragEvent) => { e.preventDefault() setIsDragging(false) if (disabled) return const file = e.dataTransfer.files?.[0] ?? null handleFile(file) }, [disabled, handleFile], ) const handleDragOver = useCallback( (e: React.DragEvent) => { e.preventDefault() if (!disabled) setIsDragging(true) }, [disabled], ) const handleDragLeave = useCallback(() => setIsDragging(false), []) const handleClear = useCallback( (e: React.MouseEvent) => { e.stopPropagation() onChange(null) if (inputRef.current) inputRef.current.value = "" }, [onChange], ) const FileIcon = value ? getFileIcon(value) : FileUp return (
!disabled && inputRef.current?.click()} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault() inputRef.current?.click() } }} onDrop={handleDrop} onDragOver={handleDragOver} onDragLeave={handleDragLeave} onBlur={onBlur} aria-invalid={invalid || undefined} className={cn( "relative flex min-h-35 cursor-pointer flex-col items-center justify-center gap-2 rounded-md border border-dashed border-input bg-background p-4 text-sm transition-colors", isDragging && "border-primary bg-primary/5", invalid && "border-destructive", disabled && "pointer-events-none opacity-50", )} > handleFile(e.target.files?.[0] ?? null)} /> {value ? ( <> {isImage && preview ? ( Preview ) : (
{value.name} {formatFileSize(value.size)}
)} {!disabled && ( )} ) : ( <> Click or drag & drop a file Images, PDF, Word, Excel, CSV, or text files )}
) }