summaryrefslogtreecommitdiff
path: root/lib/swp/table/swp-table.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/swp/table/swp-table.tsx')
-rw-r--r--lib/swp/table/swp-table.tsx275
1 files changed, 13 insertions, 262 deletions
diff --git a/lib/swp/table/swp-table.tsx b/lib/swp/table/swp-table.tsx
index 8ae90bdd..47c9905a 100644
--- a/lib/swp/table/swp-table.tsx
+++ b/lib/swp/table/swp-table.tsx
@@ -17,16 +17,9 @@ import {
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogDescription,
-} from "@/components/ui/dialog";
-import { Loader2 } from "lucide-react";
-import { swpDocumentColumns, swpRevisionColumns, swpFileColumns, type RevisionRow, type FileRow } from "./swp-table-columns";
+import { swpDocumentColumns, type RevisionRow, type FileRow } from "./swp-table-columns";
import { fetchDocumentRevisions, fetchRevisionFiles, type SwpDocumentWithStats } from "../actions";
+import { SwpRevisionListDialog } from "./swp-revision-list-dialog";
interface SwpTableProps {
initialData: SwpDocumentWithStats[];
@@ -227,259 +220,17 @@ export function SwpTable({
</div>
{/* 문서 상세 Dialog */}
- <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
- <DialogContent className="max-w-6xl max-h-[90vh]">
- <DialogHeader>
- <DialogTitle>문서 상세</DialogTitle>
- {selectedDocument && (
- <DialogDescription>
- {selectedDocument.DOC_NO} - {selectedDocument.DOC_TITLE}
- </DialogDescription>
- )}
- </DialogHeader>
-
- {selectedDocument && (
- <div className="space-y-4 overflow-y-auto">
- {/* 문서 정보 */}
- <div className="grid grid-cols-1 md:grid-cols-4 gap-4 p-4 bg-muted/30 rounded-lg">
- <div>
- <span className="text-sm font-semibold">프로젝트:</span>
- <div className="text-sm">{selectedDocument.PROJ_NO}</div>
- {selectedDocument.PROJ_NM && (
- <div className="text-xs text-muted-foreground">{selectedDocument.PROJ_NM}</div>
- )}
- </div>
- <div>
- <span className="text-sm font-semibold">패키지:</span>
- <div className="text-sm">{selectedDocument.PKG_NO || "-"}</div>
- </div>
- <div>
- <span className="text-sm font-semibold">업체:</span>
- <div className="text-sm">{selectedDocument.CPY_NM || "-"}</div>
- {selectedDocument.VNDR_CD && (
- <div className="text-xs text-muted-foreground">{selectedDocument.VNDR_CD}</div>
- )}
- </div>
- <div>
- <span className="text-sm font-semibold">최신 리비전:</span>
- <div className="text-sm">{selectedDocument.LTST_REV_NO || "-"}</div>
- </div>
- </div>
-
- {/* 리비전 및 파일 목록 */}
- {loadingRevisions.has(selectedDocument.DOC_NO) ? (
- <div className="flex items-center justify-center p-8">
- <Loader2 className="h-6 w-6 animate-spin" />
- <span className="ml-2">리비전 로딩 중...</span>
- </div>
- ) : revisionData[selectedDocument.DOC_NO]?.length ? (
- <DocumentDetailView
- revisions={revisionData[selectedDocument.DOC_NO]}
- fileData={fileData}
- loadingFiles={loadingFiles}
- onLoadFiles={loadFiles}
- onLoadAllFiles={() => loadAllFiles(selectedDocument.DOC_NO)}
- />
- ) : (
- <div className="p-8 text-center text-muted-foreground">
- 리비전 없음
- </div>
- )}
- </div>
- )}
- </DialogContent>
- </Dialog>
- </div>
- );
-}
-
-// ============================================================================
-// 문서 상세 뷰 (Dialog용)
-// ============================================================================
-
-interface DocumentDetailViewProps {
- revisions: RevisionRow[];
- fileData: Record<number, FileRow[]>;
- loadingFiles: Set<number>;
- onLoadFiles: (revisionId: number) => void;
- onLoadAllFiles: () => void;
-}
-
-function DocumentDetailView({
- revisions,
- fileData,
- loadingFiles,
- onLoadFiles,
- onLoadAllFiles,
-}: DocumentDetailViewProps) {
- const [expandedRevisions, setExpandedRevisions] = useState<ExpandedState>({});
- const [allExpanded, setAllExpanded] = useState(false);
-
- const revisionTable = useReactTable({
- data: revisions,
- columns: swpRevisionColumns,
- state: {
- expanded: expandedRevisions,
- },
- onExpandedChange: setExpandedRevisions,
- getCoreRowModel: getCoreRowModel(),
- getExpandedRowModel: getExpandedRowModel(),
- getRowCanExpand: () => true,
- });
-
- const handleExpandAll = () => {
- if (allExpanded) {
- setExpandedRevisions({});
- } else {
- const expanded: ExpandedState = {};
- revisions.forEach((_, index) => {
- expanded[index] = true;
- });
- setExpandedRevisions(expanded);
- onLoadAllFiles();
- }
- setAllExpanded(!allExpanded);
- };
-
- const handleRevisionExpand = (revisionId: number) => {
- onLoadFiles(revisionId);
- };
-
- return (
- <div className="space-y-4">
- {/* 전체 펼치기/접기 버튼 */}
- <div className="flex justify-end">
- <Button
- variant="outline"
- size="sm"
- onClick={handleExpandAll}
- >
- {allExpanded ? "모두 접기" : "모두 펼치기"}
- </Button>
- </div>
-
- {/* 리비전 테이블 */}
- <div className="rounded-md border">
- <Table>
- <TableHeader>
- {revisionTable.getHeaderGroups().map((headerGroup) => (
- <TableRow key={headerGroup.id} className="bg-muted/50">
- {headerGroup.headers.map((header) => (
- <TableHead key={header.id} className="font-semibold">
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
- </TableHead>
- ))}
- </TableRow>
- ))}
- </TableHeader>
- <TableBody>
- {revisionTable.getRowModel().rows.map((row) => (
- <React.Fragment key={row.id}>
- {/* 리비전 행 */}
- <TableRow className="bg-muted/20">
- {row.getVisibleCells().map((cell) => (
- <TableCell key={cell.id}>
- {cell.column.id === "expander" ? (
- <div
- onClick={() => {
- row.toggleExpanded();
- if (!row.getIsExpanded()) {
- handleRevisionExpand(row.original.id);
- }
- }}
- className="cursor-pointer"
- >
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
- </div>
- ) : (
- flexRender(cell.column.columnDef.cell, cell.getContext())
- )}
- </TableCell>
- ))}
- </TableRow>
-
- {/* 파일 행들 (확장 시) */}
- {row.getIsExpanded() && (
- <TableRow>
- <TableCell colSpan={swpRevisionColumns.length} className="p-0 bg-blue-50/30">
- {loadingFiles.has(row.original.id) ? (
- <div className="flex items-center justify-center p-4">
- <Loader2 className="h-5 w-5 animate-spin" />
- <span className="ml-2 text-sm">파일 로딩 중...</span>
- </div>
- ) : fileData[row.original.id]?.length ? (
- <FileSubTable files={fileData[row.original.id]} />
- ) : (
- <div className="p-4 text-center text-sm text-muted-foreground">
- 파일 없음
- </div>
- )}
- </TableCell>
- </TableRow>
- )}
- </React.Fragment>
- ))}
- </TableBody>
- </Table>
- </div>
- </div>
- );
-}
-
-// ============================================================================
-// 파일 서브 테이블
-// ============================================================================
-
-interface FileSubTableProps {
- files: FileRow[];
-}
-
-function FileSubTable({ files }: FileSubTableProps) {
- const fileTable = useReactTable({
- data: files,
- columns: swpFileColumns,
- getCoreRowModel: getCoreRowModel(),
- });
-
- return (
- <div className="border-l-4 border-green-200">
- <Table>
- <TableHeader>
- {fileTable.getHeaderGroups().map((headerGroup) => (
- <TableRow key={headerGroup.id} className="bg-blue-50/50">
- {headerGroup.headers.map((header) => (
- <TableHead key={header.id} className="font-semibold text-xs">
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
- </TableHead>
- ))}
- </TableRow>
- ))}
- </TableHeader>
- <TableBody>
- {fileTable.getRowModel().rows.map((row) => (
- <TableRow key={row.id} className="bg-green-50/20 hover:bg-green-50/40">
- {row.getVisibleCells().map((cell) => (
- <TableCell key={cell.id} className="py-2">
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
- </TableCell>
- ))}
- </TableRow>
- ))}
- </TableBody>
- </Table>
+ <SwpRevisionListDialog
+ open={dialogOpen}
+ onOpenChange={setDialogOpen}
+ document={selectedDocument}
+ revisions={selectedDocument ? revisionData[selectedDocument.DOC_NO] || [] : []}
+ fileData={fileData}
+ loadingRevisions={selectedDocument ? loadingRevisions.has(selectedDocument.DOC_NO) : false}
+ loadingFiles={loadingFiles}
+ onLoadFiles={loadFiles}
+ onLoadAllFiles={() => selectedDocument && loadAllFiles(selectedDocument.DOC_NO)}
+ />
</div>
);
}