diff options
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.tsx | 231 |
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 |
