// final-rfq-detail-columns.tsx "use client" import * as React from "react" import { type ColumnDef } from "@tanstack/react-table" import { type Row } from "@tanstack/react-table" import { Ellipsis, Building, Eye, Edit, MessageSquare, Settings, CheckCircle2, XCircle, DollarSign, Calendar } 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, DropdownMenuShortcut } from "@/components/ui/dropdown-menu" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { FinalRfqDetailView } from "@/db/schema" // RowAction 타입 정의 export interface DataTableRowAction { row: Row type: "update" } interface GetFinalRfqDetailColumnsProps { onSelectDetail?: (detail: any) => void setRowAction?: React.Dispatch | null>> } export function getFinalRfqDetailColumns({ onSelectDetail, setRowAction }: GetFinalRfqDetailColumnsProps = {}): 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, }, /** 1. RFQ Status */ { accessorKey: "finalRfqStatus", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue("finalRfqStatus") as string const getFinalStatusColor = (status: string) => { switch (status) { case "DRAFT": return "outline" case "Final RFQ Sent": return "default" case "Quotation Received": return "success" case "Vendor Selected": return "default" default: return "secondary" } } return ( {status} ) }, size: 120 }, /** 2. RFQ No. */ { accessorKey: "rfqCode", header: ({ column }) => ( ), cell: ({ row }) => (
{row.getValue("rfqCode") as string}
), size: 120, }, /** 3. Rev. */ { accessorKey: "returnRevision", header: ({ column }) => ( ), cell: ({ row }) => { const revision = row.getValue("returnRevision") as number return revision > 0 ? ( Rev. {revision} ) : ( Rev. 0 ) }, size: 80, }, /** 4. Vendor Code */ { accessorKey: "vendorCode", header: ({ column }) => ( ), cell: ({ row }) => (
{row.original.vendorCode}
), size: 100, }, /** 5. Vendor Name */ { accessorKey: "vendorName", header: ({ column }) => ( ), cell: ({ row }) => (
{row.original.vendorName}
), size: 150, }, /** 6. 업체분류 */ { id: "vendorClassification", header: ({ column }) => ( ), cell: ({ row }) => { const vendorCode = row.original.vendorCode as string return vendorCode ? ( 정규업체 ) : ( 잠재업체 ) }, size: 100, }, /** 7. CP 현황 */ { accessorKey: "cpRequestYn", header: ({ column }) => ( ), cell: ({ row }) => { const cpRequest = row.getValue("cpRequestYn") as boolean return cpRequest ? ( 신청 ) : ( 미신청 ) }, size: 80, }, /** 8. GTC현황 */ { id: "gtcStatus", header: ({ column }) => ( ), cell: ({ row }) => { const gtc = row.original.gtc as string const gtcValidDate = row.original.gtcValidDate as string const prjectGtcYn = row.original.prjectGtcYn as boolean if (prjectGtcYn || gtc) { return (
보유 {gtcValidDate && (
{gtcValidDate}
)}
) } return ( 미보유 ) }, size: 100, }, /** 9. TBE 결과 (스키마에 없어서 placeholder) */ { id: "tbeResult", header: ({ column }) => ( ), cell: ({ row }) => { // TODO: TBE 결과 로직 구현 필요 return ( - ) }, size: 80, }, /** 10. 최종 선정 */ { id: "finalSelection", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.original.finalRfqStatus as string return status === "Vendor Selected" ? ( 선정 ) : ( - ) }, size: 80, }, /** 11. Currency */ { accessorKey: "currency", header: ({ column }) => ( ), cell: ({ row }) => { const currency = row.getValue("currency") as string return currency ? ( {/* */} {currency} ) : ( - ) }, size: 80, }, /** 12. Terms of Payment */ { accessorKey: "paymentTermsCode", header: ({ column }) => ( ), cell: ({ row }) => { const paymentTermsCode = row.getValue("paymentTermsCode") as string return paymentTermsCode ? ( {paymentTermsCode} ) : ( - ) }, size: 120, }, /** 13. Payment Desc. */ { accessorKey: "paymentTermsDescription", header: ({ column }) => ( ), cell: ({ row }) => { const description = row.getValue("paymentTermsDescription") as string return description ? (
{description}
) : ( - ) }, size: 150, }, /** 14. TAX */ { accessorKey: "taxCode", header: ({ column }) => ( ), cell: ({ row }) => { const taxCode = row.getValue("taxCode") as string return taxCode ? ( {taxCode} ) : ( - ) }, size: 80, }, /** 15. Delivery Date* */ { accessorKey: "deliveryDate", header: ({ column }) => ( ), cell: ({ row }) => { const deliveryDate = row.getValue("deliveryDate") as Date return deliveryDate ? (
{formatDate(deliveryDate, "KR")}
) : ( - ) }, size: 120, }, /** 16. Country */ { accessorKey: "vendorCountry", header: ({ column }) => ( ), cell: ({ row }) => { const country = row.getValue("vendorCountry") as string const countryDisplay = country === "KR" ? "D" : "F" return ( {countryDisplay} ) }, size: 80, }, /** 17. Place of Shipping */ { accessorKey: "placeOfShipping", header: ({ column }) => ( ), cell: ({ row }) => { const placeOfShipping = row.getValue("placeOfShipping") as string return placeOfShipping ? (
{placeOfShipping}
) : ( - ) }, size: 120, }, /** 18. Place of Destination */ { accessorKey: "placeOfDestination", header: ({ column }) => ( ), cell: ({ row }) => { const placeOfDestination = row.getValue("placeOfDestination") as string return placeOfDestination ? (
{placeOfDestination}
) : ( - ) }, size: 120, }, /** 19. 초도 여부* */ { accessorKey: "firsttimeYn", header: ({ column }) => ( ), cell: ({ row }) => { const firsttime = row.getValue("firsttimeYn") as boolean return firsttime ? ( 초도 ) : ( 재구매 ) }, size: 80, }, /** 20. 연동제 적용* */ { accessorKey: "materialPriceRelatedYn", header: ({ column }) => ( ), cell: ({ row }) => { const materialPrice = row.getValue("materialPriceRelatedYn") as boolean return materialPrice ? ( 적용 ) : ( 미적용 ) }, size: 100, }, /** 21. Business Size */ { id: "businessSizeDisplay", header: ({ column }) => ( ), cell: ({ row }) => { const businessSize = row.original.vendorBusinessSize as string return businessSize ? ( {businessSize} ) : ( - ) }, size: 100, }, /** 22. 최종 Update일 */ { accessorKey: "updatedAt", header: ({ column }) => ( ), cell: ({ row }) => { const updated = row.getValue("updatedAt") as Date return updated ? (
{formatDate(updated, "KR")}
) : ( - ) }, size: 120, }, /** 23. 최종 Update담당자 (스키마에 없어서 placeholder) */ { id: "updatedByUser", header: ({ column }) => ( ), cell: ({ row }) => { // TODO: updatedBy 사용자 정보 조인 필요 return ( - ) }, size: 120, }, /** 24. Vendor 설명 */ { accessorKey: "vendorRemark", header: ({ column }) => ( ), cell: ({ row }) => { const vendorRemark = row.getValue("vendorRemark") as string return vendorRemark ? (
{vendorRemark}
) : ( - ) }, size: 150, }, /** 25. 비고 */ { accessorKey: "remark", header: ({ column }) => ( ), cell: ({ row }) => { const remark = row.getValue("remark") as string return remark ? (
{remark}
) : ( - ) }, size: 150, }, /** ───────────── 액션 ───────────── */ { id: "actions", enableHiding: false, cell: function Cell({ row }) { return ( 벤더 견적 보기 {setRowAction && ( setRowAction({ row, type: "update" })} > 수정 )} ) }, size: 40, }, ] }