"use client" import * as React from "react" import { useRouter } from "next/navigation" import { ColumnDef } from "@tanstack/react-table" import { Ellipsis, MessageSquare, Package, Paperclip, } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { Badge } from "@/components/ui/badge" import { getErrorMessage } from "@/lib/handle-error" import { formatDate, formatDateTime } from "@/lib/utils" import { modifyRfqVendor } from "../../rfqs/service" import type { RfqWithAll } from "../types" import type { DataTableRowAction } from "@/types/table" type NextRouter = ReturnType interface GetColumnsProps { setRowAction: React.Dispatch< React.SetStateAction | null> > router: NextRouter openAttachmentsSheet: (rfqId: number) => void openCommentSheet: (rfqId: number) => void } /** * tanstack table 컬럼 정의 (Nested Header) */ export function getColumns({ setRowAction, router, openAttachmentsSheet, openCommentSheet, }: GetColumnsProps): ColumnDef[] { // 1) 체크박스(Select) 컬럼 const selectColumn: ColumnDef = { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), size: 40, enableSorting: false, enableHiding: false, } // 2) Actions (Dropdown) const actionsColumn: ColumnDef = { id: "actions", enableHiding: false, cell: ({ row }) => { const [isUpdatePending, startUpdateTransition] = React.useTransition() return ( RFQ Response { startUpdateTransition(async () => { let newStatus: | "ACCEPTED" | "DECLINED" | "REVIEWING" switch (value) { case "ACCEPTED": newStatus = "ACCEPTED" break case "DECLINED": newStatus = "DECLINED" break default: newStatus = "REVIEWING" } await toast.promise( modifyRfqVendor({ id: row.original.responseId, status: newStatus, }), { loading: "Updating response status...", success: "Response status updated", error: (err) => getErrorMessage(err), } ) }) }} > {[ { value: "ACCEPTED", label: "Accept RFQ" }, { value: "DECLINED", label: "Decline RFQ" }, ].map((rep) => ( {rep.label} ))} {/* { router.push(`/vendor/rfqs/${row.original.rfqId}`) }} > View Details */} {/* openAttachmentsSheet(row.original.rfqId)}> View Attachments openCommentSheet(row.original.rfqId)}> View Comments setRowAction({ row, type: "items" })}> View Items */} ) }, size: 40, } // 3) RFQ Code 컬럼 const rfqCodeColumn: ColumnDef = { id: "rfqCode", accessorKey: "rfqCode", enableResizing: true, header: ({ column }) => ( ), // cell: ({ row }) => { // return ( // // ) // }, cell: ({ row }) => row.original.rfqCode || "-", size: 150, } const rfqTypeColumn: ColumnDef = { id: "rfqType", accessorKey: "rfqType", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => row.original.rfqType || "-", size: 150, } // 4) 응답 상태 컬럼 const responseStatusColumn: ColumnDef = { id: "responseStatus", accessorKey: "responseStatus", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => { const status = row.original.responseStatus; let variant: "default" | "secondary" | "destructive" | "outline"; switch (status) { case "REVIEWING": variant = "default"; break; case "ACCEPTED": variant = "secondary"; break; case "DECLINED": variant = "destructive"; break; default: variant = "outline"; } return {status}; }, size: 150, } // 5) 프로젝트 이름 컬럼 const projectNameColumn: ColumnDef = { id: "projectName", accessorKey: "projectName", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => row.original.projectName || "-", size: 150, } // 6) RFQ Description 컬럼 const descriptionColumn: ColumnDef = { id: "rfqDescription", accessorKey: "rfqDescription", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => row.original.rfqDescription || "-", size: 200, } // 7) Due Date 컬럼 const dueDateColumn: ColumnDef = { id: "rfqDueDate", accessorKey: "rfqDueDate", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => { const date = row.original.rfqDueDate; return date ? formatDate(date) : "-"; }, size: 120, } // 8) Last Updated 컬럼 const updatedAtColumn: ColumnDef = { id: "respondedAt", accessorKey: "respondedAt", enableResizing: true, header: ({ column }) => ( ), cell: ({ row }) => { const date = row.original.respondedAt; return date ? formatDateTime(date) : "-"; }, size: 150, } // 9) Items 컬럼 - 뱃지로 아이템 개수 표시 const itemsColumn: ColumnDef = { id: "items", header: ({ column }) => ( ), cell: ({ row }) => { const rfq = row.original const count = rfq.items?.length ?? 0 function handleClick() { setRowAction({ row, type: "items" }) } return ( ) }, enableSorting: false, maxSize: 80, } // 10) Attachments 컬럼 - 뱃지로 파일 개수 표시 const attachmentsColumn: ColumnDef = { id: "attachments", header: ({ column }) => ( ), cell: ({ row }) => { const attachCount = row.original.attachments?.length ?? 0 function handleClick(e: React.MouseEvent) { e.preventDefault() openAttachmentsSheet(row.original.rfqId) } return ( ) }, enableSorting: false, maxSize: 80, } // 11) Comments 컬럼 - 뱃지로 댓글 개수 표시 const commentsColumn: ColumnDef = { id: "comments", header: ({ column }) => ( ), cell: ({ row }) => { const commCount = row.original.comments?.length ?? 0 function handleClick() { setRowAction({ row, type: "comments" }) openCommentSheet(row.original.rfqId) } return ( ) }, enableSorting: false, maxSize: 80, } // 최종 컬럼 구성 - TBE/CBE 관련 컬럼 제외 return [ selectColumn, rfqCodeColumn, rfqTypeColumn, responseStatusColumn, projectNameColumn, descriptionColumn, dueDateColumn, itemsColumn, attachmentsColumn, commentsColumn, updatedAtColumn, actionsColumn, ] }