From e6403e9610253b2bfc7a46e470c236e2ed10c626 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Mon, 17 Nov 2025 20:47:44 +0900
Subject: (김준회) swp: VxDCS 와 동일하게 변경, Complete된 리스트 중 없는 건이
 있으면 DOCUMENT LIST에서 보여줌
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/swp/table/swp-document-detail-dialog.tsx | 567 +++++++++++++++------------
 1 file changed, 310 insertions(+), 257 deletions(-)

(limited to 'lib/swp/table/swp-document-detail-dialog.tsx')

diff --git a/lib/swp/table/swp-document-detail-dialog.tsx b/lib/swp/table/swp-document-detail-dialog.tsx
index 418ddea9..d69e2986 100644
--- a/lib/swp/table/swp-document-detail-dialog.tsx
+++ b/lib/swp/table/swp-document-detail-dialog.tsx
@@ -1,6 +1,6 @@
 "use client";
 
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useMemo } from "react";
 import {
   Dialog,
   DialogContent,
@@ -12,20 +12,31 @@ import { Button } from "@/components/ui/button";
 import { Badge } from "@/components/ui/badge";
 import { 
   Loader2, 
-  ChevronDown, 
-  ChevronRight, 
   Download, 
   FileIcon,
-  XCircle,
   AlertCircle,
+  ArrowDownToLine,
+  ArrowUpFromLine,
 } from "lucide-react";
+import {
+  Table,
+  TableBody,
+  TableCell,
+  TableHead,
+  TableHeader,
+  TableRow,
+} from "@/components/ui/table";
 import { 
-  fetchVendorDocumentDetail,
-  cancelVendorFile,
-  downloadVendorFile,
-} from "@/lib/swp/vendor-actions";
-import type { DocumentListItem, DocumentDetail } from "@/lib/swp/document-service";
+  fetchGetRevTreeCompleteList,
+  parseRevisionTree,
+  fetchGetActivityFileList,
+  type ActivityFileApiResponse,
+} from "@/lib/swp/api-client";
+import { downloadVendorFile } from "@/lib/swp/vendor-actions";
+import type { DocumentListItem } from "@/lib/swp/document-service";
 import { toast } from "sonner";
+import { cn } from "@/lib/utils";
+import { formatSwpDateShort, formatFileSize } from "@/lib/swp/utils";
 
 interface SwpDocumentDetailDialogProps {
   open: boolean;
@@ -36,22 +47,41 @@ interface SwpDocumentDetailDialogProps {
   userId: string;
 }
 
+// Activity 행 데이터
+interface ActivityRow {
+  revNo: string;
+  revSeq: string;
+  stage: string;
+  actvNo: string;
+  inOut: "IN" | "OUT";
+  statusCode: string;
+  statusName: string;
+  transmittalNo: string;
+  refActivityNo: string;
+  createDate: string;
+  createEmpNo: string;
+}
+
 export function SwpDocumentDetailDialog({
   open,
   onOpenChange,
   document,
   projNo,
 }: SwpDocumentDetailDialogProps) {
-  const [detail, setDetail] = useState<DocumentDetail | null>(null);
+  const [activities, setActivities] = useState<ActivityRow[]>([]);
   const [isLoading, setIsLoading] = useState(false);
-  const [expandedRevisions, setExpandedRevisions] = useState<Set<string>>(new Set());
-  const [expandedActivities, setExpandedActivities] = useState<Set<string>>(new Set());
-  const [isAllExpanded, setIsAllExpanded] = useState(true); // 기본값 true
+  const [selectedActivity, setSelectedActivity] = useState<ActivityRow | null>(null);
+  const [activityFiles, setActivityFiles] = useState<ActivityFileApiResponse[]>([]);
+  const [isLoadingFiles, setIsLoadingFiles] = useState(false);
 
   // 문서 상세 로드
   useEffect(() => {
     if (open && document) {
       loadDocumentDetail();
+    } else {
+      // 다이얼로그 닫힐 때 초기화
+      setSelectedActivity(null);
+      setActivityFiles([]);
     }
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [open, document?.DOC_NO]);
@@ -60,100 +90,79 @@ export function SwpDocumentDetailDialog({
     if (!document) return;
 
     setIsLoading(true);
+    setSelectedActivity(null);
+    setActivityFiles([]);
+    
     try {
-      const detailData = await fetchVendorDocumentDetail(projNo, document.DOC_NO);
-      setDetail(detailData);
-      
-      // 모든 리비전 자동 펼치기
-      const allRevKeys = new Set<string>();
-      const allActKeys = new Set<string>();
-      
-      detailData.revisions.forEach((revision) => {
-        const revKey = `${revision.revNo}|${revision.revSeq}`;
-        allRevKeys.add(revKey);
-        
-        // 모든 액티비티도 자동 펼치기
-        revision.activities.forEach((activity) => {
-          const actKey = `${revKey}|${activity.actvNo}`;
-          allActKeys.add(actKey);
+      // GetRevTreeCompleteList 호출
+      const tree = await fetchGetRevTreeCompleteList({
+        proj_no: projNo,
+        doc_no: document.DOC_NO,
+      });
+
+      const parsed = await parseRevisionTree(tree);
+
+      // Activity를 flat한 배열로 변환 (테이블용)
+      const flatActivities: ActivityRow[] = [];
+      parsed.revisions.forEach((rev) => {
+        rev.activities.forEach((act) => {
+          flatActivities.push({
+            revNo: rev.revNo,
+            revSeq: rev.revSeq,
+            stage: rev.stage,
+            actvNo: act.actvNo,
+            inOut: act.inOut,
+            statusCode: act.statusCode,
+            statusName: act.statusName,
+            transmittalNo: act.transmittalNo,
+            refActivityNo: act.refActivityNo,
+            createDate: act.createDate,
+            createEmpNo: act.createEmpNo,
+          });
         });
       });
-      
-      setExpandedRevisions(allRevKeys);
-      setExpandedActivities(allActKeys);
-      setIsAllExpanded(true);
+
+      setActivities(flatActivities);
     } catch (error) {
       console.error("문서 상세 조회 실패:", error);
-      toast.error("문서 상세 정보를 불러오는데 실패했습니다");
+      toast.error("문서 리비전 트리를 불러오는데 실패했습니다");
     } finally {
       setIsLoading(false);
     }
   };
 
-  const toggleRevision = (revKey: string) => {
-    setExpandedRevisions((prev) => {
-      const newSet = new Set(prev);
-      if (newSet.has(revKey)) {
-        newSet.delete(revKey);
-      } else {
-        newSet.add(revKey);
-      }
-      return newSet;
-    });
-  };
-
-  const toggleActivity = (actKey: string) => {
-    setExpandedActivities((prev) => {
-      const newSet = new Set(prev);
-      if (newSet.has(actKey)) {
-        newSet.delete(actKey);
-      } else {
-        newSet.add(actKey);
-      }
-      return newSet;
-    });
-  };
+  // Activity 선택 및 파일 로드
+  const handleActivityClick = async (activity: ActivityRow) => {
+    if (selectedActivity?.actvNo === activity.actvNo) {
+      // 같은 Activity 클릭 시 토글
+      setSelectedActivity(null);
+      setActivityFiles([]);
+      return;
+    }
 
-  // 일괄 열기/닫기
-  const handleToggleAll = () => {
-    if (!detail) return;
+    setSelectedActivity(activity);
+    setIsLoadingFiles(true);
+    setActivityFiles([]);
 
-    if (isAllExpanded) {
-      // 모두 닫기
-      setExpandedRevisions(new Set());
-      setExpandedActivities(new Set());
-      setIsAllExpanded(false);
-    } else {
-      // 모두 열기
-      const allRevKeys = new Set<string>();
-      const allActKeys = new Set<string>();
-      
-      detail.revisions.forEach((revision) => {
-        const revKey = `${revision.revNo}|${revision.revSeq}`;
-        allRevKeys.add(revKey);
-        
-        revision.activities.forEach((activity) => {
-          const actKey = `${revKey}|${activity.actvNo}`;
-          allActKeys.add(actKey);
-        });
+    try {
+      // GetActivityFileList 호출
+      const files = await fetchGetActivityFileList({
+        proj_no: projNo,
+        doc_no: document?.DOC_NO || "",
+        rev_seq: activity.revSeq,
       });
-      
-      setExpandedRevisions(allRevKeys);
-      setExpandedActivities(allActKeys);
-      setIsAllExpanded(true);
-    }
-  };
 
-  const handleCancelFile = async (boxSeq: string, actvSeq: string, fileName: string) => {
-    try {
-      await cancelVendorFile(boxSeq, actvSeq);
-      toast.success(`파일 취소 완료: ${fileName}`);
-      
-      // 문서 상세 재로드
-      await loadDocumentDetail();
+      // 해당 Activity의 파일만 필터링
+      const activitySpecificFiles = files.filter(
+        (f) => f.ACTV_NO === activity.actvNo
+      );
+
+      setActivityFiles(activitySpecificFiles);
     } catch (error) {
-      console.error("파일 취소 실패:", error);
-      toast.error("파일 취소에 실패했습니다");
+      console.error("파일 목록 조회 실패:", error);
+      toast.error("파일 목록을 불러오는데 실패했습니다");
+    } finally {
+      setIsLoadingFiles(false);
     }
   };
 
@@ -185,11 +194,24 @@ export function SwpDocumentDetailDialog({
     }
   };
 
+  // Revision별로 Activity 그룹핑 (rowspan용)
+  const groupedActivities = useMemo(() => {
+    const groups: Map<string, ActivityRow[]> = new Map();
+    activities.forEach((activity) => {
+      const key = `${activity.revNo}|${activity.stage}`;
+      if (!groups.has(key)) {
+        groups.set(key, []);
+      }
+      groups.get(key)!.push(activity);
+    });
+    return groups;
+  }, [activities]);
+
   return (
     <Dialog open={open} onOpenChange={onOpenChange}>
-      <DialogContent className="max-w-6xl max-h-[90vh] overflow-y-auto">
+      <DialogContent className="max-w-[95vw] max-h-[80vh] overflow-hidden flex flex-col">
         <DialogHeader>
-          <DialogTitle>문서 상세</DialogTitle>
+          <DialogTitle>문서 리비전 히스토리</DialogTitle>
           {document && (
             <DialogDescription>
               {document.DOC_NO} - {document.DOC_TITLE}
@@ -198,9 +220,9 @@ export function SwpDocumentDetailDialog({
         </DialogHeader>
 
         {document && (
-          <div className="space-y-4">
+          <div className="flex-1 flex flex-col space-y-4 overflow-hidden min-h-0">
             {/* 문서 정보 */}
-            <div className="grid grid-cols-1 md:grid-cols-4 gap-4 p-4 bg-muted/30 rounded-lg">
+            <div className="grid grid-cols-1 md:grid-cols-5 gap-4 p-4 bg-muted/30 rounded-lg">
               <div>
                 <span className="text-sm font-semibold">프로젝트:</span>
                 <div className="text-sm">{document.PROJ_NO}</div>
@@ -223,174 +245,216 @@ export function SwpDocumentDetailDialog({
                 <span className="text-sm font-semibold">최신 리비전:</span>
                 <div className="text-sm">{document.LTST_REV_NO || "-"}</div>
               </div>
+              <div>
+                <span className="text-sm font-semibold">총 Activity:</span>
+                <div className="text-sm">{activities.length}개</div>
+              </div>
             </div>
 
-            {/* 리비전 및 액티비티 트리 */}
+            {/* Activity 테이블 */}
             {isLoading ? (
               <div className="flex items-center justify-center p-8">
                 <Loader2 className="h-6 w-6 animate-spin" />
-                <span className="ml-2">문서 상세 로딩 중...</span>
+                <span className="ml-2">리비전 트리 로딩 중...</span>
               </div>
-            ) : detail && detail.revisions.length > 0 ? (
-              <div className="space-y-2">
-                {/* 일괄 열기/닫기 버튼 */}
-                <div className="flex justify-end">
-                  <Button
-                    variant="outline"
-                    size="sm"
-                    onClick={handleToggleAll}
-                  >
-                    {isAllExpanded ? (
+            ) : activities.length > 0 ? (
+              <>
+                {/* Activity 테이블 (위) */}
+                <div className="flex-1 overflow-auto border rounded-lg min-h-0">
+                  <Table>
+                    <TableHeader className="sticky top-0 bg-background z-10">
+                      <TableRow>
+                        <TableHead className="w-[80px]">Rev</TableHead>
+                        <TableHead className="w-[80px]">Stage</TableHead>
+                        <TableHead className="w-[80px]">IN/OUT</TableHead>
+                        <TableHead className="w-[100px]">Status</TableHead>
+                        <TableHead className="min-w-[150px]">Transmittal No</TableHead>
+                        <TableHead className="min-w-[150px]">Activity No</TableHead>
+                        <TableHead className="min-w-[100px]">Ref Activity</TableHead>
+                        <TableHead className="w-[120px]">Modified</TableHead>
+                        <TableHead className="w-[80px]">By</TableHead>
+                      </TableRow>
+                    </TableHeader>
+                    <TableBody>
+                      {Array.from(groupedActivities.entries()).map(([key, groupActivities]) => {
+                        const [revNo, stage] = key.split("|");
+                        return groupActivities.map((activity, idx) => (
+                          <TableRow
+                            key={activity.actvNo}
+                            className={cn(
+                              "cursor-pointer hover:bg-muted/50",
+                              selectedActivity?.actvNo === activity.actvNo &&
+                                "bg-blue-50 hover:bg-blue-100"
+                            )}
+                            onClick={() => handleActivityClick(activity)}
+                          >
+                            {/* Rev 컬럼 (첫 행만 표시, rowspan) */}
+                            {idx === 0 && (
+                              <TableCell 
+                                className="font-mono text-sm font-semibold align-top border-r"
+                                rowSpan={groupActivities.length}
+                              >
+                                {revNo}
+                              </TableCell>
+                            )}
+                            {/* Stage 컬럼 (첫 행만 표시, rowspan) */}
+                            {idx === 0 && (
+                              <TableCell 
+                                className="align-top border-r"
+                                rowSpan={groupActivities.length}
+                              >
+                                <Badge
+                                  variant="outline"
+                                  className={
+                                    stage === "IFC"
+                                      ? "bg-green-100 text-green-800"
+                                      : stage === "IFA"
+                                      ? "bg-blue-100 text-blue-800"
+                                      : "bg-gray-100 text-gray-800"
+                                  }
+                                >
+                                  {stage}
+                                </Badge>
+                              </TableCell>
+                            )}
+                            <TableCell>
+                              <Badge
+                                variant="outline"
+                                className={
+                                  activity.inOut === "IN"
+                                    ? "bg-blue-100 text-blue-800"
+                                    : "bg-green-100 text-green-800"
+                                }
+                              >
+                                {activity.inOut === "IN" ? (
+                                  <>
+                                    <ArrowDownToLine className="h-3 w-3 mr-1" />
+                                    IN
+                                  </>
+                                ) : (
+                                  <>
+                                    <ArrowUpFromLine className="h-3 w-3 mr-1" />
+                                    OUT
+                                  </>
+                                )}
+                              </Badge>
+                            </TableCell>
+                            <TableCell>
+                              <div className="text-sm">
+                                <div className="font-medium">{activity.statusName}</div>
+                                <div className="text-xs text-muted-foreground">
+                                  {activity.statusCode}
+                                </div>
+                              </div>
+                            </TableCell>
+                            <TableCell className="text-sm">
+                              {activity.transmittalNo || "-"}
+                            </TableCell>
+                            <TableCell className="font-mono text-xs">
+                              {activity.actvNo}
+                            </TableCell>
+                            <TableCell className="font-mono text-xs">
+                              {activity.refActivityNo || "-"}
+                            </TableCell>
+                            <TableCell className="text-xs">
+                              {formatSwpDateShort(activity.createDate)}
+                            </TableCell>
+                            <TableCell className="text-xs">
+                              {activity.createEmpNo}
+                            </TableCell>
+                          </TableRow>
+                        ));
+                      })}
+                    </TableBody>
+                  </Table>
+                </div>
+
+                {/* 파일 목록 (아래) */}
+                <div className="border rounded-lg overflow-hidden" style={{ height: "250px" }}>
+                  <div className="p-3 bg-muted/50 border-b">
+                    <h3 className="font-semibold text-sm">파일 목록</h3>
+                    {selectedActivity ? (
                       <>
-                        <ChevronDown className="h-4 w-4 mr-2" />
-                        일괄 닫기
+                        <p className="text-xs text-muted-foreground mt-1">
+                          Activity: {selectedActivity.actvNo}
+                        </p>
+                        <p className="text-xs text-muted-foreground">
+                          Rev {selectedActivity.revNo} ({selectedActivity.stage}) / {selectedActivity.inOut}
+                        </p>
                       </>
                     ) : (
-                      <>
-                        <ChevronRight className="h-4 w-4 mr-2" />
-                        일괄 열기
-                      </>
+                      <p className="text-xs text-muted-foreground mt-1">
+                        Activity를 선택하면 파일 목록이 표시됩니다
+                      </p>
                     )}
-                  </Button>
-                </div>
-                {detail.revisions.map((revision) => {
-                  const revKey = `${revision.revNo}|${revision.revSeq}`;
-                  const isRevExpanded = expandedRevisions.has(revKey);
-
-                  return (
-                    <div key={revKey} className="border rounded-lg">
-                      {/* 리비전 헤더 */}
-                      <div
-                        className="flex items-center justify-between p-3 bg-muted/50 cursor-pointer hover:bg-muted"
-                        onClick={() => toggleRevision(revKey)}
-                      >
-                        <div className="flex items-center gap-3">
-                          {isRevExpanded ? (
-                            <ChevronDown className="h-4 w-4" />
-                          ) : (
-                            <ChevronRight className="h-4 w-4" />
-                          )}
-                          <Badge variant="secondary" className="font-mono">
-                            REV {revision.revNo}
-                          </Badge>
-                          <Badge variant="outline" className={
-                            revision.stage === "IFC" ? "bg-green-100 text-green-800" :
-                            revision.stage === "IFA" ? "bg-blue-100 text-blue-800" :
-                            "bg-gray-100 text-gray-800"
-                          }>
-                            {revision.stage}
-                          </Badge>
-                          <span className="text-sm text-muted-foreground">
-                            {revision.activities.length}개 액티비티 / {revision.totalFiles}개 파일
-                          </span>
+                  </div>
+                  <div className="overflow-auto p-3" style={{ height: "calc(250px - 80px)" }}>
+                    {selectedActivity ? (
+                      isLoadingFiles ? (
+                        <div className="flex items-center justify-center h-full">
+                          <Loader2 className="h-5 w-5 animate-spin" />
+                          <span className="ml-2 text-sm">파일 로딩 중...</span>
                         </div>
-                      </div>
-
-                      {/* 액티비티 목록 */}
-                      {isRevExpanded && (
-                        <div className="p-2 space-y-2">
-                          {revision.activities.map((activity) => {
-                            const actKey = `${revKey}|${activity.actvNo}`;
-                            const isActExpanded = expandedActivities.has(actKey);
-                            
-                            // Activity 타입에 따른 색상
-                            const activityColor =
-                              activity.type === "Receive" ? "bg-blue-100 text-blue-800" :
-                              activity.type === "Send" ? "bg-green-100 text-green-800" :
-                              "bg-purple-100 text-purple-800";
-
-                            return (
-                              <div key={actKey} className="border rounded-md">
-                                {/* 액티비티 헤더 */}
-                                <div
-                                  className="flex items-center justify-between p-2 bg-muted/30 cursor-pointer hover:bg-muted/50"
-                                  onClick={() => toggleActivity(actKey)}
-                                >
-                                  <div className="flex items-center gap-2">
-                                    {isActExpanded ? (
-                                      <ChevronDown className="h-4 w-4" />
-                                    ) : (
-                                      <ChevronRight className="h-4 w-4" />
-                                    )}
-                                    <Badge variant="outline" className={activityColor}>
-                                      {activity.type}
-                                    </Badge>
-                                    <span className="text-xs text-muted-foreground font-mono">
-                                      {activity.actvNo}
-                                    </span>
-                                    <span className="text-sm text-muted-foreground">
-                                      {activity.toFrom}
-                                    </span>
-                                    <span className="text-xs text-muted-foreground">
-                                      {activity.files.length}개 파일
-                                    </span>
+                      ) : activityFiles.length > 0 ? (
+                        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
+                          {activityFiles.map((file) => (
+                            <div
+                              key={file.FILE_SEQ}
+                              className="flex flex-col gap-2 p-3 border rounded bg-background hover:bg-muted/30"
+                            >
+                              <div className="flex items-start gap-2">
+                                <FileIcon className="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" />
+                                <div className="flex-1 min-w-0">
+                                  <div className="text-sm font-medium break-all line-clamp-2">
+                                    {file.FILE_NM}
                                   </div>
+                                  {file.FILE_SZ && (
+                                    <div className="text-xs text-muted-foreground">
+                                      {formatFileSize(file.FILE_SZ)}
+                                    </div>
+                                  )}
+                                  {file.STAT && (
+                                    <Badge variant="outline" className="text-xs mt-1">
+                                      {file.STAT}
+                                    </Badge>
+                                  )}
                                 </div>
-
-                                {/* 파일 목록 */}
-                                {isActExpanded && (
-                                  <div className="p-2 space-y-1">
-                                    {activity.files.map((file, idx) => (
-                                      <div
-                                        key={idx}
-                                        className="flex items-center justify-between p-2 border rounded bg-background hover:bg-muted/30"
-                                      >
-                                        <div className="flex items-center gap-2 flex-1">
-                                          <FileIcon className="h-4 w-4 text-blue-500" />
-                                          <span className="text-sm font-mono">{file.fileNm}</span>
-                                          {file.fileSz && (
-                                            <span className="text-xs text-muted-foreground">
-                                              ({formatFileSize(file.fileSz)})
-                                            </span>
-                                          )}
-                                          {file.stat && (
-                                            <Badge variant="outline" className={
-                                              file.stat === "SCW01" ? "bg-yellow-100 text-yellow-800" :
-                                              file.stat === "SCW03" ? "bg-green-100 text-green-800" :
-                                              file.stat === "SCW09" ? "bg-gray-100 text-gray-800" :
-                                              "bg-gray-100 text-gray-800"
-                                            }>
-                                              {file.statNm || file.stat}
-                                            </Badge>
-                                          )}
-                                        </div>
-                                        <div className="flex items-center gap-1">
-                                          {file.canCancel && file.boxSeq && file.actvSeq && (
-                                            <Button
-                                              variant="outline"
-                                              size="sm"
-                                              onClick={() => handleCancelFile(file.boxSeq!, file.actvSeq!, file.fileNm)}
-                                            >
-                                              <XCircle className="h-4 w-4 mr-1" />
-                                              취소
-                                            </Button>
-                                          )}
-                                          <Button
-                                            variant="outline"
-                                            size="sm"
-                                            onClick={() => handleDownloadFile(file.fileNm, document.DOC_NO)}
-                                          >
-                                            <Download className="h-4 w-4 mr-1" />
-                                            다운로드
-                                          </Button>
-                                        </div>
-                                      </div>
-                                    ))}
-                                  </div>
-                                )}
                               </div>
-                            );
-                          })}
+                              <Button
+                                variant="outline"
+                                size="sm"
+                                className="w-full"
+                                onClick={() => handleDownloadFile(file.FILE_NM, document.OWN_DOC_NO || document.DOC_NO)}
+                              >
+                                <Download className="h-3 w-3 mr-1" />
+                                다운로드
+                              </Button>
+                            </div>
+                          ))}
                         </div>
-                      )}
-                    </div>
-                  );
-                })}
-              </div>
+                      ) : (
+                        <div className="flex items-center justify-center h-full text-sm text-muted-foreground">
+                          <div className="text-center">
+                            <AlertCircle className="h-8 w-8 mx-auto mb-2 opacity-50" />
+                            <p>파일이 없습니다</p>
+                          </div>
+                        </div>
+                      )
+                    ) : (
+                      <div className="flex items-center justify-center h-full text-sm text-muted-foreground">
+                        <div className="text-center">
+                          <FileIcon className="h-12 w-12 mx-auto mb-2 opacity-30" />
+                          <p>Activity를 선택해주세요</p>
+                        </div>
+                      </div>
+                    )}
+                  </div>
+                </div>
+              </>
             ) : (
               <div className="p-8 text-center text-muted-foreground">
                 <AlertCircle className="h-12 w-12 mx-auto mb-2 opacity-50" />
-                <p>리비전 정보가 없습니다</p>
+                <p>Activity 정보가 없습니다</p>
               </div>
             )}
           </div>
@@ -399,14 +463,3 @@ export function SwpDocumentDetailDialog({
     </Dialog>
   );
 }
-
-function formatFileSize(sizeStr: string): string {
-  const bytes = parseInt(sizeStr, 10);
-  if (isNaN(bytes)) return sizeStr;
-
-  const kb = bytes / 1024;
-  const mb = kb / 1024;
-
-  return mb >= 1 ? `${mb.toFixed(2)} MB` : `${kb.toFixed(2)} KB`;
-}
-
-- 
cgit v1.2.3

