summaryrefslogtreecommitdiff
path: root/lib/techsales-rfq/vendor-response/table
diff options
context:
space:
mode:
Diffstat (limited to 'lib/techsales-rfq/vendor-response/table')
-rw-r--r--lib/techsales-rfq/vendor-response/table/vendor-quotations-table-columns.tsx71
-rw-r--r--lib/techsales-rfq/vendor-response/table/vendor-quotations-table.tsx56
2 files changed, 92 insertions, 35 deletions
diff --git a/lib/techsales-rfq/vendor-response/table/vendor-quotations-table-columns.tsx b/lib/techsales-rfq/vendor-response/table/vendor-quotations-table-columns.tsx
index cf1dac42..ddee2317 100644
--- a/lib/techsales-rfq/vendor-response/table/vendor-quotations-table-columns.tsx
+++ b/lib/techsales-rfq/vendor-response/table/vendor-quotations-table-columns.tsx
@@ -2,7 +2,7 @@
import * as React from "react"
import { type ColumnDef } from "@tanstack/react-table"
-import { Edit, Paperclip } from "lucide-react"
+import { Edit, Paperclip, Package } from "lucide-react"
import { formatCurrency, formatDate, formatDateTime } from "@/lib/utils"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
@@ -29,7 +29,8 @@ interface QuotationWithRfqCode extends TechSalesVendorQuotations {
// 아이템 정보
itemName?: string;
- itemShipbuildingId?: number;
+
+ itemCount?: number;
// 프로젝트 정보
projNm?: string;
@@ -44,14 +45,6 @@ interface QuotationWithRfqCode extends TechSalesVendorQuotations {
createdByName?: string | null;
updatedByName?: string | null;
- // 견적 코드 및 버전
- quotationCode?: string | null;
- quotationVersion?: number | null;
-
- // 추가 상태 정보
- rejectionReason?: string | null;
- acceptedAt?: Date | null;
-
// 첨부파일 개수
attachmentCount?: number;
}
@@ -59,9 +52,10 @@ interface QuotationWithRfqCode extends TechSalesVendorQuotations {
interface GetColumnsProps {
router: AppRouterInstance;
openAttachmentsSheet: (rfqId: number) => void;
+ openItemsDialog: (rfq: { id: number; rfqCode?: string; status?: string; rfqType?: "SHIP" | "TOP" | "HULL"; }) => void;
}
-export function getColumns({ router, openAttachmentsSheet }: GetColumnsProps): ColumnDef<QuotationWithRfqCode>[] {
+export function getColumns({ router, openAttachmentsSheet, openItemsDialog }: GetColumnsProps): ColumnDef<QuotationWithRfqCode>[] {
return [
{
id: "select",
@@ -151,7 +145,7 @@ export function getColumns({ router, openAttachmentsSheet }: GetColumnsProps): C
// {
// accessorKey: "materialCode",
// header: ({ column }) => (
- // <DataTableColumnHeaderSimple column={column} title="자재 코드" />
+ // <DataTableColumnHeaderSimple column={column} title="자재 그룹" />
// ),
// cell: ({ row }) => {
// const materialCode = row.getValue("materialCode") as string;
@@ -251,6 +245,59 @@ export function getColumns({ router, openAttachmentsSheet }: GetColumnsProps): C
// enableHiding: true,
// },
{
+ id: "items",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="아이템" />
+ ),
+ cell: ({ row }) => {
+ const quotation = row.original
+ const itemCount = quotation.itemCount || 0
+
+ const handleClick = () => {
+ const rfq = {
+ id: quotation.rfqId,
+ rfqCode: quotation.rfqCode,
+ status: quotation.rfqStatus,
+ rfqType: "SHIP" as const, // 기본값
+ }
+ openItemsDialog(rfq)
+ }
+
+ return (
+ <div className="w-20">
+ <TooltipProvider>
+ <Tooltip>
+ <TooltipTrigger asChild>
+ <Button
+ variant="ghost"
+ size="sm"
+ className="relative h-8 w-8 p-0 group"
+ onClick={handleClick}
+ aria-label={`View ${itemCount} items`}
+ >
+ <Package className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
+ {itemCount > 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">
+ {itemCount}
+ </span>
+ )}
+ <span className="sr-only">
+ {itemCount > 0 ? `${itemCount} 아이템` : "아이템 없음"}
+ </span>
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent>
+ <p>{itemCount > 0 ? `${itemCount}개 아이템 보기` : "아이템 없음"}</p>
+ </TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ </div>
+ )
+ },
+ enableSorting: false,
+ enableHiding: true,
+ },
+ {
id: "attachments",
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="첨부파일" />
diff --git a/lib/techsales-rfq/vendor-response/table/vendor-quotations-table.tsx b/lib/techsales-rfq/vendor-response/table/vendor-quotations-table.tsx
index e98d6bdc..55dcad92 100644
--- a/lib/techsales-rfq/vendor-response/table/vendor-quotations-table.tsx
+++ b/lib/techsales-rfq/vendor-response/table/vendor-quotations-table.tsx
@@ -11,6 +11,7 @@ import { TechSalesVendorQuotations, TECH_SALES_QUOTATION_STATUSES, TECH_SALES_QU
import { useRouter } from "next/navigation"
import { getColumns } from "./vendor-quotations-table-columns"
import { TechSalesRfqAttachmentsSheet, ExistingTechSalesAttachment } from "../../table/tech-sales-rfq-attachments-sheet"
+import { RfqItemsViewDialog } from "../../table/rfq-items-view-dialog"
import { getTechSalesRfqAttachments, getVendorQuotations } from "@/lib/techsales-rfq/service"
import { toast } from "sonner"
import { Skeleton } from "@/components/ui/skeleton"
@@ -23,14 +24,16 @@ interface QuotationWithRfqCode extends TechSalesVendorQuotations {
itemName?: string | null;
projNm?: string | null;
quotationCode?: string | null;
- quotationVersion?: number | null;
+
rejectionReason?: string | null;
acceptedAt?: Date | null;
attachmentCount?: number;
+ itemCount?: number;
}
interface VendorQuotationsTableProps {
vendorId: string;
+ rfqType?: "SHIP" | "TOP" | "HULL";
}
// 로딩 스켈레톤 컴포넌트
@@ -92,22 +95,9 @@ function TableLoadingSkeleton() {
)
}
-// 중앙 로딩 인디케이터 컴포넌트
-function CenterLoadingIndicator() {
- return (
- <div className="flex flex-col items-center justify-center py-12 space-y-4">
- <div className="relative">
- <div className="w-12 h-12 border-4 border-gray-200 border-t-blue-600 rounded-full animate-spin"></div>
- </div>
- <div className="text-center space-y-1">
- <p className="text-sm font-medium text-gray-900">데이터를 불러오는 중...</p>
- <p className="text-xs text-gray-500">잠시만 기다려주세요.</p>
- </div>
- </div>
- )
-}
-export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps) {
+
+export function VendorQuotationsTable({ vendorId, rfqType }: VendorQuotationsTableProps) {
const searchParams = useSearchParams()
const router = useRouter()
@@ -116,6 +106,10 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
const [selectedRfqForAttachments, setSelectedRfqForAttachments] = React.useState<{ id: number; rfqCode: string | null; status: string } | null>(null)
const [attachmentsDefault, setAttachmentsDefault] = React.useState<ExistingTechSalesAttachment[]>([])
+ // 아이템 다이얼로그 상태
+ const [itemsDialogOpen, setItemsDialogOpen] = React.useState(false)
+ const [selectedRfqForItems, setSelectedRfqForItems] = React.useState<{ id: number; rfqCode?: string; status?: string; rfqType?: "SHIP" | "TOP" | "HULL"; } | null>(null)
+
// 데이터 로딩 상태
const [data, setData] = React.useState<QuotationWithRfqCode[]>([])
const [pageCount, setPageCount] = React.useState(0)
@@ -158,6 +152,7 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
search: initialSettings.search,
from: initialSettings.from,
to: initialSettings.to,
+ rfqType: rfqType,
}, vendorId)
console.log('🔍 [VendorQuotationsTable] 데이터 로드 결과:', {
@@ -176,7 +171,7 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
setIsLoading(false)
setIsInitialLoad(false)
}
- }, [vendorId, initialSettings])
+ }, [vendorId, initialSettings, rfqType])
// URL 파라미터 변경 감지 및 데이터 재로드 (초기 로드 포함)
React.useEffect(() => {
@@ -192,8 +187,9 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
searchParams?.get('search'),
searchParams?.get('from'),
searchParams?.get('to'),
- // vendorId 변경도 감지
- vendorId
+ // vendorId와 rfqType 변경도 감지
+ vendorId,
+ rfqType
])
// 데이터 안정성을 위한 메모이제이션
@@ -246,12 +242,19 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
toast.error("첨부파일 조회 중 오류가 발생했습니다.")
}
}, [data])
+
+ // 아이템 다이얼로그 열기 함수
+ const openItemsDialog = React.useCallback((rfq: { id: number; rfqCode?: string; status?: string; rfqType?: "SHIP" | "TOP" | "HULL"; }) => {
+ setSelectedRfqForItems(rfq)
+ setItemsDialogOpen(true)
+ }, [])
// 테이블 컬럼 정의
const columns = React.useMemo(() => getColumns({
router,
openAttachmentsSheet,
- }), [router, openAttachmentsSheet])
+ openItemsDialog,
+ }), [router, openAttachmentsSheet, openItemsDialog])
// 필터 필드
const filterFields = React.useMemo<DataTableFilterField<QuotationWithRfqCode>[]>(() => [
@@ -270,8 +273,8 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
},
{
id: "materialCode",
- label: "자재 코드",
- placeholder: "자재 코드 검색...",
+ label: "자재 그룹",
+ placeholder: "자재 그룹 검색...",
}
], [])
@@ -284,7 +287,7 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
},
{
id: "materialCode",
- label: "자재 코드",
+ label: "자재 그룹",
type: "text",
},
{
@@ -383,6 +386,13 @@ export function VendorQuotationsTable({ vendorId }: VendorQuotationsTableProps)
onAttachmentsUpdated={() => {}} // 읽기 전용이므로 빈 함수
readOnly={true} // 벤더 쪽에서는 항상 읽기 전용
/>
+
+ {/* 아이템 보기 다이얼로그 */}
+ <RfqItemsViewDialog
+ open={itemsDialogOpen}
+ onOpenChange={setItemsDialogOpen}
+ rfq={selectedRfqForItems}
+ />
</div>
);
} \ No newline at end of file