From aba0a396a872771d6b71cf05626ba38dc0691c51 Mon Sep 17 00:00:00 2001 From: Seok93 Date: Fri, 27 Sep 2024 17:02:03 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20#115=20=EC=9D=BC=EC=A0=95=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=A1=9C=EB=93=9C=20Validation=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/modal/task/ModalTaskForm.tsx | 44 ++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/components/modal/task/ModalTaskForm.tsx b/src/components/modal/task/ModalTaskForm.tsx index 3ebac4e8..780fd5c9 100644 --- a/src/components/modal/task/ModalTaskForm.tsx +++ b/src/components/modal/task/ModalTaskForm.tsx @@ -17,6 +17,7 @@ import useAxios from '@hooks/useAxios'; import { useReadStatuses } from '@hooks/query/useStatusQuery'; import { useReadStatusTasks } from '@hooks/query/useTaskQuery'; import { useReadProjectUserRoleList } from '@hooks/query/useProjectQuery'; +import Validator from '@utils/Validator'; import { convertBytesToString } from '@utils/converter'; import { findUserByProject } from '@services/projectService'; @@ -106,22 +107,46 @@ export default function ModalTaskForm({ formId, project, taskId, onSubmit }: Mod setValue('assignees', assigneesIdList); }; - const updateFiles = (newFiles: FileList) => { + // ToDo: 일정 수정에서도 사용하도록 분리할 것, 어디에 분리하는게 좋으려나? + const isValidTaskFile = (file: File) => { + if (!Validator.isValidFileName(file.name)) { + toastWarn( + `${file.name}은/는 업로드 할 수 없습니다. 파일명은 한글, 영어, 숫자, 특수기호(.-_), 공백문자만 가능합니다.`, + ); + return false; + } + + if (!Validator.isValidFileExtension(TASK_SETTINGS.FILE_TYPES, file.type)) { + toastWarn(`${file.name}은/는 업로드 할 수 없습니다. 지원하지 않는 파일 타입입니다.`); + return false; + } + + if (!Validator.isValidFileSize(TASK_SETTINGS.MAX_FILE_SIZE, file.size)) { + toastWarn( + `${file.name}은/는 업로드 할 수 없습니다. 최대 ${convertBytesToString(TASK_SETTINGS.MAX_FILE_SIZE)} 이하의 파일만 업로드 가능합니다.`, + ); + return false; + } + + return true; + }; + + const updateTaskFiles = (newFiles: FileList) => { // 최대 파일 등록 개수 확인 - if (files.length + newFiles.length > TASK_SETTINGS.MAX_FILE_COUNT) { + if (!Validator.isValidFileCount(TASK_SETTINGS.MAX_FILE_COUNT, files.length + newFiles.length)) { return toastWarn(`최대로 등록 가능한 파일수는 ${TASK_SETTINGS.MAX_FILE_COUNT}개입니다.`); } - // 새로운 파일별 파일 크기 확인 & 고유 ID 부여 + // 새로운 파일 Validation & 고유 ID 부여 const originFiles: File[] = files.map(({ file }) => file); const customFiles: CustomFile[] = []; for (let i = 0; i < newFiles.length; i++) { const file = newFiles[i]; - if (file.size > TASK_SETTINGS.MAX_FILE_SIZE) { - return toastWarn(`최대 ${convertBytesToString(TASK_SETTINGS.MAX_FILE_SIZE)} 이하의 파일만 업로드 가능합니다.`); + + if (isValidTaskFile(file)) { + originFiles.push(file); + customFiles.push({ fileId: `${file.name}_${Date.now()}`, fileName: file.name, file }); } - originFiles.push(file); - customFiles.push({ fileId: `${file.name}_${Date.now()}`, fileName: file.name, file }); } setValue('files', originFiles); setFiles((prev) => [...prev, ...customFiles]); @@ -130,13 +155,13 @@ export default function ModalTaskForm({ formId, project, taskId, onSubmit }: Mod const handleFileChange = (e: React.ChangeEvent) => { const { files } = e.target; if (!files || files.length === 0) return; - updateFiles(files); + updateTaskFiles(files); }; const handleFileDrop = (e: React.DragEvent) => { const { files } = e.dataTransfer; if (!files || files.length === 0) return; - updateFiles(files); + updateTaskFiles(files); }; const handleFileDeleteClick = (fileId: string) => { @@ -194,6 +219,7 @@ export default function ModalTaskForm({ formId, project, taskId, onSubmit }: Mod id="files" label="첨부파일" files={files} + accept=".jpg, .jpeg, .png, .svg, .webp, .pdf, .txt, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .hwp, .zip, .rar, .7z, .alz, .egg" onFileChange={handleFileChange} onFileDrop={handleFileDrop} onFileDeleteClick={handleFileDeleteClick}