// initial-rfq-detail-columns.tsx "use client" import * as React from "react" import { type ColumnDef } from "@tanstack/react-table" import { Ellipsis, Building, Calendar, Eye, MessageSquare, Settings, CheckCircle2, XCircle } from "lucide-react" import { formatDate } from "@/lib/utils" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" interface GetInitialRfqDetailColumnsProps { onSelectDetail?: (detail: any) => void } export function getInitialRfqDetailColumns({ onSelectDetail }: GetInitialRfqDetailColumnsProps = {}): ColumnDef[] { return [ /** ───────────── 체크박스 ───────────── */ { 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, }, /** ───────────── RFQ 정보 ───────────── */ { accessorKey: "rfqCode", header: ({ column }) => ( ), cell: ({ row }) => ( ), size: 120, }, { accessorKey: "rfqStatus", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue("rfqStatus") as string const getStatusColor = (status: string) => { switch (status) { case "DRAFT": return "secondary" case "Doc. Received": return "outline" case "PIC Assigned": return "default" case "Doc. Confirmed": return "default" case "Init. RFQ Sent": return "default" case "Init. RFQ Answered": return "success" case "TBE started": return "warning" case "TBE finished": return "warning" case "Final RFQ Sent": return "default" case "Quotation Received": return "success" case "Vendor Selected": return "success" default: return "secondary" } } return ( {status} ) }, size: 140 }, { accessorKey: "initialRfqStatus", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue("initialRfqStatus") as string const getInitialStatusColor = (status: string) => { switch (status) { case "PENDING": return "outline" case "SENT": return "default" case "RESPONDED": return "success" case "EXPIRED": return "destructive" case "CANCELLED": return "secondary" default: return "secondary" } } return ( {status} ) }, size: 120 }, /** ───────────── 벤더 정보 ───────────── */ { id: "vendorInfo", header: ({ column }) => ( ), cell: ({ row }) => { const vendorName = row.original.vendorName as string const vendorCode = row.original.vendorCode as string const vendorCountry = row.original.vendorCountry as string const businessSize = row.original.vendorBusinessSize as string return (
{vendorName}
{vendorCode} • {vendorCountry}
{businessSize && ( {businessSize} )}
) }, size: 200, }, /** ───────────── 날짜 정보 ───────────── */ { accessorKey: "dueDate", header: ({ column }) => ( ), cell: ({ row }) => { const dueDate = row.getValue("dueDate") as Date const isOverdue = dueDate && new Date(dueDate) < new Date() return dueDate ? (
{formatDate(dueDate)}
{isOverdue && (
지연
)}
) : ( - ) }, size: 120, }, { accessorKey: "validDate", header: ({ column }) => ( ), cell: ({ row }) => { const validDate = row.getValue("validDate") as Date return validDate ? (
{formatDate(validDate)}
) : ( - ) }, size: 100, }, /** ───────────── Incoterms ───────────── */ { id: "incoterms", header: ({ column }) => ( ), cell: ({ row }) => { const code = row.original.incotermsCode as string const description = row.original.incotermsDescription as string return code ? (
{code} {description && (
{description}
)}
) : ( - ) }, size: 120, }, /** ───────────── 플래그 정보 ───────────── */ { id: "flags", header: ({ column }) => ( ), cell: ({ row }) => { const shortList = row.original.shortList as boolean const returnYn = row.original.returnYn as boolean const cpRequestYn = row.original.cpRequestYn as boolean const prjectGtcYn = row.original.prjectGtcYn as boolean return (
{shortList && ( Short List )} {returnYn && ( Return )} {cpRequestYn && ( CP Request )} {prjectGtcYn && ( GTC )}
) }, size: 150, }, /** ───────────── 분류 정보 ───────────── */ { id: "classification", header: ({ column }) => ( ), cell: ({ row }) => { const classification = row.original.classification as string const sparepart = row.original.sparepart as string return (
{classification && (
{classification}
)} {sparepart && ( {sparepart} )}
) }, size: 120, }, /** ───────────── 리비전 정보 ───────────── */ { accessorKey: "returnRevision", header: ({ column }) => ( ), cell: ({ row }) => { const revision = row.getValue("returnRevision") as number return revision ? ( Rev. {revision} ) : ( - ) }, size: 80, }, /** ───────────── 등록/수정 정보 ───────────── */ { accessorKey: "createdAt", header: ({ column }) => ( ), cell: ({ row }) => { const created = row.getValue("createdAt") as Date const updated = row.original.updatedAt as Date return (
{formatDate(created)}
{updated && new Date(updated) > new Date(created) && (
수정: {formatDate(updated)}
)}
) }, size: 120, }, /** ───────────── 액션 ───────────── */ { id: "actions", enableHiding: false, cell: ({ row }) => { return ( onSelectDetail?.(row.original)}> 상세 보기 벤더 응답 보기 설정 수정 삭제 ) }, size: 40, }, ] }