summaryrefslogtreecommitdiff
path: root/lib/dolce
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dolce')
-rw-r--r--lib/dolce/components/file-upload-progress-list.tsx11
-rw-r--r--lib/dolce/dialogs/add-detail-drawing-dialog.tsx69
-rw-r--r--lib/dolce/dialogs/b4-bulk-upload-dialog.tsx6
-rw-r--r--lib/dolce/dialogs/b4-upload-validation-dialog.tsx30
-rw-r--r--lib/dolce/utils/upload-with-progress.ts7
5 files changed, 107 insertions, 16 deletions
diff --git a/lib/dolce/components/file-upload-progress-list.tsx b/lib/dolce/components/file-upload-progress-list.tsx
index d54e9eaa..7354c85b 100644
--- a/lib/dolce/components/file-upload-progress-list.tsx
+++ b/lib/dolce/components/file-upload-progress-list.tsx
@@ -85,7 +85,16 @@ function FileUploadProgressItem({ fileProgress }: FileUploadProgressItemProps) {
{/* Progress Bar */}
{status === "uploading" && (
- <Progress value={progress} className="h-1.5" />
+ <>
+ <Progress value={progress} className="h-1.5" />
+ {/* 90% 이상일 때 추가 안내 메시지 */}
+ {progress >= 90 && progress < 100 && (
+ <p className="text-xs text-muted-foreground flex items-center gap-1">
+ <Loader2 className="h-3 w-3 animate-spin" />
+ 서버에서 DOLCE API로 전송 중...
+ </p>
+ )}
+ </>
)}
{/* 에러 메시지 */}
diff --git a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx
index 2f7f15a7..2454b1ba 100644
--- a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx
+++ b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx
@@ -82,6 +82,7 @@ export function AddDetailDrawingDialog({
const [drawingUsage, setDrawingUsage] = useState<string>("");
const [registerKind, setRegisterKind] = useState<string>("");
const [revision, setRevision] = useState<string>("");
+ const [revisionError, setRevisionError] = useState<string>("");
const [isSubmitting, setIsSubmitting] = useState(false);
// 파일 업로드 훅 사용 (진행도 추적)
@@ -96,11 +97,54 @@ export function AddDetailDrawingDialog({
isDragActive,
} = useFileUploadWithProgress();
+ // Revision 유효성 검증 함수
+ const validateRevision = (value: string): string => {
+ if (!value.trim()) {
+ return "Revision을 입력하세요";
+ }
+
+ const upperValue = value.toUpperCase().trim();
+
+ // A-Z 패턴 (단일 알파벳)
+ if (/^[A-Z]$/.test(upperValue)) {
+ return "";
+ }
+
+ // R00-R99 패턴
+ if (/^R\d{2}$/.test(upperValue)) {
+ return "";
+ }
+
+ return "올바른 형식이 아닙니다 (A-Z 또는 R00-R99)";
+ };
+
+ // Revision 입력 핸들러 (자동 변환 포함)
+ const handleRevisionChange = (value: string) => {
+ let processedValue = value.toUpperCase().trim();
+
+ // R1~R9 입력시 R01~R09로 자동 변환
+ const rNumberMatch = processedValue.match(/^R(\d)$/);
+ if (rNumberMatch) {
+ processedValue = `R0${rNumberMatch[1]}`;
+ }
+
+ setRevision(processedValue);
+
+ // 값이 있을 때만 validation
+ if (processedValue) {
+ const error = validateRevision(processedValue);
+ setRevisionError(error);
+ } else {
+ setRevisionError("");
+ }
+ };
+
// 폼 초기화
const resetForm = () => {
setDrawingUsage("");
setRegisterKind("");
setRevision("");
+ setRevisionError("");
clearFiles();
};
@@ -119,8 +163,18 @@ export function AddDetailDrawingDialog({
}
if (!revision.trim()) {
toast.error("Revision을 입력하세요");
+ setRevisionError("Revision을 입력하세요");
+ return;
+ }
+
+ // Revision 형식 검증
+ const revisionValidationError = validateRevision(revision);
+ if (revisionValidationError) {
+ toast.error(revisionValidationError);
+ setRevisionError(revisionValidationError);
return;
}
+
if (files.length === 0) {
toast.error("최소 1개 이상의 파일을 첨부해야 합니다");
return;
@@ -222,6 +276,8 @@ export function AddDetailDrawingDialog({
const handleDrawingUsageChange = (value: string) => {
setDrawingUsage(value);
setRegisterKind("");
+ setRevision("");
+ setRevisionError("");
};
// 현재 선택 가능한 DrawingUsage 및 RegisterKind 옵션
@@ -302,10 +358,21 @@ export function AddDetailDrawingDialog({
<Label>Revision</Label>
<Input
value={revision}
- onChange={(e) => setRevision(e.target.value)}
+ onChange={(e) => handleRevisionChange(e.target.value)}
placeholder="예: A, B, R00, R01"
disabled={!registerKind}
+ className={revisionError ? "border-red-500 focus-visible:ring-red-500" : ""}
/>
+ {revisionError && (
+ <p className="text-sm text-red-500 flex items-center gap-1">
+ {revisionError}
+ </p>
+ )}
+ {!revisionError && revision && (
+ <p className="text-sm text-green-600 flex items-center gap-1">
+ ✓ 올바른 형식입니다
+ </p>
+ )}
</div>
{/* 파일 업로드 */}
diff --git a/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx b/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx
index cd336e92..75b221da 100644
--- a/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx
+++ b/lib/dolce/dialogs/b4-bulk-upload-dialog.tsx
@@ -591,6 +591,12 @@ export function B4BulkUploadDialog({
<span>{uploadProgress}%</span>
</div>
<Progress value={uploadProgress} className="h-2" />
+ {/* 90% 이상일 때 추가 안내 메시지 */}
+ {uploadProgress >= 90 && uploadProgress < 100 && (
+ <p className="text-xs text-muted-foreground text-center pt-2">
+ 서버에서 DOLCE API로 전송 중입니다...
+ </p>
+ )}
</div>
</div>
)}
diff --git a/lib/dolce/dialogs/b4-upload-validation-dialog.tsx b/lib/dolce/dialogs/b4-upload-validation-dialog.tsx
index b274d604..f3a7c70a 100644
--- a/lib/dolce/dialogs/b4-upload-validation-dialog.tsx
+++ b/lib/dolce/dialogs/b4-upload-validation-dialog.tsx
@@ -39,8 +39,11 @@ interface B4UploadValidationDialogProps {
/**
* B4 파일명 검증 함수
- * 형식: [버림] [DrawingNo] [RevNo].[확장자]
- * 예시: "testfile GTT-DE-007 R01.pdf" → DrawingNo: "GTT-DE-007", RevNo: "R01"
+ * 형식: [버림] [문서번호토큰1] [문서번호토큰2] ... [리비전번호].[확장자]
+ * 예시: "testfile GTT DE 007 R01.pdf" → DrawingNo: "GTT-DE-007", RevNo: "R01"
+ * - 첫 번째 토큰은 버림
+ * - 마지막 토큰은 RevNo
+ * - 중간 토큰들을 "-"로 연결하여 DrawingNo 생성
*/
export function validateB4FileName(fileName: string): {
valid: boolean;
@@ -57,23 +60,25 @@ export function validateB4FileName(fileName: string): {
};
}
- const extension = fileName.substring(lastDotIndex + 1);
const nameWithoutExt = fileName.substring(0, lastDotIndex);
// 공백으로 분리
const parts = nameWithoutExt.split(" ").filter(p => p.trim() !== "");
- // 최소 3개 파트 필요: [버림], DrawingNo, RevNo
+ // 최소 3개 파트 필요: [버림], [문서번호토큰], [RevNo]
if (parts.length < 3) {
return {
valid: false,
- error: `공백이 최소 2개 있어야 합니다 (현재: ${parts.length - 1}개). 형식: [버림] [DrawingNo] [RevNo].[확장자]`,
+ error: `공백이 최소 2개 있어야 합니다 (현재: ${parts.length - 1}개). 형식: [버림] [문서번호토큰들...] [RevNo].[확장자]`,
};
}
// 첫 번째 토큰은 버림
- const drawingNo = parts[1];
- const revNo = parts[2];
+ // 마지막 토큰은 RevNo
+ // 중간 토큰들을 "-"로 연결하여 DrawingNo 생성
+ const revNo = parts[parts.length - 1];
+ const drawingTokens = parts.slice(1, parts.length - 1);
+ const drawingNo = drawingTokens.join("-");
// 필수 항목이 비어있지 않은지 확인
if (!drawingNo || drawingNo.trim() === "") {
@@ -307,16 +312,19 @@ export function B4UploadValidationDialog({
📋 올바른 파일명 형식
</div>
<code className="text-xs text-blue-700 dark:text-blue-300">
- [버림] [DrawingNo] [RevNo].[확장자]
+ [버림] [문서번호토큰1] [문서번호토큰2] ... [RevNo].[확장자]
</code>
<div className="text-xs text-blue-600 dark:text-blue-400 mt-1">
- 예: testfile GTT-DE-007 R01.pdf
+ 예: testfile GTT DE 007 R01.pdf → DrawingNo: GTT-DE-007, Rev: R01
</div>
<div className="text-xs text-blue-600 dark:text-blue-400 mt-1">
- ※ 첫 번째 단어는 무시되며, 공백으로 구분됩니다
+ ※ 첫 번째 단어는 무시됩니다
</div>
<div className="text-xs text-blue-600 dark:text-blue-400 mt-1">
- ※ 네 번째 이상의 단어가 있으면 무시됩니다
+ ※ 마지막 단어는 리비전 번호(RevNo)입니다
+ </div>
+ <div className="text-xs text-blue-600 dark:text-blue-400 mt-1">
+ ※ 중간의 모든 단어는 &quot;-&quot;로 연결되어 문서번호(DrawingNo)가 됩니다
</div>
</div>
</div>
diff --git a/lib/dolce/utils/upload-with-progress.ts b/lib/dolce/utils/upload-with-progress.ts
index 1204bf36..c86ed8a0 100644
--- a/lib/dolce/utils/upload-with-progress.ts
+++ b/lib/dolce/utils/upload-with-progress.ts
@@ -46,11 +46,12 @@ export async function uploadFilesWithProgress({
// 전체 업로드 진행도
// 주의: xhr.upload.progress는 클라이언트→서버 전송만 추적
- // 서버에서 DOLCE API로 재업로드하는 과정은 별도 (추적 불가)
+ // 서버에서 DOLCE API로 재업로드하는 과정은 별도 (Node.js fetch는 업로드 진행도 추적 미지원)
+ // → UI에서 90% 이상일 때 "서버에서 DOLCE API로 전송 중..." 메시지 표시
xhr.upload.addEventListener("progress", (event) => {
if (event.lengthComputable) {
- // 전송 완료 = 서버에 도착 (실제 처리 시작)
- // 서버 처리를 위해 최대 95%까지만 표시
+ // 전송 완료 = 서버에 도착 (실제 DOLCE API 업로드 시작)
+ // 서버 처리를 위해 최대 95%까지만 표시 (나머지 5%는 서버→DOLCE 업로드)
const totalProgress = Math.min((event.loaded / event.total) * 95, 95);
// 현재 업로드 중인 파일 인덱스 추정