'use client'; import React, { useEffect, useRef, useState } from 'react'; import { useSession } from 'next-auth/react'; import { WebViewerInstance } from '@pdftron/webviewer'; import { Loader2 } from 'lucide-react'; import { toast } from 'sonner'; import { createCustomWatermark } from './creaetWaterMarks'; interface SecurePDFViewerProps { documentUrl: string; fileName: string; category?: string; onClose?: () => void; } export function SecurePDFViewer({ documentUrl, fileName, category, onClose }: SecurePDFViewerProps) { const viewerRef = useRef(null); const instanceRef = useRef(null); const initialized = useRef(false); const isCancelled = useRef(false); const { data: session } = useSession(); const [isLoading, setIsLoading] = useState(true); // WebViewer ์ดˆ๊ธฐํ™” useEffect(() => { if (!initialized.current && viewerRef.current) { initialized.current = true; isCancelled.current = false; requestAnimationFrame(() => { if (viewerRef.current) { import('@pdftron/webviewer').then(({ default: WebViewer }) => { if (isCancelled.current) { console.log('๐Ÿ“› WebViewer ์ดˆ๊ธฐํ™” ์ทจ์†Œ๋จ'); return; } const viewerElement = viewerRef.current; if (!viewerElement) return; WebViewer( { path: '/pdftronWeb', // BasicContractTemplateViewer์™€ ๋™์ผํ•œ ๊ฒฝ๋กœ licenseKey: process.env.NEXT_PUBLIC_PDFTRON_WEBVIEW_KEY, // ๋™์ผํ•œ ๋ผ์ด์„ผ์Šค ํ‚ค fullAPI: true, enableFilePicker: false, enableMeasurement: false, enableRedaction: false, enableAnnotations: false, enableTextSelection: false, enableFormFilling: false, enablePrint: false, enableDownload: false, }, viewerElement ).then(async (instance: WebViewerInstance) => { instanceRef.current = instance; try { const { disableElements } = instance.UI; // ๋ณด์•ˆ์„ ์œ„ํ•ด ๋ชจ๋“  ๋„๊ตฌ ๋น„ํ™œ์„ฑํ™” disableElements([ 'toolsHeader', 'viewControlsButton', 'panToolButton', 'selectToolButton', 'menuButton', 'leftPanel', 'leftPanelButton', 'searchButton', 'notesPanel', 'notesPanelButton', 'toolbarGroup-Annotate', 'toolbarGroup-Shapes', 'toolbarGroup-Edit', 'toolbarGroup-Insert', 'toolbarGroup-FillAndSign', 'toolbarGroup-Forms', 'toolsOverlay', 'printButton', 'downloadButton', 'saveAsButton', 'filePickerHandler', 'textPopup', 'contextMenuPopup', 'pageManipulationOverlay', 'documentControl', 'header', 'ribbons', 'toggleNotesButton' ]); const { Core } = instance; Core.Tools.Tool.disableAutoSwitch(); Core.Tools.Tool.disableTextSelection(); // CSS ์ ์šฉ์œผ๋กœ ์ถ”๊ฐ€ ๋ณด์•ˆ const iframeWindow = instance.UI.iframeWindow; if (iframeWindow && iframeWindow.document) { const style = iframeWindow.document.createElement('style'); style.textContent = ` /* Hide all toolbars and buttons */ .HeaderToolsContainer, .Header, .ToolsHeader, .LeftHeader, .RightHeader, .DocumentContainer > div:first-child { display: none !important; } /* Disable right-click context menu */ * { -webkit-user-select: none !important; -moz-user-select: none !important; -ms-user-select: none !important; user-select: none !important; } /* Hide page controls */ .DocumentContainer .PageControls { display: none !important; } /* Disable text selection cursor */ .pageContainer { cursor: default !important; } /* Prevent drag and drop */ * { -webkit-user-drag: none !important; -khtml-user-drag: none !important; -moz-user-drag: none !important; -o-user-drag: none !important; user-drag: none !important; } `; iframeWindow.document.head.appendChild(style); } console.log('๐Ÿ“ WebViewer ์ดˆ๊ธฐํ™” ์™„๋ฃŒ'); // ๋ฌธ์„œ ๋กœ๋“œ await loadSecureDocument(instance, documentUrl, fileName); } catch (uiError) { console.warn('โš ๏ธ UI ์„ค์ • ์ค‘ ์˜ค๋ฅ˜:', uiError); toast.error('๋ทฐ์–ด ์„ค์ • ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); } }).catch((error) => { console.error('โŒ WebViewer ์ดˆ๊ธฐํ™” ์‹คํŒจ:', error); setIsLoading(false); toast.error('๋ทฐ์–ด ์ดˆ๊ธฐํ™”์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); }); }); } }); } return () => { if (instanceRef.current) { instanceRef.current.UI.dispose(); instanceRef.current = null; } isCancelled.current = true; }; }, []); // ๋ฌธ์„œ ๋กœ๋“œ ํ•จ์ˆ˜ const loadSecureDocument = async ( instance: WebViewerInstance, documentPath: string, docFileName: string ) => { setIsLoading(true); try { // ์ ˆ๋Œ€ URL๋กœ ๋ณ€ํ™˜ const fullPath = documentPath.startsWith('http') ? documentPath : `${window.location.origin}${documentPath}`; console.log('๐Ÿ“„ ๋ณด์•ˆ ๋ฌธ์„œ ๋กœ๋“œ ์‹œ์ž‘:', fullPath); // ๋ฌธ์„œ ๋กœ๋“œ await instance.UI.loadDocument(fullPath, { filename: docFileName, extension: docFileName.split('.').pop()?.toLowerCase(), }); const { documentViewer, annotationManager } = instance.Core; // ๋ฌธ์„œ ๋กœ๋“œ ์™„๋ฃŒ ์ด๋ฒคํŠธ documentViewer.addEventListener('documentLoaded', async () => { setIsLoading(false); if (category !== 'public') { // ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€ const watermarkText = `SHI DATAROOM\n${session?.user?.email || 'CONFIDENTIAL'}\n${new Date().toLocaleString()}`; // ๋Œ€๊ฐ์„  ์›Œํ„ฐ๋งˆํฌ documentViewer.setWatermark({ custom: createCustomWatermark({ text: watermarkText, fontSize: 14, fontFamily: 'Arial', color: 'rgba(128, 128, 128, 0.5)', // ์—ฐํ•œ ํšŒ์ƒ‰ opacity: 30, // 15% ํˆฌ๋ช…๋„ rotation: -45, }) }); // ๊ฐ ํŽ˜์ด์ง€์— ์ปค์Šคํ…€ ์›Œํ„ฐ๋งˆํฌ ์ถ”๊ฐ€ const pageCount = documentViewer.getPageCount(); for (let i = 1; i <= pageCount; i++) { const pageInfo = documentViewer.getDocument().getPageInfo(i); const { width, height } = pageInfo; // FreeTextAnnotation ์ƒ์„ฑ const watermarkAnnot = new instance.Core.Annotations.FreeTextAnnotation(); watermarkAnnot.PageNumber = i; watermarkAnnot.X = width / 4; watermarkAnnot.Y = height / 2; watermarkAnnot.Width = width / 2; watermarkAnnot.Height = 100; watermarkAnnot.setContents( `${session?.user?.email}\n${docFileName}\n${new Date().toLocaleDateString()}` ); watermarkAnnot.FillColor = new instance.Core.Annotations.Color(255, 0, 0, 0.3); watermarkAnnot.TextColor = new instance.Core.Annotations.Color(255, 0, 0, 0.4); watermarkAnnot.FontSize = '24pt'; watermarkAnnot.TextAlign = 'center'; watermarkAnnot.Rotation = -45; watermarkAnnot.ReadOnly = true; watermarkAnnot.Locked = true; watermarkAnnot.Printable = true; annotationManager.addAnnotation(watermarkAnnot); } annotationManager.drawAnnotations(documentViewer.getCurrentPage()); } // Pan ๋ชจ๋“œ๋กœ ์„ค์ • (ํ…์ŠคํŠธ ์„ ํƒ ๋ถˆ๊ฐ€) documentViewer.setToolMode(documentViewer.getTool('Pan')); // ํŽ˜์ด์ง€ ์ด๋™ ๋กœ๊น… documentViewer.addEventListener('pageNumberUpdated', (pageNumber: number) => { console.log(`Page ${pageNumber} viewed at ${new Date().toISOString()}`); // ์„œ๋ฒ„๋กœ ๊ฐ์‚ฌ ๋กœ๊ทธ ์ „์†ก ๊ฐ€๋Šฅ }); console.log('โœ… ๋ณด์•ˆ ๋ฌธ์„œ ๋กœ๋“œ ์™„๋ฃŒ'); toast.success('๋ฌธ์„œ๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); }); // ์—๋Ÿฌ ์ฒ˜๋ฆฌ documentViewer.addEventListener('error', (error: any) => { console.error('Document loading error:', error); setIsLoading(false); toast.error('๋ฌธ์„œ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); }); } catch (err) { console.error('โŒ ๋ฌธ์„œ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜:', err); toast.error(`๋ฌธ์„œ ๋กœ๋“œ ์‹คํŒจ: ${err instanceof Error ? err.message : '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜'}`); setIsLoading(false); } }; // ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ์ฐจ๋‹จ useEffect(() => { const preventShortcuts = (e: KeyboardEvent) => { // Ctrl+C, Ctrl+A, Ctrl+P, Ctrl+S, F12 ๋“ฑ ์ฐจ๋‹จ if ( (e.ctrlKey && ['c', 'a', 'p', 's', 'x', 'v'].includes(e.key.toLowerCase())) || (e.metaKey && ['c', 'a', 'p', 's', 'x', 'v'].includes(e.key.toLowerCase())) || e.key === 'F12' || (e.ctrlKey && e.shiftKey && ['I', 'C', 'J'].includes(e.key)) ) { e.preventDefault(); e.stopPropagation(); return false; } }; const preventContextMenu = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); return false; }; const preventDrag = (e: DragEvent) => { e.preventDefault(); e.stopPropagation(); return false; }; document.addEventListener('keydown', preventShortcuts); document.addEventListener('contextmenu', preventContextMenu); document.addEventListener('dragstart', preventDrag); return () => { document.removeEventListener('keydown', preventShortcuts); document.removeEventListener('contextmenu', preventContextMenu); document.removeEventListener('dragstart', preventDrag); }; }, []); return (
{ e.preventDefault(); e.stopPropagation(); return false; }} onCut={(e) => { e.preventDefault(); e.stopPropagation(); return false; }} onPaste={(e) => { e.preventDefault(); e.stopPropagation(); return false; }} > {isLoading && (

๋ณด์•ˆ ๋ฌธ์„œ ๋กœ๋”ฉ ์ค‘...

)}
{/* ๋ณด์•ˆ ์˜ค๋ฒ„๋ ˆ์ด */}
); }