From 2650b7c0bb0ea12b68a58c0439f72d61df04b2f1 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 25 Jul 2025 07:51:15 +0000 Subject: (대표님) 정기평가 대상, 미들웨어 수정, nextauth 토큰 처리 개선, GTC 등 (최겸) 기술영업 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../possible-items/possible-items-table.tsx | 425 ++++++++++++--------- 1 file changed, 255 insertions(+), 170 deletions(-) (limited to 'lib/tech-vendors/possible-items/possible-items-table.tsx') diff --git a/lib/tech-vendors/possible-items/possible-items-table.tsx b/lib/tech-vendors/possible-items/possible-items-table.tsx index 9c024a93..b54e12d4 100644 --- a/lib/tech-vendors/possible-items/possible-items-table.tsx +++ b/lib/tech-vendors/possible-items/possible-items-table.tsx @@ -1,171 +1,256 @@ -"use client" - -import * as React from "react" -import type { - DataTableAdvancedFilterField, - DataTableFilterField, - DataTableRowAction, -} from "@/types/table" -import { toast } from "sonner" - -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 { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" - -import { getColumns } from "./possible-items-columns" -import { - getTechVendorPossibleItems, - deleteTechVendorPossibleItem, -} from "../service" -import type { TechVendorPossibleItem } from "../validations" -import { PossibleItemsTableToolbarActions } from "./possible-items-toolbar-actions" -import { AddItemDialog } from "./add-item-dialog" - -interface TechVendorPossibleItemsTableProps { - promises: Promise< - [ - Awaited>, - ] - > - vendorId: number -} - -export function TechVendorPossibleItemsTable({ - promises, - vendorId, -}: TechVendorPossibleItemsTableProps) { - // Suspense로 받아온 데이터 - const [{ data, pageCount }] = React.use(promises) - const [rowAction, setRowAction] = React.useState | null>(null) - const [showAddDialog, setShowAddDialog] = React.useState(false) - const [showDeleteAlert, setShowDeleteAlert] = React.useState(false) - const [isDeleting, setIsDeleting] = React.useState(false) - - // getColumns() 호출 시, setRowAction을 주입 - const columns = React.useMemo( - () => getColumns({ setRowAction }), - [setRowAction] - ) - - // 단일 아이템 삭제 핸들러 - async function handleDeleteItem() { - if (!rowAction || rowAction.type !== "delete") return - - setIsDeleting(true) - try { - const { success, error } = await deleteTechVendorPossibleItem( - rowAction.row.original.id, - vendorId - ) - - if (!success) { - throw new Error(error) - } - - toast.success("아이템이 삭제되었습니다") - setShowDeleteAlert(false) - setRowAction(null) - } catch (err) { - toast.error(err instanceof Error ? err.message : "아이템 삭제 중 오류가 발생했습니다") - } finally { - setIsDeleting(false) - } - } - - const filterFields: DataTableFilterField[] = [ - { id: "itemCode", label: "아이템 코드" }, - { id: "workType", label: "공종" }, - ] - - const advancedFilterFields: DataTableAdvancedFilterField[] = [ - { id: "itemCode", label: "아이템 코드", type: "text" }, - { id: "workType", label: "공종", type: "text" }, - { id: "itemList", label: "아이템명", type: "text" }, - { id: "shipTypes", label: "선종", type: "text" }, - { id: "subItemList", label: "서브아이템", type: "text" }, - { id: "createdAt", label: "등록일", type: "date" }, - { id: "updatedAt", label: "수정일", type: "date" }, - ] - - const { table } = useDataTable({ - data, - columns, - pageCount, - filterFields, - enablePinning: true, - enableAdvancedFilter: true, - initialState: { - sorting: [{ id: "createdAt", desc: true }], - columnPinning: { right: ["actions"] }, - }, - getRowId: (originalRow) => String(originalRow.id), - shallow: false, - clearOnDefault: true, - }) - - // rowAction 상태 변경 감지 - React.useEffect(() => { - if (rowAction?.type === "delete") { - setShowDeleteAlert(true) - } - }, [rowAction]) - - return ( - <> - - - setShowAddDialog(true)} - /> - - - - {/* Add Item Dialog */} - - - {/* Delete Confirmation Dialog */} - - - - 아이템 삭제 - - 이 아이템을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다. - - - - setRowAction(null)}> - 취소 - - - {isDeleting ? "삭제 중..." : "삭제"} - - - - - - ) +"use client" + +import * as React from "react" +import type { + DataTableAdvancedFilterField, + DataTableFilterField, + DataTableRowAction, +} from "@/types/table" +import { toast } from "sonner" + +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 { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { ScrollArea } from "@/components/ui/scroll-area" + +import { getColumns } from "./possible-items-columns" +import { getTechVendorPossibleItems } from "../../tech-vendor-possible-items/service" +import { deleteTechVendorPossibleItem, getTechVendorDetailById } from "../service" +import type { TechVendorPossibleItem } from "../validations" +import { PossibleItemsTableToolbarActions } from "./possible-items-toolbar-actions" +import { AddItemDialog } from "./add-item-dialog" // 주석처리 + +interface TechVendorPossibleItemsTableProps { + promises: Promise< + [ + Awaited>, + ] + > + vendorId: number +} + +export function TechVendorPossibleItemsTable({ + promises, + vendorId, +}: TechVendorPossibleItemsTableProps) { + // Suspense로 받아온 데이터 + const [{ data, pageCount }] = React.use(promises) + const [rowAction, setRowAction] = React.useState | null>(null) + const [showAddDialog, setShowAddDialog] = React.useState(false) // 주석처리 + const [showDeleteAlert, setShowDeleteAlert] = React.useState(false) + const [isDeleting, setIsDeleting] = React.useState(false) + + // vendor 정보와 items 다이얼로그 관련 상태 + const [vendorInfo, setVendorInfo] = React.useState<{ + id: number + vendorName: string + status: string + items: string | null + } | null>(null) + const [showItemsDialog, setShowItemsDialog] = React.useState(false) + const [isLoadingVendor, setIsLoadingVendor] = React.useState(false) + + // getColumns() 호출 시, setRowAction을 주입 + const columns = React.useMemo( + () => getColumns({ setRowAction }), + [setRowAction] + ) + + // vendor 정보 가져오기 + React.useEffect(() => { + async function fetchVendorInfo() { + try { + setIsLoadingVendor(true) + const vendorData = await getTechVendorDetailById(vendorId) + setVendorInfo(vendorData) + } catch (error) { + console.error("Error fetching vendor info:", error) + toast.error("벤더 정보를 불러오는데 실패했습니다") + } finally { + setIsLoadingVendor(false) + } + } + + fetchVendorInfo() + }, [vendorId]) + + // 단일 아이템 삭제 핸들러 + async function handleDeleteItem() { + if (!rowAction || rowAction.type !== "delete") return + + setIsDeleting(true) + try { + const { success, error } = await deleteTechVendorPossibleItem( + rowAction.row.original.id, + vendorId + ) + + if (!success) { + throw new Error(error) + } + + toast.success("아이템이 삭제되었습니다") + setShowDeleteAlert(false) + setRowAction(null) + } catch (err) { + toast.error(err instanceof Error ? err.message : "아이템 삭제 중 오류가 발생했습니다") + } finally { + setIsDeleting(false) + } + } + + const filterFields: DataTableFilterField[] = [ + { id: "vendorId", label: "벤더 ID" }, + { id: "techVendorType", label: "아이템 타입" }, + ] + + const advancedFilterFields: DataTableAdvancedFilterField[] = [ + { id: "vendorId", label: "벤더 ID", type: "number" }, + { id: "itemCode", label: "아이템 코드", type: "text" }, + { id: "workType", label: "공종", type: "text" }, + { id: "itemList", label: "아이템명", type: "text" }, + { id: "shipTypes", label: "선종", type: "text" }, + { id: "subItemList", label: "서브아이템", type: "text" }, + { id: "techVendorType", label: "아이템 타입", type: "text" }, + { id: "createdAt", label: "등록일", type: "date" }, + { id: "updatedAt", label: "수정일", type: "date" }, + ] + + const { table } = useDataTable({ + data: data as TechVendorPossibleItem[], // 타입 단언 추가 + columns, + pageCount, + filterFields, + enablePinning: true, + enableAdvancedFilter: true, + initialState: { + sorting: [{ id: "createdAt", desc: true }], + columnPinning: { right: ["actions"] }, + }, + getRowId: (originalRow) => String(originalRow.id), + shallow: false, + clearOnDefault: true, + }) + + // rowAction 상태 변경 감지 + React.useEffect(() => { + if (rowAction?.type === "delete") { + setShowDeleteAlert(true) + } + }, [rowAction]) + + // 견적비교용 벤더인지 확인 + const isQuoteComparisonVendor = vendorInfo?.status === "QUOTE_COMPARISON" + + + return ( + <> + + +
+ {/* 견적비교용 벤더일 때만 items 버튼 표시 */} + {isQuoteComparisonVendor && ( + + )} + + setShowAddDialog(true)} // 주석처리 + /> +
+
+
+ + {/* Add Item Dialog */} + + + {/* Vendor Items Dialog */} + + + + 벤더 수기입력 자재 항목 + + {vendorInfo?.vendorName} 벤더가 직접 입력한 자재 항목입니다. + + + + + {vendorInfo?.items && vendorInfo.items.length > 0 ? ( +
+

+ {vendorInfo.items} +

+
+ ) : ( +
+

등록된 수기입력 자재 항목이 없습니다.

+
+ )} +
+
+
+ + {/* Delete Confirmation Dialog */} + + + + 아이템 삭제 + + 이 아이템을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다. + + + + setRowAction(null)}> + 취소 + + + {isDeleting ? "삭제 중..." : "삭제"} + + + + + + ) } \ No newline at end of file -- cgit v1.2.3