diff options
Diffstat (limited to 'lib/dolce/hooks/use-file-upload.ts')
| -rw-r--r-- | lib/dolce/hooks/use-file-upload.ts | 107 |
1 files changed, 0 insertions, 107 deletions
diff --git a/lib/dolce/hooks/use-file-upload.ts b/lib/dolce/hooks/use-file-upload.ts deleted file mode 100644 index 38556cb9..00000000 --- a/lib/dolce/hooks/use-file-upload.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { useState, useCallback } from "react"; -import { useDropzone, FileRejection } from "react-dropzone"; -import { toast } from "sonner"; - -interface UseFileUploadOptions { - onFilesAdded?: (files: File[]) => void; -} - -export function useFileUpload(options: UseFileUploadOptions = {}) { - const [files, setFiles] = useState<File[]>([]); - - // 파일 검증 - const validateFiles = useCallback((filesToValidate: File[]): { valid: File[]; invalid: string[] } => { - const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB - const FORBIDDEN_EXTENSIONS = ['exe', 'com', 'dll', 'vbs', 'js', 'asp', 'aspx', 'bat', 'cmd']; - - const validFiles: File[] = []; - const invalidFiles: string[] = []; - - filesToValidate.forEach((file) => { - // 크기 검증 - if (file.size > MAX_FILE_SIZE) { - invalidFiles.push(`${file.name}: 파일 크기가 1GB를 초과합니다`); - return; - } - - // 확장자 검증 (블랙리스트) - const extension = file.name.split('.').pop()?.toLowerCase(); - if (extension && FORBIDDEN_EXTENSIONS.includes(extension)) { - invalidFiles.push(`${file.name}: 금지된 파일 형식입니다 (.${extension})`); - return; - } - - validFiles.push(file); - }); - - return { valid: validFiles, invalid: invalidFiles }; - }, []); - - // 파일 드롭 핸들러 - const onDrop = useCallback((acceptedFiles: File[], rejectedFiles: FileRejection[]) => { - const { valid: validFiles, invalid: invalidMessages } = validateFiles(acceptedFiles); - - // 거부된 파일 처리 - if (rejectedFiles.length > 0) { - rejectedFiles.forEach((rejected) => { - const errorMsg = rejected.errors?.[0]?.message || "파일이 거부되었습니다"; - toast.error(`${rejected.file.name}: ${errorMsg}`); - }); - } - - // 유효하지 않은 파일 메시지 표시 - if (invalidMessages.length > 0) { - invalidMessages.forEach((msg) => toast.error(msg)); - } - - if (validFiles.length > 0) { - // 중복 제거 - const existingNames = new Set(files.map((f) => f.name)); - const newFiles = validFiles.filter((f) => !existingNames.has(f.name)); - - if (newFiles.length === 0) { - toast.error("이미 선택된 파일입니다"); - return; - } - - setFiles((prev) => { - const updated = [...prev, ...newFiles]; - options.onFilesAdded?.(updated); - return updated; - }); - toast.success(`${newFiles.length}개 파일이 선택되었습니다`); - } - }, [files, validateFiles, options]); - - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - multiple: true, - maxSize: 1024 * 1024 * 1024, // 1GB - }); - - // 파일 제거 - const removeFile = useCallback((index: number) => { - setFiles((prev) => prev.filter((_, i) => i !== index)); - }, []); - - // 전체 파일 제거 - const clearFiles = useCallback(() => { - setFiles([]); - }, []); - - // 파일 배열 직접 설정 - const setFileList = useCallback((newFiles: File[]) => { - setFiles(newFiles); - }, []); - - return { - files, - setFiles: setFileList, - removeFile, - clearFiles, - getRootProps, - getInputProps, - isDragActive, - }; -} - |
