From aa86729f9a2ab95346a2851e3837de1c367aae17 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 20 Jun 2025 11:37:31 +0000
Subject: (대표님) 20250620 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../manual-create-evaluation-target-dialog.tsx     | 151 ++++++++++++---------
 1 file changed, 88 insertions(+), 63 deletions(-)

(limited to 'lib/evaluation-target-list/table/manual-create-evaluation-target-dialog.tsx')

diff --git a/lib/evaluation-target-list/table/manual-create-evaluation-target-dialog.tsx b/lib/evaluation-target-list/table/manual-create-evaluation-target-dialog.tsx
index 5704cba1..af369ea6 100644
--- a/lib/evaluation-target-list/table/manual-create-evaluation-target-dialog.tsx
+++ b/lib/evaluation-target-list/table/manual-create-evaluation-target-dialog.tsx
@@ -60,26 +60,7 @@ import {
 import { EVALUATION_TARGET_FILTER_OPTIONS, getDefaultEvaluationYear } from "../validation"
 import { useSession } from "next-auth/react"
 
-// 폼 스키마 정의
-const createEvaluationTargetSchema = z.object({
-    evaluationYear: z.number().min(2020).max(2030),
-    division: z.enum(["OCEAN", "SHIPYARD"]),
-    vendorId: z.number().min(1, "벤더를 선택해주세요"),
-    materialType: z.enum(["EQUIPMENT", "BULK", "EQUIPMENT_BULK"]),
-    adminComment: z.string().optional(),
-    // L/D 클레임 정보
-    ldClaimCount: z.number().min(0).optional(),
-    ldClaimAmount: z.number().min(0).optional(),
-    ldClaimCurrency: z.enum(["KRW", "USD", "EUR", "JPY"]).optional(),
-    reviewers: z.array(
-        z.object({
-            departmentCode: z.string(),
-            reviewerUserId: z.number().min(1, "담당자를 선택해주세요"),
-        })
-    ).min(1, "최소 1명의 담당자를 지정해주세요"),
-})
 
-type CreateEvaluationTargetFormValues = z.infer<typeof createEvaluationTargetSchema>
 
 interface ManualCreateEvaluationTargetDialogProps {
     open: boolean
@@ -114,12 +95,49 @@ export function ManualCreateEvaluationTargetDialog({
     // 부서 정보 상태
     const [departments, setDepartments] = React.useState<Array<{ code: string, name: string, key: string }>>([])
 
+    // 폼 스키마 정의
+const createEvaluationTargetSchema = z.object({
+    evaluationYear: z.number().min(2020).max(2030),
+    division: z.enum(["PLANT", "SHIP"]),
+    vendorId: z.number().min(0), // 0도 허용, 클라이언트에서 검증
+    materialType: z.enum(["EQUIPMENT", "BULK", "EQUIPMENT_BULK"]),
+    adminComment: z.string().optional(),
+    // L/D 클레임 정보
+    ldClaimCount: z.number().min(0).optional(),
+    ldClaimAmount: z.number().min(0).optional(),
+    ldClaimCurrency: z.enum(["KRW", "USD", "EUR", "JPY"]).optional(),
+    reviewers: z.array(
+        z.object({
+            departmentCode: z.string(),
+            reviewerUserId: z.number(), // min(1) 제거, 나중에 클라이언트에서 필터링
+        })
+    ),
+}).refine((data) => {
+    // 벤더가 선택되어야 함
+    if (data.vendorId === 0) {
+        return false;
+    }
+    // 최소 1명의 담당자가 지정되어야 함 (reviewerUserId > 0)
+    const validReviewers = data.reviewers
+    .filter(r => r.reviewerUserId > 0)
+    .map((r, i) => ({
+      departmentCode: r.departmentCode || departments[i]?.code,  // 없으면 보충
+      reviewerUserId: r.reviewerUserId,
+    }));
+    return validReviewers.length > 0;
+}, {
+    message: "벤더를 선택하고 최소 1명의 담당자를 지정해주세요.",
+    path: ["vendorId"]
+})
+type CreateEvaluationTargetFormValues = z.infer<typeof createEvaluationTargetSchema>
+
+
     const form = useForm<CreateEvaluationTargetFormValues>({
         resolver: zodResolver(createEvaluationTargetSchema),
         defaultValues: {
             evaluationYear: getDefaultEvaluationYear(),
-            division: "OCEAN",
-            vendorId: 0,
+            division: "SHIP",
+            vendorId: 0, // 임시로 0, 나중에 검증에서 체크
             materialType: "EQUIPMENT",
             adminComment: "",
             ldClaimCount: 0,
@@ -180,17 +198,12 @@ export function ManualCreateEvaluationTargetDialog({
     // 부서 정보가 로드되면 reviewers 기본값 설정
     React.useEffect(() => {
         if (departments.length > 0 && open) {
-            const currentReviewers = form.getValues("reviewers")
-            
-            // 이미 설정되어 있으면 다시 설정하지 않음
-            if (currentReviewers.length === 0) {
-                const defaultReviewers = departments.map(dept => ({
-                    departmentCode: dept.code,
-                    reviewerUserId: 0,
-                }))
-                form.setValue('reviewers', defaultReviewers)
-            }
-        }
+            const defaultReviewers = departments.map(dept => ({
+              departmentCode: dept.code,   // ✅ 반드시 포함
+              reviewerUserId: 0,
+            }));
+            form.setValue("reviewers", defaultReviewers, { shouldValidate: false });
+          }
     }, [departments, open]) // form 의존성 제거하고 조건 추가
 
     console.log(departments)
@@ -234,7 +247,7 @@ export function ManualCreateEvaluationTargetDialog({
                 // 폼과 상태 초기화
                 form.reset({
                     evaluationYear: getDefaultEvaluationYear(),
-                    division: "OCEAN",
+                    division: "SHIP",
                     vendorId: 0,
                     materialType: "EQUIPMENT",
                     adminComment: "",
@@ -269,7 +282,7 @@ export function ManualCreateEvaluationTargetDialog({
         if (!open) {
             form.reset({
                 evaluationYear: getDefaultEvaluationYear(),
-                division: "OCEAN",
+                division: "SHIP",
                 vendorId: 0,
                 materialType: "EQUIPMENT",
                 adminComment: "",
@@ -326,24 +339,29 @@ export function ManualCreateEvaluationTargetDialog({
 
     return (
         <Dialog open={open} onOpenChange={handleOpenChange}>
-            <DialogContent className="max-w-lg flex flex-col h-[90vh]">
+            <DialogContent className="max-w-lg h-[90vh] p-0 flex flex-col">
                 {/* 고정 헤더 */}
-                <DialogHeader className="flex-shrink-0">
-                    <DialogTitle>평가 대상 수동 생성</DialogTitle>
-                    <DialogDescription>
-                        새로운 평가 대상을 수동으로 생성하고 담당자를 지정합니다.
-                    </DialogDescription>
-                </DialogHeader>
+                <div className="flex-shrink-0 p-6 border-b">
+                    <DialogHeader>
+                        <DialogTitle>평가 대상 수동 생성</DialogTitle>
+                        <DialogDescription>
+                            새로운 평가 대상을 수동으로 생성하고 담당자를 지정합니다.
+                        </DialogDescription>
+                    </DialogHeader>
+                </div>
 
                 {/* Form을 전체 콘텐츠를 감싸도록 수정 */}
                 <Form {...form}>
                     <form 
-                        onSubmit={form.handleSubmit(onSubmit)} 
-                        className="flex flex-col flex-1"
+                          onSubmit={form.handleSubmit(
+                            onSubmit,
+                            (errors) => console.log('❌ validation errors:', errors)
+                          )}
+                        className="flex flex-col flex-1 min-h-0"
                         id="evaluation-target-form"
                     >
                         {/* 스크롤 가능한 콘텐츠 영역 */}
-                        <div className="flex-1 overflow-y-auto">
+                        <div className="flex-1 overflow-y-auto p-6">
                             <div className="space-y-6">
                                 {/* 기본 정보 */}
                                 <Card>
@@ -693,9 +711,14 @@ export function ManualCreateEvaluationTargetDialog({
                                                                                         <CommandItem
                                                                                             value="선택 안함"
                                                                                             onSelect={() => {
-                                                                                                field.onChange(0)
-                                                                                                setReviewerOpens(prev => ({...prev, [department.code]: false}))
-                                                                                            }}
+                                                                                                // reviewers[index] 전체를 갱신
+                                                                                                form.setValue(
+                                                                                                  `reviewers.${index}`,
+                                                                                                  { departmentCode: department.code, reviewerUserId: reviewer.id },
+                                                                                                  { shouldValidate: true }
+                                                                                                );
+                                                                                                setReviewerOpens(prev => ({ ...prev, [department.code]: false }));
+                                                                                              }}
                                                                                         >
                                                                                             <Check
                                                                                                 className={cn(
@@ -747,22 +770,24 @@ export function ManualCreateEvaluationTargetDialog({
                         </div>
 
                         {/* 고정 버튼 영역 */}
-                        <div className="flex-shrink-0 flex justify-end gap-3 pt-4 border-t">
-                            <Button
-                                type="button"
-                                variant="outline"
-                                onClick={() => handleOpenChange(false)}
-                                disabled={isSubmitting}
-                            >
-                                취소
-                            </Button>
-                            <Button 
-                                type="submit" 
-                                disabled={isSubmitting}
-                            >
-                                {isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
-                                생성
-                            </Button>
+                        <div className="flex-shrink-0 border-t bg-background p-6">
+                            <div className="flex justify-end gap-3">
+                                <Button
+                                    type="button"
+                                    variant="outline"
+                                    onClick={() => handleOpenChange(false)}
+                                    disabled={isSubmitting}
+                                >
+                                    취소
+                                </Button>
+                                <Button 
+                                    type="submit" 
+                                    disabled={isSubmitting}
+                                >
+                                    {isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
+                                    생성
+                                </Button>
+                            </div>
                         </div>
                     </form>
                 </Form>
-- 
cgit v1.2.3

