diff options
Diffstat (limited to 'lib/gtc-contract/gtc-clauses/table/preview-document-dialog.tsx')
| -rw-r--r-- | lib/gtc-contract/gtc-clauses/table/preview-document-dialog.tsx | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/lib/gtc-contract/gtc-clauses/table/preview-document-dialog.tsx b/lib/gtc-contract/gtc-clauses/table/preview-document-dialog.tsx new file mode 100644 index 00000000..29ab1b5a --- /dev/null +++ b/lib/gtc-contract/gtc-clauses/table/preview-document-dialog.tsx @@ -0,0 +1,189 @@ +"use client" + +import * as React from "react" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { Separator } from "@/components/ui/separator" + +import { + Eye, + Download, + Loader2, + FileText, + RefreshCw, + Settings +} from "lucide-react" +import { toast } from "sonner" + +import { type GtcClauseTreeView } from "@/db/schema/gtc" +import { ClausePreviewViewer } from "./clause-preview-viewer" + +interface PreviewDocumentDialogProps + extends React.ComponentPropsWithRef<typeof Dialog> { + clauses: GtcClauseTreeView[] + document: any + onExport?: () => void +} + +export function PreviewDocumentDialog({ + clauses, + document, + onExport, + ...props +}: PreviewDocumentDialogProps) { + const [isGenerating, setIsGenerating] = React.useState(false) + const [documentGenerated, setDocumentGenerated] = React.useState(false) + const [viewerInstance, setViewerInstance] = React.useState<any>(null) + + // 조항 통계 계산 + const stats = React.useMemo(() => { + const activeClausesCount = clauses.filter(c => c.isActive !== false).length + const topLevelCount = clauses.filter(c => !c.parentId && c.isActive !== false).length + const hasContentCount = clauses.filter(c => c.content && c.isActive !== false).length + + return { + total: activeClausesCount, + topLevel: topLevelCount, + withContent: hasContentCount, + withoutContent: activeClausesCount - hasContentCount + } + }, [clauses]) + + const handleGeneratePreview = async () => { + setIsGenerating(true) + try { + // 잠시 후 문서 생성 완료로 설정 (실제로는 뷰어에서 처리) + setTimeout(() => { + setDocumentGenerated(true) + setIsGenerating(false) + toast.success("문서 미리보기가 생성되었습니다.") + }, 1500) + } catch (error) { + setIsGenerating(false) + toast.error("문서 생성 중 오류가 발생했습니다.") + } + } + + const handleExportDocument = () => { + if (viewerInstance) { + // PDFTron의 다운로드 기능 실행 + viewerInstance.UI.downloadPdf({ + filename: `${document?.title || 'GTC계약서'}_미리보기.pdf` + }) + toast.success("문서가 다운로드됩니다.") + } + } + + const handleRegenerateDocument = () => { + setDocumentGenerated(false) + handleGeneratePreview() + } + + React.useEffect(() => { + // 다이얼로그가 열릴 때 자동으로 미리보기 생성 + if (props.open && !documentGenerated && !isGenerating) { + handleGeneratePreview() + } + }, [props.open]) + + return ( + <Dialog {...props}> + <DialogContent className="max-w-7xl h-[90vh] flex flex-col"> + <DialogHeader className="flex-shrink-0"> + <DialogTitle className="flex items-center gap-2"> + <Eye className="h-5 w-5" /> + 문서 미리보기 + </DialogTitle> + <DialogDescription> + 현재 조항들을 기반으로 생성된 문서를 미리보기합니다. + </DialogDescription> + </DialogHeader> + + {/* 문서 정보 및 통계 */} + <div className="flex-shrink-0 p-4 bg-muted/30 rounded-lg"> + <div className="flex items-center justify-between mb-3"> + <div className="flex items-center gap-2"> + <FileText className="h-4 w-4" /> + <span className="font-medium">{document?.title || 'GTC 계약서'}</span> + <Badge variant="outline">{stats.total}개 조항</Badge> + </div> + <div className="flex items-center gap-2"> + {documentGenerated && ( + <> + <Button + variant="outline" + size="sm" + onClick={handleRegenerateDocument} + disabled={isGenerating} + > + <RefreshCw className="mr-2 h-3 w-3" /> + 재생성 + </Button> + <Button + variant="outline" + size="sm" + onClick={handleExportDocument} + > + <Download className="mr-2 h-3 w-3" /> + PDF 다운로드 + </Button> + </> + )} + </div> + </div> + + <div className="grid grid-cols-4 gap-4 text-sm"> + <div className="text-center p-2 bg-background rounded"> + <div className="font-medium text-lg">{stats.total}</div> + <div className="text-muted-foreground">총 조항</div> + </div> + <div className="text-center p-2 bg-background rounded"> + <div className="font-medium text-lg">{stats.topLevel}</div> + <div className="text-muted-foreground">최상위 조항</div> + </div> + <div className="text-center p-2 bg-background rounded"> + <div className="font-medium text-lg text-green-600">{stats.withContent}</div> + <div className="text-muted-foreground">내용 있음</div> + </div> + <div className="text-center p-2 bg-background rounded"> + <div className="font-medium text-lg text-amber-600">{stats.withoutContent}</div> + <div className="text-muted-foreground">제목만</div> + </div> + </div> + </div> + + <Separator /> + + {/* PDFTron 뷰어 영역 */} + <div className="flex-1 min-h-0 relative"> + {isGenerating ? ( + <div className="absolute inset-0 flex flex-col items-center justify-center bg-background"> + <Loader2 className="h-8 w-8 animate-spin text-primary mb-4" /> + <p className="text-lg font-medium mb-2">문서 생성 중...</p> + <p className="text-sm text-muted-foreground"> + {stats.total}개의 조항을 배치하고 있습니다. + </p> + </div> + ) : documentGenerated ? ( + <ClausePreviewViewer + clauses={clauses} + document={document} + instance={viewerInstance} + setInstance={setViewerInstance} + /> + ) : ( + <div className="absolute inset-0 flex flex-col items-center justify-center bg-muted/10"> + <FileText className="h-12 w-12 text-muted-foreground mb-4" /> + <p className="text-lg font-medium mb-2">문서 미리보기 준비 중</p> + <Button onClick={handleGeneratePreview} disabled={isGenerating}> + <Eye className="mr-2 h-4 w-4" /> + 미리보기 생성 + </Button> + </div> + )} + </div> + </DialogContent> + </Dialog> + ) +}
\ No newline at end of file |
