Spaces:
Sleeping
Sleeping
| import { useState, useRef, useCallback } from 'react'; | |
| import { toast } from 'sonner'; | |
| interface UseFileUploadOptions { | |
| acceptedTypes?: string[]; | |
| maxSizeMB?: number; | |
| onFileSelected?: (file: File) => void; | |
| } | |
| interface UseFileUploadResult { | |
| fileInputRef: React.RefObject<HTMLInputElement>; | |
| isSelecting: boolean; | |
| selectedFile: File | null; | |
| triggerFileSelect: () => void; | |
| handleFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void; | |
| clearSelectedFile: () => void; | |
| } | |
| /** | |
| * A custom hook for handling file uploads with validation | |
| */ | |
| export function useFileUpload(options: UseFileUploadOptions = {}): UseFileUploadResult { | |
| const { | |
| acceptedTypes = ['.xlsx', '.xls', '.csv'], | |
| maxSizeMB = 10, | |
| onFileSelected | |
| } = options; | |
| const fileInputRef = useRef<HTMLInputElement>(null); | |
| const [isSelecting, setIsSelecting] = useState(false); | |
| const [selectedFile, setSelectedFile] = useState<File | null>(null); | |
| const triggerFileSelect = useCallback(() => { | |
| if (fileInputRef.current) { | |
| fileInputRef.current.click(); | |
| } | |
| }, []); | |
| const clearSelectedFile = useCallback(() => { | |
| setSelectedFile(null); | |
| if (fileInputRef.current) { | |
| fileInputRef.current.value = ''; | |
| } | |
| }, []); | |
| const handleFileChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { | |
| setIsSelecting(true); | |
| try { | |
| const file = event.target.files?.[0]; | |
| if (!file) { | |
| return; | |
| } | |
| // Validate file type | |
| const fileExtension = file.name.substring(file.name.lastIndexOf('.')).toLowerCase(); | |
| if (acceptedTypes.length > 0 && !acceptedTypes.includes(fileExtension)) { | |
| toast.error(`Invalid file type. Accepted types: ${acceptedTypes.join(', ')}`); | |
| return; | |
| } | |
| // Validate file size | |
| const maxSizeBytes = maxSizeMB * 1024 * 1024; | |
| if (file.size > maxSizeBytes) { | |
| toast.error(`File size too large. Maximum size is ${maxSizeMB}MB`); | |
| return; | |
| } | |
| // Set the selected file | |
| setSelectedFile(file); | |
| // Call the onFileSelected callback if provided | |
| if (onFileSelected) { | |
| onFileSelected(file); | |
| } | |
| // Reset input value | |
| event.target.value = ''; | |
| } catch (error) { | |
| console.error('Error selecting file:', error); | |
| toast.error('Error selecting file. Please try again.'); | |
| } finally { | |
| setIsSelecting(false); | |
| } | |
| }, [acceptedTypes, maxSizeMB, onFileSelected]); | |
| return { | |
| fileInputRef, | |
| isSelecting, | |
| selectedFile, | |
| triggerFileSelect, | |
| handleFileChange, | |
| clearSelectedFile, | |
| }; | |
| } | |
| export default useFileUpload; |