From 4ee8b24cfadf47452807fa2af801385ed60ab47c Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 15 Sep 2025 14:41:01 +0000
Subject: (대표님) 작업사항 - rfqLast, tbeLast, pdfTron, userAuth
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/tbe-last/vendor/tbe-table.tsx | 222 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)
 create mode 100644 lib/tbe-last/vendor/tbe-table.tsx

(limited to 'lib/tbe-last/vendor/tbe-table.tsx')

diff --git a/lib/tbe-last/vendor/tbe-table.tsx b/lib/tbe-last/vendor/tbe-table.tsx
new file mode 100644
index 00000000..d7ee0a06
--- /dev/null
+++ b/lib/tbe-last/vendor/tbe-table.tsx
@@ -0,0 +1,222 @@
+// lib/vendor-rfq-response/vendor-tbe-table/tbe-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-table-columns"
+import { TbeLastView } from "@/db/schema"
+import { getTBESessionDetail } from "@/lib/tbe-last/service"
+import { Button } from "@/components/ui/button"
+import { Download, RefreshCw, Upload } from "lucide-react"
+import { exportTableToExcel } from "@/lib/export"
+
+// Import Vendor-specific Dialogs
+import { VendorDocumentUploadDialog } from "./vendor-document-upload-dialog"
+import { VendorQADialog } from "./vendor-comment-dialog"
+import { VendorDocumentsSheet } from "./vendor-documents-sheet"
+import { VendorPrItemsDialog } from "./vendor-pr-items-dialog"
+import { getTBEforVendor } from "../vendor-tbe-service"
+
+interface TbeVendorTableProps {
+  promises: Promise<[
+    Awaited<ReturnType<typeof getTBEforVendor>>,
+  ]>
+}
+
+export function TbeVendorTable({ promises }: TbeVendorTableProps) {
+  const router = useRouter()
+  const [{ data, pageCount }] = React.use(promises)
+  
+  // Dialog states
+  const [documentUploadOpen, setDocumentUploadOpen] = React.useState(false)
+  const [qaDialogOpen, setQADialogOpen] = React.useState(false)
+  const [evaluationViewOpen, setEvaluationViewOpen] = React.useState(false)
+  const [documentsOpen, setDocumentsOpen] = React.useState(false)
+  const [prItemsOpen, setPrItemsOpen] = React.useState(false)
+  
+  const [selectedSessionId, setSelectedSessionId] = React.useState<number | null>(null)
+  const [selectedRfqId, setSelectedRfqId] = React.useState<number | null>(null)
+  const [selectedSession, setSelectedSession] = React.useState<TbeLastView | null>(null)
+  const [sessionDetail, setSessionDetail] = React.useState<any>(null)
+  const [isLoadingDetail, setIsLoadingDetail] = React.useState(false)
+  
+  // Load session detail when needed
+  const loadSessionDetail = React.useCallback(async (sessionId: number) => {
+    setIsLoadingDetail(true)
+    try {
+      const detail = await getTBESessionDetail(sessionId)
+      setSessionDetail(detail)
+    } catch (error) {
+      console.error("Failed to load session detail:", error)
+    } finally {
+      setIsLoadingDetail(false)
+    }
+  }, [])
+  
+  // Handlers
+  const handleOpenDocumentUpload = React.useCallback((sessionId: number) => {
+    setSelectedSessionId(sessionId)
+    setDocumentUploadOpen(true)
+    loadSessionDetail(sessionId)
+  }, [loadSessionDetail])
+  
+  const handleOpenComment = React.useCallback((sessionId: number) => {
+    setSelectedSessionId(sessionId)
+    setQADialogOpen(true)
+    loadSessionDetail(sessionId)
+  }, [loadSessionDetail])
+  
+  const handleOpenEvaluationView = React.useCallback((session: TbeLastView) => {
+    setSelectedSession(session)
+    setEvaluationViewOpen(true)
+    loadSessionDetail(session.tbeSessionId)
+  }, [loadSessionDetail])
+  
+  const handleOpenDocuments = React.useCallback((sessionId: number) => {
+    setSelectedSessionId(sessionId)
+    setDocumentsOpen(true)
+    loadSessionDetail(sessionId)
+  }, [loadSessionDetail])
+  
+  const handleOpenPrItems = React.useCallback((rfqId: number) => {
+    setSelectedRfqId(rfqId)
+    setPrItemsOpen(true)
+  }, [])
+  
+  const handleRefresh = React.useCallback(() => {
+    router.refresh()
+  }, [router])
+  
+  // Table columns
+  const columns = React.useMemo(
+    () =>
+      getColumns({
+        onOpenDocumentUpload: handleOpenDocumentUpload,
+        onOpenComment: handleOpenComment,
+        onOpenEvaluationView: handleOpenEvaluationView,
+        onOpenDocuments: handleOpenDocuments,
+        onOpenPrItems: handleOpenPrItems,
+      }),
+    [handleOpenDocumentUpload, handleOpenComment, handleOpenEvaluationView, handleOpenDocuments, handleOpenPrItems]
+  )
+  
+  // Filter fields
+  const filterFields: DataTableAdvancedFilterField<TbeLastView>[] = [
+    {
+      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: "Pass", value: "pass" },
+        { label: "Conditional Pass", value: "conditional_pass" },
+        { label: "Non-Pass", value: "non_pass" },
+        { label: "Pending", value: "pending" },
+      ],
+    },
+  ]
+  
+  // Data table
+  const { table } = useDataTable({
+    data,
+    columns,
+    pageCount,
+    filterFields,
+    enablePinning: true,
+    enableAdvancedFilter: true,
+    initialState: {
+      sorting: [{ id: "createdAt", desc: true }],
+      columnPinning: { right: ["actions"] },
+    },
+    getRowId: (originalRow) => String(originalRow.tbeSessionId),
+    shallow: false,
+    clearOnDefault: true,
+  })
+  
+  return (
+    <>
+      <DataTable table={table}>
+        <DataTableAdvancedToolbar
+          table={table}
+          filterFields={filterFields}
+          shallow={false}
+        >
+          <div className="flex items-center gap-2">
+            <Button
+              variant="outline"
+              size="sm"
+              onClick={handleRefresh}
+              className="gap-2"
+            >
+              <RefreshCw className="size-4" />
+              <span>Refresh</span>
+            </Button>
+            <Button
+              variant="outline"
+              size="sm"
+              onClick={() =>
+                exportTableToExcel(table, {
+                  filename: "vendor-tbe-sessions",
+                  excludeColumns: ["select", "actions"],
+                })
+              }
+              className="gap-2"
+            >
+              <Download className="size-4" />
+              <span>Export</span>
+            </Button>
+          </div>
+        </DataTableAdvancedToolbar>
+      </DataTable>
+      
+      {/* Document Upload Dialog */}
+      <VendorDocumentUploadDialog
+        open={documentUploadOpen}
+        onOpenChange={setDocumentUploadOpen}
+        sessionId={selectedSessionId}
+        sessionDetail={sessionDetail}
+        onUploadSuccess={handleRefresh}
+      />
+      
+      {/* Q&A Dialog */}
+      <VendorQADialog
+        open={qaDialogOpen}
+        onOpenChange={setQADialogOpen}
+        sessionId={selectedSessionId}
+        sessionDetail={sessionDetail}
+        onQuestionSubmit={handleRefresh}
+      />
+      
+      {/* Documents Sheet */}
+      <VendorDocumentsSheet
+        open={documentsOpen}
+        onOpenChange={setDocumentsOpen}
+        sessionDetail={sessionDetail}
+        isLoading={isLoadingDetail}
+      />
+      
+      {/* PR Items Dialog */}
+      <VendorPrItemsDialog
+        open={prItemsOpen}
+        onOpenChange={setPrItemsOpen}
+        rfqId={selectedRfqId}
+      />
+    </>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

