"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { Loader } from "lucide-react" import { useForm } from "react-hook-form" import { toast } from "sonner" import * as z from "zod" import { Button } from "@/components/ui/button" import { Switch } from "@/components/ui/switch" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription, } from "@/components/ui/form" import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Dropzone, DropzoneZone, DropzoneUploadIcon, DropzoneTitle, DropzoneDescription, DropzoneInput } from "@/components/ui/dropzone" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { updateTemplate } from "../service" import { BasicContractTemplate } from "@/db/schema" import { scopeHelpers } from "@/config/basicContractColumnsConfig" // 업데이트 템플릿 스키마 정의 (파일 업데이트 중심) export const updateTemplateSchema = z.object({ legalReviewRequired: z.boolean(), file: z .instanceof(File, { message: "파일을 업로드해주세요." }) .refine((file) => file.size <= 100 * 1024 * 1024, { message: "파일 크기는 100MB 이하여야 합니다.", }) .refine( (file) => file.type === 'application/msword' || file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', { message: "워드 파일(.doc, .docx)만 업로드 가능합니다." } ) .optional(), }); export type UpdateTemplateSchema = z.infer interface UpdateTemplateSheetProps extends React.ComponentPropsWithRef { template: BasicContractTemplate | null onSuccess?: () => void } export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTemplateSheetProps) { const [isUpdatePending, startUpdateTransition] = React.useTransition() const [selectedFile, setSelectedFile] = React.useState(null) const form = useForm({ resolver: zodResolver(updateTemplateSchema), defaultValues: { legalReviewRequired: template?.legalReviewRequired ?? false, }, mode: "onChange" }) // 파일 선택 핸들러 const handleFileChange = (files: File[]) => { if (files.length > 0) { const file = files[0]; setSelectedFile(file); form.setValue("file", file); } }; // 템플릿 변경 시 폼 값 업데이트 React.useEffect(() => { if (template) { form.reset({ legalReviewRequired: template.legalReviewRequired ?? false, }); } }, [template, form]); function onSubmit(input: UpdateTemplateSchema) { startUpdateTransition(async () => { if (!template) return // FormData 객체 생성하여 파일과 데이터를 함께 전송 const formData = new FormData(); formData.append("legalReviewRequired", input.legalReviewRequired.toString()); if (input.file) { formData.append("file", input.file); } try { // 서비스 함수 호출 const { error } = await updateTemplate({ id: template.id, formData, }); if (error) { toast.error(error); return; } form.reset(); setSelectedFile(null); props.onOpenChange?.(false); toast.success("템플릿이 성공적으로 업데이트되었습니다."); onSuccess?.(); } catch (error) { console.error("Update error:", error); toast.error("템플릿 업데이트 중 오류가 발생했습니다."); } }); } if (!template) return null; return ( {/* 고정된 헤더 */} 템플릿 업데이트 템플릿 파일을 업데이트하고 설정을 변경하세요 {/* 스크롤 가능한 컨텐츠 영역 */}
{/* 템플릿 정보 표시 */} 템플릿 정보 현재 템플릿의 기본 정보입니다
{template.templateName}
v{template.revision}
{template.fileName}
{/* 설정 */} 설정 템플릿 관련 설정을 변경할 수 있습니다 (
법무검토 필요 법무팀 검토가 필요한 템플릿인지 설정
)} />
{/* 파일 업데이트 */} 파일 업데이트 새로운 템플릿 파일을 업로드하세요 ( 새 템플릿 파일 (선택사항) {selectedFile ? selectedFile.name : "새 워드 파일을 드래그하세요"} {selectedFile ? `파일 크기: ${(selectedFile.size / (1024 * 1024)).toFixed(2)} MB` : "또는 클릭하여 워드 파일(.doc, .docx)을 선택하세요 (최대 100MB)"} 파일을 업로드하지 않으면 기존 파일이 유지됩니다 )} />
{/* 고정된 푸터 */}
) }