/* ┌──────────────────────────────────────────────────────────────────────────────┐ │ @author: Davidson Gomes │ │ @file: /app/chat/components/FileUpload.tsx │ │ Developed by: Davidson Gomes │ │ Creation date: August 24, 2025 │ │ Contact: contato@evolution-api.com │ ├──────────────────────────────────────────────────────────────────────────────┤ │ @copyright © Evolution API 2025. All rights reserved. │ │ Licensed under the Apache License, Version 2.0 │ │ │ │ You may not use this file except in compliance with the License. │ │ You may obtain a copy of the License at │ │ │ │ http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ Unless required by applicable law or agreed to in writing, software │ │ distributed under the License is distributed on an "AS IS" BASIS, │ │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ├──────────────────────────────────────────────────────────────────────────────┤ │ @important │ │ For any future changes to the code in this file, it is recommended to │ │ include, together with the modification, the information of the developer │ │ who changed it and the date of modification. │ └──────────────────────────────────────────────────────────────────────────────┘ */ "use client"; import React, { useState, useRef, useEffect } from "react"; import { FileData, formatFileSize, isImageFile } from "@/lib/file-utils"; import { Paperclip, X, Image, File, FileText } from "lucide-react"; import { toast } from "@/hooks/use-toast"; interface FileUploadProps { onFilesSelected: (files: FileData[]) => void; maxFileSize?: number; maxFiles?: number; className?: string; reset?: boolean; } export function FileUpload({ onFilesSelected, maxFileSize = 10 * 1024 * 1024, // 10MB maxFiles = 5, className = "", reset = false, // Default false }: FileUploadProps) { const [selectedFiles, setSelectedFiles] = useState([]); const fileInputRef = useRef(null); useEffect(() => { if (reset && selectedFiles.length > 0) { setSelectedFiles([]); if (fileInputRef.current) { fileInputRef.current.value = ""; } } }, [reset]); const handleFileChange = async (e: React.ChangeEvent) => { if (!e.target.files || e.target.files.length === 0) return; const newFiles = Array.from(e.target.files); if (selectedFiles.length + newFiles.length > maxFiles) { toast({ title: `You can only attach up to ${maxFiles} files.`, variant: "destructive", }); return; } const validFiles: FileData[] = []; for (const file of newFiles) { if (file.size > maxFileSize) { toast({ title: `File ${file.name} exceeds the maximum size of ${formatFileSize(maxFileSize)}.`, variant: "destructive", }); continue; } try { const reader = new FileReader(); const readFile = new Promise((resolve, reject) => { reader.onload = () => { const base64 = reader.result as string; const base64Data = base64.split(',')[1]; resolve(base64Data); }; reader.onerror = reject; }); reader.readAsDataURL(file); const base64Data = await readFile; const previewUrl = URL.createObjectURL(file); validFiles.push({ filename: file.name, content_type: file.type, data: base64Data, size: file.size, preview_url: previewUrl }); } catch (error) { console.error("Error processing file:", error); toast({ title: `Error processing file ${file.name}`, variant: "destructive", }); } } if (validFiles.length > 0) { const updatedFiles = [...selectedFiles, ...validFiles]; setSelectedFiles(updatedFiles); onFilesSelected(updatedFiles); } if (fileInputRef.current) { fileInputRef.current.value = ""; } }; const removeFile = (index: number) => { const updatedFiles = selectedFiles.filter((_, i) => i !== index); setSelectedFiles(updatedFiles); onFilesSelected(updatedFiles); }; return (
{selectedFiles.length > 0 && (
{selectedFiles.map((file, index) => (
{isImageFile(file.content_type) ? ( ) : file.content_type === 'application/pdf' ? ( ) : ( )} {file.filename} ({formatFileSize(file.size)})
))}
)} {selectedFiles.length < maxFiles && ( )}
); }