diff options
Diffstat (limited to 'components/documents')
| -rw-r--r-- | components/documents/view-document-dialog.tsx | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/components/documents/view-document-dialog.tsx b/components/documents/view-document-dialog.tsx index eaa09fad..7603fdc0 100644 --- a/components/documents/view-document-dialog.tsx +++ b/components/documents/view-document-dialog.tsx @@ -1,3 +1,4 @@ +<<<<<<< HEAD "use client"; import * as React from "react"; @@ -73,22 +74,95 @@ const DocumentViewer: React.FC<{ ); const [viwerLoading, setViewerLoading] = React.useState<boolean>(true); const [fileSetLoading, setFileSetLoading] = React.useState<boolean>(true); +======= +"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 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 ( + <> + <Button + size="sm" + className="border-blue-200" + variant="outline" + onClick={() => setOpen(prev => !prev)} + > + 문서 보기 + </Button> + {open && <DocumentViewer + open={open} + setOpen={setOpen} + versions={versions} + /> + } + </> + ); +} + +function DocumentViewer({open, setOpen, versions}){ + const [instance, setInstance] = React.useState<null | WebViewerInstance>(null) + const [viwerLoading, setViewerLoading] = React.useState<boolean>(true) + const [fileSetLoading, setFileSetLoading] = React.useState<boolean>(true) +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d const viewer = React.useRef<HTMLDivElement>(null); const initialized = React.useRef(false); const isCancelled = React.useRef(false); // 초기화 중단용 flag const cleanupHtmlStyle = () => { const htmlElement = document.documentElement; +<<<<<<< HEAD // 기존 style 속성 가져오기 const originalStyle = htmlElement.getAttribute("style") || ""; +======= + + // 기존 style 속성 가져오기 + const originalStyle = htmlElement.getAttribute("style") || ""; + +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d // "color-scheme: light" 또는 "color-scheme: dark" 찾기 const colorSchemeStyle = originalStyle .split(";") .map((s) => s.trim()) .find((s) => s.startsWith("color-scheme:")); +<<<<<<< HEAD +======= + +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d // 새로운 스타일 적용 (color-scheme만 유지) if (colorSchemeStyle) { htmlElement.setAttribute("style", colorSchemeStyle + ";"); @@ -96,13 +170,18 @@ const DocumentViewer: React.FC<{ htmlElement.removeAttribute("style"); // color-scheme도 없으면 style 속성 자체 삭제 } +<<<<<<< HEAD console.log("html style 삭제"); +======= + console.log("html style 삭제") +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }; React.useEffect(() => { if (open && !initialized.current) { initialized.current = true; isCancelled.current = false; // 다시 열릴 때는 false로 리셋 +<<<<<<< HEAD requestAnimationFrame(() => { if (viewer.current) { @@ -130,11 +209,41 @@ const DocumentViewer: React.FC<{ "multiTabsEmptyPage", ]); setViewerLoading(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: "demo:1739264618684:616161d7030000000091db1c97c6f386d41d3506ab5b507381ef2ee2bd", + 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); + +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }); }); } }); } +<<<<<<< HEAD return () => { // cleanup 시에는 중단 flag 세움 @@ -142,10 +251,20 @@ const DocumentViewer: React.FC<{ instance.UI.dispose(); } setTimeout(() => cleanupHtmlStyle(), 500); +======= + + return async () => { + // cleanup 시에는 중단 flag 세움 + if(instance){ + await instance.UI.dispose() + } + await setTimeout(() => cleanupHtmlStyle(), 500) +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }; }, [open]); React.useEffect(() => { +<<<<<<< HEAD const loadDocument = async () => { if (instance && versions.length > 0) { const { UI } = instance; @@ -211,10 +330,77 @@ const DocumentViewer: React.FC<{ try { await instance.UI.dispose(); setInstance(null); // 상태도 초기화 +======= + const loadDocument = async () => { + + if(instance && versions.length > 0){ + const { UI } = instance; + + const optionsArray = [] + + versions.forEach(c => { + const {attachments} = c + attachments.forEach(c2 => { + const {fileName, filePath, fileType} = c2 + + const options = { + filename: fileName, + ...(fileType.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 ( + <Dialog open={open} onOpenChange={async (val) => { + console.log({val, fileSetLoading}) + if(!val && fileSetLoading){ + return; + } + + if (instance) { + try { + await instance.UI.dispose(); + setInstance(null); // 상태도 초기화 + +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d } catch (e) { console.warn("dispose error", e); } } +<<<<<<< HEAD // cleanupHtmlStyle() setViewerLoading(false); @@ -244,3 +430,30 @@ const DocumentViewer: React.FC<{ </Dialog> ); }; +======= + + // cleanupHtmlStyle() + setViewerLoading(false); + setOpen(prev => !prev) + await setTimeout(() => cleanupHtmlStyle(), 1000) + }}> + <DialogContent className="w-[90vw] h-[90vh]" style={{maxWidth: "none"}}> + <DialogHeader className="h-[38px]"> + <DialogTitle> + 문서 미리보기 + </DialogTitle> + <DialogDescription> + 첨부파일 미리보기 + </DialogDescription> + </DialogHeader> + <div ref={viewer} style={{height: "calc(90vh - 20px - 38px - 1rem - 48px)"}}> + {viwerLoading && <div className="flex flex-col items-center justify-center py-12"> + <Loader2 className="h-8 w-8 text-blue-500 animate-spin mb-4" /> + <p className="text-sm text-muted-foreground">문서 뷰어 로딩 중...</p> + </div>} + </div> + </DialogContent> + </Dialog> + ); +} +>>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d |
