"use client" import * as React from "react" import { useState } from "react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Info, Download, Edit, Loader2,Eye, EyeIcon } from "lucide-react" import { getPageInformationDirect, getEditPermissionDirect } from "@/lib/information/service" import { getPageNotices } from "@/lib/notice/service" import { UpdateInformationDialog } from "@/lib/information/table/update-information-dialog" import { NoticeViewDialog } from "@/components/notice/notice-view-dialog" // import { PDFTronViewerDialog } from "@/components/document-viewer/pdftron-viewer-dialog" // 주석 처리 - 브라우저 내장 뷰어 사용 import type { PageInformation, InformationAttachment } from "@/db/schema/information" type PageInformationWithUpdatedBy = PageInformation & { updatedByName?: string | null updatedByEmail?: string | null } import type { Notice } from "@/db/schema/notice" import { useSession } from "next-auth/react" import { formatDate } from "@/lib/utils" import prettyBytes from "pretty-bytes" // downloadFile은 동적으로 import interface InformationButtonProps { pagePath: string className?: string variant?: "default" | "outline" | "ghost" | "secondary" size?: "default" | "sm" | "lg" | "icon" } type NoticeWithAuthor = Notice & { authorName: string | null authorEmail: string | null } export function InformationButton({ pagePath, className, variant = "ghost", size = "icon" }: InformationButtonProps) { const { data: session } = useSession() const [isOpen, setIsOpen] = useState(false) const [information, setInformation] = useState(null) const [notices, setNotices] = useState([]) const [hasEditPermission, setHasEditPermission] = useState(false) const [isEditDialogOpen, setIsEditDialogOpen] = useState(false) const [selectedNotice, setSelectedNotice] = useState(null) const [isNoticeViewDialogOpen, setIsNoticeViewDialogOpen] = useState(false) const [dataLoaded, setDataLoaded] = useState(false) const [isLoading, setIsLoading] = useState(false) const [retryCount, setRetryCount] = useState(0) // const [viewerDialogOpen, setViewerDialogOpen] = useState(false) // 주석 처리 - 브라우저 내장 뷰어 사용 // const [selectedFile, setSelectedFile] = useState(null) // 주석 처리 - 브라우저 내장 뷰어 사용 // 데이터 로드 함수 const loadData = React.useCallback(async () => { if (dataLoaded) return setIsLoading(true) try { // 경로 정규화 - 더 안전한 방식 let normalizedPath = pagePath if (normalizedPath.startsWith('/')) { normalizedPath = normalizedPath.slice(1) } // 빈 문자열이면 기본값 설정 if (!normalizedPath) { normalizedPath = 'home' } // 약간의 지연 추가 (프로덕션에서 DB 연결 안정성) if (retryCount > 0) { await new Promise(resolve => setTimeout(resolve, 500 * retryCount)) } // 순차적으로 데이터 조회 (프로덕션 안정성) const infoResult = await getPageInformationDirect(normalizedPath) const noticesResult = await getPageNotices(normalizedPath) setInformation(infoResult) setNotices(noticesResult) setDataLoaded(true) setRetryCount(0) // 성공시 재시도 횟수 리셋 // 권한 확인 - 세션이 확실히 있을 때만 if (session?.user?.id && infoResult) { try { const hasPermission = await getEditPermissionDirect(normalizedPath, session.user.id) setHasEditPermission(hasPermission) } catch (permError) { setHasEditPermission(false) } } } catch (error) { // 재시도 로직 if (retryCount < 2) { setRetryCount(prev => prev + 1) setIsLoading(false) return } // 최대 재시도 후 기본값 설정 setInformation(null) setNotices([]) setHasEditPermission(false) setDataLoaded(true) setRetryCount(0) } finally { setIsLoading(false) } }, [pagePath, session?.user?.id, dataLoaded, retryCount]) // 세션이 준비되면 자동으로 데이터 로드 React.useEffect(() => { if (isOpen && !dataLoaded && session !== undefined) { loadData() } }, [isOpen, dataLoaded, session]) // 재시도 처리 React.useEffect(() => { if (retryCount > 0 && retryCount <= 2) { const timer = setTimeout(() => { setDataLoaded(false) // 재시도를 위해 리셋 }, 500 * retryCount) return () => clearTimeout(timer) } }, [retryCount]) // 다이얼로그 열기 const handleDialogOpen = (open: boolean) => { setIsOpen(open) // useEffect에서 데이터 로딩 처리하므로 여기서는 제거 } // 편집 관련 핸들러 const handleEditClick = () => { setIsEditDialogOpen(true) } const handleEditSuccess = () => { setIsEditDialogOpen(false) // 편집 후 데이터 다시 로드 setDataLoaded(false) setRetryCount(0) } // 공지사항 클릭 핸들러 const handleNoticeClick = (notice: NoticeWithAuthor) => { setSelectedNotice(notice) setIsNoticeViewDialogOpen(true) } // 파일 확장자 확인 함수 const getFileExtension = (fileName: string): string => { return fileName.split('.').pop()?.toLowerCase() || '' } // 뷰어 지원 파일 형식 확인 const isViewerSupported = (fileName: string): boolean => { const extension = getFileExtension(fileName) return ['pdf', 'docx', 'doc'].includes(extension) } // 파일 클릭 핸들러 (뷰어 또는 다운로드) const handleFileClick = async (attachment: InformationAttachment) => { if (isViewerSupported(attachment.fileName)) { // PDF/DOCX 파일은 브라우저 내장 뷰어로 열기 // 동적으로 quickPreview 함수 import const { quickPreview } = await import('@/lib/file-download') await quickPreview(attachment.filePath, attachment.fileName) } else { // 기타 파일은 다운로드 await handleDownload(attachment) } } // 파일 다운로드 핸들러 const handleDownload = async (attachment: InformationAttachment) => { try { // 동적으로 downloadFile 함수 import const { downloadFile } = await import('@/lib/file-download') await downloadFile( attachment.filePath, attachment.fileName, { action: 'download', showToast: true, showSuccessToast: true } ) } catch (error) { console.error('파일 다운로드 실패:', error) } } return ( <>
{isLoading ? (
정보를 불러오는 중...
) : (
{/* 공지사항 섹션 */}

공지사항

{notices.length > 0 && ( {notices.length}개 )}
{notices.length > 0 ? (
{notices.map((notice) => (
handleNoticeClick(notice)} >
{notice.title}
{formatDate(notice.createdAt, "KR")} {notice.authorName && ( {notice.authorName} )}
))}
) : (
공지사항이 없습니다
)}
{/* 안내사항 컨텐츠 */}

안내사항

{hasEditPermission && information && ( )}
{information?.informationContent ? (
{information.informationContent}
수정자: {information.updatedByName || '시스템'} 수정일: {formatDate(information.updatedAt, "KR")}
) : (
안내사항이 없습니다
)}
{/* 첨부파일 */}

첨부파일

{information?.attachments && information.attachments.length > 0 && ( {information.attachments.length}개 )}
{information?.attachments && information.attachments.length > 0 ? (
{information.attachments.map((attachment) => (
{attachment.fileName}
{attachment.fileSize && (
{prettyBytes(Number(attachment.fileSize))}
)}
{isViewerSupported(attachment.fileName) && ( )}
))}
) : (
첨부파일이 없습니다
)}
)}
{/* 공지사항 보기 다이얼로그 */} {/* 편집 다이얼로그 */} {information && ( )} {/* PDFTron 뷰어 다이얼로그 - 주석 처리 (브라우저 내장 뷰어 사용) */} {/* */} ) }