summaryrefslogtreecommitdiff
path: root/components/information
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-01 02:53:18 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-01 02:53:18 +0000
commitd66d308169e559457878c02e3b0443da22693241 (patch)
tree257b4d1d3345d2828e6ea8473938b5113d2ae733 /components/information
parent4ab3f7fd98f544244df972f3f333bbe3525d54f8 (diff)
(최겸) 정보시스템 인포메이션 기능 개발
Diffstat (limited to 'components/information')
-rw-r--r--components/information/information-button.tsx259
1 files changed, 259 insertions, 0 deletions
diff --git a/components/information/information-button.tsx b/components/information/information-button.tsx
new file mode 100644
index 00000000..da0de548
--- /dev/null
+++ b/components/information/information-button.tsx
@@ -0,0 +1,259 @@
+"use client"
+
+import React, { useState, useEffect } from "react"
+import { Info, Download, Edit } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog"
+import { getCachedPageInformation, getCachedEditPermission } from "@/lib/information/service"
+import { UpdateInformationDialog } from "@/lib/information/table/update-information-dialog"
+import type { PageInformation } from "@/db/schema/information"
+import { useSession } from "next-auth/react"
+
+interface InformationButtonProps {
+ pageCode: string
+ className?: string
+ variant?: "default" | "outline" | "ghost" | "secondary"
+ size?: "default" | "sm" | "lg" | "icon"
+}
+
+export function InformationButton({
+ pageCode,
+ className,
+ variant = "ghost",
+ size = "icon"
+}: InformationButtonProps) {
+ const { data: session } = useSession()
+ const [information, setInformation] = useState<PageInformation | null>(null)
+ const [isLoading, setIsLoading] = useState(false)
+ const [isOpen, setIsOpen] = useState(false)
+ const [hasEditPermission, setHasEditPermission] = useState(false)
+ const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
+
+ useEffect(() => {
+ if (isOpen && !information) {
+ loadInformation()
+ }
+ }, [isOpen, information])
+
+ // 편집 권한 확인
+ useEffect(() => {
+ const checkEditPermission = async () => {
+ if (session?.user?.id) {
+ try {
+ const permission = await getCachedEditPermission(pageCode, session.user.id)
+ setHasEditPermission(permission)
+ } catch (error) {
+ console.error("Failed to check edit permission:", error)
+ setHasEditPermission(false)
+ }
+ }
+ }
+
+ checkEditPermission()
+ }, [pageCode, session?.user?.id])
+
+ const loadInformation = async () => {
+ setIsLoading(true)
+ try {
+ const data = await getCachedPageInformation(pageCode)
+ setInformation(data)
+ } catch (error) {
+ console.error("Failed to load information:", error)
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ const handleDownload = () => {
+ if (information?.attachmentFilePath && information?.attachmentFileName) {
+ const link = document.createElement('a')
+ link.href = information.attachmentFilePath
+ link.download = information.attachmentFileName
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ }
+ }
+
+ const handleEditClick = () => {
+ setIsEditDialogOpen(true)
+ }
+
+ const handleEditClose = () => {
+ setIsEditDialogOpen(false)
+ refreshInformation()
+ }
+
+ const refreshInformation = () => {
+ // 편집 후 정보 다시 로드
+ setInformation(null)
+ if (isOpen) {
+ loadInformation()
+ }
+ // 캐시 무효화를 위해 다시 확인
+ setTimeout(() => {
+ loadInformation()
+ }, 500)
+ }
+
+ // 인포메이션이 없으면 버튼을 숨김
+ const [hasInformation, setHasInformation] = useState<boolean | null>(null)
+
+ useEffect(() => {
+ const checkInformation = async () => {
+ try {
+ const data = await getCachedPageInformation(pageCode)
+ setHasInformation(!!data)
+ } catch {
+ setHasInformation(false)
+ }
+ }
+ checkInformation()
+ }, [pageCode])
+
+ // 인포메이션이 없으면 버튼을 숨김
+ if (hasInformation === false) {
+ return null
+ }
+
+ return (
+ <>
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
+ <DialogTrigger asChild>
+ <Button
+ variant={variant}
+ size={size}
+ className={className}
+ title="페이지 정보"
+ >
+ <Info className="h-4 w-4" />
+ {size !== "icon" && <span className="ml-1">정보</span>}
+ </Button>
+ </DialogTrigger>
+ <DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
+ <DialogHeader>
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-2">
+ {/* <Info className="h-5 w-5" /> */}
+ <div>
+ <DialogTitle>{information?.title || "페이지 정보"}</DialogTitle>
+ <DialogDescription>{information?.pageName}</DialogDescription>
+ </div>
+ </div>
+ {hasEditPermission && (
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleEditClick}
+ className="flex items-center gap-2 mr-2"
+ >
+ <Edit className="h-4 w-4" />
+ 편집
+ </Button>
+ )}
+ </div>
+ </DialogHeader>
+
+ <div className="mt-4 space-y-6">
+ {isLoading ? (
+ <div className="flex items-center justify-center py-8">
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
+ </div>
+ ) : information ? (
+ <>
+ {/* 공지사항 */}
+ {(information.noticeTitle || information.noticeContent) && (
+ <div className="space-y-4">
+ <div className="flex items-center gap-2">
+ <h4 className="font-semibold text-xl">공지사항</h4>
+ </div>
+ <div className="bg-blue-50 border-2 border-blue-200 rounded-xl p-6">
+ {information.noticeTitle && (
+ <div className="text-base font-semibold mb-4">
+ 제목: {information.noticeTitle}
+ </div>
+ )}
+ {information.noticeContent && (
+ <div className="bg-white border-2 border-blue-200 rounded-lg p-4 max-h-48 overflow-y-auto">
+ <div className="text-base whitespace-pre-wrap leading-relaxed">
+ {information.noticeContent}
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )}
+
+ {/* 페이지 정보 */}
+ <div className="space-y-3">
+ <h4 className="font-medium text-lg">도움말</h4>
+ <div className="bg-gray-50 border rounded-lg p-4">
+ <div className="text-sm text-gray-600 whitespace-pre-wrap max-h-40 overflow-y-auto">
+ {information.description || "페이지 설명이 없습니다."}
+ </div>
+ </div>
+ </div>
+
+ {/* 첨부파일 */}
+ <div className="space-y-3">
+ <h4 className="font-medium text-lg">첨부파일</h4>
+ {information.attachmentFileName ? (
+ <div className="bg-gray-50 border rounded-lg p-4">
+ <div className="flex items-center justify-between p-3 bg-white rounded border">
+ <div className="flex-1">
+ <div className="text-sm font-medium">
+ {information.attachmentFileName}
+ </div>
+ {information.attachmentFileSize && (
+ <div className="text-xs text-gray-500 mt-1">
+ {information.attachmentFileSize}
+ </div>
+ )}
+ </div>
+ <Button
+ size="sm"
+ variant="outline"
+ onClick={handleDownload}
+ className="flex items-center gap-1"
+ >
+ <Download className="h-3 w-3" />
+ 다운로드
+ </Button>
+ </div>
+ </div>
+ ) : (
+ <div className="text-center py-6 text-gray-500 bg-gray-50 rounded-lg">
+ <Download className="h-6 w-6 mx-auto mb-2 text-gray-400" />
+ <p className="text-sm">첨부된 파일이 없습니다.</p>
+ </div>
+ )}
+ </div>
+ </>
+ ) : (
+ <div className="text-center py-8 text-gray-500">
+ 이 페이지에 대한 정보가 없습니다.
+ </div>
+ )}
+ </div>
+ </DialogContent>
+ </Dialog>
+
+ {/* 편집 다이얼로그 */}
+ {information && (
+ <UpdateInformationDialog
+ open={isEditDialogOpen}
+ onOpenChange={setIsEditDialogOpen}
+ information={information}
+ onClose={handleEditClose}
+ />
+ )}
+ </>
+ )
+} \ No newline at end of file