From e0dfb55c5457aec489fc084c4567e791b4c65eb1 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 26 Mar 2025 00:37:41 +0000 Subject: 3/25 까지의 대표님 작업사항 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/documents/view-document-dialog.tsx | 246 ++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 components/documents/view-document-dialog.tsx (limited to 'components/documents/view-document-dialog.tsx') diff --git a/components/documents/view-document-dialog.tsx b/components/documents/view-document-dialog.tsx new file mode 100644 index 00000000..eaa09fad --- /dev/null +++ b/components/documents/view-document-dialog.tsx @@ -0,0 +1,246 @@ +"use client"; + +import * as React from "react"; +import { WebViewerInstance } from "@pdftron/webviewer"; +import { + Dialog, + DialogTrigger, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { Building2, FileIcon, Loader2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import fs from "fs"; + +// 인터페이스 +interface Attachment { + id: number; + fileName: string; + filePath: string; + fileType?: string; +} + +interface Version { + id: number; + stage: string; + revision: string; + uploaderType: string; + uploaderName: string | null; + comment: string | null; + status: string | null; + planDate: string | null; + actualDate: string | null; + approvedDate: string | null; + DocumentSubmitDate: Date; + attachments: Attachment[]; + selected: boolean; +} + +type ViewDocumentDialogProps = { + versions: Version[]; +}; + +export function ViewDocumentDialog({ versions }: ViewDocumentDialogProps) { + const [open, setOpen] = React.useState(false); + + return ( + <> + + {open && ( + + )} + + ); +} + +const DocumentViewer: React.FC<{ + open: boolean; + setOpen: React.Dispatch>; + versions: Version[]; +}> = ({ open, setOpen, versions }) => { + const [instance, setInstance] = React.useState( + null + ); + const [viwerLoading, setViewerLoading] = React.useState(true); + const [fileSetLoading, setFileSetLoading] = React.useState(true); + const viewer = React.useRef(null); + const initialized = React.useRef(false); + const isCancelled = React.useRef(false); // 초기화 중단용 flag + + const cleanupHtmlStyle = () => { + const htmlElement = document.documentElement; + + // 기존 style 속성 가져오기 + const originalStyle = htmlElement.getAttribute("style") || ""; + + // "color-scheme: light" 또는 "color-scheme: dark" 찾기 + const colorSchemeStyle = originalStyle + .split(";") + .map((s) => s.trim()) + .find((s) => s.startsWith("color-scheme:")); + + // 새로운 스타일 적용 (color-scheme만 유지) + if (colorSchemeStyle) { + htmlElement.setAttribute("style", colorSchemeStyle + ";"); + } else { + htmlElement.removeAttribute("style"); // color-scheme도 없으면 style 속성 자체 삭제 + } + + console.log("html style 삭제"); + }; + + React.useEffect(() => { + if (open && !initialized.current) { + initialized.current = true; + isCancelled.current = false; // 다시 열릴 때는 false로 리셋 + + requestAnimationFrame(() => { + if (viewer.current) { + import("@pdftron/webviewer").then(({ default: WebViewer }) => { + console.log(isCancelled.current); + if (isCancelled.current) { + console.log("📛 WebViewer 초기화 취소됨 (Dialog 닫힘)"); + + return; + } + + WebViewer( + { + path: "/pdftronWeb", + licenseKey: process.env.NEXT_PUBLIC_PDFTRON_WEBVIEW_KEY, + fullAPI: true, + css: "/globals.css", + }, + viewer.current as HTMLDivElement + ).then(async (instance: WebViewerInstance) => { + setInstance(instance); + instance.UI.enableFeatures([instance.UI.Feature.MultiTab]); + instance.UI.disableElements([ + "addTabButton", + "multiTabsEmptyPage", + ]); + setViewerLoading(false); + }); + }); + } + }); + } + + return () => { + // cleanup 시에는 중단 flag 세움 + if (instance) { + instance.UI.dispose(); + } + setTimeout(() => cleanupHtmlStyle(), 500); + }; + }, [open]); + + React.useEffect(() => { + const loadDocument = async () => { + if (instance && versions.length > 0) { + const { UI } = instance; + + const optionsArray: any[] = []; + + versions.forEach((c) => { + const { attachments } = c; + attachments.forEach((c2) => { + const { fileName, filePath, fileType } = c2; + + const fileTypeCur = fileType ?? ""; + + const options = { + filename: fileName, + ...(fileTypeCur.includes("xlsx") && { + officeOptions: { + formatOptions: { + applyPageBreaksToSheet: true, + }, + }, + }), + }; + + optionsArray.push({ + filePath, + options, + }); + }); + }); + + const tabIds = []; + + for (const option of optionsArray) { + const { filePath, options } = option; + const response = await fetch(filePath); + const blob = await response.blob(); + + const tab = await UI.TabManager.addTab(blob, options); + tabIds.push(tab); // 탭 ID 저장 + } + + if (tabIds.length > 0) { + await UI.TabManager.setActiveTab(tabIds[0]); + } + + setFileSetLoading(false); + } + }; + loadDocument(); + }, [instance, versions]); + + return ( + { + console.log({ val, fileSetLoading }); + if (!val && fileSetLoading) { + return; + } + + if (instance) { + try { + await instance.UI.dispose(); + setInstance(null); // 상태도 초기화 + } catch (e) { + console.warn("dispose error", e); + } + } + + // cleanupHtmlStyle() + setViewerLoading(false); + setOpen((prev) => !prev); + await setTimeout(() => cleanupHtmlStyle(), 1000); + }} + > + + + 문서 미리보기 + 첨부파일 미리보기 + +
+ {viwerLoading && ( +
+ +

+ 문서 뷰어 로딩 중... +

+
+ )} +
+
+
+ ); +}; -- cgit v1.2.3