summaryrefslogtreecommitdiff
path: root/lib/dolce/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dolce/hooks')
-rw-r--r--lib/dolce/hooks/use-file-upload.ts107
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,
- };
-}
-