From 2650b7c0bb0ea12b68a58c0439f72d61df04b2f1 Mon Sep 17 00:00:00 2001 From: dujinkim 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[] = [ - // 벤더 정보 - { - id: "vendorInfo", - header: "벤더 정보", - columns: [ - { - accessorKey: "vendorCode", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.vendorCode ?? "", - }, - { - accessorKey: "vendorName", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.vendorName ?? "", - }, - { - accessorKey: "vendorCountry", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const country = row.original.vendorCountry - return country || - - }, - }, - { - accessorKey: "techVendorType", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const type = row.original.techVendorType - return type || - - }, - }, - ] - }, - // 담당자 정보 - { - id: "contactInfo", - header: "담당자 정보", - columns: [ - { - accessorKey: "contactName", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const contactName = row.original.contactName - return contactName || - - }, - }, - { - accessorKey: "contactPosition", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const position = row.original.contactPosition - return position || - - }, - }, - { - accessorKey: "contactEmail", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const contactEmail = row.original.contactEmail - return contactEmail || - - }, - }, - { - accessorKey: "contactPhone", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const contactPhone = row.original.contactPhone - return contactPhone || - - }, - }, - { - accessorKey: "contactCountry", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const contactCountry = row.original.contactCountry - return contactCountry || - - }, - }, - { - accessorKey: "isPrimary", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const isPrimary = row.original.isPrimary - return isPrimary ? "예" : "아니오" - }, - }, - ] - }, - // 아이템 정보 - { - id: "itemInfo", - header: "아이템 정보", - columns: [ - { - accessorKey: "itemCode", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.itemCode ?? "", - }, - { - accessorKey: "itemList", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.itemList ?? "", - }, - { - accessorKey: "workType", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.workType ?? "", - }, - { - accessorKey: "shipTypes", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.shipTypes ?? "", - }, - { - accessorKey: "subItemList", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => row.original.subItemList ?? "", - }, - ] - }, - - // 시스템 정보 - { - id: "systemInfo", - header: "시스템 정보", - columns: [ - { - accessorKey: "createdAt", - enableResizing: true, - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const dateVal = row.getValue("createdAt") as Date - return formatDate(dateVal) - }, - }, - { - accessorKey: "updatedAt", - enableResizing: true, - header: ({ column }) => ( - - ), - 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 }) { + const dateVal = row.getValue(accessorKey) as Date + return formatDate(dateVal, "ko-KR") + } + case 'isPrimary': + return function PrimaryCell({ row }: { row: Row }) { + const isPrimary = row.original.isPrimary + return isPrimary ? "Y" : "N" + } + case 'techVendorType': + return function VendorTypeCell({ row }: { row: Row }) { + 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 ( +
+ {types.length > 0 ? types.map((type, index) => ( + + {type} + + )) : ( + - + )} +
+ ) + } + case 'vendorCountry': + case 'contactName': + case 'contactPosition': + case 'contactTitle': + case 'contactEmail': + case 'contactPhone': + case 'contactCountry': + return function OptionalCell({ row }: { row: Row }) { + const value = row.original[accessorKey] + return value || - + } + default: + return function DefaultCell({ row }: { row: Row }) { + return row.original[accessorKey] ?? "" + } + } + } + + const baseColumns: ColumnDef[] = 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 }) { + return + }, + cell: getCellRenderer(colConfig.accessorKey), + })), + })) // ---------------------------------------------------------------- // 4) 최종 컬럼 배열: select, baseColumns, actions -- cgit v1.2.3