From 15c3ae6536c264db0508e4fc4aaa59c3e6d1af30 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 15 Jul 2025 00:50:39 +0000
Subject: (대표님) 기본계약 및 정기평가 작업사항, OCR 변경사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../template/update-basicContract-sheet.tsx        | 426 ++++++++++++++-------
 1 file changed, 297 insertions(+), 129 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 2c6efc9b..810e1b77 100644
--- a/lib/basic-contract/template/update-basicContract-sheet.tsx
+++ b/lib/basic-contract/template/update-basicContract-sheet.tsx
@@ -8,6 +8,8 @@ import { toast } from "sonner"
 import * as z from "zod"
 
 import { Button } from "@/components/ui/button"
+import { Checkbox } from "@/components/ui/checkbox"
+import { Switch } from "@/components/ui/switch"
 import {
   Form,
   FormControl,
@@ -43,23 +45,44 @@ import {
   DropzoneDescription,
   DropzoneInput
 } 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"
 
-// 업데이트 템플릿 스키마 정의 (유효기간 필드 추가)
+// 업데이트 템플릿 스키마 정의
 export const updateTemplateSchema = z.object({
+  templateCode: z.string().min(1, "템플릿 코드는 필수입니다."), // readonly로 처리
   templateName: z.string().min(1, "템플릿 이름은 필수입니다."),
-  validityPeriod: z.coerce
-    .number({ invalid_type_error: "유효기간은 숫자여야 합니다." })
-    .int("유효기간은 정수여야 합니다.")
-    .min(1, "유효기간은 최소 1개월 이상이어야 합니다.")
-    .max(120, "유효기간은 최대 120개월(10년)을 초과할 수 없습니다.")
-    .default(12),
-  status: z.enum(["ACTIVE", "INACTIVE"], {
+  revision: z.coerce.number().int().min(1, "리비전은 1 이상이어야 합니다."),
+  legalReviewRequired: z.boolean(),
+  
+  // 적용 범위
+  shipBuildingApplicable: z.boolean(),
+  windApplicable: z.boolean(),
+  pcApplicable: z.boolean(),
+  nbApplicable: z.boolean(),
+  rcApplicable: z.boolean(),
+  gyApplicable: z.boolean(),
+  sysApplicable: z.boolean(),
+  infraApplicable: z.boolean(),
+  
+  status: z.enum(["ACTIVE", "DISPOSED"], {
     required_error: "상태는 필수 선택사항입니다.",
   }),
   file: z.instanceof(File, { message: "파일을 업로드해주세요." }).optional(),
-})
+}).refine((data) => {
+  // 적어도 하나의 적용 범위는 선택되어야 함
+  const hasAnyScope = BUSINESS_UNITS.some(unit => 
+    data[unit.key as keyof typeof data] as boolean
+  );
+  return hasAnyScope;
+}, {
+  message: "적어도 하나의 적용 범위를 선택해야 합니다.",
+  path: ["shipBuildingApplicable"],
+});
 
 export type UpdateTemplateSchema = z.infer<typeof updateTemplateSchema>
 
@@ -73,15 +96,22 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem
   const [isUpdatePending, startUpdateTransition] = React.useTransition()
   const [selectedFile, setSelectedFile] = React.useState<File | null>(null)
 
-  // 템플릿 데이터 확인을 위한 로그
-  console.log(template)
-
   const form = useForm<UpdateTemplateSchema>({
     resolver: zodResolver(updateTemplateSchema),
     defaultValues: {
+      templateCode: template?.templateCode ?? "",
       templateName: template?.templateName ?? "",
-      validityPeriod: template?.validityPeriod ?? 12, // 기본값 12개월
-      status: (template?.status as "ACTIVE" | "INACTIVE") || "ACTIVE"
+      revision: template?.revision ?? 1,
+      legalReviewRequired: template?.legalReviewRequired ?? false,
+      shipBuildingApplicable: template?.shipBuildingApplicable ?? false,
+      windApplicable: template?.windApplicable ?? false,
+      pcApplicable: template?.pcApplicable ?? false,
+      nbApplicable: template?.nbApplicable ?? false,
+      rcApplicable: template?.rcApplicable ?? false,
+      gyApplicable: template?.gyApplicable ?? false,
+      sysApplicable: template?.sysApplicable ?? false,
+      infraApplicable: template?.infraApplicable ?? false,
+      status: (template?.status as "ACTIVE" | "DISPOSED") || "ACTIVE"
     },
     mode: "onChange"
   })
@@ -95,26 +125,38 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem
     }
   };
 
+  // 모든 적용 범위 선택/해제
+  const handleSelectAllScopes = (checked: boolean) => {
+    BUSINESS_UNITS.forEach(unit => {
+      form.setValue(unit.key as keyof UpdateTemplateSchema, checked);
+    });
+  };
+
   // 템플릿 변경 시 폼 값 업데이트
   React.useEffect(() => {
     if (template) {
       form.reset({
+        templateCode: template.templateCode,
         templateName: template.templateName,
-        validityPeriod: template.validityPeriod ?? 12, // 기존 값이 없으면 기본값 12개월
-        status: template.status as "ACTIVE" | "INACTIVE",
+        revision: template.revision ?? 1,
+        legalReviewRequired: template.legalReviewRequired ?? false,
+        shipBuildingApplicable: template.shipBuildingApplicable ?? false,
+        windApplicable: template.windApplicable ?? false,
+        pcApplicable: template.pcApplicable ?? false,
+        nbApplicable: template.nbApplicable ?? false,
+        rcApplicable: template.rcApplicable ?? false,
+        gyApplicable: template.gyApplicable ?? false,
+        sysApplicable: template.sysApplicable ?? false,
+        infraApplicable: template.infraApplicable ?? false,
+        status: template.status as "ACTIVE" | "DISPOSED",
       });
     }
   }, [template, form]);
 
-  // 유효기간 선택 옵션
-  const validityOptions = [
-    { value: "3", label: "3개월" },
-    { value: "6", label: "6개월" },
-    { value: "12", label: "1년" },
-    { value: "24", label: "2년" },
-    { value: "36", label: "3년" },
-    { value: "60", label: "5년" },
-  ];
+  // 현재 선택된 적용 범위 수
+  const selectedScopesCount = BUSINESS_UNITS.filter(unit => 
+    form.watch(unit.key as keyof UpdateTemplateSchema)
+  ).length;
 
   function onSubmit(input: UpdateTemplateSchema) {
     startUpdateTransition(async () => {
@@ -122,8 +164,17 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem
 
       // FormData 객체 생성하여 파일과 데이터를 함께 전송
       const formData = new FormData();
+      formData.append("templateCode", input.templateCode);
       formData.append("templateName", input.templateName);
-      formData.append("validityPeriod", input.validityPeriod.toString()); // 유효기간 추가
+      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());
+      });
+      
       formData.append("status", input.status);
       
       if (input.file) {
@@ -154,124 +205,241 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem
     });
   }
 
+  if (!template) return null;
+
   return (
     <Sheet {...props}>
-      <SheetContent className="flex flex-col gap-6 sm:max-w-md">
+      <SheetContent className="flex flex-col gap-6 sm:max-w-[600px] overflow-y-auto">
         <SheetHeader className="text-left">
           <SheetTitle>템플릿 업데이트</SheetTitle>
           <SheetDescription>
             템플릿 정보를 수정하고 변경사항을 저장하세요
           </SheetDescription>
         </SheetHeader>
+        
         <Form {...form}>
           <form
             onSubmit={form.handleSubmit(onSubmit)}
-            className="flex flex-col gap-4"
+            className="flex flex-col gap-6"
           >
-            <FormField
-              control={form.control}
-              name="templateName"
-              render={({ field }) => (
-                <FormItem>
-                  <FormLabel>템플릿 이름</FormLabel>
-                  <FormControl>
-                    <Input placeholder="템플릿 이름을 입력하세요" {...field} />
-                  </FormControl>
-                  <FormMessage />
-                </FormItem>
-              )}
-            />
+            {/* 기본 정보 */}
+            <Card>
+              <CardHeader>
+                <CardTitle className="text-lg">기본 정보</CardTitle>
+                <CardDescription>
+                  현재 적용 범위: {scopeHelpers.getScopeDisplayText(template)}
+                </CardDescription>
+              </CardHeader>
+              <CardContent className="space-y-4">
+                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+                  <FormField
+                    control={form.control}
+                    name="templateCode"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel>템플릿 코드</FormLabel>
+                        <FormControl>
+                          <Input 
+                            {...field}
+                            readOnly
+                            className="bg-muted"
+                          />
+                        </FormControl>
+                        <FormDescription>
+                          템플릿 코드는 수정할 수 없습니다.
+                        </FormDescription>
+                      </FormItem>
+                    )}
+                  />
+
+                  <FormField
+                    control={form.control}
+                    name="revision"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel>리비전</FormLabel>
+                        <FormControl>
+                          <Input 
+                            type="number" 
+                            min="1" 
+                            {...field}
+                            onChange={(e) => field.onChange(parseInt(e.target.value) || 1)}
+                          />
+                        </FormControl>
+                        <FormDescription>
+                          템플릿 버전을 업데이트하세요.
+                        </FormDescription>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+                </div>
+
+                <FormField
+                  control={form.control}
+                  name="templateName"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>템플릿 이름</FormLabel>
+                      <FormControl>
+                        <Input placeholder="템플릿 이름을 입력하세요" {...field} />
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
 
-            <FormField
-              control={form.control}
-              name="validityPeriod"
-              render={({ field }) => (
-                <FormItem>
-                  <FormLabel>계약 유효기간</FormLabel>
-                  <Select
-                    value={field.value?.toString()}
-                    onValueChange={(value) => field.onChange(parseInt(value))}
-                  >
-                    <FormControl>
-                      <SelectTrigger>
-                        <SelectValue placeholder="유효기간을 선택하세요" />
-                      </SelectTrigger>
-                    </FormControl>
-                    <SelectContent>
-                      {validityOptions.map(option => (
-                        <SelectItem key={option.value} value={option.value}>
-                          {option.label}
-                        </SelectItem>
-                      ))}
-                    </SelectContent>
-                  </Select>
-                  <FormDescription>
-                    계약서의 유효 기간을 설정합니다. 이 기간이 지나면 재계약이 필요합니다.
-                  </FormDescription>
-                  <FormMessage />
-                </FormItem>
-              )}
-            />
+                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+                  <FormField
+                    control={form.control}
+                    name="status"
+                    render={({ field }) => (
+                      <FormItem>
+                        <FormLabel>상태</FormLabel>
+                        <Select 
+                          defaultValue={field.value}
+                          onValueChange={field.onChange}
+                        >
+                          <FormControl>
+                            <SelectTrigger>
+                              <SelectValue placeholder="템플릿 상태 선택" />
+                            </SelectTrigger>
+                          </FormControl>
+                          <SelectContent>
+                            <SelectGroup>
+                              <SelectItem value="ACTIVE">활성</SelectItem>
+                              <SelectItem value="DISPOSED">폐기</SelectItem>
+                            </SelectGroup>
+                          </SelectContent>
+                        </Select>
+                        <FormMessage />
+                      </FormItem>
+                    )}
+                  />
+                </div>
+
+                <FormField
+                  control={form.control}
+                  name="legalReviewRequired"
+                  render={({ field }) => (
+                    <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
+                      <div className="space-y-0.5">
+                        <FormLabel>법무검토 필요</FormLabel>
+                        <FormDescription>
+                          법무팀 검토가 필요한 템플릿인지 설정
+                        </FormDescription>
+                      </div>
+                      <FormControl>
+                        <Switch
+                          checked={field.value}
+                          onCheckedChange={field.onChange}
+                        />
+                      </FormControl>
+                    </FormItem>
+                  )}
+                />
+              </CardContent>
+            </Card>
 
-            <FormField
-              control={form.control}
-              name="status"
-              render={({ field }) => (
-                <FormItem>
-                  <FormLabel>상태</FormLabel>
-                  <Select 
-                    defaultValue={field.value}
-                    onValueChange={field.onChange}
-                  >
-                    <FormControl>
-                      <SelectTrigger>
-                        <SelectValue placeholder="템플릿 상태 선택" />
-                      </SelectTrigger>
-                    </FormControl>
-                    <SelectContent>
-                      <SelectGroup>
-                        <SelectItem value="ACTIVE">활성</SelectItem>
-                        <SelectItem value="INACTIVE">비활성</SelectItem>
-                      </SelectGroup>
-                    </SelectContent>
-                  </Select>
-                  <FormMessage />
-                </FormItem>
-              )}
-            />
+            {/* 적용 범위 */}
+            <Card>
+              <CardHeader>
+                <CardTitle className="text-lg">적용 범위</CardTitle>
+                <CardDescription>
+                  이 템플릿이 적용될 사업부를 선택하세요. ({selectedScopesCount}개 선택됨)
+                </CardDescription>
+              </CardHeader>
+              <CardContent className="space-y-4">
+                <div className="flex items-center space-x-2">
+                  <Checkbox 
+                    id="select-all"
+                    checked={selectedScopesCount === BUSINESS_UNITS.length}
+                    onCheckedChange={handleSelectAllScopes}
+                  />
+                  <label htmlFor="select-all" className="text-sm font-medium">
+                    전체 선택
+                  </label>
+                </div>
+                
+                <Separator />
+                
+                <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
+                  {BUSINESS_UNITS.map((unit) => (
+                    <FormField
+                      key={unit.key}
+                      control={form.control}
+                      name={unit.key as keyof UpdateTemplateSchema}
+                      render={({ field }) => (
+                        <FormItem className="flex flex-row items-start space-x-3 space-y-0">
+                          <FormControl>
+                            <Checkbox
+                              checked={field.value as boolean}
+                              onCheckedChange={field.onChange}
+                            />
+                          </FormControl>
+                          <div className="space-y-1 leading-none">
+                            <FormLabel className="text-sm font-normal">
+                              {unit.label}
+                            </FormLabel>
+                          </div>
+                        </FormItem>
+                      )}
+                    />
+                  ))}
+                </div>
+                
+                {form.formState.errors.shipBuildingApplicable && (
+                  <p className="text-sm text-destructive">
+                    {form.formState.errors.shipBuildingApplicable.message}
+                  </p>
+                )}
+              </CardContent>
+            </Card>
 
-            <FormField
-              control={form.control}
-              name="file"
-              render={() => (
-                <FormItem>
-                  <FormLabel>템플릿 파일 (선택사항)</FormLabel>
-                  <FormControl>
-                    <Dropzone
-                      onDrop={handleFileChange}
-                    >
-                      <DropzoneZone>
-                        <DropzoneUploadIcon className="h-10 w-10 text-muted-foreground" />
-                        <DropzoneTitle>
-                          {selectedFile 
-                            ? selectedFile.name 
-                            : template?.fileName 
-                              ? `현재 파일: ${template.fileName}` 
-                              : "새 파일을 드래그하세요"}
-                        </DropzoneTitle>
-                        <DropzoneDescription>
-                          {selectedFile 
-                            ? `파일 크기: ${(selectedFile.size / 1024).toFixed(2)} KB` 
-                            : "또는 클릭하여 파일을 선택하세요 (선택사항)"}
-                        </DropzoneDescription>
-                        <DropzoneInput />
-                      </DropzoneZone>
-                    </Dropzone>
-                  </FormControl>
-                  <FormMessage />
-                </FormItem>
-              )}
-            />
+            {/* 파일 업데이트 */}
+            <Card>
+              <CardHeader>
+                <CardTitle className="text-lg">파일 업데이트</CardTitle>
+                <CardDescription>
+                  현재 파일: {template.fileName}
+                </CardDescription>
+              </CardHeader>
+              <CardContent>
+                <FormField
+                  control={form.control}
+                  name="file"
+                  render={() => (
+                    <FormItem>
+                      <FormLabel>템플릿 파일 (선택사항)</FormLabel>
+                      <FormControl>
+                        <Dropzone
+                          onDrop={handleFileChange}
+                          accept={{
+                            'application/pdf': ['.pdf']
+                          }}
+                        >
+                          <DropzoneZone>
+                            <DropzoneUploadIcon className="h-10 w-10 text-muted-foreground" />
+                            <DropzoneTitle>
+                              {selectedFile 
+                                ? selectedFile.name 
+                                : "새 파일을 드래그하세요 (선택사항)"}
+                            </DropzoneTitle>
+                            <DropzoneDescription>
+                              {selectedFile 
+                                ? `파일 크기: ${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB` 
+                                : "또는 클릭하여 파일을 선택하세요"}
+                            </DropzoneDescription>
+                            <DropzoneInput />
+                          </DropzoneZone>
+                        </Dropzone>
+                      </FormControl>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+              </CardContent>
+            </Card>
 
             <SheetFooter className="gap-2 pt-2 sm:space-x-0">
               <SheetClose asChild>
-- 
cgit v1.2.3

