"use client"; import React, { useState, useEffect, useRef, SetStateAction, Dispatch, } from "react"; import { WebViewerInstance } from "@pdftron/webviewer"; import { Loader2 } from "lucide-react"; import { toast } from "sonner"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; interface BasicContractSignViewerProps { contractId?: number; filePath?: string; isOpen?: boolean; onClose?: () => void; onSign?: (documentData: ArrayBuffer) => Promise; instance: WebViewerInstance | null; setInstance: Dispatch>; } export function BasicContractSignViewer({ contractId, filePath, isOpen = false, onClose, onSign, instance, setInstance, }: BasicContractSignViewerProps) { const [fileLoading, setFileLoading] = useState(true); const viewer = useRef(null); const initialized = useRef(false); const isCancelled = useRef(false); const [showDialog, setShowDialog] = useState(isOpen); // 다이얼로그 상태 동기화 useEffect(() => { setShowDialog(isOpen); }, [isOpen]); // WebViewer 초기화 useEffect(() => { if (!initialized.current && viewer.current) { initialized.current = true; isCancelled.current = false; requestAnimationFrame(() => { if (viewer.current) { import("@pdftron/webviewer").then(({ default: WebViewer }) => { if (isCancelled.current) { console.log("📛 WebViewer 초기화 취소됨"); return; } // viewerElement이 확실히 존재함을 확인 const viewerElement = viewer.current; if (!viewerElement) return; WebViewer( { path: "/pdftronWeb", licenseKey: process.env.NEXT_PUBLIC_PDFTRON_WEBVIEW_KEY, fullAPI: true, }, viewerElement ).then((instance: WebViewerInstance) => { setInstance(instance); setFileLoading(false); const { disableElements, setToolbarGroup } = instance.UI; disableElements([ "toolbarGroup-Annotate", "toolbarGroup-Shapes", "toolbarGroup-Insert", "toolbarGroup-Edit", // "toolbarGroup-FillAndSign", "toolbarGroup-Forms", ]); setToolbarGroup("toolbarGroup-View"); }); }); } }); } return () => { if (instance) { instance.UI.dispose(); } isCancelled.current = true; setTimeout(() => cleanupHtmlStyle(), 500); }; }, []); // 문서 로드 useEffect(() => { if (!instance || !filePath) return; loadDocument(instance, filePath); }, [instance, filePath]); // 간소화된 문서 로드 함수 const loadDocument = async (instance: WebViewerInstance, documentPath: string) => { setFileLoading(true); try { const { documentViewer } = instance.Core; await documentViewer.loadDocument(documentPath, { extension: 'pdf' }); } catch (err) { console.error("문서 로딩 중 오류 발생:", err); toast.error("문서를 불러오는데 실패했습니다."); } finally { setFileLoading(false); } }; // 서명 저장 핸들러 const handleSave = async () => { if (!instance) return; try { const { documentViewer } = instance.Core; const doc = documentViewer.getDocument(); // 서명된 문서 데이터 가져오기 const documentData = await doc.getFileData({ includeAnnotations: true, }); // 외부에서 제공된 onSign 핸들러가 있으면 호출 if (onSign) { await onSign(documentData); } else { // 기본 동작 - 서명 성공 메시지 표시 toast.success("계약서가 성공적으로 서명되었습니다."); } handleClose(); } catch (err) { console.error("서명 저장 중 오류 발생:", err); toast.error("서명을 저장하는데 실패했습니다."); } }; // 다이얼로그 닫기 핸들러 const handleClose = () => { if (onClose) { onClose(); } else { setShowDialog(false); } }; // 인라인 뷰어 렌더링 (다이얼로그 모드가 아닐 때) if (!isOpen && !onClose) { return (
{fileLoading && (

문서 로딩 중...

)}
); } // 다이얼로그 뷰어 렌더링 return ( 기본계약서 서명 계약서를 확인하고 서명을 진행해주세요.
{fileLoading && (

문서 로딩 중...

)}
); } // WebViewer 정리 함수 const cleanupHtmlStyle = () => { // iframe 스타일 정리 (WebViewer가 추가한 스타일) const elements = document.querySelectorAll('.Document_container'); elements.forEach((elem) => { elem.remove(); }); };