From 2650b7c0bb0ea12b68a58c0439f72d61df04b2f1 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 25 Jul 2025 07:51:15 +0000
Subject: (대표님) 정기평가 대상, 미들웨어 수정, nextauth 토큰 처리 개선, GTC
 등 (최겸) 기술영업
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/contact-possible-items-table-columns.tsx | 301 +++++++--------------
 1 file changed, 102 insertions(+), 199 deletions(-)

(limited to 'lib/contact-possible-items/table/contact-possible-items-table-columns.tsx')

diff --git a/lib/contact-possible-items/table/contact-possible-items-table-columns.tsx b/lib/contact-possible-items/table/contact-possible-items-table-columns.tsx
index a3b198ae..552497e3 100644
--- a/lib/contact-possible-items/table/contact-possible-items-table-columns.tsx
+++ b/lib/contact-possible-items/table/contact-possible-items-table-columns.tsx
@@ -2,12 +2,13 @@
 
 import * as React from "react"
 import { type DataTableRowAction } from "@/types/table"
-import { type ColumnDef } from "@tanstack/react-table"
+import { type ColumnDef, type Row, type Column } from "@tanstack/react-table"
 import { Ellipsis } from "lucide-react"
 
 import { formatDate } from "@/lib/utils"
 import { Button } from "@/components/ui/button"
 import { Checkbox } from "@/components/ui/checkbox"
+import { Badge } from "@/components/ui/badge"
 import {
   DropdownMenu,
   DropdownMenuContent,
@@ -18,6 +19,7 @@ import {
 
 import { ContactPossibleItemDetail } from "../service"
 import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
+import { contactPossibleItemsColumnsConfig } from "@/config/contactPossibleItemsColumnsConfig"
 
 
 interface GetColumnsProps {
@@ -90,205 +92,106 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Contact
   }
 
   // ----------------------------------------------------------------
-  // 3) 일반 컬럼들을 "그룹"별로 묶어 중첩 columns 생성
+  // 3) config를 기반으로 컬럼 그룹들을 동적으로 생성
   // ----------------------------------------------------------------
-  const baseColumns: ColumnDef<ContactPossibleItemDetail>[] = [
-    // 벤더 정보
-    {
-      id: "vendorInfo",
-      header: "벤더 정보",
-      columns: [
-        {
-          accessorKey: "vendorCode",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="벤더 코드" />
-          ),
-          cell: ({ row }) => row.original.vendorCode ?? "",
-        },
-        {
-          accessorKey: "vendorName",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="벤더명" />
-          ),
-          cell: ({ row }) => row.original.vendorName ?? "",
-        },
-        {
-          accessorKey: "vendorCountry",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="벤더 국가" />
-          ),
-          cell: ({ row }) => {
-            const country = row.original.vendorCountry
-            return country || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "techVendorType",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="벤더 타입" />
-          ),
-          cell: ({ row }) => {
-            const type = row.original.techVendorType
-            return type || <span className="text-muted-foreground">-</span>
-          },
-        },
-      ]
-    },
-    // 담당자 정보
-    {
-      id: "contactInfo",
-      header: "담당자 정보",
-      columns: [
-        {
-          accessorKey: "contactName",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="담당자명" />
-          ),
-          cell: ({ row }) => {
-            const contactName = row.original.contactName
-            return contactName || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "contactPosition",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="직책" />
-          ),
-          cell: ({ row }) => {
-            const position = row.original.contactPosition
-            return position || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "contactEmail",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="담당자 이메일" />
-          ),
-          cell: ({ row }) => {
-            const contactEmail = row.original.contactEmail
-            return contactEmail || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "contactPhone",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="담당자 전화번호" />
-          ),
-          cell: ({ row }) => {
-            const contactPhone = row.original.contactPhone
-            return contactPhone || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "contactCountry",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="담당자 국가" />
-          ),
-          cell: ({ row }) => {
-            const contactCountry = row.original.contactCountry
-            return contactCountry || <span className="text-muted-foreground">-</span>
-          },
-        },
-        {
-          accessorKey: "isPrimary",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="주담당자" />
-          ),
-          cell: ({ row }) => {
-            const isPrimary = row.original.isPrimary
-            return isPrimary ? "예" : "아니오"
-          },
-        },
-      ]
-    },
-    // 아이템 정보
-    {
-      id: "itemInfo",
-      header: "아이템 정보",
-      columns: [
-        {
-          accessorKey: "itemCode",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="아이템 코드" />
-          ),
-          cell: ({ row }) => row.original.itemCode ?? "",
-        },
-        {
-          accessorKey: "itemList",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="아이템 리스트" />
-          ),
-          cell: ({ row }) => row.original.itemList ?? "",
-        },
-        {
-          accessorKey: "workType",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="공종" />
-          ),
-          cell: ({ row }) => row.original.workType ?? "",
-        },
-        {
-          accessorKey: "shipTypes",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="선종" />
-          ),
-          cell: ({ row }) => row.original.shipTypes ?? "",
-        },
-        {
-          accessorKey: "subItemList",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="서브아이템 리스트" />
-          ),
-          cell: ({ row }) => row.original.subItemList ?? "",
-        },
-      ]
-    },
-    
-    // 시스템 정보
-    {
-      id: "systemInfo",
-      header: "시스템 정보",
-      columns: [
-        {
-          accessorKey: "createdAt",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="생성일" />
-          ),
-          cell: ({ row }) => {
-            const dateVal = row.getValue("createdAt") as Date
-            return formatDate(dateVal)
-          },
-        },
-        {
-          accessorKey: "updatedAt",
-          enableResizing: true,
-          header: ({ column }) => (
-            <DataTableColumnHeaderSimple column={column} title="수정일" />
-          ),
-          cell: ({ row }) => {
-            const dateVal = row.getValue("updatedAt") as Date
-            return formatDate(dateVal)
-          },
-        },
-      ]
-    },
-  ]
+  
+  // 특수한 셀 렌더링이 필요한 컬럼들을 위한 헬퍼 함수
+  const getCellRenderer = (accessorKey: keyof ContactPossibleItemDetail) => {
+    switch (accessorKey) {
+      case 'createdAt':
+      case 'updatedAt':
+        return function DateCell({ row }: { row: Row<ContactPossibleItemDetail> }) {
+          const dateVal = row.getValue(accessorKey) as Date
+          return formatDate(dateVal, "ko-KR")
+        } 
+      case 'isPrimary':
+        return function PrimaryCell({ row }: { row: Row<ContactPossibleItemDetail> }) {
+          const isPrimary = row.original.isPrimary
+          return isPrimary ? "Y" : "N"
+        }
+      case 'techVendorType':
+        return function VendorTypeCell({ row }: { row: Row<ContactPossibleItemDetail> }) {
+          const techVendorType = row.original.techVendorType
+          
+          // 벤더 타입 파싱 개선 - null/undefined 안전 처리
+          let types: string[] = [];
+          if (!techVendorType) {
+            types = [];
+          } else if (techVendorType.startsWith('[') && techVendorType.endsWith(']')) {
+            // JSON 배열 형태
+            try {
+              const parsed = JSON.parse(techVendorType);
+              types = Array.isArray(parsed) ? parsed.filter(Boolean) : [techVendorType];
+            } catch {
+              types = [techVendorType];
+            }
+          } else if (techVendorType.includes(',')) {
+            // 콤마로 구분된 문자열
+            types = techVendorType.split(',').map(t => t.trim()).filter(Boolean);
+          } else {
+            // 단일 문자열
+            types = [techVendorType.trim()].filter(Boolean);
+          }
+
+          // 벤더 타입 정렬 - 조선 > 해양TOP > 해양HULL 순
+          const typeOrder = ["조선", "해양TOP", "해양HULL"];
+          types.sort((a, b) => {
+            const indexA = typeOrder.indexOf(a);
+            const indexB = typeOrder.indexOf(b);
+            
+            // 정의된 순서에 있는 경우 우선순위 적용
+            if (indexA !== -1 && indexB !== -1) {
+              return indexA - indexB;
+            }
+            return a.localeCompare(b);
+          });
+
+          return (
+            <div className="flex flex-wrap gap-1">
+              {types.length > 0 ? types.map((type, index) => (
+                <Badge key={`${type}-${index}`} variant="secondary" className="text-xs">
+                  {type}
+                </Badge>
+              )) : (
+                <span className="text-muted-foreground">-</span>
+              )}
+            </div>
+          )
+        }
+      case 'vendorCountry':
+      case 'contactName':
+      case 'contactPosition':
+      case 'contactTitle':
+      case 'contactEmail':
+      case 'contactPhone':
+      case 'contactCountry':
+        return function OptionalCell({ row }: { row: Row<ContactPossibleItemDetail> }) {
+          const value = row.original[accessorKey]
+          return value || <span className="text-muted-foreground">-</span>
+        }
+      default:
+        return function DefaultCell({ row }: { row: Row<ContactPossibleItemDetail> }) {
+          return row.original[accessorKey] ?? ""
+        }
+    }
+  }
+
+  const baseColumns: ColumnDef<ContactPossibleItemDetail>[] = contactPossibleItemsColumnsConfig.map(group => ({
+    id: group.id,
+    header: group.header,
+    columns: group.columns.map(colConfig => ({
+      accessorKey: colConfig.accessorKey,
+      enableResizing: colConfig.enableResizing,
+      enableSorting: colConfig.enableSorting,
+      size: colConfig.size,
+      minSize: colConfig.minSize,
+      maxSize: colConfig.maxSize,
+      header: function HeaderCell({ column }: { column: Column<ContactPossibleItemDetail> }) {
+        return <DataTableColumnHeaderSimple column={column} title={colConfig.title} />
+      },
+      cell: getCellRenderer(colConfig.accessorKey),
+    })),
+  }))
 
   // ----------------------------------------------------------------
   // 4) 최종 컬럼 배열: select, baseColumns, actions
-- 
cgit v1.2.3

