"use client" import * as React from "react" import type { ColumnDef, Row } from "@tanstack/react-table"; import { formatDate } from "@/lib/utils" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { Checkbox } from "@/components/ui/checkbox"; import { MessageCircle, MoreHorizontal, Trash2, Paperclip, Users } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; export interface DataTableRowAction { row: Row; type: "communicate" | "delete"; } // 벤더 견적 데이터 타입 정의 export interface RfqDetailView { id: number rfqId: number vendorId?: number | null vendorName: string | null vendorCode: string | null totalPrice: string | number | null currency: string | null validUntil: Date | null status: string | null remark: string | null submittedAt: Date | null acceptedAt: Date | null rejectionReason: string | null createdAt: Date | null updatedAt: Date | null createdByName: string | null quotationCode?: string | null rfqCode?: string | null quotationAttachments?: Array<{ id: number revisionId: number fileName: string fileSize: number filePath: string description?: string | null }> } // 견적서 정보 타입 (Sheet용) export interface QuotationInfo { id: number quotationCode: string | null vendorName?: string rfqCode?: string } interface GetColumnsProps { setRowAction: React.Dispatch< React.SetStateAction | null> >; unreadMessages?: Record; // 읽지 않은 메시지 개수 onQuotationClick?: (quotationId: number) => void; // 견적 클릭 핸들러 openQuotationAttachmentsSheet?: (quotationId: number, quotationInfo: QuotationInfo) => void; // 견적서 첨부파일 sheet 열기 openContactsDialog?: (quotationId: number, vendorName?: string) => void; // 담당자 조회 다이얼로그 열기 } export function getRfqDetailColumns({ setRowAction, unreadMessages = {}, onQuotationClick, openQuotationAttachmentsSheet, openContactsDialog }: GetColumnsProps): ColumnDef[] { return [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="모두 선택" /> ), cell: ({ row }) => { const status = row.original.status; const isSelectable = status ? !["Accepted", "Rejected"].includes(status) : true; return ( row.toggleSelected(!!value)} disabled={!isSelectable} aria-label="행 선택" className={!isSelectable ? "opacity-50 cursor-not-allowed" : ""} /> ); }, enableSorting: false, enableHiding: false, size: 40, }, { accessorKey: "status", header: ({ column }) => ( ), cell: ({ row }) => { const status = row.getValue("status") as string; // 상태에 따른 배지 색상 설정 let variant: "default" | "secondary" | "outline" | "destructive" = "outline"; if (status === "Submitted") { variant = "default"; // 제출됨 - 기본 색상 } else if (status === "Accepted") { variant = "secondary"; // 승인됨 - 보조 색상 } else if (status === "Rejected") { variant = "destructive"; // 거부됨 - 위험 색상 } return ( {status || "Draft"} ); }, meta: { excelHeader: "견적 상태" }, enableResizing: true, size: 120, }, { accessorKey: "vendorCode", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("vendorCode")}
, meta: { excelHeader: "벤더 코드" }, enableResizing: true, size: 120, }, { accessorKey: "vendorName", header: ({ column }) => ( ), cell: ({ row }) => { const vendorName = row.getValue("vendorName") as string | null; const vendorId = row.original.vendorId; if (!vendorName) return
-
; if (vendorId) { return ( ); } return
{vendorName}
; }, meta: { excelHeader: "벤더명" }, enableResizing: true, size: 160, }, { accessorKey: "totalPrice", header: ({ column }) => ( ), cell: ({ row }) => { const value = row.getValue("totalPrice") as string | number | null; const currency = row.getValue("currency") as string | null; const quotationId = row.original.id; if (value === null || value === undefined) return "-"; // 숫자로 변환 시도 const numValue = typeof value === 'string' ? parseFloat(value) : value; const displayValue = isNaN(numValue) ? value : numValue.toLocaleString(); // 견적값이 있고 클릭 핸들러가 있는 경우 클릭 가능한 버튼으로 표시 if (onQuotationClick && quotationId) { return ( ); } return (
{displayValue} {currency}
); }, meta: { excelHeader: "견적 금액" }, enableResizing: true, size: 140, }, { accessorKey: "quotationAttachments", header: ({ column }) => ( ), cell: ({ row }) => { const attachments = row.original.quotationAttachments || []; const attachmentCount = attachments.length; if (attachmentCount === 0) { return
-
; } return ( ); }, meta: { excelHeader: "첨부파일" }, enableResizing: false, size: 80, }, { id: "contacts", header: "담당자", cell: ({ row }) => { const quotation = row.original; const handleClick = () => { if (openContactsDialog) { openContactsDialog(quotation.id, quotation.vendorName || undefined); } }; return (

RFQ 발송 담당자 보기

); }, meta: { excelHeader: "담당자" }, enableResizing: false, size: 80, }, { accessorKey: "currency", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("currency")}
, meta: { excelHeader: "통화" }, enableResizing: true, size: 80, }, { accessorKey: "validUntil", header: ({ column }) => ( ), cell: ({ cell }) => { const value = cell.getValue() as Date | null; return value ? formatDate(value, "KR") : "-"; }, meta: { excelHeader: "유효기간" }, enableResizing: true, size: 120, }, { accessorKey: "submittedAt", header: ({ column }) => ( ), cell: ({ cell }) => { const value = cell.getValue() as Date | null; return value ? formatDate(value, "KR") : "-"; }, meta: { excelHeader: "제출일" }, enableResizing: true, size: 120, }, { accessorKey: "createdByName", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("createdByName")}
, meta: { excelHeader: "등록자" }, enableResizing: true, size: 120, }, { accessorKey: "remark", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("remark") || "-"}
, meta: { excelHeader: "비고" }, enableResizing: true, size: 200, }, { id: "actions", header: () =>
동작
, cell: function Cell({ row }) { const vendorId = row.original.vendorId; const unreadCount = vendorId ? unreadMessages[vendorId] || 0 : 0; const status = row.original.status; const isDraft = status === "Draft"; return (
{/* 커뮤니케이션 버튼 */}
{unreadCount > 0 && ( {unreadCount > 9 ? '9+' : unreadCount} )}
{/* 컨텍스트 메뉴 */} setRowAction({ row, type: "delete" })} disabled={!isDraft} className={!isDraft ? "opacity-50 cursor-not-allowed" : "text-destructive focus:text-destructive"} > 벤더 삭제
); }, enableResizing: false, size: 120, }, ]; }