summaryrefslogtreecommitdiff
path: root/components/ship-vendor-document
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-09-04 06:25:57 +0000
committerjoonhoekim <26rote@gmail.com>2025-09-04 06:25:57 +0000
commit2d4fc5d4c4fb5136b1a90f374e1090658129c8a5 (patch)
treefe4a6af4c1e2c1e5a9d032507af0173d58553308 /components/ship-vendor-document
parente0db6590a73853327d74dff9235a7b915aa27372 (diff)
(김준회) 옥창명 프로 요구사항 반영 - 도면업로드시 특수문자불가 가이드 문구 추가, 실패시 간략한 원인 안내, 기준정보 프로젝트 메뉴에서 getProject 버튼 숨김
Diffstat (limited to 'components/ship-vendor-document')
-rw-r--r--components/ship-vendor-document/add-attachment-dialog.tsx47
-rw-r--r--components/ship-vendor-document/new-revision-dialog.tsx74
2 files changed, 89 insertions, 32 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: &lt; &gt; : &quot; &apos; | ? *
+ </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: &lt; &gt; : &quot; &apos; | ? *
+ </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)