diff options
Diffstat (limited to 'lib/contact-possible-items/table')
| -rw-r--r-- | lib/contact-possible-items/table/contact-possible-items-table-columns.tsx | 301 |
1 files changed, 102 insertions, 199 deletions
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
|
