diff options
Diffstat (limited to 'lib/b-rfq/final/final-rfq-detail-table.tsx')
| -rw-r--r-- | lib/b-rfq/final/final-rfq-detail-table.tsx | 297 |
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 |
