summaryrefslogtreecommitdiff
path: root/lib/basic-contract/gtc-vendor/preview-document-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/basic-contract/gtc-vendor/preview-document-dialog.tsx')
-rw-r--r--lib/basic-contract/gtc-vendor/preview-document-dialog.tsx272
1 files changed, 272 insertions, 0 deletions
diff --git a/lib/basic-contract/gtc-vendor/preview-document-dialog.tsx b/lib/basic-contract/gtc-vendor/preview-document-dialog.tsx
new file mode 100644
index 00000000..78ddc7f7
--- /dev/null
+++ b/lib/basic-contract/gtc-vendor/preview-document-dialog.tsx
@@ -0,0 +1,272 @@
+"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,
+ AlertCircle
+} 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 [hasError, setHasError] = React.useState(false)
+
+ // 조항 통계 계산
+ 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)
+ setHasError(false)
+ setDocumentGenerated(false)
+
+ try {
+ // 실제로는 ClausePreviewViewer에서 문서 생성을 처리하므로
+ // 여기서는 상태만 관리
+ console.log("🚀 문서 미리보기 생성 시작")
+
+ // ClausePreviewViewer가 완전히 로드될 때까지 기다림
+ await new Promise(resolve => setTimeout(resolve, 2000))
+
+ if (!hasError) {
+ setDocumentGenerated(true)
+ toast.success("문서 미리보기가 생성되었습니다.")
+ }
+ } catch (error) {
+ console.error("문서 생성 중 오류:", error)
+ setHasError(true)
+ toast.error("문서 생성 중 오류가 발생했습니다.")
+ } finally {
+ setIsGenerating(false)
+ }
+ }
+
+ const handleExportDocument = () => {
+ if (viewerInstance) {
+ try {
+ // PDFTron의 다운로드 기능 실행
+ viewerInstance.UI.downloadPdf({
+ filename: `${document?.title || 'GTC계약서'}_미리보기.pdf`
+ })
+ toast.success("PDF 다운로드가 시작됩니다.")
+ } catch (error) {
+ console.error("다운로드 오류:", error)
+ toast.error("다운로드 중 오류가 발생했습니다.")
+ }
+ } else {
+ toast.error("뷰어가 준비되지 않았습니다.")
+ }
+ }
+
+ const handleRegenerateDocument = () => {
+ console.log("🔄 문서 재생성 시작")
+ setDocumentGenerated(false)
+ setHasError(false)
+ handleGeneratePreview()
+ }
+
+ const handleViewerSuccess = React.useCallback(() => {
+ setDocumentGenerated(true)
+ setIsGenerating(false)
+ setHasError(false)
+ }, [])
+
+ const handleViewerError = React.useCallback(() => {
+ setHasError(true)
+ setIsGenerating(false)
+ setDocumentGenerated(false)
+ }, [])
+
+ // 다이얼로그가 열릴 때 자동으로 미리보기 생성
+ React.useEffect(() => {
+ if (props.open && !documentGenerated && !isGenerating && !hasError) {
+ const timer = setTimeout(() => {
+ handleGeneratePreview()
+ }, 300) // 다이얼로그 애니메이션 후 시작
+
+ return () => clearTimeout(timer)
+ }
+ }, [props.open, documentGenerated, isGenerating, hasError])
+
+ // 다이얼로그가 닫힐 때 상태 초기화
+ React.useEffect(() => {
+ if (!props.open) {
+ setDocumentGenerated(false)
+ setIsGenerating(false)
+ setHasError(false)
+ setViewerInstance(null)
+ }
+ }, [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>
+ {hasError && (
+ <Badge variant="destructive" className="gap-1">
+ <AlertCircle className="h-3 w-3" />
+ 오류 발생
+ </Badge>
+ )}
+ </div>
+ <div className="flex items-center gap-2">
+ {documentGenerated && !hasError && (
+ <>
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleRegenerateDocument}
+ disabled={isGenerating}
+ >
+ <RefreshCw className={`mr-2 h-3 w-3 ${isGenerating ? 'animate-spin' : ''}`} />
+ 재생성
+ </Button>
+ {/* <Button
+ variant="outline"
+ size="sm"
+ onClick={handleExportDocument}
+ disabled={!viewerInstance}
+ >
+ <Download className="mr-2 h-3 w-3" />
+ PDF 다운로드
+ </Button> */}
+ </>
+ )}
+ {hasError && (
+ <Button
+ variant="default"
+ size="sm"
+ onClick={handleRegenerateDocument}
+ disabled={isGenerating}
+ >
+ <RefreshCw className={`mr-2 h-3 w-3 ${isGenerating ? 'animate-spin' : ''}`} />
+ 다시 시도
+ </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>
+ <p className="text-xs text-gray-400 mt-2">
+ 초기화에 시간이 걸릴 수 있습니다...
+ </p>
+ </div>
+ ) : hasError ? (
+ <div className="absolute inset-0 flex flex-col items-center justify-center bg-muted/10">
+ <AlertCircle className="h-12 w-12 text-destructive mb-4" />
+ <p className="text-lg font-medium mb-2 text-destructive">문서 생성 실패</p>
+ <p className="text-sm text-muted-foreground mb-4 text-center max-w-md">
+ 문서 생성 중 오류가 발생했습니다. 네트워크 연결이나 파일 권한을 확인해주세요.
+ </p>
+ <Button onClick={handleRegenerateDocument} disabled={isGenerating}>
+ <RefreshCw className="mr-2 h-4 w-4" />
+ 다시 시도
+ </Button>
+ </div>
+ ) : documentGenerated ? (
+ <ClausePreviewViewer
+ clauses={clauses}
+ document={document}
+ instance={viewerInstance}
+ setInstance={setViewerInstance}
+ onSuccess={handleViewerSuccess}
+ onError={handleViewerError}
+ />
+ ) : (
+ <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