summaryrefslogtreecommitdiff
path: root/lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-01 09:12:09 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-01 09:12:09 +0000
commit18954df6565108a469fb1608ea3715dd9bb1b02d (patch)
tree2675d254c547861a903a32459d89283a324e0e0d /lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx
parentf91cd16a872d9cda04aeb5c4e31538e3e2bd1895 (diff)
(대표님) 구매 기본계약, gtc 개발
Diffstat (limited to 'lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx')
-rw-r--r--lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx231
1 files changed, 231 insertions, 0 deletions
diff --git a/lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx b/lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx
new file mode 100644
index 00000000..e500c069
--- /dev/null
+++ b/lib/basic-contract/gtc-vendor/view-clause-variables-dialog.tsx
@@ -0,0 +1,231 @@
+"use client"
+
+import * as React from "react"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Badge } from "@/components/ui/badge"
+import { Input } from "@/components/ui/input"
+
+import { Eye, Copy, Check, Settings2 } from "lucide-react"
+import { toast } from "sonner"
+import { cn } from "@/lib/utils"
+
+import { type GtcClauseTreeView } from "@/db/schema/gtc"
+
+interface ViewClauseVariablesDialogProps
+ extends React.ComponentPropsWithRef<typeof Dialog> {
+ clause: GtcClauseTreeView | null
+ onEditVariables?: () => void
+}
+
+export function ViewClauseVariablesDialog({
+ clause,
+ onEditVariables,
+ ...props
+}: ViewClauseVariablesDialogProps) {
+ const [copiedField, setCopiedField] = React.useState<string | null>(null)
+
+ const copyToClipboard = async (text: string, fieldName: string) => {
+ try {
+ await navigator.clipboard.writeText(text)
+ setCopiedField(fieldName)
+ toast.success(`${fieldName} 변수명이 복사되었습니다.`)
+
+ // 2초 후 복사 상태 초기화
+ setTimeout(() => {
+ setCopiedField(null)
+ }, 2000)
+ } catch (error) {
+ toast.error("복사 중 오류가 발생했습니다.")
+ }
+ }
+
+ const copyAllVariables = async () => {
+ if (!clause) return
+
+ const allVariables = [
+ clause.autoNumberVariable,
+ clause.autoSubtitleVariable,
+ clause.autoContentVariable
+ ].filter(Boolean).join('\n')
+
+ try {
+ await navigator.clipboard.writeText(allVariables)
+ toast.success("모든 변수명이 복사되었습니다.")
+ } catch (error) {
+ toast.error("복사 중 오류가 발생했습니다.")
+ }
+ }
+
+ if (!clause) {
+ return null
+ }
+
+ const variables = [
+ {
+ label: "채번 변수명",
+ value: clause.autoNumberVariable,
+ fieldName: "채번",
+ description: "조항 번호를 표시하는 변수"
+ },
+ {
+ label: "소제목 변수명",
+ value: clause.autoSubtitleVariable,
+ fieldName: "소제목",
+ description: "조항 제목을 표시하는 변수"
+ },
+ {
+ label: "상세항목 변수명",
+ value: clause.autoContentVariable,
+ fieldName: "상세항목",
+ description: "조항 내용을 표시하는 변수"
+ }
+ ]
+
+ return (
+ <Dialog {...props}>
+ <DialogContent className="max-w-2xl">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <Eye className="h-5 w-5" />
+ PDFTron 변수명 보기
+ </DialogTitle>
+ <DialogDescription>
+ 현재 조항에 설정된 PDFTron 변수명을 확인하고 복사할 수 있습니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ {/* 조항 정보 */}
+ <div className="p-3 bg-muted/50 rounded-lg">
+ <div className="font-medium mb-2">조항 정보</div>
+ <div className="space-y-1 text-sm text-muted-foreground">
+ <div className="flex items-center gap-2">
+ <Badge variant="outline">{clause.itemNumber}</Badge>
+ <span>{clause.subtitle}</span>
+ <Badge variant={clause.hasAllVariableNames ? "default" : "destructive"}>
+ {clause.hasAllVariableNames ? "설정됨" : "미설정"}
+ </Badge>
+ </div>
+ {clause.fullPath && (
+ <div>경로: {clause.fullPath}</div>
+ )}
+ {clause.category && (
+ <div>분류: {clause.category}</div>
+ )}
+ </div>
+ </div>
+
+ {/* 변수명 목록 */}
+ <div className="space-y-4">
+ <div className="flex items-center justify-between">
+ <h3 className="text-sm font-medium">설정된 변수명</h3>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={copyAllVariables}
+ className="h-8"
+ >
+ <Copy className="mr-2 h-3 w-3" />
+ 전체 복사
+ </Button>
+ </div>
+
+ <div className="space-y-3">
+ {variables.map((variable, index) => (
+ <div key={index} className="space-y-2">
+ <div className="flex items-center justify-between">
+ <div>
+ <div className="text-sm font-medium">{variable.label}</div>
+ <div className="text-xs text-muted-foreground">{variable.description}</div>
+ </div>
+ <Button
+ variant="ghost"
+ size="sm"
+ onClick={() => copyToClipboard(variable.value, variable.fieldName)}
+ className="h-8 px-2"
+ >
+ {copiedField === variable.fieldName ? (
+ <Check className="h-3 w-3 text-green-500" />
+ ) : (
+ <Copy className="h-3 w-3" />
+ )}
+ </Button>
+ </div>
+ <div className="relative">
+ <Input
+ value={variable.value}
+ readOnly
+ className="font-mono text-xs bg-muted/30"
+ />
+ </div>
+ </div>
+ ))}
+ </div>
+ </div>
+
+ {/* PDFTron 템플릿 미리보기 */}
+ <div className="space-y-2">
+ <h3 className="text-sm font-medium">PDFTron 템플릿 미리보기</h3>
+ <div className="p-3 bg-gray-50 border rounded-lg">
+ <div className="space-y-2 text-xs font-mono">
+ <div className="text-blue-600">
+ {"{{" + clause.autoNumberVariable + "}}"}. {"{{" + clause.autoSubtitleVariable + "}}"}
+ </div>
+ <div className="text-gray-600 ml-4">
+ {"{{" + clause.autoContentVariable + "}}"}
+ </div>
+ </div>
+ <div className="text-xs text-muted-foreground mt-2">
+ 실제 문서에서 위와 같은 형태로 표시됩니다.
+ </div>
+ </div>
+ </div>
+
+ {/* 실제 값 미리보기 */}
+ <div className="space-y-2">
+ <h3 className="text-sm font-medium">실제 값 미리보기</h3>
+ <div className="p-3 bg-blue-50 border border-blue-200 rounded-lg">
+ <div className="space-y-2 text-sm">
+ <div className="font-medium text-blue-900">
+ {clause.itemNumber}. {clause.subtitle}
+ </div>
+ {clause.content && (
+ <div className="text-blue-800 ml-4">
+ {clause.content.length > 150
+ ? `${clause.content.substring(0, 150)}...`
+ : clause.content
+ }
+ </div>
+ )}
+ {!clause.content && (
+ <div className="text-blue-600 ml-4 italic">
+ (그룹핑 조항 - 상세내용 없음)
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+
+ <DialogFooter>
+ {onEditVariables && (
+ <Button
+ variant="outline"
+ onClick={() => {
+ props.onOpenChange?.(false)
+ onEditVariables()
+ }}
+ >
+ <Settings2 className="mr-2 h-4 w-4" />
+ 변수 설정 수정
+ </Button>
+ )}
+ <Button
+ onClick={() => props.onOpenChange?.(false)}
+ >
+ Close
+ </Button>
+ </DialogFooter>
+ </DialogContent>
+ </Dialog>
+ )
+} \ No newline at end of file