summaryrefslogtreecommitdiff
path: root/lib/b-rfq/final/final-rfq-detail-table.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/b-rfq/final/final-rfq-detail-table.tsx')
-rw-r--r--lib/b-rfq/final/final-rfq-detail-table.tsx297
1 files changed, 297 insertions, 0 deletions
diff --git a/lib/b-rfq/final/final-rfq-detail-table.tsx b/lib/b-rfq/final/final-rfq-detail-table.tsx
new file mode 100644
index 00000000..8ae42e7e
--- /dev/null
+++ b/lib/b-rfq/final/final-rfq-detail-table.tsx
@@ -0,0 +1,297 @@
+"use client"
+
+import * as React from "react"
+import { type DataTableAdvancedFilterField, type DataTableFilterField } from "@/types/table"
+import { useDataTable } from "@/hooks/use-data-table"
+import { DataTable } from "@/components/data-table/data-table"
+import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"
+import { getFinalRfqDetail } from "../service" // 앞서 만든 서버 액션
+import {
+ getFinalRfqDetailColumns,
+ type DataTableRowAction
+} from "./final-rfq-detail-columns"
+import { FinalRfqDetailTableToolbarActions } from "./final-rfq-detail-toolbar-actions"
+import { UpdateFinalRfqSheet } from "./update-final-rfq-sheet"
+import { FinalRfqDetailView } from "@/db/schema"
+
+interface FinalRfqDetailTableProps {
+ promises: Promise<Awaited<ReturnType<typeof getFinalRfqDetail>>>
+ rfqId?: number
+}
+
+export function FinalRfqDetailTable({ promises, rfqId }: FinalRfqDetailTableProps) {
+ const { data, pageCount } = React.use(promises)
+
+ // 선택된 상세 정보
+ const [selectedDetail, setSelectedDetail] = React.useState<any>(null)
+
+ // Row action 상태 (update만)
+ const [rowAction, setRowAction] = React.useState<DataTableRowAction<FinalRfqDetailView> | null>(null)
+
+ const columns = React.useMemo(
+ () => getFinalRfqDetailColumns({
+ onSelectDetail: setSelectedDetail,
+ setRowAction: setRowAction
+ }),
+ []
+ )
+
+ /**
+ * 필터 필드 정의
+ */
+ const filterFields: DataTableFilterField<any>[] = [
+ {
+ id: "rfqCode",
+ label: "RFQ 코드",
+ placeholder: "RFQ 코드로 검색...",
+ },
+ {
+ id: "vendorName",
+ label: "벤더명",
+ placeholder: "벤더명으로 검색...",
+ },
+ {
+ id: "rfqStatus",
+ label: "RFQ 상태",
+ options: [
+ { label: "Draft", value: "DRAFT", count: 0 },
+ { label: "문서 접수", value: "Doc. Received", count: 0 },
+ { label: "담당자 배정", value: "PIC Assigned", count: 0 },
+ { label: "문서 확정", value: "Doc. Confirmed", count: 0 },
+ { label: "초기 RFQ 발송", value: "Init. RFQ Sent", count: 0 },
+ { label: "초기 RFQ 응답", value: "Init. RFQ Answered", count: 0 },
+ { label: "TBE 시작", value: "TBE started", count: 0 },
+ { label: "TBE 완료", value: "TBE finished", count: 0 },
+ { label: "최종 RFQ 발송", value: "Final RFQ Sent", count: 0 },
+ { label: "견적 접수", value: "Quotation Received", count: 0 },
+ { label: "벤더 선정", value: "Vendor Selected", count: 0 },
+ ],
+ },
+ {
+ id: "finalRfqStatus",
+ label: "최종 RFQ 상태",
+ options: [
+ { label: "초안", value: "DRAFT", count: 0 },
+ { label: "발송", value: "Final RFQ Sent", count: 0 },
+ { label: "견적 접수", value: "Quotation Received", count: 0 },
+ { label: "벤더 선정", value: "Vendor Selected", count: 0 },
+ ],
+ },
+ {
+ id: "vendorCountry",
+ label: "벤더 국가",
+ options: [
+ { label: "한국", value: "KR", count: 0 },
+ { label: "중국", value: "CN", count: 0 },
+ { label: "일본", value: "JP", count: 0 },
+ { label: "미국", value: "US", count: 0 },
+ { label: "독일", value: "DE", count: 0 },
+ ],
+ },
+ {
+ id: "currency",
+ label: "통화",
+ options: [
+ { label: "USD", value: "USD", count: 0 },
+ { label: "EUR", value: "EUR", count: 0 },
+ { label: "KRW", value: "KRW", count: 0 },
+ { label: "JPY", value: "JPY", count: 0 },
+ { label: "CNY", value: "CNY", count: 0 },
+ ],
+ },
+ ]
+
+ /**
+ * 고급 필터 필드
+ */
+ const advancedFilterFields: DataTableAdvancedFilterField<any>[] = [
+ {
+ id: "rfqCode",
+ label: "RFQ 코드",
+ type: "text",
+ },
+ {
+ id: "vendorName",
+ label: "벤더명",
+ type: "text",
+ },
+ {
+ id: "vendorCode",
+ label: "벤더 코드",
+ type: "text",
+ },
+ {
+ id: "vendorCountry",
+ label: "벤더 국가",
+ type: "multi-select",
+ options: [
+ { label: "한국", value: "KR" },
+ { label: "중국", value: "CN" },
+ { label: "일본", value: "JP" },
+ { label: "미국", value: "US" },
+ { label: "독일", value: "DE" },
+ ],
+ },
+ {
+ id: "rfqStatus",
+ label: "RFQ 상태",
+ type: "multi-select",
+ options: [
+ { label: "Draft", value: "DRAFT" },
+ { label: "문서 접수", value: "Doc. Received" },
+ { label: "담당자 배정", value: "PIC Assigned" },
+ { label: "문서 확정", value: "Doc. Confirmed" },
+ { label: "초기 RFQ 발송", value: "Init. RFQ Sent" },
+ { label: "초기 RFQ 응답", value: "Init. RFQ Answered" },
+ { label: "TBE 시작", value: "TBE started" },
+ { label: "TBE 완료", value: "TBE finished" },
+ { label: "최종 RFQ 발송", value: "Final RFQ Sent" },
+ { label: "견적 접수", value: "Quotation Received" },
+ { label: "벤더 선정", value: "Vendor Selected" },
+ ],
+ },
+ {
+ id: "finalRfqStatus",
+ label: "최종 RFQ 상태",
+ type: "multi-select",
+ options: [
+ { label: "초안", value: "DRAFT" },
+ { label: "발송", value: "Final RFQ Sent" },
+ { label: "견적 접수", value: "Quotation Received" },
+ { label: "벤더 선정", value: "Vendor Selected" },
+ ],
+ },
+ {
+ id: "vendorBusinessSize",
+ label: "벤더 규모",
+ type: "multi-select",
+ options: [
+ { label: "대기업", value: "LARGE" },
+ { label: "중기업", value: "MEDIUM" },
+ { label: "소기업", value: "SMALL" },
+ { label: "스타트업", value: "STARTUP" },
+ ],
+ },
+ {
+ id: "incotermsCode",
+ label: "Incoterms",
+ type: "text",
+ },
+ {
+ id: "paymentTermsCode",
+ label: "Payment Terms",
+ type: "text",
+ },
+ {
+ id: "currency",
+ label: "통화",
+ type: "multi-select",
+ options: [
+ { label: "USD", value: "USD" },
+ { label: "EUR", value: "EUR" },
+ { label: "KRW", value: "KRW" },
+ { label: "JPY", value: "JPY" },
+ { label: "CNY", value: "CNY" },
+ ],
+ },
+ {
+ id: "dueDate",
+ label: "마감일",
+ type: "date",
+ },
+ {
+ id: "validDate",
+ label: "유효일",
+ type: "date",
+ },
+ {
+ id: "deliveryDate",
+ label: "납기일",
+ type: "date",
+ },
+ {
+ id: "shortList",
+ label: "Short List",
+ type: "boolean",
+ },
+ {
+ id: "returnYn",
+ label: "Return 여부",
+ type: "boolean",
+ },
+ {
+ id: "cpRequestYn",
+ label: "CP Request 여부",
+ type: "boolean",
+ },
+ {
+ id: "prjectGtcYn",
+ label: "Project GTC 여부",
+ type: "boolean",
+ },
+ {
+ id: "firsttimeYn",
+ label: "First Time 여부",
+ type: "boolean",
+ },
+ {
+ id: "materialPriceRelatedYn",
+ label: "Material Price Related 여부",
+ type: "boolean",
+ },
+ {
+ id: "classification",
+ label: "분류",
+ type: "text",
+ },
+ {
+ id: "sparepart",
+ label: "예비부품",
+ type: "text",
+ },
+ {
+ id: "createdAt",
+ label: "등록일",
+ type: "date",
+ },
+ ]
+
+ const { table } = useDataTable({
+ data,
+ columns,
+ pageCount,
+ filterFields,
+ enableAdvancedFilter: true,
+ initialState: {
+ sorting: [{ id: "createdAt", desc: true }],
+ columnPinning: { right: ["actions"] },
+ },
+ getRowId: (originalRow) => originalRow.finalRfqId ? originalRow.finalRfqId.toString() : "1",
+ shallow: false,
+ clearOnDefault: true,
+ })
+
+ return (
+ <div className="space-y-6">
+ {/* 메인 테이블 */}
+ <div className="h-full w-full">
+ <DataTable table={table} className="h-full">
+ <DataTableAdvancedToolbar
+ table={table}
+ filterFields={advancedFilterFields}
+ shallow={false}
+ >
+ <FinalRfqDetailTableToolbarActions table={table} rfqId={rfqId} />
+ </DataTableAdvancedToolbar>
+ </DataTable>
+ </div>
+
+ {/* Update Sheet */}
+ <UpdateFinalRfqSheet
+ open={rowAction?.type === "update"}
+ onOpenChange={() => setRowAction(null)}
+ finalRfq={rowAction?.type === "update" ? rowAction.row.original : null}
+ />
+ </div>
+ )
+} \ No newline at end of file