// lib/tbe-last/table/tbe-last-table.tsx "use client" import * as React from "react" import { useRouter } from "next/navigation" import { type DataTableAdvancedFilterField } 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 { getColumns } from "./tbe-last-table-columns" import { TbeLastView } from "@/db/schema" import { getAllTBELast, getTBESessionDetail, requestTBEForRFQ } from "@/lib/tbe-last/service" import { Button } from "@/components/ui/button" import { Download, RefreshCw } from "lucide-react" import { exportTableToExcel } from "@/lib/export" // Import Dialogs and Sheets import { SessionDetailDialog } from "./session-detail-dialog" import { DocumentsSheet } from "./documents-sheet" import { PrItemsDialog } from "./pr-items-dialog" import { EvaluationDialog } from "./evaluation-dialog" import { toast } from "sonner" interface TbeLastTableProps { promises: Promise<[ Awaited>, ]> } export function TbeLastTable({ promises }: TbeLastTableProps) { const router = useRouter() const [{ data, pageCount }] = React.use(promises) console.log(data, "data") // Dialog states const [sessionDetailOpen, setSessionDetailOpen] = React.useState(false) const [documentsOpen, setDocumentsOpen] = React.useState(false) const [prItemsOpen, setPrItemsOpen] = React.useState(false) const [evaluationOpen, setEvaluationOpen] = React.useState(false) const [selectedSessionId, setSelectedSessionId] = React.useState(null) const [selectedRfqId, setSelectedRfqId] = React.useState(null) const [selectedSession, setSelectedSession] = React.useState(null) const [sessionDetail, setSessionDetail] = React.useState(null) const [isLoadingDetail, setIsLoadingDetail] = React.useState(false) // PR Items count overrides per sessionId (sourced from dialog detail) const [prItemsCountsBySessionId, setPrItemsCountsBySessionId] = React.useState>({}) // Load session detail when needed const loadSessionDetail = React.useCallback(async (sessionId: number) => { setIsLoadingDetail(true) try { const detail = await getTBESessionDetail(sessionId) setSessionDetail(detail) // Update PR items count override for this session if (detail?.session?.tbeSessionId) { const sid = detail.session.tbeSessionId as number const items = Array.isArray(detail?.prItems) ? detail.prItems : [] const total = items.length const major = items.filter((it: any) => it?.majorYn === true).length setPrItemsCountsBySessionId(prev => ({ ...prev, [sid]: { total, major } })) } } catch (error) { console.error("Failed to load session detail:", error) } finally { setIsLoadingDetail(false) } }, []) // Handlers const handleOpenSessionDetail = React.useCallback((sessionId: number) => { setSelectedSessionId(sessionId) setSessionDetailOpen(true) loadSessionDetail(sessionId) }, [loadSessionDetail]) const handleOpenDocuments = React.useCallback((sessionId: number) => { setSelectedSessionId(sessionId) setDocumentsOpen(true) loadSessionDetail(sessionId) }, [loadSessionDetail]) const handleOpenPrItems = React.useCallback((sessionId: number) => { setSelectedSessionId(sessionId) setPrItemsOpen(true) loadSessionDetail(sessionId) }, [loadSessionDetail]) const handleOpenEvaluation = React.useCallback((session: TbeLastView) => { setSelectedSession(session) setEvaluationOpen(true) loadSessionDetail(session.rfqId) }, []) // Refresh 기능 제거됨 // Table columns const columns = React.useMemo( () => getColumns({ onOpenSessionDetail: handleOpenSessionDetail, onOpenDocuments: handleOpenDocuments, onOpenPrItems: handleOpenPrItems, onOpenEvaluation: handleOpenEvaluation, getPrCountsOverride: (sessionId: number) => prItemsCountsBySessionId[sessionId] }), [handleOpenSessionDetail, handleOpenDocuments, handleOpenPrItems, handleOpenEvaluation, prItemsCountsBySessionId] ) // Filter fields const filterFields: DataTableAdvancedFilterField[] = [ { id: "sessionCode", label: "TBE Code", type: "text", }, { id: "rfqCode", label: "RFQ Code", type: "text", }, { id: "rfqTitle", label: "RFQ Title", type: "text", }, { id: "rfqDueDate", label: "Due Date", type: "date", }, { id: "packageNo", label: "Package No", type: "text", }, { id: "projectCode", label: "Project", type: "text", }, { id: "vendorCode", label: "Vendor Code", type: "text", }, { id: "vendorName", label: "Vendor Name", type: "text", }, { id: "picName", label: "구매담당자", type: "text", }, { id: "EngPicName", label: "설계담당자", type: "text", }, { id: "sessionStatus", label: "Status", type: "select", options: [ { label: "준비중", value: "준비중" }, { label: "진행중", value: "진행중" }, { label: "검토중", value: "검토중" }, { label: "보류", value: "보류" }, { label: "완료", value: "완료" }, ], }, { id: "evaluationResult", label: "Result", type: "select", options: [ { label: "Acceptable", value: "Acceptable" }, { label: "Conditional", value: "Acceptable with Comment" }, { label: "Not Acceptable", value: "Not Acceptable" }, { label: "Pending", value: "" }, ], }, ] // Data table const { table } = useDataTable({ data, columns, pageCount, filterFields, enablePinning: true, enableAdvancedFilter: true, initialState: { sorting: [{ id: "createdAt", desc: true }], columnPinning: { right: ["documents"] }, }, getRowId: (originalRow) => String(originalRow.tbeSessionId), shallow: false, clearOnDefault: true, }) const handleBulkTBERequest = React.useCallback(async (rfqGroups: Map) => { try { const promises = Array.from(rfqGroups.entries()).map(async ([rfqCode, sessions]) => { // 준비중 상태인 세션만 필터링 const pendingSessions = sessions.filter(s => s.sessionStatus === "준비중"); if (pendingSessions.length === 0) { toast.info(`RFQ ${rfqCode}: 이미 TBE가 요청되었습니다.`); return null; } const vendors = pendingSessions.map(session => ({ sessionId: session.tbeSessionId, vendorId: session.vendorId, // vendor ID 추가 vendorCode: session.vendorCode, vendorName: session.vendorName, })); const rfqInfo = { rfqId: sessions[0].rfqId, // rfqLastId 추가 rfqCode: sessions[0].rfqCode, rfqTitle: sessions[0].rfqTitle || "", rfqDueDate: sessions[0].rfqDueDate, projectCode: sessions[0].projectCode || "", projectName: sessions[0].projectName || "", packageNo: sessions[0].packageNo || "", packageName: sessions[0].packageName || "", picName: sessions[0].picName || "", }; return requestTBEForRFQ(rfqInfo, vendors); }); const results = await Promise.allSettled(promises); const successCount = results.filter(r => r.status === "fulfilled" && r.value?.success).length; const failCount = results.filter(r => r.status === "rejected" || (r.status === "fulfilled" && !r.value?.success)).length; if (successCount > 0) { toast.success(`${successCount}개 RFQ에 대한 TBE 요청이 완료되었습니다.`); } if (failCount > 0) { toast.error(`${failCount}개 RFQ에 대한 TBE 요청이 실패했습니다.`); } // 테이블 새로고침 router.refresh(); table.resetRowSelection(); } catch (error) { console.error("TBE 요청 처리 중 오류:", error); toast.error("TBE 요청 처리 중 오류가 발생했습니다."); } }, [router, table]); return ( <>
{table.getFilteredSelectedRowModel().rows.length > 0 && ( )} {/* Refresh 버튼 제거됨 */}
{/* Session Detail Dialog */} {/* Documents Sheet */} {/* PR Items Dialog */} {/* Evaluation Dialog */} { router.refresh() }} /> ) }