From 1dc24d48e52f2e490f5603ceb02842586ecae533 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 24 Jul 2025 11:06:32 +0000 Subject: (대표님) 정기평가 피드백 반영, 설계 피드백 반영, (최겸) 기술영업 피드백 반영 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/update-basicContract-sheet.tsx | 106 +++++++++------------ 1 file changed, 43 insertions(+), 63 deletions(-) (limited to 'lib/basic-contract/template/update-basicContract-sheet.tsx') diff --git a/lib/basic-contract/template/update-basicContract-sheet.tsx b/lib/basic-contract/template/update-basicContract-sheet.tsx index 88783461..66037601 100644 --- a/lib/basic-contract/template/update-basicContract-sheet.tsx +++ b/lib/basic-contract/template/update-basicContract-sheet.tsx @@ -36,7 +36,6 @@ import { SheetHeader, SheetTitle, } from "@/components/ui/sheet" -import { Input } from "@/components/ui/input" import { Dropzone, DropzoneZone, @@ -47,14 +46,16 @@ import { } from "@/components/ui/dropzone" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Separator } from "@/components/ui/separator" +import { Badge } from "@/components/ui/badge" import { updateTemplate } from "../service" import { BasicContractTemplate } from "@/db/schema" import { BUSINESS_UNITS, scopeHelpers } from "@/config/basicContractColumnsConfig" // 템플릿 이름 옵션 정의 const TEMPLATE_NAME_OPTIONS = [ - "준법서약", - "기술자료 요구서", + "준법서약 (한글)", + "준법서약 (영문)", + "기술자료 요구서", "비밀유지 계약서", "표준하도급기본 계약서", "General GTC", @@ -66,14 +67,13 @@ const TEMPLATE_NAME_OPTIONS = [ "직납자재 하도급대급등 연동제 의향서" ] as const; -// 업데이트 템플릿 스키마 정의 (templateCode, status 제거, 워드파일만 허용) +// 업데이트 템플릿 스키마 정의 (리비전 필드 제거, 워드파일만 허용) export const updateTemplateSchema = z.object({ templateName: z.enum(TEMPLATE_NAME_OPTIONS, { required_error: "템플릿 이름을 선택해주세요.", }), - revision: z.coerce.number().int().min(1, "리비전은 1 이상이어야 합니다."), legalReviewRequired: z.boolean(), - + // 적용 범위 shipBuildingApplicable: z.boolean(), windApplicable: z.boolean(), @@ -83,22 +83,22 @@ export const updateTemplateSchema = z.object({ gyApplicable: z.boolean(), sysApplicable: z.boolean(), infraApplicable: z.boolean(), - + file: z .instanceof(File, { message: "파일을 업로드해주세요." }) .refine((file) => file.size <= 100 * 1024 * 1024, { message: "파일 크기는 100MB 이하여야 합니다.", }) .refine( - (file) => - file.type === 'application/msword' || + (file) => + file.type === 'application/msword' || file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', { message: "워드 파일(.doc, .docx)만 업로드 가능합니다." } ) .optional(), }).refine((data) => { // 적어도 하나의 적용 범위는 선택되어야 함 - const hasAnyScope = BUSINESS_UNITS.some(unit => + const hasAnyScope = BUSINESS_UNITS.some(unit => data[unit.key as keyof typeof data] as boolean ); return hasAnyScope; @@ -122,8 +122,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem const form = useForm({ resolver: zodResolver(updateTemplateSchema), defaultValues: { - templateName: template?.templateName as typeof TEMPLATE_NAME_OPTIONS[number] ?? "준법서약", - revision: template?.revision ?? 1, + templateName: template?.templateName as typeof TEMPLATE_NAME_OPTIONS[number] ?? "준법서약 (한글)", legalReviewRequired: template?.legalReviewRequired ?? false, shipBuildingApplicable: template?.shipBuildingApplicable ?? false, windApplicable: template?.windApplicable ?? false, @@ -147,9 +146,10 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem }; // 모든 적용 범위 선택/해제 - const handleSelectAllScopes = (checked: boolean) => { + const handleSelectAllScopes = (checked: boolean | "indeterminate") => { + const value = checked === true; BUSINESS_UNITS.forEach(unit => { - form.setValue(unit.key as keyof UpdateTemplateSchema, checked); + form.setValue(unit.key as keyof UpdateTemplateSchema, value); }); }; @@ -158,7 +158,6 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem if (template) { form.reset({ templateName: template.templateName as typeof TEMPLATE_NAME_OPTIONS[number], - revision: template.revision ?? 1, legalReviewRequired: template.legalReviewRequired ?? false, shipBuildingApplicable: template.shipBuildingApplicable ?? false, windApplicable: template.windApplicable ?? false, @@ -173,7 +172,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem }, [template, form]); // 현재 선택된 적용 범위 수 - const selectedScopesCount = BUSINESS_UNITS.filter(unit => + const selectedScopesCount = BUSINESS_UNITS.filter(unit => form.watch(unit.key as keyof UpdateTemplateSchema) ).length; @@ -181,22 +180,21 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem startUpdateTransition(async () => { if (!template) return - // FormData 객체 생성하여 파일과 데이터를 함께 전송 (templateCode, status 제거) + // FormData 객체 생성하여 파일과 데이터를 함께 전송 const formData = new FormData(); formData.append("templateName", input.templateName); - formData.append("revision", input.revision.toString()); formData.append("legalReviewRequired", input.legalReviewRequired.toString()); - + // 적용 범위 추가 BUSINESS_UNITS.forEach(unit => { const value = input[unit.key as keyof UpdateTemplateSchema] as boolean; formData.append(unit.key, value.toString()); }); - + if (input.file) { formData.append("file", input.file); } - + try { // 서비스 함수 호출 const { error } = await updateTemplate({ @@ -223,6 +221,15 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem if (!template) return null; + const scopeSelected = BUSINESS_UNITS.some( + (unit) => form.watch(unit.key as keyof UpdateTemplateSchema) + ); + + const isDisabled = + isUpdatePending || + !form.watch("templateName") || + !scopeSelected; + return ( @@ -234,7 +241,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem * 표시된 항목은 필수 입력사항입니다. - + {/* 스크롤 가능한 컨텐츠 영역 */}
@@ -247,11 +254,13 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem 기본 정보 + 현재 리비전: v{template.revision} +
현재 적용 범위: {scopeHelpers.getScopeDisplayText(template)}
-
+
)} /> - - ( - - 리비전 - - field.onChange(parseInt(e.target.value) || 1)} - /> - - - 템플릿 버전을 업데이트하세요. -
- - 동일한 템플릿 이름의 리비전은 중복될 수 없습니다. - -
- -
- )} - />
-
- + - +
{BUSINESS_UNITS.map((unit) => ( ))}
- + {form.formState.errors.shipBuildingApplicable && (

{form.formState.errors.shipBuildingApplicable.message} @@ -417,13 +400,13 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem - {selectedFile - ? selectedFile.name + {selectedFile + ? selectedFile.name : "새 워드 파일을 드래그하세요 (선택사항)"} - {selectedFile - ? `파일 크기: ${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB` + {selectedFile + ? `파일 크기: ${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB` : "또는 클릭하여 워드 파일(.doc, .docx)을 선택하세요 (최대 100MB)"} @@ -447,16 +430,13 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem 취소 - -- cgit v1.2.3