summaryrefslogtreecommitdiff
path: root/lib/vendor-document-list/table/revision-upload-dialog.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-06-11 12:18:38 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-06-11 12:18:38 +0000
commitff902243a658067fae858a615c0629aa2e0a4837 (patch)
tree42d30e986d1cbfb282c644c01730cd053b816b7a /lib/vendor-document-list/table/revision-upload-dialog.tsx
parent42e38f41cb4c0b4bf9c08b71ed087cd7f0c7fc18 (diff)
(대표님) 20250611 21시 15분 OCR 등
Diffstat (limited to 'lib/vendor-document-list/table/revision-upload-dialog.tsx')
-rw-r--r--lib/vendor-document-list/table/revision-upload-dialog.tsx132
1 files changed, 116 insertions, 16 deletions
diff --git a/lib/vendor-document-list/table/revision-upload-dialog.tsx b/lib/vendor-document-list/table/revision-upload-dialog.tsx
index 546fa7a3..16fc9fbb 100644
--- a/lib/vendor-document-list/table/revision-upload-dialog.tsx
+++ b/lib/vendor-document-list/table/revision-upload-dialog.tsx
@@ -66,7 +66,29 @@ const revisionUploadSchema = z.object({
uploaderName: z.string().optional(),
comment: z.string().optional(),
attachments: z.array(z.instanceof(File)).min(1, "최소 1개 파일이 필요합니다"),
-})
+ // ✅ B3 문서용 usage 필드 추가
+ usage: z.string().optional(),
+}).refine((data) => {
+ // B3 문서이고 특정 stage인 경우 usage 필수
+ // 이 검증은 컴포넌트 내에서 조건부로 처리
+ return true;
+}, {
+ message: "Usage는 필수입니다",
+ path: ["usage"],
+});
+
+const getUsageOptions = (stageName: string): string[] => {
+ const stageNameLower = stageName.toLowerCase();
+
+ if (stageNameLower.includes('approval')) {
+ return ['Approval (Partial)', 'Approval (Full)'];
+ } else if (stageNameLower.includes('working')) {
+ return ['Working (Partial)', 'Working (Full)'];
+ }
+
+ return [];
+};
+
type RevisionUploadSchema = z.infer<typeof revisionUploadSchema>
@@ -93,7 +115,7 @@ export function RevisionUploadDialog({
presetStage,
presetRevision,
mode = 'new',
- onUploadComplete, // ✅ 추가된 prop
+ onUploadComplete,
}: RevisionUploadDialogProps) {
const targetSystem = React.useMemo(
@@ -106,7 +128,6 @@ export function RevisionUploadDialog({
const [uploadProgress, setUploadProgress] = React.useState(0)
const router = useRouter()
- // ✅ next-auth session 가져오기
const { data: session } = useSession()
// 사용 가능한 스테이지 옵션
@@ -125,17 +146,33 @@ export function RevisionUploadDialog({
uploaderName: session?.user?.name || "",
comment: "",
attachments: [],
+ usage: "", // ✅ usage 기본값 추가
},
})
- // ✅ session이 로드되면 uploaderName 업데이트
+ // ✅ 현재 선택된 stage 값을 watch
+ const currentStage = form.watch('stage')
+
+ // ✅ B3 문서 여부 확인
+ const isB3Document = document?.drawingKind === 'B3'
+
+ // ✅ 현재 stage에 따른 usage 옵션
+ const usageOptions = React.useMemo(() => {
+ if (!isB3Document || !currentStage) return []
+ return getUsageOptions(currentStage)
+ }, [isB3Document, currentStage])
+
+ // ✅ usage 필드가 필요한지 확인
+ const isUsageRequired = isB3Document && usageOptions.length > 0
+
+ // session이 로드되면 uploaderName 업데이트
React.useEffect(() => {
if (session?.user?.name) {
form.setValue('uploaderName', session.user.name)
}
}, [session?.user?.name, form])
- // ✅ presetStage와 presetRevision이 변경될 때 폼 값 업데이트
+ // presetStage와 presetRevision이 변경될 때 폼 값 업데이트
React.useEffect(() => {
if (presetStage) {
form.setValue('stage', presetStage)
@@ -145,6 +182,22 @@ export function RevisionUploadDialog({
}
}, [presetStage, presetRevision, form])
+ // ✅ stage가 변경될 때 usage 값 리셋
+ React.useEffect(() => {
+ if (isB3Document) {
+ const newUsageOptions = getUsageOptions(currentStage)
+ if (newUsageOptions.length === 0) {
+ form.setValue('usage', '')
+ } else {
+ // 기존 값이 새로운 옵션에 없으면 리셋
+ const currentUsage = form.getValues('usage')
+ if (currentUsage && !newUsageOptions.includes(currentUsage)) {
+ form.setValue('usage', '')
+ }
+ }
+ }
+ }, [currentStage, isB3Document, form])
+
// 파일 드롭 처리
const handleDropAccepted = (acceptedFiles: File[]) => {
const newFiles = [...selectedFiles, ...acceptedFiles]
@@ -159,26 +212,22 @@ export function RevisionUploadDialog({
form.setValue('attachments', updatedFiles, { shouldValidate: true })
}
- // ✅ 캐시 갱신 함수
+ // 캐시 갱신 함수
const refreshCaches = async () => {
try {
- // 1. 서버 컴포넌트 캐시 갱신 (Enhanced Documents 등)
router.refresh()
- // 2. SWR 캐시 갱신 (Sync Status)
if (document?.contractId) {
await mutate(`/api/sync/status/${document.contractId}/${targetSystem}`)
console.log('✅ Sync status cache refreshed')
}
- // 3. 다른 관련 SWR 캐시들도 갱신 (필요시)
await mutate(key =>
typeof key === 'string' &&
key.includes('sync') &&
key.includes(String(document?.contractId))
)
- // 4. 상위 컴포넌트 콜백 호출
onUploadComplete?.()
console.log('✅ All caches refreshed after upload')
@@ -187,10 +236,19 @@ export function RevisionUploadDialog({
}
}
- // 업로드 처리
+ // ✅ 업로드 처리 - usage 필드 검증 및 전송
async function onSubmit(data: RevisionUploadSchema) {
if (!document) return
+ // ✅ B3 문서에서 usage가 필요한 경우 검증
+ if (isUsageRequired && !data.usage) {
+ form.setError('usage', {
+ type: 'required',
+ message: 'Usage 선택은 필수입니다'
+ })
+ return
+ }
+
setIsUploading(true)
setUploadProgress(0)
@@ -210,6 +268,11 @@ export function RevisionUploadDialog({
formData.append("comment", data.comment)
}
+ // ✅ B3 문서인 경우 usage 추가
+ if (isB3Document && data.usage) {
+ formData.append("usage", data.usage)
+ }
+
// 파일들 추가
data.attachments.forEach((file) => {
formData.append("attachments", file)
@@ -220,7 +283,6 @@ export function RevisionUploadDialog({
setUploadProgress(Math.min(progress, 95))
}
- // 파일 크기에 따른 진행률 시뮬레이션
const totalSize = data.attachments.reduce((sum, file) => sum + file.size, 0)
let uploadedSize = 0
@@ -230,7 +292,6 @@ export function RevisionUploadDialog({
updateProgress(progress)
}, 300)
- // ✅ 실제 API 호출
const response = await fetch('/api/revision-upload', {
method: 'POST',
body: formData,
@@ -253,7 +314,6 @@ export function RevisionUploadDialog({
console.log('✅ 업로드 성공:', result)
- // ✅ 캐시 갱신 및 다이얼로그 닫기
setTimeout(async () => {
await refreshCaches()
handleDialogClose()
@@ -275,6 +335,7 @@ export function RevisionUploadDialog({
uploaderName: session?.user?.name || "",
comment: "",
attachments: [],
+ usage: "", // ✅ usage 리셋 추가
})
setSelectedFiles([])
setIsUploading(false)
@@ -295,14 +356,19 @@ export function RevisionUploadDialog({
mode === 'new' ? "문서에 새 리비전을 업로드합니다." : "기존 리비전에 파일을 추가합니다."}
</DialogDescription>
- <div className="flex items-center gap-2 pt-2">
+ <div className="flex items-center gap-2 pt-2 flex-wrap">
<Badge variant={projectType === "ship" ? "default" : "secondary"}>
{projectType === "ship" ? "조선 프로젝트" : "플랜트 프로젝트"}
</Badge>
- {/* ✅ 타겟 시스템 표시 추가 */}
<Badge variant="outline" className="text-xs">
→ {targetSystem}
</Badge>
+ {/* ✅ B3 문서 표시 */}
+ {isB3Document && (
+ <Badge variant="outline" className="text-xs bg-orange-50 text-orange-700 border-orange-200">
+ B3 문서
+ </Badge>
+ )}
{session?.user?.name && (
<Badge variant="outline" className="text-xs">
업로더: {session.user.name}
@@ -379,6 +445,40 @@ export function RevisionUploadDialog({
/>
</div>
+ {/* ✅ B3 문서용 Usage 필드 - 조건부 표시 */}
+ {isB3Document && usageOptions.length > 0 && (
+ <FormField
+ control={form.control}
+ name="usage"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel className="flex items-center gap-2">
+ 용도
+ {isUsageRequired && <span className="text-red-500">*</span>}
+ </FormLabel>
+ <Select onValueChange={field.onChange} value={field.value}>
+ <FormControl>
+ <SelectTrigger>
+ <SelectValue placeholder="용도를 선택하세요" />
+ </SelectTrigger>
+ </FormControl>
+ <SelectContent>
+ {usageOptions.map((usage) => (
+ <SelectItem key={usage} value={usage}>
+ {usage}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ <FormMessage />
+ <p className="text-xs text-gray-500">
+ {currentStage} 스테이지에 필요한 용도를 선택하세요.
+ </p>
+ </FormItem>
+ )}
+ />
+ )}
+
<FormField
control={form.control}
name="uploaderName"