diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-25 15:42:00 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-25 15:42:00 +0900 |
| commit | 4586f2cd95f1cd7112cbec80399da8817df0d289 (patch) | |
| tree | 48572a71cb01d3850defb6cab6c616ca545f5f25 /lib/dolce/dialogs/add-detail-drawing-dialog.tsx | |
| parent | 25b2561bf17128b96f023c977efb5cb51da0b4aa (diff) | |
(김준회) dolce: i18n 적용, 상세도면 수정 적용
Diffstat (limited to 'lib/dolce/dialogs/add-detail-drawing-dialog.tsx')
| -rw-r--r-- | lib/dolce/dialogs/add-detail-drawing-dialog.tsx | 465 |
1 files changed, 0 insertions, 465 deletions
diff --git a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx b/lib/dolce/dialogs/add-detail-drawing-dialog.tsx deleted file mode 100644 index 48614ecf..00000000 --- a/lib/dolce/dialogs/add-detail-drawing-dialog.tsx +++ /dev/null @@ -1,465 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogFooter, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; -import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Upload, X, FileIcon, Info } from "lucide-react"; -import { toast } from "sonner"; -import { UnifiedDwgReceiptItem, editDetailDwgReceipt } from "../actions"; -import { v4 as uuidv4 } from "uuid"; -import { useFileUploadWithProgress } from "../hooks/use-file-upload-with-progress"; -import { uploadFilesWithProgress } from "../utils/upload-with-progress"; -import { FileUploadProgressList } from "../components/file-upload-progress-list"; -import { - getB3DrawingUsageOptions, - getB3RegisterKindOptions, - getB4DrawingUsageOptions, - getB4RegisterKindOptions -} from "../utils/code-translator"; - -interface AddDetailDrawingDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; - drawing: UnifiedDwgReceiptItem | null; - vendorCode: string; - userId: string; - userName: string; - userEmail: string; - onComplete: () => void; - drawingKind: "B3" | "B4"; - lng?: string; // i18n support -} - -export function AddDetailDrawingDialog({ - open, - onOpenChange, - drawing, - vendorCode, - userId, - userName, - userEmail, - onComplete, - drawingKind, - lng = "ko", -}: AddDetailDrawingDialogProps) { - 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); - - // 옵션 생성 (다국어 지원) - const drawingUsageOptions = drawingKind === "B3" - ? getB3DrawingUsageOptions(lng) - : getB4DrawingUsageOptions(lng); - - const registerKindOptions = drawingKind === "B3" - ? getB3RegisterKindOptions(drawingUsage, lng).map(opt => ({ - ...opt, - revisionRule: lng === "ko" ? "예: A, B, C 또는 R00, R01, R02" : "e.g. A, B, C or R00, R01, R02" - })) - : getB4RegisterKindOptions(drawingUsage, lng).map(opt => ({ - ...opt, - revisionRule: lng === "ko" ? "예: R00, R01, R02, R03" : "e.g. R00, R01, R02, R03" - })); - - // 파일 업로드 훅 사용 (진행도 추적) - const { - fileProgresses, - files, - removeFile, - clearFiles, - updateFileProgress, - getRootProps, - getInputProps, - 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) => { - const processedValue = value.toUpperCase(); - setRevision(processedValue); - - // 값이 있을 때만 validation - if (processedValue.trim()) { - const error = validateRevision(processedValue); - setRevisionError(error); - } else { - setRevisionError(""); - } - }; - - // 폼 초기화 - const resetForm = () => { - setDrawingUsage(""); - setRegisterKind(""); - setRevision(""); - setRevisionError(""); - clearFiles(); - }; - - // 제출 - const handleSubmit = async () => { - if (!drawing) return; - - // 유효성 검사 - if (!drawingUsage) { - toast.error("도면용도를 선택하세요"); - return; - } - if (!registerKind) { - toast.error("등록종류를 선택하세요"); - return; - } - 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; - } - - try { - setIsSubmitting(true); - - // 파일 업로드 ID 생성 - const uploadId = uuidv4(); - - // 상세도면 추가 - const result = await editDetailDwgReceipt({ - dwgList: [ - { - Mode: "ADD", - Status: "Draft", - RegisterId: 0, - ProjectNo: drawing.ProjectNo, - Discipline: drawing.Discipline, - DrawingKind: drawing.DrawingKind, - DrawingNo: drawing.DrawingNo, - DrawingName: drawing.DrawingName, - RegisterGroupId: drawing.RegisterGroupId, - RegisterSerialNo: 0, // 자동 증가 - RegisterKind: registerKind, - DrawingRevNo: revision, - Category: "TS", // To SHI (벤더가 SHI에게 제출) - Receiver: null, - Manager: "", - RegisterDesc: "", - UploadId: uploadId, - RegCompanyCode: vendorCode, - }, - ], - userId, - userNm: userName, - vendorCode, - email: userEmail, - }); - - if (result > 0) { - // 파일 업로드 처리 (상세도면 추가 후) - if (files.length > 0) { - toast.info(`${files.length}개 파일 업로드를 진행합니다...`); - - // 모든 파일 상태를 uploading으로 변경 - files.forEach((_, index) => { - updateFileProgress(index, 0, "uploading"); - }); - - const uploadResult = await uploadFilesWithProgress({ - uploadId, - userId, - files, - callbacks: { - onProgress: (fileIndex, progress) => { - updateFileProgress(fileIndex, progress, "uploading"); - }, - onFileComplete: (fileIndex) => { - updateFileProgress(fileIndex, 100, "completed"); - }, - onFileError: (fileIndex, error) => { - updateFileProgress(fileIndex, 0, "error", error); - }, - }, - }); - - if (uploadResult.success) { - toast.success(`상세도면 추가 및 ${uploadResult.uploadedCount}개 파일 업로드 완료`); - } else { - toast.warning(`상세도면은 추가되었으나 파일 업로드 실패: ${uploadResult.error}`); - } - } else { - toast.success("상세도면이 추가되었습니다"); - } - - // API 호출 성공 시 무조건 다이얼로그 닫기 (파일 업로드 성공 여부와 무관) - resetForm(); - onComplete(); - onOpenChange(false); - } else { - toast.error("상세도면 추가에 실패했습니다"); - } - } catch (error) { - console.error("상세도면 추가 실패:", error); - toast.error("상세도면 추가 중 오류가 발생했습니다"); - } finally { - setIsSubmitting(false); - } - }; - - const handleCancel = () => { - resetForm(); - onOpenChange(false); - }; - - // DrawingUsage가 변경되면 RegisterKind 초기화 - const handleDrawingUsageChange = (value: string) => { - setDrawingUsage(value); - setRegisterKind(""); - setRevision(""); - setRevisionError(""); - }; - - // 선택된 RegisterKind의 Revision Rule - const revisionRule = registerKindOptions.find((opt) => opt.value === registerKind)?.revisionRule || ""; - - // 추가 버튼 활성화 조건 - const isFormValid = - drawingUsage.trim() !== "" && - registerKind.trim() !== "" && - revision.trim() !== "" && - !revisionError && - files.length > 0; - - return ( - <Dialog open={open} onOpenChange={onOpenChange}> - <DialogContent className="max-w-2xl"> - <DialogHeader> - <DialogTitle>상세도면 추가</DialogTitle> - </DialogHeader> - - <div className="space-y-6"> - {/* 도면 정보 표시 */} - {drawing && ( - <Alert> - <Info className="h-4 w-4" /> - <AlertDescription> - <div className="font-medium">{drawing.DrawingNo}</div> - <div className="text-sm text-muted-foreground">{drawing.DrawingName}</div> - </AlertDescription> - </Alert> - )} - - {/* 도면용도 선택 */} - <div className="space-y-2"> - <Label>도면용도 (Drawing Usage)</Label> - <Select value={drawingUsage} onValueChange={handleDrawingUsageChange}> - <SelectTrigger> - <SelectValue placeholder="도면용도를 선택하세요" /> - </SelectTrigger> - <SelectContent> - {drawingUsageOptions.map((option) => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - </div> - - {/* 등록종류 선택 */} - <div className="space-y-2"> - <Label>등록종류 (Register Kind)</Label> - <Select - value={registerKind} - onValueChange={setRegisterKind} - disabled={!drawingUsage} - > - <SelectTrigger> - <SelectValue placeholder="등록종류를 선택하세요" /> - </SelectTrigger> - <SelectContent> - {registerKindOptions.map((option) => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - {revisionRule && ( - <p className="text-sm text-muted-foreground"> - Revision 입력 형식: {revisionRule} - </p> - )} - </div> - - {/* Revision 입력 */} - <div className="space-y-2"> - <Label>Revision</Label> - <Input - value={revision} - 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> - - {/* 파일 업로드 */} - <div className="space-y-2"> - <Label>첨부파일 (필수) *</Label> - <div - {...getRootProps()} - className={` - border-2 border-dashed rounded-lg p-8 text-center cursor-pointer - transition-colors - ${isDragActive ? "border-primary bg-primary/5" : "border-muted-foreground/25"} - ${files.length > 0 ? "py-4" : ""} - `} - > - <input {...getInputProps()} /> - {files.length === 0 ? ( - <div className="space-y-2"> - <Upload className="h-8 w-8 mx-auto text-muted-foreground" /> - <div> - <p className="text-sm font-medium"> - 파일을 드래그하거나 클릭하여 선택 - </p> - <p className="text-xs text-muted-foreground"> - 여러 파일을 한 번에 업로드할 수 있습니다 (최대 1GB/파일) - </p> - </div> - </div> - ) : ( - <div className="space-y-2"> - <p className="text-sm font-medium"> - {files.length}개 파일 선택됨 - </p> - <p className="text-xs text-muted-foreground"> - 추가로 파일을 드래그하거나 클릭하여 더 추가할 수 있습니다 - </p> - </div> - )} - </div> - - {/* 선택된 파일 목록 */} - {files.length > 0 && ( - <div className="space-y-2 mt-4"> - {isSubmitting ? ( - // 업로드 중: 진행도 표시 - <FileUploadProgressList fileProgresses={fileProgresses} /> - ) : ( - // 대기 중: 삭제 버튼 표시 - <> - <div className="flex items-center justify-between mb-2"> - <h4 className="text-sm font-medium"> - 선택된 파일 ({files.length}개) - </h4> - <Button - variant="ghost" - size="sm" - onClick={clearFiles} - > - 전체 제거 - </Button> - </div> - <div className="max-h-60 overflow-y-auto space-y-2"> - {files.map((file, index) => ( - <div - key={index} - className="flex items-center gap-2 p-2 border rounded-lg bg-muted/50" - > - <FileIcon className="h-4 w-4 text-muted-foreground shrink-0" /> - <div className="flex-1 min-w-0"> - <p className="text-sm truncate">{file.name}</p> - <p className="text-xs text-muted-foreground"> - {(file.size / 1024 / 1024).toFixed(2)} MB - </p> - </div> - <Button - variant="ghost" - size="sm" - onClick={() => removeFile(index)} - > - <X className="h-4 w-4" /> - </Button> - </div> - ))} - </div> - </> - )} - </div> - )} - </div> - </div> - - <DialogFooter> - <Button variant="outline" onClick={handleCancel} disabled={isSubmitting}> - 취소 - </Button> - <Button onClick={handleSubmit} disabled={isSubmitting || !isFormValid}> - {isSubmitting ? "처리 중..." : "추가"} - </Button> - </DialogFooter> - </DialogContent> - </Dialog> - ); -} - |
