diff options
| author | joonhoekim <26rote@gmail.com> | 2025-09-04 06:25:57 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-09-04 06:25:57 +0000 |
| commit | 2d4fc5d4c4fb5136b1a90f374e1090658129c8a5 (patch) | |
| tree | fe4a6af4c1e2c1e5a9d032507af0173d58553308 | |
| parent | e0db6590a73853327d74dff9235a7b915aa27372 (diff) | |
(김준회) 옥창명 프로 요구사항 반영 - 도면업로드시 특수문자불가 가이드 문구 추가, 실패시 간략한 원인 안내, 기준정보 프로젝트 메뉴에서 getProject 버튼 숨김
3 files changed, 91 insertions, 34 deletions
diff --git a/components/ship-vendor-document/add-attachment-dialog.tsx b/components/ship-vendor-document/add-attachment-dialog.tsx index 1e9bfb51..8c5e17c8 100644 --- a/components/ship-vendor-document/add-attachment-dialog.tsx +++ b/components/ship-vendor-document/add-attachment-dialog.tsx @@ -147,6 +147,9 @@ function FileUploadArea({ <p className="text-xs text-gray-500"> Supports PDF, Word, Excel, Image, Text, ZIP, CAD files (DWG, DXF, STEP, STL, IGES) (max 1GB) </p> + <p className="text-xs text-orange-600 mt-1"> + Note: File names cannot contain these characters: < > : " ' | ? * + </p> <input ref={fileInputRef} type="file" @@ -285,7 +288,49 @@ export function AddAttachmentDialog({ } catch (error) { console.error('❌ Attachment upload error:', error) - toast.error(error instanceof Error ? error.message : "An error occurred while uploading attachments") + + let userMessage = "An error occurred while uploading attachments" + + if (error instanceof Error) { + const message = error.message.toLowerCase() + + // 파일명 관련 에러 (보안상 허용) + if (message.includes("안전하지 않은 파일명") || message.includes("unsafe filename") || + message.includes("filename") && message.includes("invalid")) { + userMessage = "File name contains invalid characters. Please avoid using < > : \" ' | ? * in file names. filename can't start with '..'." + } + // 파일명 길이 에러 (보안상 허용) + else if (message.includes("파일명이 너무 깁니다") || message.includes("filename too long") || + message.includes("파일명") && message.includes("길이")) { + userMessage = "File name is too long. Please use a shorter name (max 255 characters)." + } + // 파일 크기 에러 (보안상 허용) + else if (message.includes("파일 크기가 너무 큽니다") || message.includes("file size") || + message.includes("1gb limit") || message.includes("exceeds") && message.includes("limit")) { + userMessage = "File size is too large. Please use files smaller than 1GB." + } + // 클라이언트측 네트워크 에러 (기존과 같이 처리) + else if (message.includes("network") || message.includes("fetch") || + message.includes("connection") || message.includes("timeout")) { + userMessage = "Network error occurred. Please check your connection and try again." + } + // 서버측 오류는 보안상 일반적인 메시지로 처리 + else if (message.includes("500") || message.includes("server") || + message.includes("database") || message.includes("internal") || + message.includes("security") || message.includes("validation")) { + userMessage = "Please try again later. If the problem persists, please contact the administrator." + } + // 기타 알려진 클라이언트 에러는 원본 메시지 사용 (영어인 경우) + else if (!/[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(error.message) && error.message.length < 200) { + userMessage = error.message + } + // 그 외는 일반적인 메시지 + else { + userMessage = "Please try again later. If the problem persists, please contact the administrator." + } + } + + toast.error(userMessage) } finally { setIsUploading(false) setTimeout(() => setUploadProgress(0), 2000) diff --git a/components/ship-vendor-document/new-revision-dialog.tsx b/components/ship-vendor-document/new-revision-dialog.tsx index a1ddad13..4fe4de98 100644 --- a/components/ship-vendor-document/new-revision-dialog.tsx +++ b/components/ship-vendor-document/new-revision-dialog.tsx @@ -30,13 +30,11 @@ import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { Button } from "@/components/ui/button" import { Progress } from "@/components/ui/progress" -import { Badge } from "@/components/ui/badge" import { Upload, FileText, X, Loader2, - AlertCircle, CheckCircle } from "lucide-react" import { toast } from "sonner" @@ -50,33 +48,7 @@ import { useSession } from "next-auth/react" * -----------------------------------------------------------------------------------------------*/ // 파일 검증 스키마 -const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 50MB -const ACCEPTED_FILE_TYPES = [ - 'application/pdf', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'application/vnd.ms-excel', - 'image/jpeg', - 'image/png', - 'image/gif', - 'text/plain', - 'application/zip', - 'application/x-zip-compressed', - // Presentations - 'application/vnd.ms-powerpoint', // .ppt - 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx - // CAD and Drawing files - 'application/acad', // .dwg - 'image/vnd.dwg', // .dwg (alternative MIME) - 'application/x-autocad', // .dwg (alternative MIME) - 'application/dxf', // .dxf - 'image/vnd.dxf', // .dxf (alternative MIME) - 'application/x-dxf', // .dxf (alternative MIME) - 'application/step', // .step/.stp - 'application/sla', // .stl - 'model/stl', // .stl (alternative MIME) - 'application/iges', // .iges/.igs -] +const MAX_FILE_SIZE = 1024 * 1024 * 1024 // 1GB // drawingKind에 따른 동적 스키마 생성 @@ -235,6 +207,9 @@ function FileUploadArea({ <p className="text-xs text-gray-500"> Supports PDF, Word, Excel, Image, Text, ZIP files (max 1GB) </p> + <p className="text-xs text-orange-600 mt-1"> + Note: File names cannot contain these characters: < > : " ' | ? * + </p> <input ref={fileInputRef} type="file" @@ -322,7 +297,6 @@ export function NewRevisionDialog({ const watchedFiles = form.watch("attachments") const watchedUsage = form.watch("usage") - const watchedUsageType = form.watch("usageType") // 용도 선택에 따른 용도 타입 옵션 업데이트 const usageTypeOptions = React.useMemo(() => { @@ -420,7 +394,45 @@ export function NewRevisionDialog({ } catch (error) { console.error('❌ Upload error:', error) - toast.error(error instanceof Error ? error.message : "An error occurred during upload") + + let userMessage = "An error occurred during upload" + + if (error instanceof Error) { + const message = error.message.toLowerCase() + + // 파일명 관련 에러 (보안상 허용) + if (message.includes("안전하지 않은 파일명") || message.includes("unsafe filename") || + message.includes("filename") && message.includes("invalid")) { + userMessage = "File name contains invalid characters. Please avoid using < > : \" ' | ? * in file names. filename can't start with '..'." + } + // 파일명 길이 에러 (보안상 허용) + else if (message.includes("파일명이 너무 깁니다") || message.includes("filename too long") || + message.includes("파일명") && message.includes("길이")) { + userMessage = "File name is too long. Please use a shorter name (max 255 characters)." + } + // 파일 크기 에러 (보안상 허용) + else if (message.includes("파일 크기가 너무 큽니다") || message.includes("file size") || + message.includes("1gb limit") || message.includes("exceeds") && message.includes("limit")) { + userMessage = "File size is too large. Please use files smaller than 1GB." + } + // 클라이언트측 네트워크 에러 (기존과 같이 처리) + else if (message.includes("network") || message.includes("fetch") || + message.includes("connection") || message.includes("timeout")) { + userMessage = "Network error occurred. Please check your connection and try again." + } + // 서버측 오류는 보안상 일반적인 메시지로 처리 + else if (message.includes("500") || message.includes("server") || + message.includes("database") || message.includes("internal") || + message.includes("security") || message.includes("validation")) { + userMessage = "Please try again later. If the problem persists, please contact the administrator." + } + // 그 외는 일반적인 메시지 + else { + userMessage = "Please try again later. If the problem persists, please contact the administrator." + } + } + + toast.error(userMessage) } finally { setIsUploading(false) setTimeout(() => setUploadProgress(0), 2000) diff --git a/lib/projects/table/projects-table-toolbar-actions.tsx b/lib/projects/table/projects-table-toolbar-actions.tsx index dc55423d..28eee40a 100644 --- a/lib/projects/table/projects-table-toolbar-actions.tsx +++ b/lib/projects/table/projects-table-toolbar-actions.tsx @@ -52,7 +52,7 @@ export function ProjectTableToolbarActions({ table }: ItemsTableToolbarActionsPr return ( <div className="flex items-center gap-2"> - <Button + {/* <Button variant="samsung" size="sm" className="gap-2" @@ -66,7 +66,7 @@ export function ProjectTableToolbarActions({ table }: ItemsTableToolbarActionsPr <span className="hidden sm:inline"> {isLoading ? 'Syncing...' : 'Get Projects'} </span> - </Button> + </Button> */} {/** 4) Export 버튼 */} <Button |
