From 18954df6565108a469fb1608ea3715dd9bb1b02d Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 1 Sep 2025 09:12:09 +0000 Subject: (대표님) 구매 기본계약, gtc 개발 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gtc-vendor/clause-variable-settings-dialog.tsx | 364 +++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 lib/basic-contract/gtc-vendor/clause-variable-settings-dialog.tsx (limited to 'lib/basic-contract/gtc-vendor/clause-variable-settings-dialog.tsx') diff --git a/lib/basic-contract/gtc-vendor/clause-variable-settings-dialog.tsx b/lib/basic-contract/gtc-vendor/clause-variable-settings-dialog.tsx new file mode 100644 index 00000000..36d47403 --- /dev/null +++ b/lib/basic-contract/gtc-vendor/clause-variable-settings-dialog.tsx @@ -0,0 +1,364 @@ +"use client" + +import * as React from "react" +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" +import { Badge } from "@/components/ui/badge" + +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, + FormDescription, +} from "@/components/ui/form" +import { Loader, Settings2, Wand2, Copy, Eye } from "lucide-react" +import { toast } from "sonner" +import { cn } from "@/lib/utils" + +import { updateGtcClauseSchema, type UpdateGtcClauseSchema } from "@/lib/gtc-contract/gtc-clauses/validations" +import { updateGtcClause } from "@/lib/gtc-contract/gtc-clauses/service" +import { type GtcClauseTreeView } from "@/db/schema/gtc" +import { useSession } from "next-auth/react" + +interface ClauseVariableSettingsDialogProps + extends React.ComponentPropsWithRef { + clause: GtcClauseTreeView | null + onSuccess?: () => void +} + +export function ClauseVariableSettingsDialog({ + clause, + onSuccess, + ...props +}: ClauseVariableSettingsDialogProps) { + const [isUpdatePending, startUpdateTransition] = React.useTransition() + const [showPreview, setShowPreview] = React.useState(false) + const { data: session } = useSession() + + const currentUserId = React.useMemo(() => { + return session?.user?.id ? Number(session.user.id) : null + }, [session]) + + const form = useForm({ + resolver: zodResolver(updateGtcClauseSchema), + defaultValues: { + numberVariableName: "", + subtitleVariableName: "", + contentVariableName: "", + editReason: "", + }, + }) + + // clause가 변경될 때 폼 데이터 설정 + React.useEffect(() => { + if (clause) { + form.reset({ + numberVariableName: clause.numberVariableName || "", + subtitleVariableName: clause.subtitleVariableName || "", + contentVariableName: clause.contentVariableName || "", + editReason: "", + }) + } + }, [clause, form]) + + const generateAutoVariableNames = () => { + if (!clause) return + + const fullPath = clause.fullPath || clause.itemNumber + + console.log(clause.fullPath,fullPath,"fullPath") + console.log(clause, "clause") + + const prefix = "CLAUSE_" + fullPath.replace(/\./g, "_") + + form.setValue("numberVariableName", `${prefix}_NUMBER`) + form.setValue("subtitleVariableName", `${prefix}_SUBTITLE`) + form.setValue("contentVariableName", `${prefix}_CONTENT`) + + toast.success("변수명이 자동 생성되었습니다.") + } + + const copyCurrentVariableNames = () => { + if (!clause) return + + const currentVars = { + number: clause.autoNumberVariable, + subtitle: clause.autoSubtitleVariable, + content: clause.autoContentVariable, + } + + form.setValue("numberVariableName", currentVars.number) + form.setValue("subtitleVariableName", currentVars.subtitle) + form.setValue("contentVariableName", currentVars.content) + + toast.success("현재 변수명이 복사되었습니다.") + } + + async function onSubmit(data: UpdateGtcClauseSchema) { + startUpdateTransition(async () => { + if (!clause || !currentUserId) { + toast.error("조항 정보를 찾을 수 없습니다.") + return + } + + try { + const result = await updateGtcClause(clause.id, { + numberVariableName: data.numberVariableName, + subtitleVariableName: data.subtitleVariableName, + contentVariableName: data.contentVariableName, + editReason: data.editReason || "PDFTron 변수명 설정", + updatedById: currentUserId, + }) + + if (result.error) { + toast.error(result.error) + return + } + + form.reset() + props.onOpenChange?.(false) + toast.success("변수명이 설정되었습니다!") + onSuccess?.() + } catch (error) { + toast.error("변수명 설정 중 오류가 발생했습니다.") + } + }) + } + + function handleDialogOpenChange(nextOpen: boolean) { + if (!nextOpen) { + form.reset() + setShowPreview(false) + } + props.onOpenChange?.(nextOpen) + } + + const currentNumberVar = form.watch("numberVariableName") + const currentSubtitleVar = form.watch("subtitleVariableName") + const currentContentVar = form.watch("contentVariableName") + + const hasAllVariables = currentNumberVar && currentSubtitleVar && currentContentVar + + if (!clause) { + return null + } + + return ( + + + + + + PDFTron 변수명 설정 + + + 조항의 PDFTron 변수명을 설정하여 문서 생성에 사용합니다. + + + + {/* 조항 정보 */} +
+
대상 조항
+
+
+ {clause.itemNumber} + {clause.subtitle} + + {clause.hasAllVariableNames ? "설정됨" : "미설정"} + +
+ {clause.fullPath && ( +
경로: {clause.fullPath}
+ )} + {clause.category && ( +
분류: {clause.category}
+ )} +
+
+ +
+ +
+
+ {/* 자동 생성 버튼들 */} +
+ + + + + +
+ + {/* 현재 설정된 변수명 표시 */} + {clause.hasAllVariableNames && ( +
+
현재 설정된 변수명
+
+
{clause.numberVariableName}
+
{clause.subtitleVariableName}
+
{clause.contentVariableName}
+
+
+ )} + + {/* 변수명 입력 필드들 */} +
+ ( + + 채번 변수명 * + + + + + 문서에서 조항 번호를 표시할 변수명입니다. + + + + )} + /> + + ( + + 소제목 변수명 * + + + + + 문서에서 조항 제목을 표시할 변수명입니다. + + + + )} + /> + + ( + + 상세항목 변수명 * + + + + + 문서에서 조항 내용을 표시할 변수명입니다. + + + + )} + /> +
+ + {/* 미리보기 */} + {showPreview && hasAllVariables && ( +
+
PDFTron 템플릿 미리보기
+
+
{"{{" + currentNumberVar + "}}"}. {"{{" + currentSubtitleVar + "}}"}
+
{"{{" + currentContentVar + "}}"}
+
+
+ 실제 문서에서 위와 같은 형태로 표시됩니다. +
+
+ )} + + {/* 편집 사유 */} + ( + + 편집 사유 (선택사항) + +