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/add-item-dialog.tsx | 29 +- .../possible-items/possible-items-columns.tsx | 470 ++++++++++++--------- .../possible-items/possible-items-table.tsx | 425 +++++++++++-------- .../possible-items-toolbar-actions.tsx | 235 +++++------ 4 files changed, 651 insertions(+), 508 deletions(-) (limited to 'lib/tech-vendors/possible-items') diff --git a/lib/tech-vendors/possible-items/add-item-dialog.tsx b/lib/tech-vendors/possible-items/add-item-dialog.tsx index ef15a5ce..0e6edd19 100644 --- a/lib/tech-vendors/possible-items/add-item-dialog.tsx +++ b/lib/tech-vendors/possible-items/add-item-dialog.tsx @@ -27,6 +27,7 @@ interface ItemData { workType: string | null; shipTypes?: string | null; subItemList?: string | null; + itemType: "SHIP" | "TOP" | "HULL"; createdAt: Date; updatedAt: Date; } @@ -80,7 +81,7 @@ export function AddItemDialog({ open, onOpenChange, vendorId }: AddItemDialogPro console.log("Loaded items:", result.data.length, result.data); // itemCode가 null이 아닌 항목만 필터링 const validItems = result.data.filter(item => item.itemCode != null); - setItems(validItems); + setItems(validItems as ItemData[]); } catch (error) { console.error("Failed to load items:", error); toast.error("아이템 목록을 불러오는데 실패했습니다."); @@ -93,13 +94,13 @@ export function AddItemDialog({ open, onOpenChange, vendorId }: AddItemDialogPro if (!item.itemCode) return; // itemCode가 null인 경우 처리하지 않음 setSelectedItems(prev => { - // itemCode + shipTypes 조합으로 중복 체크 + // id + itemType 조합으로 중복 체크 const isSelected = prev.some(i => - i.itemCode === item.itemCode && i.shipTypes === item.shipTypes + i.id === item.id && i.itemType === item.itemType ); if (isSelected) { return prev.filter(i => - !(i.itemCode === item.itemCode && i.shipTypes === item.shipTypes) + !(i.id === item.id && i.itemType === item.itemType) ); } else { return [...prev, item]; @@ -120,11 +121,8 @@ export function AddItemDialog({ open, onOpenChange, vendorId }: AddItemDialogPro const result = await addTechVendorPossibleItem({ vendorId: vendorId, - itemCode: item.itemCode, - workType: item.workType || undefined, - shipTypes: item.shipTypes || undefined, - itemList: item.itemList || undefined, - subItemList: item.subItemList || undefined, + itemId: item.id, + itemType: item.itemType, }); if (result.success) { @@ -197,10 +195,11 @@ export function AddItemDialog({ open, onOpenChange, vendorId }: AddItemDialogPro
{selectedItems.map((item) => { if (!item.itemCode) return null; - const itemKey = `${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`; + const itemKey = `${item.itemType}-${item.id}-${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`; + const displayText = `[${item.itemType}] ${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`; return ( - {itemKey} + {displayText} { @@ -232,11 +231,11 @@ export function AddItemDialog({ open, onOpenChange, vendorId }: AddItemDialogPro filteredItems.map((item) => { if (!item.itemCode) return null; // itemCode가 null인 경우 렌더링하지 않음 - // itemCode + shipTypes 조합으로 선택 여부 체크 + // id + itemType 조합으로 선택 여부 체크 const isSelected = selectedItems.some(i => - i.itemCode === item.itemCode && i.shipTypes === item.shipTypes + i.id === item.id && i.itemType === item.itemType ); - const itemKey = `${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`; + const itemKey = `${item.itemType}-${item.id}-${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`; return (
handleItemToggle(item)} >
- {itemKey} + {`[${item.itemType}] ${item.itemCode}${item.shipTypes ? `-${item.shipTypes}` : ''}`}
{item.itemList || "-"} diff --git a/lib/tech-vendors/possible-items/possible-items-columns.tsx b/lib/tech-vendors/possible-items/possible-items-columns.tsx index ef48c5b5..252dae9b 100644 --- a/lib/tech-vendors/possible-items/possible-items-columns.tsx +++ b/lib/tech-vendors/possible-items/possible-items-columns.tsx @@ -1,206 +1,266 @@ -"use client" - -import * as React from "react" -import { type DataTableRowAction } from "@/types/table" -import { type ColumnDef } from "@tanstack/react-table" -import { Ellipsis } from "lucide-react" - -import { formatDate } from "@/lib/utils" -import { Badge } from "@/components/ui/badge" -import { Button } from "@/components/ui/button" -import { Checkbox } from "@/components/ui/checkbox" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuShortcut, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" - -import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" -import type { TechVendorPossibleItem } from "../validations" - -interface GetColumnsProps { - setRowAction: React.Dispatch | null>>; -} - -export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { - return [ - // 선택 체크박스 - { - id: "select", - header: ({ table }) => ( - table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all" - className="translate-y-0.5" - /> - ), - cell: ({ row }) => ( - row.toggleSelected(!!value)} - aria-label="Select row" - className="translate-y-0.5" - /> - ), - size: 40, - enableSorting: false, - enableHiding: false, - }, - - // 아이템 코드 - { - accessorKey: "itemCode", - header: ({ column }) => ( - - ), - cell: ({ row }) => ( -
- {row.getValue("itemCode")} -
- ), - size: 150, - }, - - // 공종 - { - accessorKey: "workType", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const workType = row.getValue("workType") as string | null - return workType ? ( - - {workType} - - ) : ( - - - ) - }, - size: 100, - }, - - // 아이템명 - { - accessorKey: "itemList", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const itemList = row.getValue("itemList") as string | null - return ( -
- {itemList || -} -
- ) - }, - size: 300, - }, - - // 선종 (조선용) - { - accessorKey: "shipTypes", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const shipTypes = row.getValue("shipTypes") as string | null - return shipTypes ? ( - - {shipTypes} - - ) : ( - - - ) - }, - size: 120, - }, - - // 서브아이템 (해양용) - { - accessorKey: "subItemList", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const subItemList = row.getValue("subItemList") as string | null - return ( -
- {subItemList || -} -
- ) - }, - size: 200, - }, - - // 등록일 - { - accessorKey: "createdAt", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const date = row.getValue("createdAt") as Date - return ( -
- {formatDate(date)} -
- ) - }, - size: 120, - }, - - // 수정일 - { - accessorKey: "updatedAt", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const date = row.getValue("updatedAt") as Date - return ( -
- {formatDate(date)} -
- ) - }, - size: 120, - }, - - // 액션 메뉴 - { - id: "actions", - enableHiding: false, - cell: function Cell({ row }) { - return ( - - - - - - setRowAction({ row, type: "delete" })} - > - 삭제 - ⌘⌫ - - - - ) - }, - size: 40, - }, - ] +"use client" + +import * as React from "react" +import { type DataTableRowAction } from "@/types/table" +import { type ColumnDef } from "@tanstack/react-table" +import { Ellipsis } from "lucide-react" + +import { formatDate } from "@/lib/utils" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Checkbox } from "@/components/ui/checkbox" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import type { TechVendorPossibleItem } from "../validations" + +interface GetColumnsProps { + setRowAction: React.Dispatch | null>>; +} + +export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { + return [ + // 선택 체크박스 + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + className="translate-y-0.5" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + className="translate-y-0.5" + /> + ), + size: 40, + enableSorting: false, + enableHiding: false, + }, + + // 아이템 코드 + { + accessorKey: "itemCode", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const itemCode = row.getValue("itemCode") as string | undefined + return ( +
+ {itemCode || -} +
+ ) + }, + size: 150, + }, + + // // 타입 + // { + // accessorKey: "techVendorType", + // header: ({ column }) => ( + // + // ), + // cell: ({ row }) => { + // const techVendorType = row.getValue("techVendorType") as string | undefined + + // // 벤더 타입 파싱 개선 - null/undefined 안전 처리 + // let types: string[] = []; + // if (!techVendorType) { + // types = []; + // } else if (techVendorType.startsWith('[') && techVendorType.endsWith(']')) { + // // JSON 배열 형태 + // try { + // const parsed = JSON.parse(techVendorType); + // types = Array.isArray(parsed) ? parsed.filter(Boolean) : [techVendorType]; + // } catch { + // types = [techVendorType]; + // } + // } else if (techVendorType.includes(',')) { + // // 콤마로 구분된 문자열 + // types = techVendorType.split(',').map(t => t.trim()).filter(Boolean); + // } else { + // // 단일 문자열 + // types = [techVendorType.trim()].filter(Boolean); + // } + + // // 벤더 타입 정렬 - 조선 > 해양TOP > 해양HULL 순 + // const typeOrder = ["조선", "해양TOP", "해양HULL"]; + // types.sort((a, b) => { + // const indexA = typeOrder.indexOf(a); + // const indexB = typeOrder.indexOf(b); + + // // 정의된 순서에 있는 경우 우선순위 적용 + // if (indexA !== -1 && indexB !== -1) { + // return indexA - indexB; + // } + // return a.localeCompare(b); + // }); + + // return ( + //
+ // {types.length > 0 ? types.map((type, index) => ( + // + // {type} + // + // )) : ( + // - + // )} + //
+ // ) + // }, + // size: 120, + // }, + + // 공종 + { + accessorKey: "workType", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const workType = row.getValue("workType") as string | null + return workType ? ( + + {workType} + + ) : ( + - + ) + }, + size: 100, + }, + + // 아이템명 + { + accessorKey: "itemList", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const itemList = row.getValue("itemList") as string | null + return ( +
+ {itemList || -} +
+ ) + }, + size: 300, + }, + + // 선종 (조선용) + { + accessorKey: "shipTypes", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const shipTypes = row.getValue("shipTypes") as string | null + return shipTypes ? ( + + {shipTypes} + + ) : ( + - + ) + }, + size: 120, + }, + + // 서브아이템 (해양용) + { + accessorKey: "subItemList", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const subItemList = row.getValue("subItemList") as string | null + return ( +
+ {subItemList || -} +
+ ) + }, + size: 200, + }, + + // 등록일 + { + accessorKey: "createdAt", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const date = row.getValue("createdAt") as Date + return ( +
+ {formatDate(date, "ko-KR")} +
+ ) + }, + size: 120, + }, + + // 수정일 + { + accessorKey: "updatedAt", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const date = row.getValue("updatedAt") as Date + return ( +
+ {formatDate(date, "ko-KR")} +
+ ) + }, + size: 120, + }, + + // 액션 메뉴 + { + id: "actions", + enableHiding: false, + cell: function Cell({ row }) { + return ( + + + + + + setRowAction({ row, type: "delete" })} + > + 삭제 + ⌘⌫ + + + + ) + }, + size: 40, + }, + ] } \ No newline at end of file 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 diff --git a/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx b/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx index 074dc187..192bf614 100644 --- a/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx +++ b/lib/tech-vendors/possible-items/possible-items-toolbar-actions.tsx @@ -1,119 +1,118 @@ -"use client" - -import * as React from "react" -import type { Table } from "@tanstack/react-table" -import { Plus, Trash2 } from "lucide-react" -import { toast } from "sonner" - -import { Button } from "@/components/ui/button" -import { Separator } from "@/components/ui/separator" -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" - -import type { TechVendorPossibleItem } from "../validations" -import { deleteTechVendorPossibleItemsNew } from "../service" - -interface PossibleItemsTableToolbarActionsProps { - table: Table - vendorId: number - onAdd: () => void -} - -export function PossibleItemsTableToolbarActions({ - table, - vendorId, - onAdd, -}: PossibleItemsTableToolbarActionsProps) { - const [showDeleteAlert, setShowDeleteAlert] = React.useState(false) - const [isDeleting, setIsDeleting] = React.useState(false) - - const selectedRows = table.getFilteredSelectedRowModel().rows - - async function handleDelete() { - setIsDeleting(true) - try { - const ids = selectedRows.map((row) => row.original.id) - const { error } = await deleteTechVendorPossibleItemsNew(ids, vendorId) - - if (error) { - throw new Error(error) - } - - toast.success(`${ids.length}개의 아이템이 삭제되었습니다`) - table.resetRowSelection() - setShowDeleteAlert(false) - } catch { - toast.error("아이템 삭제 중 오류가 발생했습니다") - } finally { - setIsDeleting(false) - } - } - - return ( - <> -
- - - {selectedRows.length > 0 && ( - <> - - - - - - - 선택된 {selectedRows.length}개 아이템을 삭제합니다 - - - - )} -
- - - - - 아이템 삭제 - - 선택된 {selectedRows.length}개의 아이템을 삭제하시겠습니까? - 이 작업은 되돌릴 수 없습니다. - - - - 취소 - - {isDeleting ? "삭제 중..." : "삭제"} - - - - - - ) +"use client" + +import * as React from "react" +import type { Table } from "@tanstack/react-table" +import { Plus, Trash2 } from "lucide-react" +import { toast } from "sonner" + +import { Button } from "@/components/ui/button" +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" + +import type { TechVendorPossibleItem } from "../validations" +import { deleteTechVendorPossibleItemsNew } from "../service" + +interface PossibleItemsTableToolbarActionsProps { + table: Table + vendorId: number + onAdd: () => void // 주석처리 +} + +export function PossibleItemsTableToolbarActions({ + table, + vendorId, + onAdd, // 주석처리 +}: PossibleItemsTableToolbarActionsProps) { + const [showDeleteAlert, setShowDeleteAlert] = React.useState(false) + const [isDeleting, setIsDeleting] = React.useState(false) + + const selectedRows = table.getFilteredSelectedRowModel().rows + + async function handleDelete() { + setIsDeleting(true) + try { + const ids = selectedRows.map((row) => row.original.id) + const { error } = await deleteTechVendorPossibleItemsNew(ids, vendorId) + + if (error) { + throw new Error(error) + } + + toast.success(`${ids.length}개의 아이템이 삭제되었습니다`) + table.resetRowSelection() + setShowDeleteAlert(false) + } catch { + toast.error("아이템 삭제 중 오류가 발생했습니다") + } finally { + setIsDeleting(false) + } + } + + return ( + <> +
+ {/* 아이템 추가 버튼 주석처리 */} + + + {selectedRows.length > 0 && ( + <> + + + + + + 선택된 {selectedRows.length}개 아이템을 삭제합니다 + + + + )} +
+ + + + + 아이템 삭제 + + 선택된 {selectedRows.length}개의 아이템을 삭제하시겠습니까? + 이 작업은 되돌릴 수 없습니다. + + + + 취소 + + {isDeleting ? "삭제 중..." : "삭제"} + + + + + + ) } \ No newline at end of file -- cgit v1.2.3