diff options
Diffstat (limited to 'lib/incoterms')
| -rw-r--r-- | lib/incoterms/table/delete-incoterms-dialog.tsx | 154 | ||||
| -rw-r--r-- | lib/incoterms/table/incoterms-add-dialog.tsx | 12 | ||||
| -rw-r--r-- | lib/incoterms/table/incoterms-edit-sheet.tsx | 60 | ||||
| -rw-r--r-- | lib/incoterms/table/incoterms-table-columns.tsx | 206 | ||||
| -rw-r--r-- | lib/incoterms/table/incoterms-table-toolbar.tsx | 41 | ||||
| -rw-r--r-- | lib/incoterms/table/incoterms-table.tsx | 102 |
6 files changed, 444 insertions, 131 deletions
diff --git a/lib/incoterms/table/delete-incoterms-dialog.tsx b/lib/incoterms/table/delete-incoterms-dialog.tsx new file mode 100644 index 00000000..8b91033c --- /dev/null +++ b/lib/incoterms/table/delete-incoterms-dialog.tsx @@ -0,0 +1,154 @@ +"use client" + +import * as React from "react" +import { type Row } from "@tanstack/react-table" +import { Loader, Trash } from "lucide-react" +import { toast } from "sonner" + +import { useMediaQuery } from "@/hooks/use-media-query" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer" + +import { deleteIncoterm } from "../service" +import { incoterms } from "@/db/schema/procurementRFQ" + +interface DeleteIncotermsDialogProps + extends React.ComponentPropsWithoutRef<typeof Dialog> { + incoterms: Row<typeof incoterms.$inferSelect>["original"][] + showTrigger?: boolean + onSuccess?: () => void +} + +export function DeleteIncotermsDialog({ + incoterms, + showTrigger = true, + onSuccess, + ...props +}: DeleteIncotermsDialogProps) { + const [isDeletePending, startDeleteTransition] = React.useTransition() + const isDesktop = useMediaQuery("(min-width: 640px)") + + function onDelete() { + startDeleteTransition(async () => { + try { + // 각 인코텀즈를 순차적으로 삭제 + for (const incoterm of incoterms) { + const result = await deleteIncoterm(incoterm.code) + if (!result.success) { + toast.error(`인코텀즈 ${incoterm.code} 삭제 실패: ${result.error}`) + return + } + } + + props.onOpenChange?.(false) + toast.success("인코텀즈가 성공적으로 삭제되었습니다.") + onSuccess?.() + } catch (error) { + console.error("Delete error:", error) + toast.error("인코텀즈 삭제 중 오류가 발생했습니다.") + } + }) + } + + if (isDesktop) { + return ( + <Dialog {...props}> + {showTrigger ? ( + <DialogTrigger asChild> + <Button variant="outline" size="sm"> + <Trash className="mr-2 size-4" aria-hidden="true" /> + delete ({incoterms.length}) + </Button> + </DialogTrigger> + ) : null} + <DialogContent> + <DialogHeader> + <DialogTitle>정말로 삭제하시겠습니까?</DialogTitle> + <DialogDescription> + 이 작업은 되돌릴 수 없습니다. 선택된{" "} + <span className="font-medium">{incoterms.length}</span> + 개의 인코텀즈를 서버에서 영구적으로 삭제합니다. + </DialogDescription> + </DialogHeader> + <DialogFooter className="gap-2 sm:space-x-0"> + <DialogClose asChild> + <Button variant="outline">취소</Button> + </DialogClose> + <Button + aria-label="선택된 행 삭제" + variant="destructive" + onClick={onDelete} + disabled={isDeletePending} + > + {isDeletePending && ( + <Loader + className="mr-2 size-4 animate-spin" + aria-hidden="true" + /> + )} + 삭제 + </Button> + </DialogFooter> + </DialogContent> + </Dialog> + ) + } + + return ( + <Drawer {...props}> + {showTrigger ? ( + <DrawerTrigger asChild> + <Button variant="outline" size="sm"> + <Trash className="mr-2 size-4" aria-hidden="true" /> + delete ({incoterms.length}) + </Button> + </DrawerTrigger> + ) : null} + <DrawerContent> + <DrawerHeader> + <DrawerTitle>정말로 삭제하시겠습니까?</DrawerTitle> + <DrawerDescription> + 이 작업은 되돌릴 수 없습니다. 선택된{" "} + <span className="font-medium">{incoterms.length}</span> + 개의 인코텀즈를 서버에서 영구적으로 삭제합니다. + </DrawerDescription> + </DrawerHeader> + <DrawerFooter className="gap-2 sm:space-x-0"> + <DrawerClose asChild> + <Button variant="outline">취소</Button> + </DrawerClose> + <Button + aria-label="선택된 행 삭제" + variant="destructive" + onClick={onDelete} + disabled={isDeletePending} + > + {isDeletePending && ( + <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" /> + )} + delete + </Button> + </DrawerFooter> + </DrawerContent> + </Drawer> + ) +}
\ No newline at end of file diff --git a/lib/incoterms/table/incoterms-add-dialog.tsx b/lib/incoterms/table/incoterms-add-dialog.tsx index ef378e1e..0f7384d6 100644 --- a/lib/incoterms/table/incoterms-add-dialog.tsx +++ b/lib/incoterms/table/incoterms-add-dialog.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { z } from "zod"; +import * as z from "zod"; import { Plus, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -70,7 +70,8 @@ export function IncotermsAddDialog({ onSuccess }: IncotermsAddDialogProps) { try { const result = await createIncoterm(data); if (result.data) { - toast.success("인코텀즈가 추가되었습니다."); + toast.success("인코텀즈가 성공적으로 추가되었습니다."); + form.reset(); setOpen(false); if (onSuccess) { onSuccess(); @@ -89,16 +90,17 @@ export function IncotermsAddDialog({ onSuccess }: IncotermsAddDialogProps) { return ( <Dialog open={open} onOpenChange={handleOpenChange}> <DialogTrigger asChild> - <Button size="sm" variant="outline"> + <Button variant="outline" size="sm"> <Plus className="mr-2 h-4 w-4" /> 인코텀즈 추가 </Button> </DialogTrigger> <DialogContent className="max-w-md"> <DialogHeader> - <DialogTitle>인코텀즈 추가</DialogTitle> + <DialogTitle>새 인코텀즈 추가</DialogTitle> <DialogDescription> 새로운 인코텀즈를 추가합니다. 필수 정보를 입력해주세요. + <span className="text-red-500 mt-1 block text-sm">* 표시된 항목은 필수 입력사항입니다.</span> </DialogDescription> </DialogHeader> @@ -153,7 +155,7 @@ export function IncotermsAddDialog({ onSuccess }: IncotermsAddDialogProps) { disabled={isLoading} > {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} - {isLoading ? "생성 중..." : "인코텀즈 추가"} + {isLoading ? "생성 중..." : "추가"} </Button> </DialogFooter> </DialogContent> diff --git a/lib/incoterms/table/incoterms-edit-sheet.tsx b/lib/incoterms/table/incoterms-edit-sheet.tsx index 9cd067c7..1ae6e902 100644 --- a/lib/incoterms/table/incoterms-edit-sheet.tsx +++ b/lib/incoterms/table/incoterms-edit-sheet.tsx @@ -5,6 +5,8 @@ import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { toast } from "sonner" import * as z from "zod" +import { Loader } from "lucide-react" + import { Button } from "@/components/ui/button" import { Form, @@ -16,8 +18,10 @@ import { } from "@/components/ui/form" import { Sheet, + SheetClose, SheetContent, SheetDescription, + SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" @@ -37,7 +41,7 @@ type UpdateIncotermSchema = z.infer<typeof updateIncotermSchema> interface IncotermsEditSheetProps { open: boolean onOpenChange: (open: boolean) => void - data: typeof incoterms.$inferSelect + data: typeof incoterms.$inferSelect | null onSuccess: () => void } @@ -47,12 +51,14 @@ export function IncotermsEditSheet({ data, onSuccess, }: IncotermsEditSheetProps) { + const [isUpdatePending, startUpdateTransition] = React.useTransition() + const form = useForm<UpdateIncotermSchema>({ resolver: zodResolver(updateIncotermSchema), defaultValues: { - code: data.code, - description: data.description, - isActive: data.isActive, + code: data?.code ?? "", + description: data?.description ?? "", + isActive: data?.isActive ?? true, }, mode: "onChange" }) @@ -68,14 +74,19 @@ export function IncotermsEditSheet({ }, [data, form]) async function onSubmit(input: UpdateIncotermSchema) { - try { - await updateIncoterm(data.code, input) - toast.success("수정이 완료되었습니다.") - onSuccess() - onOpenChange(false) - } catch { - toast.error("수정 중 오류가 발생했습니다.") - } + if (!data) return + + startUpdateTransition(async () => { + try { + await updateIncoterm(data.code, input) + toast.success("인코텀즈가 성공적으로 수정되었습니다.") + onSuccess() + onOpenChange(false) + } catch (error) { + console.error("Update error:", error) + toast.error("인코텀즈 수정 중 오류가 발생했습니다.") + } + }) } return ( @@ -96,7 +107,7 @@ export function IncotermsEditSheet({ <FormItem> <FormLabel>코드</FormLabel> <FormControl> - <Input {...field} disabled /> + <Input {...field} /> </FormControl> <FormMessage /> </FormItem> @@ -132,12 +143,25 @@ export function IncotermsEditSheet({ </FormItem> )} /> - <div className="flex justify-end space-x-2"> - <Button type="button" variant="outline" onClick={() => onOpenChange(false)}> - 취소 + <SheetFooter className="gap-2 pt-2 sm:space-x-0"> + <SheetClose asChild> + <Button type="button" variant="outline"> + 취소 + </Button> + </SheetClose> + <Button + type="submit" + disabled={isUpdatePending || !form.formState.isValid} + > + {isUpdatePending && ( + <Loader + className="mr-2 size-4 animate-spin" + aria-hidden="true" + /> + )} + 저장 </Button> - <Button type="submit">저장</Button> - </div> + </SheetFooter> </form> </Form> </SheetContent> diff --git a/lib/incoterms/table/incoterms-table-columns.tsx b/lib/incoterms/table/incoterms-table-columns.tsx index 56a44e8b..91ce4482 100644 --- a/lib/incoterms/table/incoterms-table-columns.tsx +++ b/lib/incoterms/table/incoterms-table-columns.tsx @@ -1,76 +1,71 @@ -import type { ColumnDef, Row } from "@tanstack/react-table"; -import { Button } from "@/components/ui/button"; -import { Badge } from "@/components/ui/badge"; -import { Ellipsis } from "lucide-react"; +"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 { formatDateTime } 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, DropdownMenuSeparator, + DropdownMenuShortcut, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { incoterms } from "@/db/schema/procurementRFQ"; -import { toast } from "sonner"; -import { deleteIncoterm } from "../service"; +} from "@/components/ui/dropdown-menu" -type Incoterm = typeof incoterms.$inferSelect; +import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" +import { incoterms } from "@/db/schema/procurementRFQ" interface GetColumnsProps { - setRowAction: (action: { type: string; row: Row<Incoterm> }) => void; - onSuccess: () => void; + setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<typeof incoterms.$inferSelect> | null>> } -const handleDelete = async (code: string, onSuccess: () => void) => { - const result = await deleteIncoterm(code); - if (result.success) { - toast.success("삭제 완료"); - onSuccess(); - } else { - toast.error(result.error || "삭제 실패"); +/** + * tanstack table 컬럼 정의 + */ +export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<typeof incoterms.$inferSelect>[] { + // ---------------------------------------------------------------- + // 1) select 컬럼 (체크박스) + // ---------------------------------------------------------------- + const selectColumn: ColumnDef<typeof incoterms.$inferSelect> = { + id: "select", + header: ({ table }) => ( + <Checkbox + checked={ + table.getIsAllPageRowsSelected() || + (table.getIsSomePageRowsSelected() && "indeterminate") + } + onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + className="translate-y-0.5" + /> + ), + cell: ({ row }) => ( + <Checkbox + checked={row.getIsSelected()} + onCheckedChange={(value) => row.toggleSelected(!!value)} + aria-label="Select row" + className="translate-y-0.5" + /> + ), + maxSize: 30, + enableSorting: false, + enableHiding: false, } -}; -export function getColumns({ setRowAction, onSuccess }: GetColumnsProps): ColumnDef<Incoterm>[] { - return [ - { - id: "code", - header: () => <div>코드</div>, - cell: ({ row }) => <div>{row.original.code}</div>, - enableSorting: true, - enableHiding: false, - }, - { - id: "description", - header: () => <div>설명</div>, - cell: ({ row }) => <div>{row.original.description}</div>, - enableSorting: true, - enableHiding: false, - }, - { - id: "isActive", - header: () => <div>상태</div>, - cell: ({ row }) => ( - <Badge variant={row.original.isActive ? "default" : "secondary"}> - {row.original.isActive ? "활성" : "비활성"} - </Badge> - ), - enableSorting: true, - enableHiding: false, - }, - { - id: "createdAt", - header: () => <div>생성일</div>, - cell: ({ row }) => { - const value = row.original.createdAt; - const date = value ? new Date(value) : null; - return date ? date.toLocaleDateString() : ""; - }, - enableSorting: true, - enableHiding: false, - }, - { - id: "actions", - cell: ({ row }) => ( + // ---------------------------------------------------------------- + // 2) actions 컬럼 (Dropdown 메뉴) + // ---------------------------------------------------------------- + const actionsColumn: ColumnDef<typeof incoterms.$inferSelect> = { + id: "actions", + enableHiding: false, + cell: function Cell({ row }) { + return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button @@ -83,20 +78,99 @@ export function getColumns({ setRowAction, onSuccess }: GetColumnsProps): Column </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-40"> <DropdownMenuItem - onSelect={() => setRowAction({ type: "edit", row })} + onSelect={() => setRowAction({ row, type: "update" })} > - 수정 + Edit </DropdownMenuItem> + <DropdownMenuSeparator /> <DropdownMenuItem - onSelect={() => handleDelete(row.original.code, onSuccess)} - className="text-destructive" + onSelect={() => setRowAction({ row, type: "delete" })} > - 삭제 + Delete + <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut> </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> + ) + }, + maxSize: 30, + } + + // ---------------------------------------------------------------- + // 3) 데이터 컬럼들 + // ---------------------------------------------------------------- + const dataColumns: ColumnDef<typeof incoterms.$inferSelect>[] = [ + { + accessorKey: "code", + enableResizing: true, + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="코드" /> + ), + meta: { + excelHeader: "코드", + type: "text", + }, + cell: ({ row }) => row.getValue("code") ?? "", + minSize: 80 + }, + { + accessorKey: "description", + enableResizing: true, + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="설명" /> ), + meta: { + excelHeader: "설명", + type: "text", + }, + cell: ({ row }) => row.getValue("description") ?? "", + minSize: 80 }, - ]; + { + accessorKey: "isActive", + enableResizing: true, + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="상태" /> + ), + meta: { + excelHeader: "상태", + type: "boolean", + }, + cell: ({ row }) => { + const isActive = row.getValue("isActive") as boolean + return ( + <Badge variant={isActive ? "default" : "secondary"}> + {isActive ? "활성" : "비활성"} + </Badge> + ) + }, + minSize: 80 + }, + { + accessorKey: "createdAt", + enableResizing: true, + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="생성일" /> + ), + meta: { + excelHeader: "생성일", + type: "date", + }, + cell: ({ row }) => { + const dateVal = row.getValue("createdAt") as Date + return formatDateTime(dateVal) + }, + minSize: 80 + } + ] + + // ---------------------------------------------------------------- + // 4) 최종 컬럼 배열: select, dataColumns, actions + // ---------------------------------------------------------------- + return [ + selectColumn, + ...dataColumns, + actionsColumn, + ] }
\ No newline at end of file diff --git a/lib/incoterms/table/incoterms-table-toolbar.tsx b/lib/incoterms/table/incoterms-table-toolbar.tsx index b87982c9..698acf59 100644 --- a/lib/incoterms/table/incoterms-table-toolbar.tsx +++ b/lib/incoterms/table/incoterms-table-toolbar.tsx @@ -1,16 +1,53 @@ "use client"; import * as React from "react"; +import { type Table } from "@tanstack/react-table"; +import { Download } from "lucide-react"; + +import { exportTableToExcel } from "@/lib/export"; +import { Button } from "@/components/ui/button"; +import { DeleteIncotermsDialog } from "./delete-incoterms-dialog"; import { IncotermsAddDialog } from "./incoterms-add-dialog"; +import { incoterms } from "@/db/schema/procurementRFQ"; -interface IncotermsTableToolbarProps { +interface IncotermsTableToolbarActionsProps { + table: Table<typeof incoterms.$inferSelect>; onSuccess?: () => void; } -export function IncotermsTableToolbar({ onSuccess }: IncotermsTableToolbarProps) { +export function IncotermsTableToolbarActions({ table, onSuccess }: IncotermsTableToolbarActionsProps) { return ( <div className="flex items-center gap-2"> + {/** 1) 선택된 로우가 있으면 삭제 다이얼로그 */} + {table.getFilteredSelectedRowModel().rows.length > 0 ? ( + <DeleteIncotermsDialog + incoterms={table + .getFilteredSelectedRowModel() + .rows.map((row) => row.original)} + onSuccess={() => { + table.toggleAllRowsSelected(false); + onSuccess?.(); + }} + /> + ) : null} + <IncotermsAddDialog onSuccess={onSuccess} /> + + {/** 3) Export 버튼 */} + <Button + variant="outline" + size="sm" + onClick={() => + exportTableToExcel(table, { + filename: "incoterms-list", + excludeColumns: ["select", "actions"], + }) + } + className="gap-2" + > + <Download className="size-4" aria-hidden="true" /> + <span className="hidden sm:inline">Export</span> + </Button> </div> ); }
\ No newline at end of file diff --git a/lib/incoterms/table/incoterms-table.tsx b/lib/incoterms/table/incoterms-table.tsx index c5b5bba4..c98de810 100644 --- a/lib/incoterms/table/incoterms-table.tsx +++ b/lib/incoterms/table/incoterms-table.tsx @@ -3,13 +3,16 @@ import * as React from "react"; 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 type { + DataTableAdvancedFilterField, + DataTableRowAction, +} from "@/types/table" +import { getIncoterms } from "../service"; import { getColumns } from "./incoterms-table-columns"; -import { incoterms } from "@/db/schema/procurementRFQ"; -import { IncotermsTableToolbar } from "./incoterms-table-toolbar"; -import { toast } from "sonner"; +import { DeleteIncotermsDialog } from "./delete-incoterms-dialog"; import { IncotermsEditSheet } from "./incoterms-edit-sheet"; -import { Row } from "@tanstack/react-table"; -import { getIncoterms } from "../service"; +import { IncotermsTableToolbarActions } from "./incoterms-table-toolbar"; +import { incoterms } from "@/db/schema/procurementRFQ"; interface IncotermsTableProps { promises?: Promise<[{ data: typeof incoterms.$inferSelect[]; pageCount: number }] >; @@ -17,8 +20,7 @@ interface IncotermsTableProps { export function IncotermsTable({ promises }: IncotermsTableProps) { const [rawData, setRawData] = React.useState<{ data: typeof incoterms.$inferSelect[]; pageCount: number }>({ data: [], pageCount: 0 }); - const [isEditSheetOpen, setIsEditSheetOpen] = React.useState(false); - const [selectedRow, setSelectedRow] = React.useState<typeof incoterms.$inferSelect | null>(null); + const [rowAction, setRowAction] = React.useState<DataTableRowAction<typeof incoterms.$inferSelect> | null>(null); React.useEffect(() => { if (promises) { @@ -44,7 +46,6 @@ export function IncotermsTable({ promises }: IncotermsTableProps) { setRawData(result); } catch (error) { console.error("Error refreshing data:", error); - toast.error("데이터를 불러오는 중 오류가 발생했습니다."); } })(); } @@ -67,50 +68,71 @@ export function IncotermsTable({ promises }: IncotermsTableProps) { setRawData(result); } catch (error) { console.error("Error refreshing data:", error); - toast.error("데이터를 불러오는 중 오류가 발생했습니다."); } }, []); - const handleRowAction = async (action: { type: string; row: Row<typeof incoterms.$inferSelect> }) => { - if (action.type === "edit") { - setSelectedRow(action.row.original); - setIsEditSheetOpen(true); - } - }; + // 컬럼 설정 - 외부 파일에서 가져옴 + const columns = React.useMemo( + () => getColumns({ setRowAction }), + [setRowAction] + ) - const columns = React.useMemo(() => getColumns({ setRowAction: handleRowAction, onSuccess: refreshData }), [refreshData]); + // 고급 필터 필드 설정 + const advancedFilterFields: DataTableAdvancedFilterField<typeof incoterms.$inferSelect>[] = [ + { id: "code", label: "코드", type: "text" }, + { + id: "isActive", label: "상태", type: "select", options: [ + { label: "활성", value: "true" }, + { label: "비활성", value: "false" }, + ] + }, + { id: "description", label: "설명", type: "text" }, + { id: "createdAt", label: "생성일", type: "date" }, + ]; const { table } = useDataTable({ - data: rawData.data, - columns, - pageCount: rawData.pageCount, - filterFields: [], - enablePinning: true, - enableAdvancedFilter: true, - initialState: { - sorting: [{ id: "createdAt", desc: true }], - columnPinning: { right: ["actions"] }, - }, - getRowId: (originalRow) => String(originalRow.code), - shallow: false, - clearOnDefault: true, - }); + data: rawData.data, + columns, + pageCount: rawData.pageCount, + enablePinning: true, + enableAdvancedFilter: true, + initialState: { + sorting: [{ id: "createdAt", desc: true }], + columnPinning: { right: ["actions"] }, + }, + getRowId: (originalRow) => String(originalRow.code), + shallow: false, + clearOnDefault: true, + }) return ( <> <DataTable table={table}> - <DataTableAdvancedToolbar table={table} filterFields={[]} shallow={false}> - <IncotermsTableToolbar onSuccess={refreshData} /> + <DataTableAdvancedToolbar + table={table} + filterFields={advancedFilterFields} + > + <IncotermsTableToolbarActions table={table} onSuccess={refreshData} /> </DataTableAdvancedToolbar> </DataTable> - {isEditSheetOpen && selectedRow && ( - <IncotermsEditSheet - open={isEditSheetOpen} - onOpenChange={setIsEditSheetOpen} - data={selectedRow} - onSuccess={refreshData} - /> - )} + + <DeleteIncotermsDialog + open={rowAction?.type === "delete"} + onOpenChange={() => setRowAction(null)} + incoterms={rowAction?.row.original ? [rowAction?.row.original] : []} + showTrigger={false} + onSuccess={() => { + rowAction?.row.toggleSelected(false) + refreshData() + }} + /> + + <IncotermsEditSheet + open={rowAction?.type === "update"} + onOpenChange={() => setRowAction(null)} + data={rowAction?.row.original ?? null} + onSuccess={refreshData} + /> </> ); }
\ No newline at end of file |
