// enhanced-doc-table-columns-with-b4.tsx "use client" import * as React from "react" import { ColumnDef } from "@tanstack/react-table" import { formatDate, formatDateTime } from "@/lib/utils" import { Checkbox } from "@/components/ui/checkbox" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { DataTableRowAction } from "@/types/table" import { EnhancedDocumentsView } from "@/db/schema/vendorDocu" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Progress } from "@/components/ui/progress" import { Ellipsis, AlertTriangle, Clock, CheckCircle, Upload, Calendar, User, FileText, Eye, Edit, Trash2, Building, Code, Settings } from "lucide-react" import { cn } from "@/lib/utils" interface GetColumnsProps { setRowAction: React.Dispatch | null>> projectType: string | null drawingKindFilter?: string // ✅ 추가 } // 유틸리티 함수들 const getStatusColor = (status: string, isOverdue = false) => { if (isOverdue) return 'destructive' switch (status) { case 'COMPLETED': case 'APPROVED': return 'success' case 'IN_PROGRESS': return 'default' case 'SUBMITTED': case 'UNDER_REVIEW': return 'secondary' case 'REJECTED': return 'destructive' default: return 'outline' } } const getPriorityColor = (priority: string) => { switch (priority) { case 'HIGH': return 'destructive' case 'MEDIUM': return 'default' case 'LOW': return 'secondary' default: return 'outline' } } const getStatusText = (status: string) => { switch (status) { case 'PLANNED': return '계획됨' case 'IN_PROGRESS': return '진행중' case 'SUBMITTED': return '제출됨' case 'UNDER_REVIEW': return '검토중' case 'APPROVED': return '승인됨' case 'REJECTED': return '반려됨' case 'COMPLETED': return '완료됨' default: return status } } const getPriorityText = (priority: string) => { switch (priority) { case 'HIGH': return '높음' case 'MEDIUM': return '보통' case 'LOW': return '낮음' default: return priority } } // 마감일 정보 컴포넌트 const DueDateInfo = ({ daysUntilDue, isOverdue, className = "" }: { daysUntilDue: number | null isOverdue: boolean className?: string }) => { if (isOverdue && daysUntilDue !== null && daysUntilDue < 0) { return (
{Math.abs(daysUntilDue)}일 지연
) } if (daysUntilDue === 0) { return (
오늘 마감
) } if (daysUntilDue && daysUntilDue > 0 && daysUntilDue <= 3) { return (
{daysUntilDue}일 남음
) } if (daysUntilDue && daysUntilDue > 0) { return (
{daysUntilDue}일 남음
) } return (
완료
) } export function getUpdatedEnhancedColumns({ setRowAction, projectType, drawingKindFilter = "all" // ✅ 추가 }: GetColumnsProps): ColumnDef[] { const isPlantProject = projectType === "plant" const showB4Columns = drawingKindFilter === "B4" // ✅ B4 컬럼 표시 여부 // 기본 컬럼들 const baseColumns: ColumnDef[] = [ // 체크박스 선택 { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" className="translate-y-0.5" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" className="translate-y-0.5" /> ), size: 40, enableSorting: false, enableHiding: false, }, // 문서번호 + Drawing Kind { accessorKey: "docNumber", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.docNumber} {doc.drawingKind && ( {doc.drawingKind} )}
) }, size: 120, enableResizing: true, meta: { excelHeader: "문서번호" }, }, ] // ✅ Plant 프로젝트용 추가 컬럼들 const plantColumns: ColumnDef[] = isPlantProject ? [ // 벤더 문서번호 { accessorKey: "vendorDocNumber", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.vendorDocNumber ? ( {doc.vendorDocNumber} ) : ( - )}
) }, size: 120, enableResizing: true, meta: { excelHeader: "벤더 문서번호" }, }, // 프로젝트 코드 { accessorKey: "projectCode", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.projectCode || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "프로젝트 코드" }, }, // 벤더 정보 { accessorKey: "vendorName", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.vendorName || '-'}
{doc.vendorCode && ( {doc.vendorCode} )}
) }, size: 150, enableResizing: true, meta: { excelHeader: "벤더명" }, }, ] : [] // ✅ B4 전용 컬럼들 (B4 필터 선택 시에만 표시) const b4Columns: ColumnDef[] = showB4Columns ? [ { accessorKey: "cGbn", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.cGbn || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "cGbn" }, }, { accessorKey: "dGbn", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.dGbn || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "dGbn" }, }, { accessorKey: "degreeGbn", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.degreeGbn || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "degreeGbn" }, }, { accessorKey: "deptGbn", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.deptGbn || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "deptGbn" }, }, { accessorKey: "sGbn", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.sGbn || '-'}
) }, size: 100, enableResizing: true, meta: { excelHeader: "sGbn" }, }, ] : [] // 나머지 공통 컬럼들 const commonColumns: ColumnDef[] = [ // 문서명 + 담당자 { accessorKey: "title", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original return (
{doc.title}
{doc.pic && ( PIC: {doc.pic} )} {doc.currentStageAssigneeName && (
{doc.currentStageAssigneeName}
)}
) }, size: showB4Columns ? 180 : (isPlantProject ? 200 : 250), // ✅ B4 컬럼이 있을 때 너비 조정 enableResizing: true, meta: { excelHeader: "문서명" }, }, // 현재 스테이지 { accessorKey: "currentStageName", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original if (!doc.currentStageName) return - return (
{doc.currentStageName} {getStatusText(doc.currentStageStatus || '')}
) }, size: 140, enableResizing: true, meta: { excelHeader: "현재 스테이지" }, }, // 일정 정보 { accessorKey: "currentStagePlanDate", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original if (!doc.currentStagePlanDate) return - return (
계획: {formatDate(doc.currentStagePlanDate)}
{doc.currentStageActualDate && (
실제: {formatDate(doc.currentStageActualDate)}
)}
) }, size: 140, enableResizing: true, meta: { excelHeader: "일정" }, }, // 진행률 { accessorKey: "progressPercentage", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original const progress = doc.progressPercentage || 0 const completed = doc.completedStages || 0 const total = doc.totalStages || 0 return (
{progress}%
{completed} / {total} 스테이지
) }, size: 120, enableResizing: true, meta: { excelHeader: "진행률" }, }, // 최신 리비전 { accessorKey: "latestRevision", header: ({ column }) => ( ), cell: ({ row }) => { const doc = row.original if (!doc.latestRevision) return 없음 return (
{doc.latestRevision} {doc.latestRevisionStatus && ( {getStatusText(doc.latestRevisionStatus)} )} {doc.latestSubmittedDate && (
{formatDate(doc.latestSubmittedDate)}
)}
) }, size: 140, enableResizing: true, meta: { excelHeader: "최신 리비전" }, }, // 업데이트 일시 { accessorKey: "updatedAt", header: ({ column }) => ( ), cell: ({ cell }) => ( {formatDateTime(cell.getValue() as Date)} ), size: 140, enableResizing: true, meta: { excelHeader: "업데이트" }, }, // 액션 메뉴 { id: "actions", enableHiding: false, cell: function Cell({ row }) { const doc = row.original const canSubmit = doc.currentStageStatus === 'IN_PROGRESS' const canApprove = doc.currentStageStatus === 'SUBMITTED' const isPlantProject = projectType === "plant" const viewActions = [ { key: "view", label: "상세보기", icon: Eye, action: () => setRowAction({ row, type: "view" }), show: true } ] const editActions = [ { key: "update", label: "편집", icon: Edit, action: () => setRowAction({ row, type: "update" }), show: isPlantProject } ] const fileActions = [ { key: "upload", label: "리비전 업로드", icon: Upload, action: () => setRowAction({ row, type: "upload" }), show: canSubmit } ] const dangerActions = [ { key: "delete", label: "삭제", icon: Trash2, action: () => setRowAction({ row, type: "delete" }), show: isPlantProject, className: "text-red-600", shortcut: "⌘⌫" } ] const hasEditActions = editActions.some(action => action.show) const hasFileActions = fileActions.some(action => action.show) const hasDangerActions = dangerActions.some(action => action.show) return ( {viewActions.map(action => action.show && ( {action.label} {action.shortcut && ( {action.shortcut} )} ))} {hasEditActions && ( <> {editActions.map(action => action.show && ( {action.label} {action.shortcut && ( {action.shortcut} )} ))} )} {hasFileActions && ( <> {fileActions.map(action => action.show && ( {action.label} {action.shortcut && ( {action.shortcut} )} ))} )} {hasDangerActions && ( <> {dangerActions.map(action => action.show && ( {action.label} {action.shortcut && ( {action.shortcut} )} ))} )} ) }, size: 40, } ] // ✅ 모든 컬럼을 순서대로 결합 return [ ...baseColumns, // 체크박스, 문서번호 ...plantColumns, // Plant 전용 컬럼들 (조건부) ...b4Columns, // B4 전용 컬럼들 (조건부) ...commonColumns // 나머지 공통 컬럼들 ] }