diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-03-28 06:12:09 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-03-28 06:12:09 +0000 |
| commit | f2c29e0023200b58d5e5c7a4c677a3c473c9bb8e (patch) | |
| tree | f6fcfb6e5dcddceab7529d7ca5fb0a4b44bd8798 /components/documents/view-document-dialog.tsx | |
| parent | f3e640b666c57f133c229d2742fb214c586d21e4 (diff) | |
| parent | dbfc752cbbae6bded6040f4727ec7564d2a3b759 (diff) | |
기만프로 작업내역 머지
Diffstat (limited to 'components/documents/view-document-dialog.tsx')
| -rw-r--r-- | components/documents/view-document-dialog.tsx | 265 |
1 files changed, 136 insertions, 129 deletions
diff --git a/components/documents/view-document-dialog.tsx b/components/documents/view-document-dialog.tsx index 6daa806b..bd802b77 100644 --- a/components/documents/view-document-dialog.tsx +++ b/components/documents/view-document-dialog.tsx @@ -9,78 +9,80 @@ import { import { Building2, FileIcon, Loader2 } from "lucide-react" import { Button } from "@/components/ui/button" +// 인터페이스 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 + 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[] -} + versions: Version[]; +}; -export function ViewDocumentDialog({versions}: ViewDocumentDialogProps){ - const [open, setOpen] = React.useState(false) - +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} - /> - } - </> + <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) +const DocumentViewer: React.FC<{ + open: boolean; + setOpen: React.Dispatch<React.SetStateAction<boolean>>; + versions: Version[]; +}> = ({ 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); const viewer = React.useRef<HTMLDivElement>(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 + ";"); @@ -88,146 +90,151 @@ function DocumentViewer({open, setOpen, versions}){ htmlElement.removeAttribute("style"); // color-scheme도 없으면 style 속성 자체 삭제 } - console.log("html 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) + console.log(isCancelled.current); if (isCancelled.current) { console.log("📛 WebViewer 초기화 취소됨 (Dialog 닫힘)"); - + return; } - + WebViewer( { path: "/pdftronWeb", - licenseKey: "demo:1739264618684:616161d7030000000091db1c97c6f386d41d3506ab5b507381ef2ee2bd", + licenseKey: + "demo:1739264618684:616161d7030000000091db1c97c6f386d41d3506ab5b507381ef2ee2bd", fullAPI: true, - css:"/globals.css" + 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"]); + instance.UI.disableElements([ + "addTabButton", + "multiTabsEmptyPage", + ]); setViewerLoading(false); - }); }); } }); } - - return async () => { + + return () => { // cleanup 시에는 중단 flag 세움 - if(instance){ - await instance.UI.dispose() + if (instance) { + instance.UI.dispose(); } - await setTimeout(() => cleanupHtmlStyle(), 500) + setTimeout(() => cleanupHtmlStyle(), 500); }; }, [open]); React.useEffect(() => { - 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, + 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 - }) - }) - }) + optionsArray.push({ + filePath, + options, + }); + }); + }); - const tabIds = []; + const tabIds = []; - for (const option of optionsArray) { - const { filePath, options } = option; - const response = await fetch(filePath); - const blob = await response.blob(); + 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 저장 - } + const tab = await UI.TabManager.addTab(blob, options); + tabIds.push(tab); // 탭 ID 저장 + } - if (tabIds.length > 0) { - await UI.TabManager.setActiveTab(tabIds[0]); - } + if (tabIds.length > 0) { + await UI.TabManager.setActiveTab(tabIds[0]); + } - setFileSetLoading(false) - } - } - loadDocument(); - }, [instance, versions]) + setFileSetLoading(false); + } + }; + loadDocument(); + }, [instance, versions]); - return ( - <Dialog open={open} onOpenChange={async (val) => { - console.log({val, fileSetLoading}) - if(!val && fileSetLoading){ - return; - } - + <Dialog + open={open} + onOpenChange={async (val) => { + if (!val && fileSetLoading) { + return; + } + if (instance) { try { await instance.UI.dispose(); - setInstance(null); // 상태도 초기화 - + setInstance(null); // 상태도 초기화 } catch (e) { console.warn("dispose error", e); } } - + // 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> + setViewerLoading(false); + setOpen((prev) => !prev); + 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 + 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> + </DialogContent> </Dialog> ); -}
\ No newline at end of file +}; |
