From aa86729f9a2ab95346a2851e3837de1c367aae17 Mon Sep 17 00:00:00 2001 From: dujinkim 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 interface ManualCreateEvaluationTargetDialogProps { open: boolean @@ -114,12 +95,49 @@ export function ManualCreateEvaluationTargetDialog({ // 부서 정보 상태 const [departments, setDepartments] = React.useState>([]) + // 폼 스키마 정의 +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 + + const form = useForm({ 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 ( - + {/* 고정 헤더 */} - - 평가 대상 수동 생성 - - 새로운 평가 대상을 수동으로 생성하고 담당자를 지정합니다. - - +
+ + 평가 대상 수동 생성 + + 새로운 평가 대상을 수동으로 생성하고 담당자를 지정합니다. + + +
{/* Form을 전체 콘텐츠를 감싸도록 수정 */}
console.log('❌ validation errors:', errors) + )} + className="flex flex-col flex-1 min-h-0" id="evaluation-target-form" > {/* 스크롤 가능한 콘텐츠 영역 */} -
+
{/* 기본 정보 */} @@ -693,9 +711,14 @@ export function ManualCreateEvaluationTargetDialog({ { - 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 })); + }} > {/* 고정 버튼 영역 */} -
- - +
+
+ + +
-- cgit v1.2.3