From 1110427907bbe9c11a378da4c1a233b83b5ca3b1 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 26 Aug 2025 12:09:39 +0000
Subject: (김준회) 구매정의서 구현 - PO (shi & vendor)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/po/vendor-table/vendor-po-table.tsx | 247 ++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)
 create mode 100644 lib/po/vendor-table/vendor-po-table.tsx

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

diff --git a/lib/po/vendor-table/vendor-po-table.tsx b/lib/po/vendor-table/vendor-po-table.tsx
new file mode 100644
index 00000000..a3ad4949
--- /dev/null
+++ b/lib/po/vendor-table/vendor-po-table.tsx
@@ -0,0 +1,247 @@
+"use client"
+
+import * as React from "react"
+import type {
+  DataTableAdvancedFilterField,
+  DataTableFilterField,
+  DataTableRowAction,
+} 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 { toast } from "sonner"
+
+import { getVendorPOs, handleVendorPOAction } from "./service"
+import { getVendorColumns } from "./vendor-po-columns"
+import { VendorPO, VendorPOActionType } from "./types"
+import { VendorPOItemsDialog } from "./vendor-po-items-dialog"
+import { VendorPOToolbarActions } from "./vendor-po-toolbar-actions"
+
+interface VendorPoTableProps {
+  promises: Promise<
+    [
+      Awaited<ReturnType<typeof getVendorPOs>>,
+    ]
+  >
+}
+
+export function VendorPoTable({ promises }: VendorPoTableProps) {
+  const [data, setData] = React.useState<{
+    data: VendorPO[];
+    pageCount: number;
+  }>({ data: [], pageCount: 0 });
+
+  const [selectedRows, setSelectedRows] = React.useState<number[]>([])
+
+  // 데이터 로딩
+  React.useEffect(() => {
+    promises.then(([result]) => {
+      console.log("Vendor PO data:", result.data)
+      setData(result);
+    });
+  }, [promises]);
+
+  const [rowAction, setRowAction] =
+    React.useState<DataTableRowAction<VendorPO> | null>(null)
+
+  // 다이얼로그 상태
+  const [itemsDialogOpen, setItemsDialogOpen] = React.useState(false)
+  const [selectedPO, setSelectedPO] = React.useState<VendorPO | null>(null)
+
+  // 행 선택 처리 (1개만 선택 가능)
+  const handleRowSelect = (id: number, selected: boolean) => {
+    if (selected) {
+      setSelectedRows([id]) // 1개만 선택
+    } else {
+      setSelectedRows([])
+    }
+  }
+
+  // 행 액션 처리
+  React.useEffect(() => {
+    if (!rowAction) return
+
+    const po = rowAction.row.original
+    setSelectedPO(po)
+
+    switch (rowAction.type as VendorPOActionType) {
+      case "view-items":
+        setItemsDialogOpen(true)
+        break
+      case "pcr-create":
+        handleAction(po.id, "pcr-create")
+        break
+      case "approve":
+        handleAction(po.id, "approve")
+        break
+      case "cancel-approve":
+        handleAction(po.id, "cancel-approve")
+        break
+      case "reject-contract":
+        handleAction(po.id, "reject-contract")
+        break
+      case "print-contract":
+        handleAction(po.id, "print-contract")
+        break
+      case "item-status":
+        setItemsDialogOpen(true)
+        break
+      case "contract-detail":
+        toast.info("계약상세 기능은 개발 중입니다.")
+        break
+      case "po-note":
+        toast.info("PO Note 기능은 개발 중입니다.")
+        break
+      case "price-index":
+        toast.info("연동표입력 기능은 개발 중입니다.")
+        break
+      default:
+        toast.info("해당 기능은 개발 중입니다.")
+    }
+
+    setRowAction(null)
+  }, [rowAction])
+
+  // 액션 처리 함수
+  const handleAction = async (poId: number, action: string) => {
+    try {
+      const result = await handleVendorPOAction(poId, action)
+      if (result.success) {
+        toast.success(result.message)
+        // 필요시 데이터 새로고침
+      } else {
+        toast.error(result.message)
+      }
+    } catch (error) {
+      console.error("Action error:", error)
+      toast.error("액션 처리 중 오류가 발생했습니다.")
+    }
+  }
+
+  const columns = React.useMemo(
+    () => getVendorColumns({ 
+      setRowAction, 
+      selectedRows, 
+      onRowSelect: handleRowSelect 
+    }),
+    [selectedRows]
+  )
+
+  const filterFields: DataTableFilterField<VendorPO>[] = [
+    {
+      id: "contractStatus",
+      label: "계약상태",
+      options: [
+        { label: "승인대기", value: "승인대기" },
+        { label: "계약완료", value: "계약완료" },
+        { label: "진행중", value: "진행중" },
+        { label: "수정요청", value: "수정요청" },
+        { label: "거절됨", value: "거절됨" },
+      ]
+    },
+    {
+      id: "contractType",
+      label: "계약종류",
+      options: [
+        { label: "구매계약", value: "구매계약" },
+        { label: "서비스계약", value: "서비스계약" },
+        { label: "임가공계약", value: "임가공계약" },
+      ]
+    },
+    {
+      id: "currency",
+      label: "계약통화",
+      options: [
+        { label: "KRW", value: "KRW" },
+        { label: "USD", value: "USD" },
+        { label: "EUR", value: "EUR" },
+        { label: "JPY", value: "JPY" },
+      ]
+    }
+  ]
+
+  const advancedFilterFields: DataTableAdvancedFilterField<VendorPO>[] = [
+    {
+      id: "contractNo",
+      label: "PO/계약번호",
+      type: "text",
+    },
+    {
+      id: "contractName",
+      label: "계약명/자재내역",
+      type: "text",
+    },
+    {
+      id: "projectName",
+      label: "프로젝트",
+      type: "text",
+    },
+    {
+      id: "purchaseManager",
+      label: "구매/계약담당",
+      type: "text",
+    },
+    {
+      id: "poReceiveDate",
+      label: "PO/계약수신일",
+      type: "date",
+    },
+    {
+      id: "contractDate",
+      label: "계약체결일",
+      type: "date",
+    },
+    {
+      id: "lastModifiedDate",
+      label: "최종수정일",
+      type: "date",
+    },
+  ]
+
+  const { table } = useDataTable({
+    data: data.data,
+    columns,
+    pageCount: data.pageCount,
+    filterFields,
+    enablePinning: true,
+    enableAdvancedFilter: true,
+    initialState: {
+      sorting: [{ id: "lastModifiedDate", desc: true }],
+      columnPinning: { right: ["actions"] },
+    },
+    getRowId: (originalRow) => String(originalRow.id),
+    shallow: false,
+    clearOnDefault: true,
+  })
+
+  return (
+    <>
+      <DataTable
+        table={table}
+      >
+        <DataTableAdvancedToolbar
+          table={table}
+          filterFields={advancedFilterFields}
+          shallow={false}
+        >
+          <VendorPOToolbarActions 
+            table={table} 
+            selectedRows={selectedRows}
+            onAction={handleAction}
+            onViewItems={(po) => {
+              setSelectedPO(po)
+              setItemsDialogOpen(true)
+            }}
+          />
+        </DataTableAdvancedToolbar>
+      </DataTable>
+
+      <VendorPOItemsDialog
+        open={itemsDialogOpen}
+        onOpenChange={setItemsDialogOpen}
+        po={selectedPO}
+      />
+    </>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

