diff options
Diffstat (limited to 'lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx')
| -rw-r--r-- | lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx b/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx index 3e50a516..e921fcaa 100644 --- a/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx +++ b/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx @@ -5,7 +5,7 @@ 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 } from "lucide-react"; +import { MessageCircle, MoreHorizontal, Trash2, Paperclip } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { @@ -38,6 +38,24 @@ export interface RfqDetailView { 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<TData> { @@ -45,11 +63,15 @@ interface GetColumnsProps<TData> { React.SetStateAction<DataTableRowAction<TData> | null> >; unreadMessages?: Record<number, number>; // 읽지 않은 메시지 개수 + onQuotationClick?: (quotationId: number) => void; // 견적 클릭 핸들러 + openQuotationAttachmentsSheet?: (quotationId: number, quotationInfo: QuotationInfo) => void; // 견적서 첨부파일 sheet 열기 } export function getRfqDetailColumns({ setRowAction, - unreadMessages = {} + unreadMessages = {}, + onQuotationClick, + openQuotationAttachmentsSheet }: GetColumnsProps<RfqDetailView>): ColumnDef<RfqDetailView>[] { return [ { @@ -66,15 +88,15 @@ export function getRfqDetailColumns({ ), cell: ({ row }) => { const status = row.original.status; - const isDraft = status === "Draft"; + const isSelectable = status ? !["Accepted", "Rejected"].includes(status) : true; return ( <Checkbox checked={row.getIsSelected()} onCheckedChange={(value) => row.toggleSelected(!!value)} - disabled={!isDraft} + disabled={!isSelectable} aria-label="행 선택" - className={!isDraft ? "opacity-50 cursor-not-allowed" : ""} + className={!isSelectable ? "opacity-50 cursor-not-allowed" : ""} /> ); }, @@ -163,15 +185,31 @@ export function getRfqDetailColumns({ 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 ( + <Button + variant="link" + className="p-0 h-auto font-medium text-left justify-start hover:underline" + onClick={() => onQuotationClick(quotationId)} + title="견적 히스토리 보기" + > + {displayValue} {currency} + </Button> + ); + } return ( <div className="font-medium"> - {isNaN(numValue) ? value : numValue.toLocaleString()} {currency} + {displayValue} {currency} </div> ); }, @@ -182,6 +220,57 @@ export function getRfqDetailColumns({ size: 140, }, { + accessorKey: "quotationAttachments", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="첨부파일" /> + ), + cell: ({ row }) => { + const attachments = row.original.quotationAttachments || []; + const attachmentCount = attachments.length; + + if (attachmentCount === 0) { + return <div className="text-muted-foreground">-</div>; + } + + return ( + <Button + variant="ghost" + size="sm" + className="relative h-8 w-8 p-0 group" + onClick={() => { + // 견적서 첨부파일 sheet 열기 + if (openQuotationAttachmentsSheet) { + const quotation = row.original; + openQuotationAttachmentsSheet(quotation.id, { + id: quotation.id, + quotationCode: quotation.quotationCode || null, + vendorName: quotation.vendorName || undefined, + rfqCode: quotation.rfqCode || undefined, + }); + } + }} + title={ + attachmentCount === 1 + ? `${attachments[0].fileName} (${(attachments[0].fileSize / 1024 / 1024).toFixed(2)} MB)` + : `${attachmentCount}개의 첨부파일:\n${attachments.map(att => att.fileName).join('\n')}` + } + > + <Paperclip className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" /> + {attachmentCount > 0 && ( + <span className="pointer-events-none absolute -top-1 -right-1 inline-flex h-4 min-w-[1rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-medium leading-none text-primary-foreground"> + {attachmentCount} + </span> + )} + </Button> + ); + }, + meta: { + excelHeader: "첨부파일" + }, + enableResizing: false, + size: 80, + }, + { accessorKey: "currency", header: ({ column }) => ( <DataTableColumnHeaderSimple column={column} title="통화" /> |
